activerecord 7.2.2.1 → 8.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +523 -677
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +1 -0
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +34 -10
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +10 -8
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +34 -4
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +37 -26
- data/lib/active_record/autosave_association.rb +91 -39
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +34 -25
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +55 -47
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +91 -44
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +40 -10
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +92 -70
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +35 -46
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +50 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +84 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -9
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +72 -43
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +60 -17
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +61 -99
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +80 -100
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +10 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +63 -17
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
- data/lib/active_record/connection_adapters.rb +0 -56
- data/lib/active_record/connection_handling.rb +35 -9
- data/lib/active_record/core.rb +57 -22
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +4 -0
- data/lib/active_record/database_configurations/hash_config.rb +16 -2
- data/lib/active_record/delegated_type.rb +18 -18
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encryptor.rb +37 -28
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +22 -34
- data/lib/active_record/errors.rb +16 -8
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +0 -2
- data/lib/active_record/future_result.rb +15 -9
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/insert_all.rb +3 -3
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -11
- data/lib/active_record/migration/command_recorder.rb +32 -12
- data/lib/active_record/migration/compatibility.rb +5 -2
- data/lib/active_record/migration.rb +40 -43
- data/lib/active_record/model_schema.rb +3 -4
- data/lib/active_record/nested_attributes.rb +4 -6
- data/lib/active_record/persistence.rb +128 -130
- data/lib/active_record/query_logs.rb +106 -50
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +12 -12
- data/lib/active_record/railtie.rb +4 -28
- data/lib/active_record/railties/databases.rake +11 -34
- data/lib/active_record/reflection.rb +18 -21
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +132 -72
- data/lib/active_record/relation/calculations.rb +71 -65
- data/lib/active_record/relation/delegation.rb +25 -14
- data/lib/active_record/relation/finder_methods.rb +32 -31
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +13 -0
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +121 -70
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +9 -3
- data/lib/active_record/relation.rb +95 -67
- data/lib/active_record/result.rb +66 -4
- data/lib/active_record/sanitization.rb +7 -6
- data/lib/active_record/schema_dumper.rb +34 -11
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +7 -6
- data/lib/active_record/statement_cache.rb +14 -14
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +1 -3
- data/lib/active_record/tasks/database_tasks.rb +69 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +9 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +12 -0
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transactions.rb +8 -7
- data/lib/active_record/type/serialized.rb +5 -0
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +22 -49
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/node.rb +1 -1
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +6 -2
- data/lib/arel/table.rb +3 -7
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -0
- data/lib/arel/visitors/to_sql.rb +3 -1
- metadata +11 -15
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -27,6 +27,7 @@ module ActiveRecord
|
|
|
27
27
|
col["name"]
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
where = where.sub(/\s*\/\*.*\*\/\z/, "") if where
|
|
30
31
|
orders = {}
|
|
31
32
|
|
|
32
33
|
if columns.any?(&:nil?) # index created with an expression
|
|
@@ -74,6 +75,7 @@ module ActiveRecord
|
|
|
74
75
|
Base.pluralize_table_names ? table.pluralize : table
|
|
75
76
|
end
|
|
76
77
|
table = strip_table_name_prefix_and_suffix(table)
|
|
78
|
+
options = options.slice(*fk.options.keys)
|
|
77
79
|
fk_to_table = strip_table_name_prefix_and_suffix(fk.to_table)
|
|
78
80
|
fk_to_table == table && options.all? { |k, v| fk.options[k].to_s == v.to_s }
|
|
79
81
|
end || raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
|
|
@@ -82,6 +84,10 @@ module ActiveRecord
|
|
|
82
84
|
alter_table(from_table, foreign_keys)
|
|
83
85
|
end
|
|
84
86
|
|
|
87
|
+
def virtual_table_exists?(table_name)
|
|
88
|
+
query_values(data_source_sql(table_name, type: "VIRTUAL TABLE"), "SCHEMA").any?
|
|
89
|
+
end
|
|
90
|
+
|
|
85
91
|
def check_constraints(table_name)
|
|
86
92
|
table_sql = query_value(<<-SQL, "SCHEMA")
|
|
87
93
|
SELECT sql
|
|
@@ -176,7 +182,8 @@ module ActiveRecord
|
|
|
176
182
|
scope = quoted_scope(name, type: type)
|
|
177
183
|
scope[:type] ||= "'table','view'"
|
|
178
184
|
|
|
179
|
-
sql = +"SELECT name FROM
|
|
185
|
+
sql = +"SELECT name FROM pragma_table_list WHERE schema <> 'temp'"
|
|
186
|
+
sql << " AND name NOT IN ('sqlite_sequence', 'sqlite_schema')"
|
|
180
187
|
sql << " AND name = #{scope[:name]}" if scope[:name]
|
|
181
188
|
sql << " AND type IN (#{scope[:type]})"
|
|
182
189
|
sql
|
|
@@ -189,6 +196,8 @@ module ActiveRecord
|
|
|
189
196
|
"'table'"
|
|
190
197
|
when "VIEW"
|
|
191
198
|
"'view'"
|
|
199
|
+
when "VIRTUAL TABLE"
|
|
200
|
+
"'virtual'"
|
|
192
201
|
end
|
|
193
202
|
scope = {}
|
|
194
203
|
scope[:name] = quote(name) if name
|
|
@@ -11,9 +11,12 @@ require "active_record/connection_adapters/sqlite3/schema_definitions"
|
|
|
11
11
|
require "active_record/connection_adapters/sqlite3/schema_dumper"
|
|
12
12
|
require "active_record/connection_adapters/sqlite3/schema_statements"
|
|
13
13
|
|
|
14
|
-
gem "sqlite3", ">= 1
|
|
14
|
+
gem "sqlite3", ">= 2.1"
|
|
15
15
|
require "sqlite3"
|
|
16
16
|
|
|
17
|
+
# Suppress the warning that SQLite3 issues when open writable connections are carried across fork()
|
|
18
|
+
SQLite3::ForkSafety.suppress_warnings!
|
|
19
|
+
|
|
17
20
|
module ActiveRecord
|
|
18
21
|
module ConnectionAdapters # :nodoc:
|
|
19
22
|
# = Active Record SQLite3 Adapter
|
|
@@ -21,7 +24,7 @@ module ActiveRecord
|
|
|
21
24
|
# The SQLite3 adapter works with the sqlite3-ruby drivers
|
|
22
25
|
# (available as gem from https://rubygems.org/gems/sqlite3).
|
|
23
26
|
#
|
|
24
|
-
# Options
|
|
27
|
+
# ==== Options
|
|
25
28
|
#
|
|
26
29
|
# * <tt>:database</tt> - Path to the database file.
|
|
27
30
|
class SQLite3Adapter < AbstractAdapter
|
|
@@ -45,7 +48,7 @@ module ActiveRecord
|
|
|
45
48
|
args << "-header" if options[:header]
|
|
46
49
|
args << File.expand_path(config.database, Rails.respond_to?(:root) ? Rails.root : nil)
|
|
47
50
|
|
|
48
|
-
find_cmd_and_exec(
|
|
51
|
+
find_cmd_and_exec(ActiveRecord.database_cli[:sqlite], *args)
|
|
49
52
|
end
|
|
50
53
|
end
|
|
51
54
|
|
|
@@ -119,9 +122,14 @@ module ActiveRecord
|
|
|
119
122
|
end
|
|
120
123
|
end
|
|
121
124
|
|
|
125
|
+
@last_affected_rows = nil
|
|
126
|
+
@previous_read_uncommitted = nil
|
|
122
127
|
@config[:strict] = ConnectionAdapters::SQLite3Adapter.strict_strings_by_default unless @config.key?(:strict)
|
|
123
|
-
@connection_parameters = @config.merge(
|
|
124
|
-
|
|
128
|
+
@connection_parameters = @config.merge(
|
|
129
|
+
database: @config[:database].to_s,
|
|
130
|
+
results_as_hash: true,
|
|
131
|
+
default_transaction_mode: :immediate,
|
|
132
|
+
)
|
|
125
133
|
end
|
|
126
134
|
|
|
127
135
|
def database_exists?
|
|
@@ -199,7 +207,12 @@ module ActiveRecord
|
|
|
199
207
|
!(@raw_connection.nil? || @raw_connection.closed?)
|
|
200
208
|
end
|
|
201
209
|
|
|
202
|
-
|
|
210
|
+
def active?
|
|
211
|
+
if connected?
|
|
212
|
+
verified!
|
|
213
|
+
true
|
|
214
|
+
end
|
|
215
|
+
end
|
|
203
216
|
|
|
204
217
|
alias :reset! :reconnect!
|
|
205
218
|
|
|
@@ -278,6 +291,38 @@ module ActiveRecord
|
|
|
278
291
|
exec_query "DROP INDEX #{quote_column_name(index_name)}"
|
|
279
292
|
end
|
|
280
293
|
|
|
294
|
+
VIRTUAL_TABLE_REGEX = /USING\s+(\w+)\s*\((.*)\)/i
|
|
295
|
+
|
|
296
|
+
# Returns a list of defined virtual tables
|
|
297
|
+
def virtual_tables
|
|
298
|
+
query = <<~SQL
|
|
299
|
+
SELECT name, sql FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL %';
|
|
300
|
+
SQL
|
|
301
|
+
|
|
302
|
+
exec_query(query, "SCHEMA").cast_values.each_with_object({}) do |row, memo|
|
|
303
|
+
table_name, sql = row[0], row[1]
|
|
304
|
+
_, module_name, arguments = sql.match(VIRTUAL_TABLE_REGEX).to_a
|
|
305
|
+
memo[table_name] = [module_name, arguments]
|
|
306
|
+
end.to_a
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Creates a virtual table
|
|
310
|
+
#
|
|
311
|
+
# Example:
|
|
312
|
+
# create_virtual_table :emails, :fts5, ['sender', 'title', 'body']
|
|
313
|
+
def create_virtual_table(table_name, module_name, values)
|
|
314
|
+
exec_query "CREATE VIRTUAL TABLE IF NOT EXISTS #{table_name} USING #{module_name} (#{values.join(", ")})"
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Drops a virtual table
|
|
318
|
+
#
|
|
319
|
+
# Although this command ignores +module_name+ and +values+,
|
|
320
|
+
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
|
321
|
+
# In that case, +module_name+, +values+ and +options+ will be used by #create_virtual_table.
|
|
322
|
+
def drop_virtual_table(table_name, module_name, values, **options)
|
|
323
|
+
drop_table(table_name)
|
|
324
|
+
end
|
|
325
|
+
|
|
281
326
|
# Renames a table.
|
|
282
327
|
#
|
|
283
328
|
# Example:
|
|
@@ -367,7 +412,7 @@ module ActiveRecord
|
|
|
367
412
|
end
|
|
368
413
|
alias :add_belongs_to :add_reference
|
|
369
414
|
|
|
370
|
-
FK_REGEX = /.*FOREIGN KEY\s+\("(
|
|
415
|
+
FK_REGEX = /.*FOREIGN KEY\s+\("([^"]+)"\)\s+REFERENCES\s+"(\w+)"\s+\("(\w+)"\)/
|
|
371
416
|
DEFERRABLE_REGEX = /DEFERRABLE INITIALLY (\w+)/
|
|
372
417
|
def foreign_keys(table_name)
|
|
373
418
|
# SQLite returns 1 row for each column of composite foreign keys.
|
|
@@ -428,10 +473,6 @@ module ActiveRecord
|
|
|
428
473
|
@config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE)
|
|
429
474
|
end
|
|
430
475
|
|
|
431
|
-
def use_insert_returning?
|
|
432
|
-
@use_insert_returning
|
|
433
|
-
end
|
|
434
|
-
|
|
435
476
|
def get_database_version # :nodoc:
|
|
436
477
|
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
|
|
437
478
|
end
|
|
@@ -542,8 +583,8 @@ module ActiveRecord
|
|
|
542
583
|
yield definition if block_given?
|
|
543
584
|
end
|
|
544
585
|
|
|
545
|
-
|
|
546
|
-
|
|
586
|
+
disable_referential_integrity do
|
|
587
|
+
transaction do
|
|
547
588
|
move_table(table_name, altered_table_name, options.merge(temporary: true))
|
|
548
589
|
move_table(altered_table_name, table_name, &caller)
|
|
549
590
|
end
|
|
@@ -661,6 +702,8 @@ module ActiveRecord
|
|
|
661
702
|
InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
662
703
|
elsif exception.message.match?(/called on a closed database/i)
|
|
663
704
|
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
|
705
|
+
elsif exception.is_a?(::SQLite3::BusyException)
|
|
706
|
+
StatementTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
664
707
|
else
|
|
665
708
|
super
|
|
666
709
|
end
|
|
@@ -778,12 +821,15 @@ module ActiveRecord
|
|
|
778
821
|
if @config[:timeout] && @config[:retries]
|
|
779
822
|
raise ArgumentError, "Cannot specify both timeout and retries arguments"
|
|
780
823
|
elsif @config[:timeout]
|
|
781
|
-
|
|
824
|
+
timeout = self.class.type_cast_config_to_integer(@config[:timeout])
|
|
825
|
+
raise TypeError, "timeout must be integer, not #{timeout}" unless timeout.is_a?(Integer)
|
|
826
|
+
@raw_connection.busy_handler_timeout = timeout
|
|
782
827
|
elsif @config[:retries]
|
|
828
|
+
ActiveRecord.deprecator.warn(<<~MSG)
|
|
829
|
+
The retries option is deprecated and will be removed in Rails 8.1. Use timeout instead.
|
|
830
|
+
MSG
|
|
783
831
|
retries = self.class.type_cast_config_to_integer(@config[:retries])
|
|
784
|
-
raw_connection.busy_handler
|
|
785
|
-
count <= retries
|
|
786
|
-
end
|
|
832
|
+
raw_connection.busy_handler { |count| count <= retries }
|
|
787
833
|
end
|
|
788
834
|
|
|
789
835
|
super
|
|
@@ -4,93 +4,63 @@ module ActiveRecord
|
|
|
4
4
|
module ConnectionAdapters
|
|
5
5
|
module Trilogy
|
|
6
6
|
module DatabaseStatements
|
|
7
|
-
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
|
|
8
|
-
sql = transform_query(sql)
|
|
9
|
-
check_if_write_query(sql)
|
|
10
|
-
mark_transaction_written_if_write(sql)
|
|
11
|
-
|
|
12
|
-
result = raw_execute(sql, name, async: async, allow_retry: allow_retry)
|
|
13
|
-
ActiveRecord::Result.new(result.fields, result.to_a)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
7
|
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil, returning: nil) # :nodoc:
|
|
17
|
-
sql = transform_query(sql)
|
|
18
|
-
check_if_write_query(sql)
|
|
19
|
-
mark_transaction_written_if_write(sql)
|
|
20
|
-
|
|
21
8
|
sql, _binds = sql_for_insert(sql, pk, binds, returning)
|
|
22
|
-
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
|
26
|
-
sql = transform_query(sql)
|
|
27
|
-
check_if_write_query(sql)
|
|
28
|
-
mark_transaction_written_if_write(sql)
|
|
29
|
-
|
|
30
|
-
result = raw_execute(to_sql(sql, binds), name)
|
|
31
|
-
result.affected_rows
|
|
9
|
+
internal_execute(sql, name)
|
|
32
10
|
end
|
|
33
11
|
|
|
34
|
-
alias :exec_update :exec_delete # :nodoc:
|
|
35
|
-
|
|
36
12
|
private
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
result = conn.query(sql)
|
|
42
|
-
while conn.more_results_exist?
|
|
43
|
-
conn.next_result
|
|
44
|
-
end
|
|
45
|
-
verified!
|
|
46
|
-
handle_warnings(sql)
|
|
47
|
-
notification_payload[:row_count] = result.count
|
|
48
|
-
result
|
|
49
|
-
end
|
|
13
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
|
|
14
|
+
reset_multi_statement = if batch && !@config[:multi_statement]
|
|
15
|
+
raw_connection.set_server_option(::Trilogy::SET_SERVER_MULTI_STATEMENTS_ON)
|
|
16
|
+
true
|
|
50
17
|
end
|
|
51
|
-
end
|
|
52
18
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
19
|
+
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
20
|
+
# made since we established the connection
|
|
21
|
+
if default_timezone == :local
|
|
22
|
+
raw_connection.query_flags |= ::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
|
|
56
23
|
else
|
|
57
|
-
|
|
24
|
+
raw_connection.query_flags &= ~::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
|
|
58
25
|
end
|
|
59
|
-
end
|
|
60
26
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
27
|
+
result = raw_connection.query(sql)
|
|
28
|
+
while raw_connection.more_results_exist?
|
|
29
|
+
raw_connection.next_result
|
|
30
|
+
end
|
|
31
|
+
verified!
|
|
32
|
+
handle_warnings(sql)
|
|
33
|
+
notification_payload[:row_count] = result.count
|
|
34
|
+
result
|
|
35
|
+
ensure
|
|
36
|
+
if reset_multi_statement && active?
|
|
37
|
+
raw_connection.set_server_option(::Trilogy::SET_SERVER_MULTI_STATEMENTS_OFF)
|
|
67
38
|
end
|
|
68
39
|
end
|
|
69
40
|
|
|
70
|
-
def
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
end
|
|
41
|
+
def cast_result(result)
|
|
42
|
+
if result.fields.empty?
|
|
43
|
+
ActiveRecord::Result.empty
|
|
44
|
+
else
|
|
45
|
+
ActiveRecord::Result.new(result.fields, result.rows)
|
|
76
46
|
end
|
|
77
47
|
end
|
|
78
48
|
|
|
79
|
-
def
|
|
80
|
-
|
|
49
|
+
def affected_rows(result)
|
|
50
|
+
result.affected_rows
|
|
81
51
|
end
|
|
82
52
|
|
|
83
|
-
def
|
|
84
|
-
if
|
|
85
|
-
|
|
53
|
+
def last_inserted_id(result)
|
|
54
|
+
if supports_insert_returning?
|
|
55
|
+
super
|
|
56
|
+
else
|
|
57
|
+
result.last_insert_id
|
|
86
58
|
end
|
|
59
|
+
end
|
|
87
60
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
yield
|
|
92
|
-
ensure
|
|
93
|
-
conn.set_server_option(::Trilogy::SET_SERVER_MULTI_STATEMENTS_OFF) if active?
|
|
61
|
+
def execute_batch(statements, name = nil, **kwargs)
|
|
62
|
+
combine_multi_statements(statements).each do |statement|
|
|
63
|
+
raw_execute(statement, name, batch: true, **kwargs)
|
|
94
64
|
end
|
|
95
65
|
end
|
|
96
66
|
end
|
|
@@ -121,7 +121,7 @@ module ActiveRecord
|
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
def active?
|
|
124
|
-
connected? && @lock.synchronize { @raw_connection&.ping } || false
|
|
124
|
+
connected? && @lock.synchronize { @raw_connection&.ping; verified! } || false
|
|
125
125
|
rescue ::Trilogy::Error
|
|
126
126
|
false
|
|
127
127
|
end
|
|
@@ -149,23 +149,6 @@ module ActiveRecord
|
|
|
149
149
|
TYPE_MAP.lookup(type).is_a?(Type::String) || TYPE_MAP.lookup(type).is_a?(Type::Text)
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
-
def each_hash(result)
|
|
153
|
-
return to_enum(:each_hash, result) unless block_given?
|
|
154
|
-
|
|
155
|
-
keys = result.fields.map(&:to_sym)
|
|
156
|
-
result.rows.each do |row|
|
|
157
|
-
hash = {}
|
|
158
|
-
idx = 0
|
|
159
|
-
row.each do |value|
|
|
160
|
-
hash[keys[idx]] = value
|
|
161
|
-
idx += 1
|
|
162
|
-
end
|
|
163
|
-
yield hash
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
nil
|
|
167
|
-
end
|
|
168
|
-
|
|
169
152
|
def error_number(exception)
|
|
170
153
|
exception.error_code if exception.respond_to?(:error_code)
|
|
171
154
|
end
|
|
@@ -31,62 +31,6 @@ module ActiveRecord
|
|
|
31
31
|
class_name, path_to_adapter = @adapters[adapter_name.to_s]
|
|
32
32
|
|
|
33
33
|
unless class_name
|
|
34
|
-
# To provide better error messages for adapters expecting the pre-7.2 adapter registration API, we attempt
|
|
35
|
-
# to load the adapter file from the old location which was required by convention, and then raise an error
|
|
36
|
-
# describing how to upgrade the adapter to the new API.
|
|
37
|
-
legacy_adapter_path = "active_record/connection_adapters/#{adapter_name}_adapter"
|
|
38
|
-
legacy_adapter_connection_method_name = "#{adapter_name}_connection".to_sym
|
|
39
|
-
|
|
40
|
-
begin
|
|
41
|
-
require legacy_adapter_path
|
|
42
|
-
# If we reach here it means we found the found a file that may be the legacy adapter and should raise.
|
|
43
|
-
if ActiveRecord::ConnectionHandling.method_defined?(legacy_adapter_connection_method_name)
|
|
44
|
-
# If we find the connection method then we care certain it is a legacy adapter.
|
|
45
|
-
deprecation_message = <<~MSG.squish
|
|
46
|
-
Database configuration specifies '#{adapter_name}' adapter but that adapter has not been registered.
|
|
47
|
-
Rails 7.2 has changed the way Active Record database adapters are loaded. The adapter needs to be
|
|
48
|
-
updated to register itself rather than being loaded by convention.
|
|
49
|
-
Ensure that the adapter in the Gemfile is at the latest version. If it is, then the adapter may need to
|
|
50
|
-
be modified.
|
|
51
|
-
See:
|
|
52
|
-
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters.html#method-c-register
|
|
53
|
-
MSG
|
|
54
|
-
|
|
55
|
-
exception_message = <<~MSG.squish
|
|
56
|
-
Database configuration specifies '#{adapter_name}' adapter but that adapter has not been registered.
|
|
57
|
-
Ensure that the adapter in the Gemfile is at the latest version. If it is, then the adapter may need to
|
|
58
|
-
be modified.
|
|
59
|
-
MSG
|
|
60
|
-
else
|
|
61
|
-
# If we do not find the connection method we are much less certain it is a legacy adapter. Even though the
|
|
62
|
-
# file exists in the location defined by convenntion, it does not necessarily mean that file is supposed
|
|
63
|
-
# to define the adapter the legacy way. So raise an error that explains both possibilities.
|
|
64
|
-
deprecation_message = <<~MSG.squish
|
|
65
|
-
Database configuration specifies nonexistent '#{adapter_name}' adapter.
|
|
66
|
-
Available adapters are: #{@adapters.keys.sort.join(", ")}.
|
|
67
|
-
Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary
|
|
68
|
-
adapter gem to your Gemfile if it's not in the list of available adapters.
|
|
69
|
-
Rails 7.2 has changed the way Active Record database adapters are loaded. Ensure that the adapter in
|
|
70
|
-
the Gemfile is at the latest version. If it is up to date, the adapter may need to be modified.
|
|
71
|
-
See:
|
|
72
|
-
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters.html#method-c-register
|
|
73
|
-
MSG
|
|
74
|
-
|
|
75
|
-
exception_message = <<~MSG.squish
|
|
76
|
-
Database configuration specifies nonexistent '#{adapter_name}' adapter.
|
|
77
|
-
Available adapters are: #{@adapters.keys.sort.join(", ")}.
|
|
78
|
-
Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary
|
|
79
|
-
adapter gem to your Gemfile and that it is at its latest version. If it is up to date, the adapter may
|
|
80
|
-
need to be modified.
|
|
81
|
-
MSG
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
ActiveRecord.deprecator.warn(deprecation_message)
|
|
85
|
-
raise AdapterNotFound, exception_message
|
|
86
|
-
rescue LoadError => error
|
|
87
|
-
# The adapter was not found in the legacy location so fall through to the error handling for a missing adapter.
|
|
88
|
-
end
|
|
89
|
-
|
|
90
34
|
raise AdapterNotFound, <<~MSG.squish
|
|
91
35
|
Database configuration specifies nonexistent '#{adapter_name}' adapter.
|
|
92
36
|
Available adapters are: #{@adapters.keys.sort.join(", ")}.
|
|
@@ -87,6 +87,8 @@ module ActiveRecord
|
|
|
87
87
|
|
|
88
88
|
connections = []
|
|
89
89
|
|
|
90
|
+
@shard_keys = shards.keys
|
|
91
|
+
|
|
90
92
|
if shards.empty?
|
|
91
93
|
shards[:default] = database
|
|
92
94
|
end
|
|
@@ -170,9 +172,23 @@ module ActiveRecord
|
|
|
170
172
|
prevent_writes = true if role == ActiveRecord.reading_role
|
|
171
173
|
|
|
172
174
|
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
begin
|
|
176
|
+
yield
|
|
177
|
+
ensure
|
|
178
|
+
connected_to_stack.pop
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Passes the block to +connected_to+ for every +shard+ the
|
|
183
|
+
# model is configured to connect to (if any), and returns the
|
|
184
|
+
# results in an array.
|
|
185
|
+
#
|
|
186
|
+
# Optionally, +role+ and/or +prevent_writes+ can be passed which
|
|
187
|
+
# will be forwarded to each +connected_to+ call.
|
|
188
|
+
def connected_to_all_shards(role: nil, prevent_writes: false, &blk)
|
|
189
|
+
shard_keys.map do |shard|
|
|
190
|
+
connected_to(shard: shard, role: role, prevent_writes: prevent_writes, &blk)
|
|
191
|
+
end
|
|
176
192
|
end
|
|
177
193
|
|
|
178
194
|
# Use a specified connection.
|
|
@@ -287,7 +303,7 @@ module ActiveRecord
|
|
|
287
303
|
|
|
288
304
|
# Checkouts a connection from the pool, yield it and then check it back in.
|
|
289
305
|
# If a connection was already leased via #lease_connection or a parent call to
|
|
290
|
-
# #with_connection, that same connection is
|
|
306
|
+
# #with_connection, that same connection is yielded.
|
|
291
307
|
# If #lease_connection is called inside the block, the connection won't be checked
|
|
292
308
|
# back in.
|
|
293
309
|
# If #connection is called inside the block, the connection won't be checked back in
|
|
@@ -359,6 +375,14 @@ module ActiveRecord
|
|
|
359
375
|
connection_pool.schema_cache.clear!
|
|
360
376
|
end
|
|
361
377
|
|
|
378
|
+
def shard_keys
|
|
379
|
+
connection_class_for_self.instance_variable_get(:@shard_keys) || []
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def sharded?
|
|
383
|
+
shard_keys.any?
|
|
384
|
+
end
|
|
385
|
+
|
|
362
386
|
private
|
|
363
387
|
def resolve_config_for_connection(config_or_env)
|
|
364
388
|
raise "Anonymous class is not allowed." unless name
|
|
@@ -373,11 +397,13 @@ module ActiveRecord
|
|
|
373
397
|
prevent_writes = true if role == ActiveRecord.reading_role
|
|
374
398
|
|
|
375
399
|
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
400
|
+
begin
|
|
401
|
+
return_value = yield
|
|
402
|
+
return_value.load if return_value.is_a? ActiveRecord::Relation
|
|
403
|
+
return_value
|
|
404
|
+
ensure
|
|
405
|
+
self.connected_to_stack.pop
|
|
406
|
+
end
|
|
381
407
|
end
|
|
382
408
|
|
|
383
409
|
def append_to_connected_to_stack(entry)
|