Module: ActiveRecord::ConnectionAdapters::Duckdb::DatabaseStatements

Included in:
ActiveRecord::ConnectionAdapters::DuckdbAdapter
Defined in:
lib/active_record/connection_adapters/duckdb/database_statements.rb

Constant Summary collapse

READ_QUERY_PATTERN =

SQL statements that are considered read-only (SELECT, EXPLAIN, etc.)

/\A\s*(SELECT|SHOW|DESCRIBE|EXPLAIN|PRAGMA)\b/i

Instance Method Summary collapse

Instance Method Details

#affected_rows(raw_result) ⇒ Integer

Returns the number of affected rows from a raw DuckDB result. Required by Rails 8.0+ for exec_delete/exec_update via internal_execute. The base class calls affected_rows(raw_execute(...)) for DELETE/UPDATE operations.

Parameters:

  • raw_result (DuckDB::Result)

    The raw DuckDB result

Returns:

  • (Integer)

    Number of rows affected



92
93
94
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 92

def affected_rows(raw_result)
  raw_result.rows_changed
end

#begin_db_transactionvoid

This method returns an undefined value.

Begins a database transaction.



13
14
15
16
17
18
19
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 13

def begin_db_transaction
  log('BEGIN', 'TRANSACTION') do
    with_raw_connection do |conn|
      conn.query('BEGIN TRANSACTION')
    end
  end
end

#cast_result(result) ⇒ ActiveRecord::Result

Casts a DuckDB result to ActiveRecord::Result format. Used by Rails 8.0+ internal_exec_query which calls cast_result(raw_execute(...)). Also called by Rails 7.2's internal_exec_query implementation in DatabaseStatementsRails72.

Parameters:

  • result (DuckDB::Result, nil)

    The DuckDB result to cast

Returns:

  • (ActiveRecord::Result)

    The ActiveRecord-compatible result



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 71

def cast_result(result)
  return ActiveRecord::Result.empty if result.nil?

  columns = result.columns.map do |col|
    if col.respond_to?(:name)
      col.name
    elsif col.respond_to?(:column_name)
      col.column_name
    else
      col.to_s
    end
  end

  ActiveRecord::Result.new(columns, result.to_a)
end

#columns_for_insert(table_name) ⇒ Array<ActiveRecord::ConnectionAdapters::Column>

Returns columns that should be included in INSERT statements

Parameters:

  • table_name (String)

    The name of the table

Returns:

  • (Array<ActiveRecord::ConnectionAdapters::Column>)

    Columns to include in INSERT



99
100
101
102
103
104
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 99

def columns_for_insert(table_name)
  columns(table_name).reject do |column|
    # Exclude columns that have a default function (like nextval)
    column.default_function.present?
  end
end

#commit_db_transactionvoid

This method returns an undefined value.

Commits the current database transaction.



23
24
25
26
27
28
29
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 23

def commit_db_transaction
  log('COMMIT', 'TRANSACTION') do
    with_raw_connection do |conn|
      conn.query('COMMIT')
    end
  end
end

#exec_rollback_db_transactionvoid

This method returns an undefined value.

Rolls back the current database transaction.



33
34
35
36
37
38
39
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 33

def exec_rollback_db_transaction
  log('ROLLBACK', 'TRANSACTION') do
    with_raw_connection do |conn|
      conn.query('ROLLBACK')
    end
  end
end

#execute(sql, name = nil) ⇒ DuckDB::Result

Executes a SQL statement against the DuckDB database. Used for DDL and raw SQL execution.

Parameters:

  • sql (String)

    The SQL statement to execute

  • name (String, nil) (defaults to: nil)

    Optional name for logging purposes

Returns:

  • (DuckDB::Result)

    The result of the query execution



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 54

def execute(sql, name = nil) # :nodoc:
  # Check for write queries on read-only connections (replica support)
  # Rails 8.1+ uses ensure_writes_are_allowed, earlier versions use check_if_write_query
  ensure_write_query_allowed(sql)

  log(sql, name) do
    with_raw_connection do |conn|
      conn.query(sql)
    end
  end
end

#last_inserted_id(result) ⇒ Object

Extracts the last inserted ID from an insert result

Parameters:

  • result (ActiveRecord::Result)

    The result from an insert operation

Returns:

  • (Object)

    The last inserted ID value



118
119
120
121
122
123
124
125
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 118

def last_inserted_id(result)
  # Handle ActiveRecord::Result from RETURNING clause
  if result.is_a?(ActiveRecord::Result) && result.rows.any?
    id_value = result.rows.first.first
    return id_value
  end
  super
end

#return_value_after_insert?(column) ⇒ Boolean

Determines if a column value should be returned after insert This is crucial - it tells Rails which columns should use RETURNING

Parameters:

  • column (ActiveRecord::ConnectionAdapters::Column)

    The column to check

Returns:

  • (Boolean)

    true if column value should be returned after insert



110
111
112
113
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 110

def return_value_after_insert?(column)
  # Return true for any column with a sequence default
  column.default_function&.include?('nextval') || super
end

#write_query?(sql) ⇒ Boolean

Determines if a SQL query is a write operation (INSERT, UPDATE, DELETE, etc.) Used for read replica support and transaction tracking.

Parameters:

  • sql (String)

    The SQL query to check

Returns:

  • (Boolean)

    true if the query modifies data



45
46
47
# File 'lib/active_record/connection_adapters/duckdb/database_statements.rb', line 45

def write_query?(sql)
  !READ_QUERY_PATTERN.match?(sql)
end