activerecord 6.1.7 → 7.2.0
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 +520 -1385
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +2 -12
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +60 -21
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +37 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +41 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +4 -4
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +46 -36
- data/lib/active_record/associations/collection_proxy.rb +44 -16
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +29 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +212 -53
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -16
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +15 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +404 -509
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +2 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +47 -27
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +14 -11
- data/lib/active_record/attribute_methods/serialization.rb +174 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -9
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +164 -52
- data/lib/active_record/attributes.rb +51 -49
- data/lib/active_record/autosave_association.rb +74 -57
- data/lib/active_record/base.rb +27 -5
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +327 -612
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +377 -142
- data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
- data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +345 -166
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
- data/lib/active_record/connection_adapters/pool_config.rb +26 -16
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- 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/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +401 -77
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +518 -251
- data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +130 -6
- data/lib/active_record/connection_handling.rb +132 -146
- data/lib/active_record/core.rb +276 -251
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -3
- data/lib/active_record/database_configurations/database_config.rb +34 -10
- data/lib/active_record/database_configurations/hash_config.rb +107 -31
- data/lib/active_record/database_configurations/url_config.rb +38 -13
- data/lib/active_record/database_configurations.rb +96 -60
- data/lib/active_record/delegated_type.rb +90 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +3 -3
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -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 +170 -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 +157 -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 +53 -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_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +163 -63
- data/lib/active_record/errors.rb +210 -27
- data/lib/active_record/explain.rb +21 -12
- 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/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +179 -112
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +85 -31
- data/lib/active_record/insert_all.rb +148 -32
- data/lib/active_record/integration.rb +14 -10
- data/lib/active_record/internal_metadata.rb +123 -23
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +43 -27
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +41 -29
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +113 -16
- data/lib/active_record/migration/compatibility.rb +235 -46
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +374 -177
- data/lib/active_record/model_schema.rb +143 -159
- data/lib/active_record/nested_attributes.rb +48 -21
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +282 -283
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +19 -25
- data/lib/active_record/query_logs.rb +189 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +44 -9
- data/lib/active_record/railtie.rb +234 -71
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +189 -256
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +325 -103
- data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +300 -111
- data/lib/active_record/relation/delegation.rb +33 -22
- data/lib/active_record/relation/finder_methods.rb +123 -52
- data/lib/active_record/relation/merger.rb +26 -19
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +29 -22
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +842 -150
- data/lib/active_record/relation/record_fetch_warning.rb +10 -9
- data/lib/active_record/relation/spawn_methods.rb +7 -6
- data/lib/active_record/relation/where_clause.rb +15 -36
- data/lib/active_record/relation.rb +736 -145
- data/lib/active_record/result.rb +67 -54
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +84 -34
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +90 -31
- data/lib/active_record/schema_migration.rb +74 -23
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +30 -9
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +277 -149
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +173 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +118 -41
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -7
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -7
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +64 -15
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +444 -32
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +7 -2
- data/lib/arel/predications.rb +14 -4
- data/lib/arel/select_manager.rb +11 -5
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +20 -5
- data/lib/arel/visitors/dot.rb +81 -90
- data/lib/arel/visitors/mysql.rb +23 -5
- data/lib/arel/visitors/postgresql.rb +1 -22
- data/lib/arel/visitors/to_sql.rb +170 -36
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +23 -4
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- 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 +100 -14
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -5,20 +5,24 @@ require "concurrent/map"
|
|
5
5
|
module ActiveRecord
|
6
6
|
module ConnectionAdapters # :nodoc:
|
7
7
|
module QueryCache
|
8
|
+
DEFAULT_SIZE = 100 # :nodoc:
|
9
|
+
|
8
10
|
class << self
|
9
|
-
def included(base)
|
10
|
-
dirties_query_cache base, :create, :insert, :update, :delete, :truncate,
|
11
|
-
:rollback_to_savepoint, :rollback_db_transaction, :
|
11
|
+
def included(base) # :nodoc:
|
12
|
+
dirties_query_cache base, :exec_query, :execute, :create, :insert, :update, :delete, :truncate,
|
13
|
+
:truncate_tables, :rollback_to_savepoint, :rollback_db_transaction, :restart_db_transaction,
|
14
|
+
:exec_insert_all
|
12
15
|
|
13
|
-
base.set_callback :
|
14
|
-
base.set_callback :checkin, :after, :disable_query_cache!
|
16
|
+
base.set_callback :checkin, :after, :unset_query_cache!
|
15
17
|
end
|
16
18
|
|
17
19
|
def dirties_query_cache(base, *method_names)
|
18
20
|
method_names.each do |method_name|
|
19
21
|
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
|
20
|
-
def #{method_name}(
|
21
|
-
|
22
|
+
def #{method_name}(...)
|
23
|
+
if pool.dirties_query_cache
|
24
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
25
|
+
end
|
22
26
|
super
|
23
27
|
end
|
24
28
|
end_code
|
@@ -26,59 +30,168 @@ module ActiveRecord
|
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
29
|
-
|
30
|
-
|
33
|
+
class Store # :nodoc:
|
34
|
+
attr_accessor :enabled, :dirties
|
35
|
+
alias_method :enabled?, :enabled
|
36
|
+
alias_method :dirties?, :dirties
|
37
|
+
|
38
|
+
def initialize(max_size)
|
39
|
+
@map = {}
|
40
|
+
@max_size = max_size
|
41
|
+
@enabled = false
|
42
|
+
@dirties = true
|
43
|
+
end
|
44
|
+
|
45
|
+
def size
|
46
|
+
@map.size
|
47
|
+
end
|
48
|
+
|
49
|
+
def empty?
|
50
|
+
@map.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
def [](key)
|
54
|
+
return unless @enabled
|
55
|
+
|
56
|
+
if entry = @map.delete(key)
|
57
|
+
@map[key] = entry
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def compute_if_absent(key)
|
62
|
+
return yield unless @enabled
|
63
|
+
|
64
|
+
if entry = @map.delete(key)
|
65
|
+
return @map[key] = entry
|
66
|
+
end
|
67
|
+
|
68
|
+
if @max_size && @map.size >= @max_size
|
69
|
+
@map.shift # evict the oldest entry
|
70
|
+
end
|
71
|
+
|
72
|
+
@map[key] ||= yield
|
73
|
+
end
|
74
|
+
|
75
|
+
def clear
|
76
|
+
@map.clear
|
77
|
+
self
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module ConnectionPoolConfiguration # :nodoc:
|
82
|
+
def initialize(...)
|
31
83
|
super
|
32
|
-
@
|
84
|
+
@thread_query_caches = Concurrent::Map.new(initial_capacity: @size)
|
85
|
+
@query_cache_max_size = \
|
86
|
+
case query_cache = db_config&.query_cache
|
87
|
+
when 0, false
|
88
|
+
nil
|
89
|
+
when Integer
|
90
|
+
query_cache
|
91
|
+
when nil
|
92
|
+
DEFAULT_SIZE
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def checkout_and_verify(connection)
|
97
|
+
super
|
98
|
+
connection.query_cache ||= query_cache
|
99
|
+
connection
|
100
|
+
end
|
101
|
+
|
102
|
+
# Disable the query cache within the block.
|
103
|
+
def disable_query_cache(dirties: true)
|
104
|
+
cache = query_cache
|
105
|
+
old_enabled, cache.enabled, old_dirties, cache.dirties = cache.enabled, false, cache.dirties, dirties
|
106
|
+
begin
|
107
|
+
yield
|
108
|
+
ensure
|
109
|
+
cache.enabled, cache.dirties = old_enabled, old_dirties
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def enable_query_cache
|
114
|
+
cache = query_cache
|
115
|
+
old_enabled, cache.enabled, old_dirties, cache.dirties = cache.enabled, true, cache.dirties, true
|
116
|
+
begin
|
117
|
+
yield
|
118
|
+
ensure
|
119
|
+
cache.enabled, cache.dirties = old_enabled, old_dirties
|
120
|
+
end
|
33
121
|
end
|
34
122
|
|
35
123
|
def enable_query_cache!
|
36
|
-
|
37
|
-
connection.enable_query_cache! if active_connection?
|
124
|
+
query_cache.enabled, query_cache.dirties = true, true
|
38
125
|
end
|
39
126
|
|
40
127
|
def disable_query_cache!
|
41
|
-
|
42
|
-
connection.disable_query_cache! if active_connection?
|
128
|
+
query_cache.enabled, query_cache.dirties = false, true
|
43
129
|
end
|
44
130
|
|
45
131
|
def query_cache_enabled
|
46
|
-
|
132
|
+
query_cache.enabled
|
133
|
+
end
|
134
|
+
|
135
|
+
def dirties_query_cache
|
136
|
+
query_cache.dirties
|
137
|
+
end
|
138
|
+
|
139
|
+
def clear_query_cache
|
140
|
+
if @pinned_connection
|
141
|
+
# With transactional fixtures, and especially systems test
|
142
|
+
# another thread may use the same connection, but with a different
|
143
|
+
# query cache. So we must clear them all.
|
144
|
+
@thread_query_caches.each_value(&:clear)
|
145
|
+
else
|
146
|
+
query_cache.clear
|
147
|
+
end
|
47
148
|
end
|
149
|
+
|
150
|
+
def query_cache
|
151
|
+
@thread_query_caches.compute_if_absent(ActiveSupport::IsolatedExecutionState.context) do
|
152
|
+
Store.new(@query_cache_max_size)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
def prune_thread_cache
|
158
|
+
dead_threads = @thread_query_caches.keys.reject(&:alive?)
|
159
|
+
dead_threads.each do |dead_thread|
|
160
|
+
@thread_query_caches.delete(dead_thread)
|
161
|
+
end
|
162
|
+
end
|
48
163
|
end
|
49
164
|
|
50
|
-
|
165
|
+
attr_accessor :query_cache
|
51
166
|
|
52
167
|
def initialize(*)
|
53
168
|
super
|
54
|
-
@query_cache
|
55
|
-
|
169
|
+
@query_cache = nil
|
170
|
+
end
|
171
|
+
|
172
|
+
def query_cache_enabled
|
173
|
+
@query_cache&.enabled?
|
56
174
|
end
|
57
175
|
|
58
176
|
# Enable the query cache within the block.
|
59
|
-
def cache
|
60
|
-
|
61
|
-
yield
|
62
|
-
ensure
|
63
|
-
@query_cache_enabled = old
|
64
|
-
clear_query_cache unless @query_cache_enabled
|
177
|
+
def cache(&block)
|
178
|
+
pool.enable_query_cache(&block)
|
65
179
|
end
|
66
180
|
|
67
181
|
def enable_query_cache!
|
68
|
-
|
182
|
+
pool.enable_query_cache!
|
69
183
|
end
|
70
184
|
|
71
|
-
|
72
|
-
|
73
|
-
|
185
|
+
# Disable the query cache within the block.
|
186
|
+
#
|
187
|
+
# Set <tt>dirties: false</tt> to prevent query caches on all connections from being cleared by write operations.
|
188
|
+
# (By default, write operations dirty all connections' query caches in case they are replicas whose cache would now be outdated.)
|
189
|
+
def uncached(dirties: true, &block)
|
190
|
+
pool.disable_query_cache(dirties: dirties, &block)
|
74
191
|
end
|
75
192
|
|
76
|
-
|
77
|
-
|
78
|
-
old, @query_cache_enabled = @query_cache_enabled, false
|
79
|
-
yield
|
80
|
-
ensure
|
81
|
-
@query_cache_enabled = old
|
193
|
+
def disable_query_cache!
|
194
|
+
pool.disable_query_cache!
|
82
195
|
end
|
83
196
|
|
84
197
|
# Clears the query cache.
|
@@ -88,37 +201,71 @@ module ActiveRecord
|
|
88
201
|
# the same SQL query and repeatedly return the same result each time, silently
|
89
202
|
# undermining the randomness you were expecting.
|
90
203
|
def clear_query_cache
|
91
|
-
|
92
|
-
@query_cache.clear
|
93
|
-
end
|
204
|
+
pool.clear_query_cache
|
94
205
|
end
|
95
206
|
|
96
|
-
def select_all(arel, name = nil, binds = [], preparable: nil)
|
97
|
-
|
98
|
-
arel = arel_from_relation(arel)
|
99
|
-
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
207
|
+
def select_all(arel, name = nil, binds = [], preparable: nil, async: false, allow_retry: false) # :nodoc:
|
208
|
+
arel = arel_from_relation(arel)
|
100
209
|
|
101
|
-
|
210
|
+
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch.
|
211
|
+
# Such queries should not be cached.
|
212
|
+
if @query_cache&.enabled? && !(arel.respond_to?(:locked) && arel.locked)
|
213
|
+
sql, binds, preparable, allow_retry = to_sql_and_binds(arel, binds, preparable)
|
214
|
+
|
215
|
+
if async
|
216
|
+
result = lookup_sql_cache(sql, name, binds) || super(sql, name, binds, preparable: preparable, async: async, allow_retry: allow_retry)
|
217
|
+
FutureResult.wrap(result)
|
218
|
+
else
|
219
|
+
cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable, async: async, allow_retry: allow_retry) }
|
220
|
+
end
|
102
221
|
else
|
103
222
|
super
|
104
223
|
end
|
105
224
|
end
|
106
225
|
|
107
226
|
private
|
227
|
+
def unset_query_cache!
|
228
|
+
@query_cache = nil
|
229
|
+
end
|
230
|
+
|
231
|
+
def lookup_sql_cache(sql, name, binds)
|
232
|
+
key = binds.empty? ? sql : [sql, binds]
|
233
|
+
|
234
|
+
result = nil
|
235
|
+
@lock.synchronize do
|
236
|
+
result = @query_cache[key]
|
237
|
+
end
|
238
|
+
|
239
|
+
if result
|
240
|
+
ActiveSupport::Notifications.instrument(
|
241
|
+
"sql.active_record",
|
242
|
+
cache_notification_info(sql, name, binds)
|
243
|
+
)
|
244
|
+
end
|
245
|
+
|
246
|
+
result
|
247
|
+
end
|
248
|
+
|
108
249
|
def cache_sql(sql, name, binds)
|
250
|
+
key = binds.empty? ? sql : [sql, binds]
|
251
|
+
result = nil
|
252
|
+
hit = true
|
253
|
+
|
109
254
|
@lock.synchronize do
|
110
|
-
result =
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
255
|
+
result = @query_cache.compute_if_absent(key) do
|
256
|
+
hit = false
|
257
|
+
yield
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
if hit
|
262
|
+
ActiveSupport::Notifications.instrument(
|
263
|
+
"sql.active_record",
|
264
|
+
cache_notification_info(sql, name, binds)
|
265
|
+
)
|
121
266
|
end
|
267
|
+
|
268
|
+
result.dup
|
122
269
|
end
|
123
270
|
|
124
271
|
# Database adapters can override this method to
|
@@ -130,20 +277,10 @@ module ActiveRecord
|
|
130
277
|
type_casted_binds: -> { type_casted_binds(binds) },
|
131
278
|
name: name,
|
132
279
|
connection: self,
|
280
|
+
transaction: current_transaction.user_transaction.presence,
|
133
281
|
cached: true
|
134
282
|
}
|
135
283
|
end
|
136
|
-
|
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
|
-
def configure_query_cache!
|
145
|
-
enable_query_cache! if pool.query_cache_enabled
|
146
|
-
end
|
147
284
|
end
|
148
285
|
end
|
149
286
|
end
|
@@ -5,42 +5,112 @@ require "active_support/multibyte/chars"
|
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
7
|
module ConnectionAdapters # :nodoc:
|
8
|
+
# = Active Record Connection Adapters \Quoting
|
8
9
|
module Quoting
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
module ClassMethods # :nodoc:
|
13
|
+
# Regexp for column names (with or without a table name prefix).
|
14
|
+
# Matches the following:
|
15
|
+
#
|
16
|
+
# "#{table_name}.#{column_name}"
|
17
|
+
# "#{column_name}"
|
18
|
+
def column_name_matcher
|
19
|
+
/
|
20
|
+
\A
|
21
|
+
(
|
22
|
+
(?:
|
23
|
+
# table_name.column_name | function(one or no argument)
|
24
|
+
((?:\w+\.)?\w+ | \w+\((?:|\g<2>)\))
|
25
|
+
)
|
26
|
+
(?:(?:\s+AS)?\s+\w+)?
|
27
|
+
)
|
28
|
+
(?:\s*,\s*\g<1>)*
|
29
|
+
\z
|
30
|
+
/ix
|
31
|
+
end
|
32
|
+
|
33
|
+
# Regexp for column names with order (with or without a table name prefix,
|
34
|
+
# with or without various order modifiers). Matches the following:
|
35
|
+
#
|
36
|
+
# "#{table_name}.#{column_name}"
|
37
|
+
# "#{table_name}.#{column_name} #{direction}"
|
38
|
+
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
|
39
|
+
# "#{table_name}.#{column_name} NULLS LAST"
|
40
|
+
# "#{column_name}"
|
41
|
+
# "#{column_name} #{direction}"
|
42
|
+
# "#{column_name} #{direction} NULLS FIRST"
|
43
|
+
# "#{column_name} NULLS LAST"
|
44
|
+
def column_name_with_order_matcher
|
45
|
+
/
|
46
|
+
\A
|
47
|
+
(
|
48
|
+
(?:
|
49
|
+
# table_name.column_name | function(one or no argument)
|
50
|
+
((?:\w+\.)?\w+ | \w+\((?:|\g<2>)\))
|
51
|
+
)
|
52
|
+
(?:\s+ASC|\s+DESC)?
|
53
|
+
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
54
|
+
)
|
55
|
+
(?:\s*,\s*\g<1>)*
|
56
|
+
\z
|
57
|
+
/ix
|
58
|
+
end
|
59
|
+
|
60
|
+
# Quotes the column name. Must be implemented by subclasses
|
61
|
+
def quote_column_name(column_name)
|
62
|
+
raise NotImplementedError
|
63
|
+
end
|
64
|
+
|
65
|
+
# Quotes the table name. Defaults to column name quoting.
|
66
|
+
def quote_table_name(table_name)
|
67
|
+
quote_column_name(table_name)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
9
71
|
# Quotes the column value to help prevent
|
10
72
|
# {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
|
11
73
|
def quote(value)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
74
|
+
case value
|
75
|
+
when String, Symbol, ActiveSupport::Multibyte::Chars
|
76
|
+
"'#{quote_string(value.to_s)}'"
|
77
|
+
when true then quoted_true
|
78
|
+
when false then quoted_false
|
79
|
+
when nil then "NULL"
|
80
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
81
|
+
when BigDecimal then value.to_s("F")
|
82
|
+
when Numeric then value.to_s
|
83
|
+
when Type::Binary::Data then quoted_binary(value)
|
84
|
+
when Type::Time::Value then "'#{quoted_time(value)}'"
|
85
|
+
when Date, Time then "'#{quoted_date(value)}'"
|
86
|
+
when Class then "'#{value}'"
|
87
|
+
else raise TypeError, "can't quote #{value.class.name}"
|
18
88
|
end
|
19
|
-
|
20
|
-
_quote(value)
|
21
89
|
end
|
22
90
|
|
23
91
|
# Cast a +value+ to a type that the database understands. For example,
|
24
92
|
# SQLite does not understand dates, so this method will convert a Date
|
25
93
|
# 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)
|
94
|
+
def type_cast(value)
|
95
|
+
case value
|
96
|
+
when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
|
97
|
+
value.to_s
|
98
|
+
when true then unquoted_true
|
99
|
+
when false then unquoted_false
|
100
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
101
|
+
when BigDecimal then value.to_s("F")
|
102
|
+
when nil, Numeric, String then value
|
103
|
+
when Type::Time::Value then quoted_time(value)
|
104
|
+
when Date, Time then quoted_date(value)
|
105
|
+
else raise TypeError, "can't cast #{value.class.name}"
|
41
106
|
end
|
107
|
+
end
|
42
108
|
|
43
|
-
|
109
|
+
# Cast a value to be used as a bound parameter of unknown type. For example,
|
110
|
+
# MySQL might perform dangerous castings when comparing a string to a number,
|
111
|
+
# so this method will cast numbers to string.
|
112
|
+
def cast_bound_value(value) # :nodoc:
|
113
|
+
value
|
44
114
|
end
|
45
115
|
|
46
116
|
# If you are having to call this function, you are likely doing something
|
@@ -59,23 +129,23 @@ module ActiveRecord
|
|
59
129
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
60
130
|
# characters.
|
61
131
|
def quote_string(s)
|
62
|
-
s.gsub(
|
132
|
+
s.gsub("\\", '\&\&').gsub("'", "''") # ' (for ruby-mode)
|
63
133
|
end
|
64
134
|
|
65
|
-
# Quotes the column name.
|
135
|
+
# Quotes the column name.
|
66
136
|
def quote_column_name(column_name)
|
67
|
-
column_name
|
137
|
+
self.class.quote_column_name(column_name)
|
68
138
|
end
|
69
139
|
|
70
|
-
# Quotes the table name.
|
140
|
+
# Quotes the table name.
|
71
141
|
def quote_table_name(table_name)
|
72
|
-
|
142
|
+
self.class.quote_table_name(table_name)
|
73
143
|
end
|
74
144
|
|
75
145
|
# Override to return the quoted table name for assignment. Defaults to
|
76
146
|
# table quoting.
|
77
147
|
#
|
78
|
-
# This works for
|
148
|
+
# This works for MySQL where table.column can be used to
|
79
149
|
# resolve ambiguity.
|
80
150
|
#
|
81
151
|
# We override this in the sqlite3 and postgresql adapters to use only
|
@@ -113,14 +183,14 @@ module ActiveRecord
|
|
113
183
|
# if the value is a Time responding to usec.
|
114
184
|
def quoted_date(value)
|
115
185
|
if value.acts_like?(:time)
|
116
|
-
if
|
117
|
-
value = value.getutc if
|
186
|
+
if default_timezone == :utc
|
187
|
+
value = value.getutc if !value.utc?
|
118
188
|
else
|
119
|
-
value = value.getlocal
|
189
|
+
value = value.getlocal
|
120
190
|
end
|
121
191
|
end
|
122
192
|
|
123
|
-
result = value.
|
193
|
+
result = value.to_fs(:db)
|
124
194
|
if value.respond_to?(:usec) && value.usec > 0
|
125
195
|
result << "." << sprintf("%06d", value.usec)
|
126
196
|
else
|
@@ -138,74 +208,25 @@ module ActiveRecord
|
|
138
208
|
end
|
139
209
|
|
140
210
|
def sanitize_as_sql_comment(value) # :nodoc:
|
141
|
-
|
211
|
+
# Sanitize a string to appear within a SQL comment
|
212
|
+
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
213
|
+
# charcacters, possibly with single surrounding space.
|
214
|
+
# Then follows that by replacing any internal "*/" or "/ *" with
|
215
|
+
# "* /" or "/ *"
|
216
|
+
comment = value.to_s.dup
|
217
|
+
comment.gsub!(%r{\A\s*/\*\+?\s?|\s?\*/\s*\Z}, "")
|
218
|
+
comment.gsub!("*/", "* /")
|
219
|
+
comment.gsub!("/*", "/ *")
|
220
|
+
comment
|
142
221
|
end
|
143
222
|
|
144
|
-
def column_name_matcher # :nodoc:
|
145
|
-
COLUMN_NAME
|
146
|
-
end
|
147
|
-
|
148
|
-
def column_name_with_order_matcher # :nodoc:
|
149
|
-
COLUMN_NAME_WITH_ORDER
|
150
|
-
end
|
151
|
-
|
152
|
-
# Regexp for column names (with or without a table name prefix).
|
153
|
-
# Matches the following:
|
154
|
-
#
|
155
|
-
# "#{table_name}.#{column_name}"
|
156
|
-
# "#{column_name}"
|
157
|
-
COLUMN_NAME = /
|
158
|
-
\A
|
159
|
-
(
|
160
|
-
(?:
|
161
|
-
# table_name.column_name | function(one or no argument)
|
162
|
-
((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
|
163
|
-
)
|
164
|
-
(?:(?:\s+AS)?\s+\w+)?
|
165
|
-
)
|
166
|
-
(?:\s*,\s*\g<1>)*
|
167
|
-
\z
|
168
|
-
/ix
|
169
|
-
|
170
|
-
# Regexp for column names with order (with or without a table name prefix,
|
171
|
-
# with or without various order modifiers). Matches the following:
|
172
|
-
#
|
173
|
-
# "#{table_name}.#{column_name}"
|
174
|
-
# "#{table_name}.#{column_name} #{direction}"
|
175
|
-
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
|
176
|
-
# "#{table_name}.#{column_name} NULLS LAST"
|
177
|
-
# "#{column_name}"
|
178
|
-
# "#{column_name} #{direction}"
|
179
|
-
# "#{column_name} #{direction} NULLS FIRST"
|
180
|
-
# "#{column_name} NULLS LAST"
|
181
|
-
COLUMN_NAME_WITH_ORDER = /
|
182
|
-
\A
|
183
|
-
(
|
184
|
-
(?:
|
185
|
-
# table_name.column_name | function(one or no argument)
|
186
|
-
((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
|
187
|
-
)
|
188
|
-
(?:\s+ASC|\s+DESC)?
|
189
|
-
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
190
|
-
)
|
191
|
-
(?:\s*,\s*\g<1>)*
|
192
|
-
\z
|
193
|
-
/ix
|
194
|
-
|
195
|
-
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
196
|
-
|
197
223
|
private
|
198
224
|
def type_casted_binds(binds)
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
if ActiveModel::Attribute === value
|
205
|
-
type_cast(value.value_for_database)
|
206
|
-
else
|
207
|
-
type_cast(value)
|
208
|
-
end
|
225
|
+
binds.map do |value|
|
226
|
+
if ActiveModel::Attribute === value
|
227
|
+
type_cast(value.value_for_database)
|
228
|
+
else
|
229
|
+
type_cast(value)
|
209
230
|
end
|
210
231
|
end
|
211
232
|
end
|
@@ -213,39 +234,6 @@ module ActiveRecord
|
|
213
234
|
def lookup_cast_type(sql_type)
|
214
235
|
type_map.lookup(sql_type)
|
215
236
|
end
|
216
|
-
|
217
|
-
def _quote(value)
|
218
|
-
case value
|
219
|
-
when String, Symbol, ActiveSupport::Multibyte::Chars
|
220
|
-
"'#{quote_string(value.to_s)}'"
|
221
|
-
when true then quoted_true
|
222
|
-
when false then quoted_false
|
223
|
-
when nil then "NULL"
|
224
|
-
# BigDecimals need to be put in a non-normalized form and quoted.
|
225
|
-
when BigDecimal then value.to_s("F")
|
226
|
-
when Numeric, ActiveSupport::Duration then value.to_s
|
227
|
-
when Type::Binary::Data then quoted_binary(value)
|
228
|
-
when Type::Time::Value then "'#{quoted_time(value)}'"
|
229
|
-
when Date, Time then "'#{quoted_date(value)}'"
|
230
|
-
when Class then "'#{value}'"
|
231
|
-
else raise TypeError, "can't quote #{value.class.name}"
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
def _type_cast(value)
|
236
|
-
case value
|
237
|
-
when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
|
238
|
-
value.to_s
|
239
|
-
when true then unquoted_true
|
240
|
-
when false then unquoted_false
|
241
|
-
# BigDecimals need to be put in a non-normalized form and quoted.
|
242
|
-
when BigDecimal then value.to_s("F")
|
243
|
-
when nil, Numeric, String then value
|
244
|
-
when Type::Time::Value then quoted_time(value)
|
245
|
-
when Date, Time then quoted_date(value)
|
246
|
-
else raise TypeError, "can't cast #{value.class.name}"
|
247
|
-
end
|
248
|
-
end
|
249
237
|
end
|
250
238
|
end
|
251
239
|
end
|
@@ -2,21 +2,22 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
|
+
# = Active Record Connection Adapters \Savepoints
|
5
6
|
module Savepoints
|
6
7
|
def current_savepoint_name
|
7
8
|
current_transaction.savepoint_name
|
8
9
|
end
|
9
10
|
|
10
11
|
def create_savepoint(name = current_savepoint_name)
|
11
|
-
|
12
|
+
internal_execute("SAVEPOINT #{name}", "TRANSACTION")
|
12
13
|
end
|
13
14
|
|
14
15
|
def exec_rollback_to_savepoint(name = current_savepoint_name)
|
15
|
-
|
16
|
+
internal_execute("ROLLBACK TO SAVEPOINT #{name}", "TRANSACTION")
|
16
17
|
end
|
17
18
|
|
18
19
|
def release_savepoint(name = current_savepoint_name)
|
19
|
-
|
20
|
+
internal_execute("RELEASE SAVEPOINT #{name}", "TRANSACTION")
|
20
21
|
end
|
21
22
|
end
|
22
23
|
end
|