activerecord 6.1.7.8 → 7.0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1582 -1018
- data/README.rdoc +3 -3
- 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 +20 -22
- data/lib/active_record/associations/collection_proxy.rb +15 -5
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +8 -5
- 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 +23 -15
- 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 +50 -14
- 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 +138 -100
- 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 +8 -6
- data/lib/active_record/attribute_methods/serialization.rb +57 -19
- 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 +19 -22
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +8 -23
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +14 -16
- data/lib/active_record/coders/yaml_column.rb +4 -8
- 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 +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +52 -23
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +144 -82
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +115 -85
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +37 -25
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -23
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
- 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 +19 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- 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 +30 -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 +76 -73
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -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 +40 -21
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
- 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 +33 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +19 -17
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +98 -36
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +49 -55
- data/lib/active_record/core.rb +123 -148
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -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 +53 -12
- 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 +67 -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 +206 -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 +50 -43
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- 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 +20 -23
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +5 -5
- 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 +36 -21
- data/lib/active_record/locking/pessimistic.rb +10 -4
- data/lib/active_record/log_subscriber.rb +23 -7
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +18 -6
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +8 -9
- data/lib/active_record/migration/compatibility.rb +93 -46
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +167 -87
- data/lib/active_record/model_schema.rb +58 -59
- 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 +231 -61
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +149 -0
- data/lib/active_record/querying.rb +16 -6
- data/lib/active_record/railtie.rb +136 -22
- data/lib/active_record/railties/controller_runtime.rb +4 -5
- data/lib/active_record/railties/databases.rake +78 -136
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +80 -49
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +6 -6
- data/lib/active_record/relation/calculations.rb +92 -60
- data/lib/active_record/relation/delegation.rb +7 -7
- 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/association_query_value.rb +20 -1
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +28 -11
- data/lib/active_record/relation/query_methods.rb +304 -68
- 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 +189 -88
- data/lib/active_record/result.rb +23 -11
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +17 -12
- data/lib/active_record/schema.rb +38 -23
- data/lib/active_record/schema_dumper.rb +29 -19
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +60 -13
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +3 -3
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/table_metadata.rb +6 -2
- data/lib/active_record/tasks/database_tasks.rb +127 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -6
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +12 -17
- data/lib/active_record/translation.rb +3 -3
- 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 +9 -5
- 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 +4 -4
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +225 -27
- 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/and.rb +4 -0
- 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 +53 -9
@@ -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_fs(:db)
|
124
132
|
if value.respond_to?(:usec) && value.usec > 0
|
125
133
|
result << "." << sprintf("%06d", value.usec)
|
126
134
|
else
|
@@ -205,16 +213,11 @@ module ActiveRecord
|
|
205
213
|
|
206
214
|
private
|
207
215
|
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
|
216
|
+
binds.map do |value|
|
217
|
+
if ActiveModel::Attribute === value
|
218
|
+
type_cast(value.value_for_database)
|
219
|
+
else
|
220
|
+
type_cast(value)
|
218
221
|
end
|
219
222
|
end
|
220
223
|
end
|
@@ -222,39 +225,6 @@ module ActiveRecord
|
|
222
225
|
def lookup_cast_type(sql_type)
|
223
226
|
type_map.lookup(sql_type)
|
224
227
|
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
228
|
end
|
259
229
|
end
|
260
230
|
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
|
@@ -257,6 +261,7 @@ module ActiveRecord
|
|
257
261
|
define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
|
258
262
|
:float, :integer, :json, :string, :text, :time, :timestamp, :virtual
|
259
263
|
|
264
|
+
alias :blob :binary
|
260
265
|
alias :numeric :decimal
|
261
266
|
end
|
262
267
|
|
@@ -281,7 +286,7 @@ module ActiveRecord
|
|
281
286
|
# Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
|
282
287
|
# is actually of this type:
|
283
288
|
#
|
284
|
-
# class SomeMigration < ActiveRecord::Migration[
|
289
|
+
# class SomeMigration < ActiveRecord::Migration[7.0]
|
285
290
|
# def up
|
286
291
|
# create_table :foo do |t|
|
287
292
|
# puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
|
@@ -406,14 +411,7 @@ module ActiveRecord
|
|
406
411
|
name = name.to_s
|
407
412
|
type = type.to_sym if type
|
408
413
|
|
409
|
-
|
410
|
-
if @columns_hash[name].primary_key?
|
411
|
-
raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
|
412
|
-
else
|
413
|
-
raise ArgumentError, "you can't define an already defined column '#{name}'."
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
414
|
+
raise_on_duplicate_column(name)
|
417
415
|
@columns_hash[name] = new_column_definition(name, type, **options)
|
418
416
|
|
419
417
|
if index
|
@@ -438,12 +436,12 @@ module ActiveRecord
|
|
438
436
|
indexes << [column_name, options]
|
439
437
|
end
|
440
438
|
|
441
|
-
def foreign_key(
|
442
|
-
foreign_keys <<
|
439
|
+
def foreign_key(to_table, **options)
|
440
|
+
foreign_keys << new_foreign_key_definition(to_table, options)
|
443
441
|
end
|
444
442
|
|
445
443
|
def check_constraint(expression, **options)
|
446
|
-
check_constraints <<
|
444
|
+
check_constraints << new_check_constraint_definition(expression, options)
|
447
445
|
end
|
448
446
|
|
449
447
|
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
@@ -480,11 +478,31 @@ module ActiveRecord
|
|
480
478
|
type = integer_like_primary_key_type(type, options)
|
481
479
|
end
|
482
480
|
type = aliased_types(type.to_s, type)
|
481
|
+
|
482
|
+
if @conn.supports_datetime_with_precision?
|
483
|
+
if type == :datetime && !options.key?(:precision)
|
484
|
+
options[:precision] = 6
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
483
488
|
options[:primary_key] ||= type == :primary_key
|
484
489
|
options[:null] = false if options[:primary_key]
|
485
490
|
create_column_definition(name, type, options)
|
486
491
|
end
|
487
492
|
|
493
|
+
def new_foreign_key_definition(to_table, options) # :nodoc:
|
494
|
+
prefix = ActiveRecord::Base.table_name_prefix
|
495
|
+
suffix = ActiveRecord::Base.table_name_suffix
|
496
|
+
to_table = "#{prefix}#{to_table}#{suffix}"
|
497
|
+
options = @conn.foreign_key_options(name, to_table, options)
|
498
|
+
ForeignKeyDefinition.new(name, to_table, options)
|
499
|
+
end
|
500
|
+
|
501
|
+
def new_check_constraint_definition(expression, options) # :nodoc:
|
502
|
+
options = @conn.check_constraint_options(name, expression, options)
|
503
|
+
CheckConstraintDefinition.new(name, expression, options)
|
504
|
+
end
|
505
|
+
|
488
506
|
private
|
489
507
|
def create_column_definition(name, type, options)
|
490
508
|
ColumnDefinition.new(name, type, options)
|
@@ -501,6 +519,16 @@ module ActiveRecord
|
|
501
519
|
def integer_like_primary_key_type(type, options)
|
502
520
|
type
|
503
521
|
end
|
522
|
+
|
523
|
+
def raise_on_duplicate_column(name)
|
524
|
+
if @columns_hash[name]
|
525
|
+
if @columns_hash[name].primary_key?
|
526
|
+
raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
|
527
|
+
else
|
528
|
+
raise ArgumentError, "you can't define an already defined column '#{name}'."
|
529
|
+
end
|
530
|
+
end
|
531
|
+
end
|
504
532
|
end
|
505
533
|
|
506
534
|
class AlterTable # :nodoc:
|
@@ -520,7 +548,7 @@ module ActiveRecord
|
|
520
548
|
def name; @td.name; end
|
521
549
|
|
522
550
|
def add_foreign_key(to_table, options)
|
523
|
-
@foreign_key_adds <<
|
551
|
+
@foreign_key_adds << @td.new_foreign_key_definition(to_table, options)
|
524
552
|
end
|
525
553
|
|
526
554
|
def drop_foreign_key(name)
|
@@ -528,7 +556,7 @@ module ActiveRecord
|
|
528
556
|
end
|
529
557
|
|
530
558
|
def add_check_constraint(expression, options)
|
531
|
-
@check_constraint_adds <<
|
559
|
+
@check_constraint_adds << @td.new_check_constraint_definition(expression, options)
|
532
560
|
end
|
533
561
|
|
534
562
|
def drop_check_constraint(constraint_name)
|
@@ -572,6 +600,7 @@ module ActiveRecord
|
|
572
600
|
# t.time
|
573
601
|
# t.date
|
574
602
|
# t.binary
|
603
|
+
# t.blob
|
575
604
|
# t.boolean
|
576
605
|
# t.foreign_key
|
577
606
|
# t.json
|
@@ -636,8 +665,8 @@ module ActiveRecord
|
|
636
665
|
# end
|
637
666
|
#
|
638
667
|
# See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
|
639
|
-
def index_exists?(column_name, options
|
640
|
-
@base.index_exists?(name, column_name, options)
|
668
|
+
def index_exists?(column_name, **options)
|
669
|
+
@base.index_exists?(name, column_name, **options)
|
641
670
|
end
|
642
671
|
|
643
672
|
# Renames the given index on the table.
|
@@ -789,8 +818,8 @@ module ActiveRecord
|
|
789
818
|
# t.check_constraint("price > 0", name: "price_check")
|
790
819
|
#
|
791
820
|
# See {connection.add_check_constraint}[rdoc-ref:SchemaStatements#add_check_constraint]
|
792
|
-
def check_constraint(*args)
|
793
|
-
@base.add_check_constraint(name, *args)
|
821
|
+
def check_constraint(*args, **options)
|
822
|
+
@base.add_check_constraint(name, *args, **options)
|
794
823
|
end
|
795
824
|
|
796
825
|
# Removes the given check constraint from the table.
|
@@ -798,8 +827,8 @@ module ActiveRecord
|
|
798
827
|
# t.remove_check_constraint(name: "price_check")
|
799
828
|
#
|
800
829
|
# See {connection.remove_check_constraint}[rdoc-ref:SchemaStatements#remove_check_constraint]
|
801
|
-
def remove_check_constraint(*args)
|
802
|
-
@base.remove_check_constraint(name, *args)
|
830
|
+
def remove_check_constraint(*args, **options)
|
831
|
+
@base.remove_check_constraint(name, *args, **options)
|
803
832
|
end
|
804
833
|
end
|
805
834
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters # :nodoc:
|
5
5
|
class SchemaDumper < SchemaDumper # :nodoc:
|
6
|
+
DEFAULT_DATETIME_PRECISION = 6 # :nodoc:
|
7
|
+
|
6
8
|
def self.create(connection, options)
|
7
9
|
new(connection, options)
|
8
10
|
end
|
@@ -63,7 +65,18 @@ module ActiveRecord
|
|
63
65
|
end
|
64
66
|
|
65
67
|
def schema_precision(column)
|
66
|
-
column.
|
68
|
+
if column.type == :datetime
|
69
|
+
case column.precision
|
70
|
+
when nil
|
71
|
+
"nil"
|
72
|
+
when DEFAULT_DATETIME_PRECISION
|
73
|
+
nil
|
74
|
+
else
|
75
|
+
column.precision.inspect
|
76
|
+
end
|
77
|
+
elsif column.precision
|
78
|
+
column.precision.inspect
|
79
|
+
end
|
67
80
|
end
|
68
81
|
|
69
82
|
def schema_scale(column)
|