activerecord 6.1.7.4 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1055 -1170
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +18 -19
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +6 -2
- data/lib/active_record/associations/preloader/association.rb +186 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +49 -13
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +90 -82
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +13 -14
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +6 -21
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +2 -14
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +43 -82
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +69 -18
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +35 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -76
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +27 -16
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -107
- data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +47 -53
- data/lib/active_record/core.rb +121 -146
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +15 -32
- data/lib/active_record/delegated_type.rb +52 -11
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +49 -42
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +17 -20
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +14 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +89 -10
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +110 -80
- data/lib/active_record/model_schema.rb +45 -58
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +219 -52
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +127 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +66 -129
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +67 -50
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +40 -36
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +235 -63
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +169 -84
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +10 -3
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +61 -12
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/store.rb +1 -6
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +116 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -13
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +204 -28
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +58 -14
@@ -59,17 +59,13 @@ module ActiveRecord
|
|
59
59
|
end
|
60
60
|
|
61
61
|
# Returns an ActiveRecord::Result instance.
|
62
|
-
def select_all(arel, name = nil, binds = [], preparable: nil)
|
62
|
+
def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
|
63
63
|
arel = arel_from_relation(arel)
|
64
64
|
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
65
65
|
|
66
|
-
|
67
|
-
select_prepared(sql, name, binds)
|
68
|
-
else
|
69
|
-
select(sql, name, binds)
|
70
|
-
end
|
66
|
+
select(sql, name, binds, prepare: prepared_statements && preparable, async: async && FutureResult::SelectAll)
|
71
67
|
rescue ::RangeError
|
72
|
-
ActiveRecord::Result.
|
68
|
+
ActiveRecord::Result.empty
|
73
69
|
end
|
74
70
|
|
75
71
|
# Returns a record hash with the column names as keys and column values
|
@@ -310,20 +306,20 @@ module ActiveRecord
|
|
310
306
|
#
|
311
307
|
# The mysql2 and postgresql adapters support setting the transaction
|
312
308
|
# isolation level.
|
313
|
-
def transaction(requires_new: nil, isolation: nil, joinable: true)
|
309
|
+
def transaction(requires_new: nil, isolation: nil, joinable: true, &block)
|
314
310
|
if !requires_new && current_transaction.joinable?
|
315
311
|
if isolation
|
316
312
|
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
317
313
|
end
|
318
314
|
yield
|
319
315
|
else
|
320
|
-
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable)
|
316
|
+
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable, &block)
|
321
317
|
end
|
322
318
|
rescue ActiveRecord::Rollback
|
323
319
|
# rollbacks are silently swallowed
|
324
320
|
end
|
325
321
|
|
326
|
-
attr_reader :transaction_manager
|
322
|
+
attr_reader :transaction_manager # :nodoc:
|
327
323
|
|
328
324
|
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
329
325
|
:commit_transaction, :rollback_transaction, :materialize_transactions,
|
@@ -340,7 +336,7 @@ module ActiveRecord
|
|
340
336
|
current_transaction.open?
|
341
337
|
end
|
342
338
|
|
343
|
-
def reset_transaction
|
339
|
+
def reset_transaction # :nodoc:
|
344
340
|
@transaction_manager = ConnectionAdapters::TransactionManager.new(self)
|
345
341
|
end
|
346
342
|
|
@@ -378,7 +374,7 @@ module ActiveRecord
|
|
378
374
|
exec_rollback_db_transaction
|
379
375
|
end
|
380
376
|
|
381
|
-
def exec_rollback_db_transaction() end
|
377
|
+
def exec_rollback_db_transaction() end # :nodoc:
|
382
378
|
|
383
379
|
def rollback_to_savepoint(name = nil)
|
384
380
|
exec_rollback_to_savepoint(name)
|
@@ -445,6 +441,19 @@ module ActiveRecord
|
|
445
441
|
end
|
446
442
|
end
|
447
443
|
|
444
|
+
# This is a safe default, even if not high precision on all databases
|
445
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP").freeze # :nodoc:
|
446
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
447
|
+
|
448
|
+
# Returns an Arel SQL literal for the CURRENT_TIMESTAMP for usage with
|
449
|
+
# arbitrary precision date/time columns.
|
450
|
+
#
|
451
|
+
# Adapters supporting datetime with precision should override this to
|
452
|
+
# provide as much precision as is available.
|
453
|
+
def high_precision_current_timestamp
|
454
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
455
|
+
end
|
456
|
+
|
448
457
|
private
|
449
458
|
def execute_batch(statements, name = nil)
|
450
459
|
statements.each do |statement|
|
@@ -460,7 +469,7 @@ module ActiveRecord
|
|
460
469
|
end
|
461
470
|
|
462
471
|
def build_fixture_sql(fixtures, table_name)
|
463
|
-
columns = schema_cache.columns_hash(table_name)
|
472
|
+
columns = schema_cache.columns_hash(table_name).reject { |_, column| supports_virtual_columns? && column.virtual? }
|
464
473
|
|
465
474
|
values_list = fixtures.map do |fixture|
|
466
475
|
fixture = fixture.stringify_keys
|
@@ -481,8 +490,7 @@ module ActiveRecord
|
|
481
490
|
end
|
482
491
|
|
483
492
|
table = Arel::Table.new(table_name)
|
484
|
-
manager = Arel::InsertManager.new
|
485
|
-
manager.into(table)
|
493
|
+
manager = Arel::InsertManager.new(table)
|
486
494
|
|
487
495
|
if values_list.size == 1
|
488
496
|
values = values_list.shift
|
@@ -503,10 +511,10 @@ module ActiveRecord
|
|
503
511
|
end
|
504
512
|
|
505
513
|
def build_fixture_statements(fixture_set)
|
506
|
-
fixture_set.
|
514
|
+
fixture_set.filter_map do |table_name, fixtures|
|
507
515
|
next if fixtures.empty?
|
508
516
|
build_fixture_sql(fixtures, table_name)
|
509
|
-
end
|
517
|
+
end
|
510
518
|
end
|
511
519
|
|
512
520
|
def build_truncate_statement(table_name)
|
@@ -528,12 +536,28 @@ module ActiveRecord
|
|
528
536
|
end
|
529
537
|
|
530
538
|
# Returns an ActiveRecord::Result instance.
|
531
|
-
def select(sql, name = nil, binds = [])
|
532
|
-
|
533
|
-
|
539
|
+
def select(sql, name = nil, binds = [], prepare: false, async: false)
|
540
|
+
if async && async_enabled?
|
541
|
+
if current_transaction.joinable?
|
542
|
+
raise AsynchronousQueryInsideTransactionError, "Asynchronous queries are not allowed inside transactions"
|
543
|
+
end
|
544
|
+
|
545
|
+
future_result = async.new(
|
546
|
+
pool,
|
547
|
+
sql,
|
548
|
+
name,
|
549
|
+
binds,
|
550
|
+
prepare: prepare,
|
551
|
+
)
|
552
|
+
if supports_concurrent_connections? && current_transaction.closed?
|
553
|
+
future_result.schedule!(ActiveRecord::Base.asynchronous_queries_session)
|
554
|
+
else
|
555
|
+
future_result.execute!(self)
|
556
|
+
end
|
557
|
+
return future_result
|
558
|
+
end
|
534
559
|
|
535
|
-
|
536
|
-
exec_query(sql, name, binds, prepare: true)
|
560
|
+
exec_query(sql, name, binds, prepare: prepare)
|
537
561
|
end
|
538
562
|
|
539
563
|
def sql_for_insert(sql, pk, binds)
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters # :nodoc:
|
7
7
|
module QueryCache
|
8
8
|
class << self
|
9
|
-
def included(base)
|
9
|
+
def included(base) # :nodoc:
|
10
10
|
dirties_query_cache base, :create, :insert, :update, :delete, :truncate, :truncate_tables,
|
11
11
|
:rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
|
12
12
|
|
@@ -93,18 +93,37 @@ module ActiveRecord
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
def select_all(arel, name = nil, binds = [], preparable: nil)
|
97
|
-
|
98
|
-
|
96
|
+
def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
|
97
|
+
arel = arel_from_relation(arel)
|
98
|
+
|
99
|
+
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch.
|
100
|
+
# Such queries should not be cached.
|
101
|
+
if @query_cache_enabled && !(arel.respond_to?(:locked) && arel.locked)
|
99
102
|
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
100
103
|
|
101
|
-
|
104
|
+
if async
|
105
|
+
lookup_sql_cache(sql, name, binds) || super(sql, name, binds, preparable: preparable, async: async)
|
106
|
+
else
|
107
|
+
cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable, async: async) }
|
108
|
+
end
|
102
109
|
else
|
103
110
|
super
|
104
111
|
end
|
105
112
|
end
|
106
113
|
|
107
114
|
private
|
115
|
+
def lookup_sql_cache(sql, name, binds)
|
116
|
+
@lock.synchronize do
|
117
|
+
if @query_cache[sql].key?(binds)
|
118
|
+
ActiveSupport::Notifications.instrument(
|
119
|
+
"sql.active_record",
|
120
|
+
cache_notification_info(sql, name, binds)
|
121
|
+
)
|
122
|
+
@query_cache[sql][binds]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
108
127
|
def cache_sql(sql, name, binds)
|
109
128
|
@lock.synchronize do
|
110
129
|
result =
|
@@ -134,13 +153,6 @@ module ActiveRecord
|
|
134
153
|
}
|
135
154
|
end
|
136
155
|
|
137
|
-
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
|
138
|
-
# queries should not be cached.
|
139
|
-
def locked?(arel)
|
140
|
-
arel = arel.arel if arel.is_a?(Relation)
|
141
|
-
arel.respond_to?(:locked) && arel.locked
|
142
|
-
end
|
143
|
-
|
144
156
|
def configure_query_cache!
|
145
157
|
enable_query_cache! if pool.query_cache_enabled
|
146
158
|
end
|
@@ -9,38 +9,46 @@ module ActiveRecord
|
|
9
9
|
# Quotes the column value to help prevent
|
10
10
|
# {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
|
11
11
|
def quote(value)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
case value
|
13
|
+
when String, Symbol, ActiveSupport::Multibyte::Chars
|
14
|
+
"'#{quote_string(value.to_s)}'"
|
15
|
+
when true then quoted_true
|
16
|
+
when false then quoted_false
|
17
|
+
when nil then "NULL"
|
18
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
19
|
+
when BigDecimal then value.to_s("F")
|
20
|
+
when Numeric, ActiveSupport::Duration then value.to_s
|
21
|
+
when Type::Binary::Data then quoted_binary(value)
|
22
|
+
when Type::Time::Value then "'#{quoted_time(value)}'"
|
23
|
+
when Date, Time then "'#{quoted_date(value)}'"
|
24
|
+
when Class then "'#{value}'"
|
25
|
+
else raise TypeError, "can't quote #{value.class.name}"
|
18
26
|
end
|
19
|
-
|
20
|
-
_quote(value)
|
21
27
|
end
|
22
28
|
|
23
29
|
# Cast a +value+ to a type that the database understands. For example,
|
24
30
|
# SQLite does not understand dates, so this method will convert a Date
|
25
31
|
# to a String.
|
26
|
-
def type_cast(value
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
MSG
|
39
|
-
type = lookup_cast_type_from_column(column)
|
40
|
-
value = type.serialize(value)
|
32
|
+
def type_cast(value)
|
33
|
+
case value
|
34
|
+
when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
|
35
|
+
value.to_s
|
36
|
+
when true then unquoted_true
|
37
|
+
when false then unquoted_false
|
38
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
39
|
+
when BigDecimal then value.to_s("F")
|
40
|
+
when nil, Numeric, String then value
|
41
|
+
when Type::Time::Value then quoted_time(value)
|
42
|
+
when Date, Time then quoted_date(value)
|
43
|
+
else raise TypeError, "can't cast #{value.class.name}"
|
41
44
|
end
|
45
|
+
end
|
42
46
|
|
43
|
-
|
47
|
+
# Quote a value to be used as a bound parameter of unknown type. For example,
|
48
|
+
# MySQL might perform dangerous castings when comparing a string to a number,
|
49
|
+
# so this method will cast numbers to string.
|
50
|
+
def quote_bound_value(value)
|
51
|
+
quote(value)
|
44
52
|
end
|
45
53
|
|
46
54
|
# If you are having to call this function, you are likely doing something
|
@@ -59,7 +67,7 @@ module ActiveRecord
|
|
59
67
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
60
68
|
# characters.
|
61
69
|
def quote_string(s)
|
62
|
-
s.gsub(
|
70
|
+
s.gsub("\\", '\&\&').gsub("'", "''") # ' (for ruby-mode)
|
63
71
|
end
|
64
72
|
|
65
73
|
# Quotes the column name. Defaults to no quoting.
|
@@ -113,14 +121,14 @@ module ActiveRecord
|
|
113
121
|
# if the value is a Time responding to usec.
|
114
122
|
def quoted_date(value)
|
115
123
|
if value.acts_like?(:time)
|
116
|
-
if ActiveRecord
|
117
|
-
value = value.getutc if
|
124
|
+
if ActiveRecord.default_timezone == :utc
|
125
|
+
value = value.getutc if !value.utc?
|
118
126
|
else
|
119
|
-
value = value.getlocal
|
127
|
+
value = value.getlocal
|
120
128
|
end
|
121
129
|
end
|
122
130
|
|
123
|
-
result = value.
|
131
|
+
result = value.to_formatted_s(:db)
|
124
132
|
if value.respond_to?(:usec) && value.usec > 0
|
125
133
|
result << "." << sprintf("%06d", value.usec)
|
126
134
|
else
|
@@ -138,16 +146,7 @@ module ActiveRecord
|
|
138
146
|
end
|
139
147
|
|
140
148
|
def sanitize_as_sql_comment(value) # :nodoc:
|
141
|
-
|
142
|
-
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
143
|
-
# charcacters, possibly with single surrounding space.
|
144
|
-
# Then follows that by replacing any internal "*/" or "/ *" with
|
145
|
-
# "* /" or "/ *"
|
146
|
-
comment = value.to_s.dup
|
147
|
-
comment.gsub!(%r{\A\s*/\*\+?\s?|\s?\*/\s*\Z}, "")
|
148
|
-
comment.gsub!("*/", "* /")
|
149
|
-
comment.gsub!("/*", "/ *")
|
150
|
-
comment
|
149
|
+
value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
|
151
150
|
end
|
152
151
|
|
153
152
|
def column_name_matcher # :nodoc:
|
@@ -205,16 +204,11 @@ module ActiveRecord
|
|
205
204
|
|
206
205
|
private
|
207
206
|
def type_casted_binds(binds)
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
if ActiveModel::Attribute === value
|
214
|
-
type_cast(value.value_for_database)
|
215
|
-
else
|
216
|
-
type_cast(value)
|
217
|
-
end
|
207
|
+
binds.map do |value|
|
208
|
+
if ActiveModel::Attribute === value
|
209
|
+
type_cast(value.value_for_database)
|
210
|
+
else
|
211
|
+
type_cast(value)
|
218
212
|
end
|
219
213
|
end
|
220
214
|
end
|
@@ -222,39 +216,6 @@ module ActiveRecord
|
|
222
216
|
def lookup_cast_type(sql_type)
|
223
217
|
type_map.lookup(sql_type)
|
224
218
|
end
|
225
|
-
|
226
|
-
def _quote(value)
|
227
|
-
case value
|
228
|
-
when String, Symbol, ActiveSupport::Multibyte::Chars
|
229
|
-
"'#{quote_string(value.to_s)}'"
|
230
|
-
when true then quoted_true
|
231
|
-
when false then quoted_false
|
232
|
-
when nil then "NULL"
|
233
|
-
# BigDecimals need to be put in a non-normalized form and quoted.
|
234
|
-
when BigDecimal then value.to_s("F")
|
235
|
-
when Numeric, ActiveSupport::Duration then value.to_s
|
236
|
-
when Type::Binary::Data then quoted_binary(value)
|
237
|
-
when Type::Time::Value then "'#{quoted_time(value)}'"
|
238
|
-
when Date, Time then "'#{quoted_date(value)}'"
|
239
|
-
when Class then "'#{value}'"
|
240
|
-
else raise TypeError, "can't quote #{value.class.name}"
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
def _type_cast(value)
|
245
|
-
case value
|
246
|
-
when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
|
247
|
-
value.to_s
|
248
|
-
when true then unquoted_true
|
249
|
-
when false then unquoted_false
|
250
|
-
# BigDecimals need to be put in a non-normalized form and quoted.
|
251
|
-
when BigDecimal then value.to_s("F")
|
252
|
-
when nil, Numeric, String then value
|
253
|
-
when Type::Time::Value then quoted_time(value)
|
254
|
-
when Date, Time then quoted_date(value)
|
255
|
-
else raise TypeError, "can't cast #{value.class.name}"
|
256
|
-
end
|
257
|
-
end
|
258
219
|
end
|
259
220
|
end
|
260
221
|
end
|
@@ -14,8 +14,8 @@ module ActiveRecord
|
|
14
14
|
end
|
15
15
|
|
16
16
|
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
17
|
-
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?,
|
18
|
-
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
|
17
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?,
|
18
|
+
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
|
19
19
|
to: :@conn, private: true
|
20
20
|
|
21
21
|
private
|
@@ -52,11 +52,11 @@ module ActiveRecord
|
|
52
52
|
end
|
53
53
|
|
54
54
|
if supports_foreign_keys?
|
55
|
-
statements.concat(o.foreign_keys.map { |
|
55
|
+
statements.concat(o.foreign_keys.map { |fk| accept fk })
|
56
56
|
end
|
57
57
|
|
58
58
|
if supports_check_constraints?
|
59
|
-
statements.concat(o.check_constraints.map { |
|
59
|
+
statements.concat(o.check_constraints.map { |chk| accept chk })
|
60
60
|
end
|
61
61
|
|
62
62
|
create_sql << "(#{statements.join(', ')})" if statements.present?
|
@@ -159,19 +159,6 @@ module ActiveRecord
|
|
159
159
|
" TEMPORARY" if o.temporary
|
160
160
|
end
|
161
161
|
|
162
|
-
def foreign_key_in_create(from_table, to_table, options)
|
163
|
-
prefix = ActiveRecord::Base.table_name_prefix
|
164
|
-
suffix = ActiveRecord::Base.table_name_suffix
|
165
|
-
to_table = "#{prefix}#{to_table}#{suffix}"
|
166
|
-
options = foreign_key_options(from_table, to_table, options)
|
167
|
-
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
168
|
-
end
|
169
|
-
|
170
|
-
def check_constraint_in_create(table_name, expression, options)
|
171
|
-
options = check_constraint_options(table_name, expression, options)
|
172
|
-
accept CheckConstraintDefinition.new(table_name, expression, options)
|
173
|
-
end
|
174
|
-
|
175
162
|
def action_sql(action, dependency)
|
176
163
|
case dependency
|
177
164
|
when :nullify then "ON #{action} SET NULL"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
module ConnectionAdapters
|
4
|
+
module ConnectionAdapters # :nodoc:
|
5
5
|
# Abstract representation of an index definition on a table. Instances of
|
6
6
|
# this type are typically created and returned by methods in database
|
7
7
|
# adapters. e.g. ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#indexes
|
@@ -79,13 +79,13 @@ module ActiveRecord
|
|
79
79
|
|
80
80
|
AddColumnDefinition = Struct.new(:column) # :nodoc:
|
81
81
|
|
82
|
-
ChangeColumnDefinition = Struct.new(:column, :name)
|
82
|
+
ChangeColumnDefinition = Struct.new(:column, :name) # :nodoc:
|
83
83
|
|
84
84
|
CreateIndexDefinition = Struct.new(:index, :algorithm, :if_not_exists) # :nodoc:
|
85
85
|
|
86
86
|
PrimaryKeyDefinition = Struct.new(:name) # :nodoc:
|
87
87
|
|
88
|
-
ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do
|
88
|
+
ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do # :nodoc:
|
89
89
|
def name
|
90
90
|
options[:name]
|
91
91
|
end
|
@@ -106,6 +106,10 @@ module ActiveRecord
|
|
106
106
|
options[:on_update]
|
107
107
|
end
|
108
108
|
|
109
|
+
def deferrable
|
110
|
+
options[:deferrable]
|
111
|
+
end
|
112
|
+
|
109
113
|
def custom_primary_key?
|
110
114
|
options[:primary_key] != default_primary_key
|
111
115
|
end
|
@@ -198,10 +202,6 @@ module ActiveRecord
|
|
198
202
|
|
199
203
|
def index_options(table_name)
|
200
204
|
index_options = as_options(index)
|
201
|
-
|
202
|
-
# legacy reference index names are used on versions 6.0 and earlier
|
203
|
-
return index_options if options[:_uses_legacy_reference_index_name]
|
204
|
-
|
205
205
|
index_options[:name] ||= polymorphic_index_name(table_name) if polymorphic
|
206
206
|
index_options
|
207
207
|
end
|
@@ -257,6 +257,7 @@ module ActiveRecord
|
|
257
257
|
define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
|
258
258
|
:float, :integer, :json, :string, :text, :time, :timestamp, :virtual
|
259
259
|
|
260
|
+
alias :blob :binary
|
260
261
|
alias :numeric :decimal
|
261
262
|
end
|
262
263
|
|
@@ -281,7 +282,7 @@ module ActiveRecord
|
|
281
282
|
# Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
|
282
283
|
# is actually of this type:
|
283
284
|
#
|
284
|
-
# class SomeMigration < ActiveRecord::Migration[
|
285
|
+
# class SomeMigration < ActiveRecord::Migration[7.0]
|
285
286
|
# def up
|
286
287
|
# create_table :foo do |t|
|
287
288
|
# puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
|
@@ -414,6 +415,12 @@ module ActiveRecord
|
|
414
415
|
end
|
415
416
|
end
|
416
417
|
|
418
|
+
if @conn.supports_datetime_with_precision?
|
419
|
+
if type == :datetime && !options.key?(:precision)
|
420
|
+
options[:precision] = 6
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
417
424
|
@columns_hash[name] = new_column_definition(name, type, **options)
|
418
425
|
|
419
426
|
if index
|
@@ -438,12 +445,12 @@ module ActiveRecord
|
|
438
445
|
indexes << [column_name, options]
|
439
446
|
end
|
440
447
|
|
441
|
-
def foreign_key(
|
442
|
-
foreign_keys <<
|
448
|
+
def foreign_key(to_table, **options)
|
449
|
+
foreign_keys << new_foreign_key_definition(to_table, options)
|
443
450
|
end
|
444
451
|
|
445
452
|
def check_constraint(expression, **options)
|
446
|
-
check_constraints <<
|
453
|
+
check_constraints << new_check_constraint_definition(expression, options)
|
447
454
|
end
|
448
455
|
|
449
456
|
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
@@ -485,6 +492,19 @@ module ActiveRecord
|
|
485
492
|
create_column_definition(name, type, options)
|
486
493
|
end
|
487
494
|
|
495
|
+
def new_foreign_key_definition(to_table, options) # :nodoc:
|
496
|
+
prefix = ActiveRecord::Base.table_name_prefix
|
497
|
+
suffix = ActiveRecord::Base.table_name_suffix
|
498
|
+
to_table = "#{prefix}#{to_table}#{suffix}"
|
499
|
+
options = @conn.foreign_key_options(name, to_table, options)
|
500
|
+
ForeignKeyDefinition.new(name, to_table, options)
|
501
|
+
end
|
502
|
+
|
503
|
+
def new_check_constraint_definition(expression, options) # :nodoc:
|
504
|
+
options = @conn.check_constraint_options(name, expression, options)
|
505
|
+
CheckConstraintDefinition.new(name, expression, options)
|
506
|
+
end
|
507
|
+
|
488
508
|
private
|
489
509
|
def create_column_definition(name, type, options)
|
490
510
|
ColumnDefinition.new(name, type, options)
|
@@ -520,7 +540,7 @@ module ActiveRecord
|
|
520
540
|
def name; @td.name; end
|
521
541
|
|
522
542
|
def add_foreign_key(to_table, options)
|
523
|
-
@foreign_key_adds <<
|
543
|
+
@foreign_key_adds << @td.new_foreign_key_definition(to_table, options)
|
524
544
|
end
|
525
545
|
|
526
546
|
def drop_foreign_key(name)
|
@@ -528,7 +548,7 @@ module ActiveRecord
|
|
528
548
|
end
|
529
549
|
|
530
550
|
def add_check_constraint(expression, options)
|
531
|
-
@check_constraint_adds <<
|
551
|
+
@check_constraint_adds << @td.new_check_constraint_definition(expression, options)
|
532
552
|
end
|
533
553
|
|
534
554
|
def drop_check_constraint(constraint_name)
|
@@ -572,6 +592,7 @@ module ActiveRecord
|
|
572
592
|
# t.time
|
573
593
|
# t.date
|
574
594
|
# t.binary
|
595
|
+
# t.blob
|
575
596
|
# t.boolean
|
576
597
|
# t.foreign_key
|
577
598
|
# t.json
|