activerecord 6.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 +7 -0
- data/CHANGELOG.md +1013 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +219 -0
- data/examples/performance.rb +185 -0
- data/examples/simple.rb +15 -0
- data/lib/active_record.rb +195 -0
- data/lib/active_record/aggregations.rb +285 -0
- data/lib/active_record/association_relation.rb +40 -0
- data/lib/active_record/associations.rb +1865 -0
- data/lib/active_record/associations/alias_tracker.rb +81 -0
- data/lib/active_record/associations/association.rb +332 -0
- data/lib/active_record/associations/association_scope.rb +166 -0
- data/lib/active_record/associations/belongs_to_association.rb +124 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +36 -0
- data/lib/active_record/associations/builder/association.rb +136 -0
- data/lib/active_record/associations/builder/belongs_to.rb +130 -0
- data/lib/active_record/associations/builder/collection_association.rb +72 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +114 -0
- data/lib/active_record/associations/builder/has_many.rb +19 -0
- data/lib/active_record/associations/builder/has_one.rb +64 -0
- data/lib/active_record/associations/builder/singular_association.rb +44 -0
- data/lib/active_record/associations/collection_association.rb +498 -0
- data/lib/active_record/associations/collection_proxy.rb +1128 -0
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +136 -0
- data/lib/active_record/associations/has_many_through_association.rb +220 -0
- data/lib/active_record/associations/has_one_association.rb +118 -0
- data/lib/active_record/associations/has_one_through_association.rb +45 -0
- data/lib/active_record/associations/join_dependency.rb +258 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +80 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
- data/lib/active_record/associations/preloader.rb +201 -0
- data/lib/active_record/associations/preloader/association.rb +133 -0
- data/lib/active_record/associations/preloader/through_association.rb +116 -0
- data/lib/active_record/associations/singular_association.rb +59 -0
- data/lib/active_record/associations/through_association.rb +121 -0
- data/lib/active_record/attribute_assignment.rb +85 -0
- data/lib/active_record/attribute_decorators.rb +90 -0
- data/lib/active_record/attribute_methods.rb +420 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +81 -0
- data/lib/active_record/attribute_methods/dirty.rb +221 -0
- data/lib/active_record/attribute_methods/primary_key.rb +136 -0
- data/lib/active_record/attribute_methods/query.rb +41 -0
- data/lib/active_record/attribute_methods/read.rb +47 -0
- data/lib/active_record/attribute_methods/serialization.rb +90 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
- data/lib/active_record/attribute_methods/write.rb +61 -0
- data/lib/active_record/attributes.rb +279 -0
- data/lib/active_record/autosave_association.rb +508 -0
- data/lib/active_record/base.rb +328 -0
- data/lib/active_record/callbacks.rb +339 -0
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1165 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +85 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +512 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +154 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +251 -0
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +713 -0
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1475 -0
- data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +761 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +821 -0
- data/lib/active_record/connection_adapters/column.rb +95 -0
- data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +146 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +949 -0
- data/lib/active_record/connection_adapters/schema_cache.rb +141 -0
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +557 -0
- data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
- data/lib/active_record/connection_handling.rb +267 -0
- data/lib/active_record/core.rb +599 -0
- data/lib/active_record/counter_cache.rb +193 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +122 -0
- data/lib/active_record/enum.rb +274 -0
- data/lib/active_record/errors.rb +388 -0
- data/lib/active_record/explain.rb +50 -0
- data/lib/active_record/explain_registry.rb +32 -0
- data/lib/active_record/explain_subscriber.rb +34 -0
- data/lib/active_record/fixture_set/file.rb +82 -0
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +738 -0
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +293 -0
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +207 -0
- data/lib/active_record/internal_metadata.rb +53 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +48 -0
- data/lib/active_record/locking/optimistic.rb +197 -0
- data/lib/active_record/locking/pessimistic.rb +89 -0
- data/lib/active_record/log_subscriber.rb +118 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +1397 -0
- data/lib/active_record/migration/command_recorder.rb +284 -0
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +17 -0
- data/lib/active_record/model_schema.rb +542 -0
- data/lib/active_record/nested_attributes.rb +600 -0
- data/lib/active_record/no_touching.rb +65 -0
- data/lib/active_record/null_relation.rb +68 -0
- data/lib/active_record/persistence.rb +967 -0
- data/lib/active_record/query_cache.rb +52 -0
- data/lib/active_record/querying.rb +82 -0
- data/lib/active_record/railtie.rb +263 -0
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +7 -0
- data/lib/active_record/railties/controller_runtime.rb +51 -0
- data/lib/active_record/railties/databases.rake +527 -0
- data/lib/active_record/readonly_attributes.rb +24 -0
- data/lib/active_record/reflection.rb +1042 -0
- data/lib/active_record/relation.rb +859 -0
- data/lib/active_record/relation/batches.rb +290 -0
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/calculations.rb +424 -0
- data/lib/active_record/relation/delegation.rb +130 -0
- data/lib/active_record/relation/finder_methods.rb +552 -0
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +184 -0
- data/lib/active_record/relation/predicate_builder.rb +150 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +1359 -0
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +77 -0
- data/lib/active_record/relation/where_clause.rb +190 -0
- data/lib/active_record/relation/where_clause_factory.rb +33 -0
- data/lib/active_record/result.rb +168 -0
- data/lib/active_record/runtime_registry.rb +24 -0
- data/lib/active_record/sanitization.rb +214 -0
- data/lib/active_record/schema.rb +61 -0
- data/lib/active_record/schema_dumper.rb +270 -0
- data/lib/active_record/schema_migration.rb +60 -0
- data/lib/active_record/scoping.rb +106 -0
- data/lib/active_record/scoping/default.rb +151 -0
- data/lib/active_record/scoping/named.rb +217 -0
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +22 -0
- data/lib/active_record/statement_cache.rb +148 -0
- data/lib/active_record/store.rb +290 -0
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +75 -0
- data/lib/active_record/tasks/database_tasks.rb +506 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +167 -0
- data/lib/active_record/touch_later.rb +66 -0
- data/lib/active_record/transactions.rb +493 -0
- data/lib/active_record/translation.rb +24 -0
- data/lib/active_record/type.rb +78 -0
- data/lib/active_record/type/adapter_specific_registry.rb +129 -0
- data/lib/active_record/type/date.rb +9 -0
- data/lib/active_record/type/date_time.rb +9 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +71 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +21 -0
- data/lib/active_record/type/type_map.rb +62 -0
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/type_caster/connection.rb +34 -0
- data/lib/active_record/type_caster/map.rb +20 -0
- data/lib/active_record/validations.rb +94 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +60 -0
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +68 -0
- data/lib/active_record/validations/uniqueness.rb +226 -0
- data/lib/active_record/version.rb +10 -0
- data/lib/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record.rb +19 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration.rb +48 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +75 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +49 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
- metadata +415 -0
@@ -0,0 +1,323 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
class TransactionState
|
6
|
+
def initialize(state = nil)
|
7
|
+
@state = state
|
8
|
+
@children = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_child(state)
|
12
|
+
@children << state
|
13
|
+
end
|
14
|
+
|
15
|
+
def finalized?
|
16
|
+
@state
|
17
|
+
end
|
18
|
+
|
19
|
+
def committed?
|
20
|
+
@state == :committed || @state == :fully_committed
|
21
|
+
end
|
22
|
+
|
23
|
+
def fully_committed?
|
24
|
+
@state == :fully_committed
|
25
|
+
end
|
26
|
+
|
27
|
+
def rolledback?
|
28
|
+
@state == :rolledback || @state == :fully_rolledback
|
29
|
+
end
|
30
|
+
|
31
|
+
def fully_rolledback?
|
32
|
+
@state == :fully_rolledback
|
33
|
+
end
|
34
|
+
|
35
|
+
def fully_completed?
|
36
|
+
completed?
|
37
|
+
end
|
38
|
+
|
39
|
+
def completed?
|
40
|
+
committed? || rolledback?
|
41
|
+
end
|
42
|
+
|
43
|
+
def rollback!
|
44
|
+
@children.each { |c| c.rollback! }
|
45
|
+
@state = :rolledback
|
46
|
+
end
|
47
|
+
|
48
|
+
def full_rollback!
|
49
|
+
@children.each { |c| c.rollback! }
|
50
|
+
@state = :fully_rolledback
|
51
|
+
end
|
52
|
+
|
53
|
+
def commit!
|
54
|
+
@state = :committed
|
55
|
+
end
|
56
|
+
|
57
|
+
def full_commit!
|
58
|
+
@state = :fully_committed
|
59
|
+
end
|
60
|
+
|
61
|
+
def nullify!
|
62
|
+
@state = nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class NullTransaction #:nodoc:
|
67
|
+
def initialize; end
|
68
|
+
def state; end
|
69
|
+
def closed?; true; end
|
70
|
+
def open?; false; end
|
71
|
+
def joinable?; false; end
|
72
|
+
def add_record(record); end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Transaction #:nodoc:
|
76
|
+
attr_reader :connection, :state, :records, :savepoint_name, :isolation_level
|
77
|
+
|
78
|
+
def initialize(connection, options, run_commit_callbacks: false)
|
79
|
+
@connection = connection
|
80
|
+
@state = TransactionState.new
|
81
|
+
@records = []
|
82
|
+
@isolation_level = options[:isolation]
|
83
|
+
@materialized = false
|
84
|
+
@joinable = options.fetch(:joinable, true)
|
85
|
+
@run_commit_callbacks = run_commit_callbacks
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_record(record)
|
89
|
+
records << record
|
90
|
+
end
|
91
|
+
|
92
|
+
def materialize!
|
93
|
+
@materialized = true
|
94
|
+
end
|
95
|
+
|
96
|
+
def materialized?
|
97
|
+
@materialized
|
98
|
+
end
|
99
|
+
|
100
|
+
def rollback_records
|
101
|
+
ite = records.uniq(&:object_id)
|
102
|
+
already_run_callbacks = {}
|
103
|
+
while record = ite.shift
|
104
|
+
trigger_callbacks = record.trigger_transactional_callbacks?
|
105
|
+
should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
|
106
|
+
already_run_callbacks[record] ||= trigger_callbacks
|
107
|
+
record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
|
108
|
+
end
|
109
|
+
ensure
|
110
|
+
ite.each do |i|
|
111
|
+
i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def before_commit_records
|
116
|
+
records.uniq.each(&:before_committed!) if @run_commit_callbacks
|
117
|
+
end
|
118
|
+
|
119
|
+
def commit_records
|
120
|
+
ite = records.uniq(&:object_id)
|
121
|
+
already_run_callbacks = {}
|
122
|
+
while record = ite.shift
|
123
|
+
if @run_commit_callbacks
|
124
|
+
trigger_callbacks = record.trigger_transactional_callbacks?
|
125
|
+
should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
|
126
|
+
already_run_callbacks[record] ||= trigger_callbacks
|
127
|
+
record.committed!(should_run_callbacks: should_run_callbacks)
|
128
|
+
else
|
129
|
+
# if not running callbacks, only adds the record to the parent transaction
|
130
|
+
connection.add_transaction_record(record)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
ensure
|
134
|
+
ite.each { |i| i.committed!(should_run_callbacks: false) }
|
135
|
+
end
|
136
|
+
|
137
|
+
def full_rollback?; true; end
|
138
|
+
def joinable?; @joinable; end
|
139
|
+
def closed?; false; end
|
140
|
+
def open?; !closed?; end
|
141
|
+
end
|
142
|
+
|
143
|
+
class SavepointTransaction < Transaction
|
144
|
+
def initialize(connection, savepoint_name, parent_transaction, *args)
|
145
|
+
super(connection, *args)
|
146
|
+
|
147
|
+
parent_transaction.state.add_child(@state)
|
148
|
+
|
149
|
+
if isolation_level
|
150
|
+
raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
|
151
|
+
end
|
152
|
+
|
153
|
+
@savepoint_name = savepoint_name
|
154
|
+
end
|
155
|
+
|
156
|
+
def materialize!
|
157
|
+
connection.create_savepoint(savepoint_name)
|
158
|
+
super
|
159
|
+
end
|
160
|
+
|
161
|
+
def rollback
|
162
|
+
connection.rollback_to_savepoint(savepoint_name) if materialized?
|
163
|
+
@state.rollback!
|
164
|
+
end
|
165
|
+
|
166
|
+
def commit
|
167
|
+
connection.release_savepoint(savepoint_name) if materialized?
|
168
|
+
@state.commit!
|
169
|
+
end
|
170
|
+
|
171
|
+
def full_rollback?; false; end
|
172
|
+
end
|
173
|
+
|
174
|
+
class RealTransaction < Transaction
|
175
|
+
def materialize!
|
176
|
+
if isolation_level
|
177
|
+
connection.begin_isolated_db_transaction(isolation_level)
|
178
|
+
else
|
179
|
+
connection.begin_db_transaction
|
180
|
+
end
|
181
|
+
|
182
|
+
super
|
183
|
+
end
|
184
|
+
|
185
|
+
def rollback
|
186
|
+
connection.rollback_db_transaction if materialized?
|
187
|
+
@state.full_rollback!
|
188
|
+
end
|
189
|
+
|
190
|
+
def commit
|
191
|
+
connection.commit_db_transaction if materialized?
|
192
|
+
@state.full_commit!
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
class TransactionManager #:nodoc:
|
197
|
+
def initialize(connection)
|
198
|
+
@stack = []
|
199
|
+
@connection = connection
|
200
|
+
@has_unmaterialized_transactions = false
|
201
|
+
@materializing_transactions = false
|
202
|
+
@lazy_transactions_enabled = true
|
203
|
+
end
|
204
|
+
|
205
|
+
def begin_transaction(options = {})
|
206
|
+
@connection.lock.synchronize do
|
207
|
+
run_commit_callbacks = !current_transaction.joinable?
|
208
|
+
transaction =
|
209
|
+
if @stack.empty?
|
210
|
+
RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
|
211
|
+
else
|
212
|
+
SavepointTransaction.new(@connection, "active_record_#{@stack.size}", @stack.last, options,
|
213
|
+
run_commit_callbacks: run_commit_callbacks)
|
214
|
+
end
|
215
|
+
|
216
|
+
if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && options[:_lazy] != false
|
217
|
+
@has_unmaterialized_transactions = true
|
218
|
+
else
|
219
|
+
transaction.materialize!
|
220
|
+
end
|
221
|
+
@stack.push(transaction)
|
222
|
+
transaction
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def disable_lazy_transactions!
|
227
|
+
materialize_transactions
|
228
|
+
@lazy_transactions_enabled = false
|
229
|
+
end
|
230
|
+
|
231
|
+
def enable_lazy_transactions!
|
232
|
+
@lazy_transactions_enabled = true
|
233
|
+
end
|
234
|
+
|
235
|
+
def lazy_transactions_enabled?
|
236
|
+
@lazy_transactions_enabled
|
237
|
+
end
|
238
|
+
|
239
|
+
def materialize_transactions
|
240
|
+
return if @materializing_transactions
|
241
|
+
return unless @has_unmaterialized_transactions
|
242
|
+
|
243
|
+
@connection.lock.synchronize do
|
244
|
+
begin
|
245
|
+
@materializing_transactions = true
|
246
|
+
@stack.each { |t| t.materialize! unless t.materialized? }
|
247
|
+
ensure
|
248
|
+
@materializing_transactions = false
|
249
|
+
end
|
250
|
+
@has_unmaterialized_transactions = false
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def commit_transaction
|
255
|
+
@connection.lock.synchronize do
|
256
|
+
transaction = @stack.last
|
257
|
+
|
258
|
+
begin
|
259
|
+
transaction.before_commit_records
|
260
|
+
ensure
|
261
|
+
@stack.pop
|
262
|
+
end
|
263
|
+
|
264
|
+
transaction.commit
|
265
|
+
transaction.commit_records
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def rollback_transaction(transaction = nil)
|
270
|
+
@connection.lock.synchronize do
|
271
|
+
transaction ||= @stack.pop
|
272
|
+
transaction.rollback
|
273
|
+
transaction.rollback_records
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def within_new_transaction(options = {})
|
278
|
+
@connection.lock.synchronize do
|
279
|
+
transaction = begin_transaction options
|
280
|
+
yield
|
281
|
+
rescue Exception => error
|
282
|
+
if transaction
|
283
|
+
rollback_transaction
|
284
|
+
after_failure_actions(transaction, error)
|
285
|
+
end
|
286
|
+
raise
|
287
|
+
ensure
|
288
|
+
if !error && transaction
|
289
|
+
if Thread.current.status == "aborting"
|
290
|
+
rollback_transaction
|
291
|
+
else
|
292
|
+
begin
|
293
|
+
commit_transaction
|
294
|
+
rescue Exception
|
295
|
+
rollback_transaction(transaction) unless transaction.state.completed?
|
296
|
+
raise
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def open_transactions
|
304
|
+
@stack.size
|
305
|
+
end
|
306
|
+
|
307
|
+
def current_transaction
|
308
|
+
@stack.last || NULL_TRANSACTION
|
309
|
+
end
|
310
|
+
|
311
|
+
private
|
312
|
+
|
313
|
+
NULL_TRANSACTION = NullTransaction.new
|
314
|
+
|
315
|
+
# Deallocate invalidated prepared statements outside of the transaction
|
316
|
+
def after_failure_actions(transaction, error)
|
317
|
+
return unless transaction.is_a?(RealTransaction)
|
318
|
+
return unless error.is_a?(ActiveRecord::PreparedStatementCacheExpired)
|
319
|
+
@connection.clear_cache!
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
@@ -0,0 +1,761 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/connection_adapters/determine_if_preparable_visitor"
|
4
|
+
require "active_record/connection_adapters/schema_cache"
|
5
|
+
require "active_record/connection_adapters/sql_type_metadata"
|
6
|
+
require "active_record/connection_adapters/abstract/schema_dumper"
|
7
|
+
require "active_record/connection_adapters/abstract/schema_creation"
|
8
|
+
require "active_support/concurrency/load_interlock_aware_monitor"
|
9
|
+
require "active_support/deprecation"
|
10
|
+
require "arel/collectors/bind"
|
11
|
+
require "arel/collectors/composite"
|
12
|
+
require "arel/collectors/sql_string"
|
13
|
+
require "arel/collectors/substitute_binds"
|
14
|
+
require "concurrent/atomic/thread_local_var"
|
15
|
+
|
16
|
+
module ActiveRecord
|
17
|
+
module ConnectionAdapters # :nodoc:
|
18
|
+
extend ActiveSupport::Autoload
|
19
|
+
|
20
|
+
autoload :Column
|
21
|
+
autoload :ConnectionSpecification
|
22
|
+
|
23
|
+
autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
|
24
|
+
autoload :IndexDefinition
|
25
|
+
autoload :ColumnDefinition
|
26
|
+
autoload :ChangeColumnDefinition
|
27
|
+
autoload :ForeignKeyDefinition
|
28
|
+
autoload :TableDefinition
|
29
|
+
autoload :Table
|
30
|
+
autoload :AlterTable
|
31
|
+
autoload :ReferenceDefinition
|
32
|
+
end
|
33
|
+
|
34
|
+
autoload_at "active_record/connection_adapters/abstract/connection_pool" do
|
35
|
+
autoload :ConnectionHandler
|
36
|
+
end
|
37
|
+
|
38
|
+
autoload_under "abstract" do
|
39
|
+
autoload :SchemaStatements
|
40
|
+
autoload :DatabaseStatements
|
41
|
+
autoload :DatabaseLimits
|
42
|
+
autoload :Quoting
|
43
|
+
autoload :ConnectionPool
|
44
|
+
autoload :QueryCache
|
45
|
+
autoload :Savepoints
|
46
|
+
end
|
47
|
+
|
48
|
+
autoload_at "active_record/connection_adapters/abstract/transaction" do
|
49
|
+
autoload :TransactionManager
|
50
|
+
autoload :NullTransaction
|
51
|
+
autoload :RealTransaction
|
52
|
+
autoload :SavepointTransaction
|
53
|
+
autoload :TransactionState
|
54
|
+
end
|
55
|
+
|
56
|
+
# Active Record supports multiple database systems. AbstractAdapter and
|
57
|
+
# related classes form the abstraction layer which makes this possible.
|
58
|
+
# An AbstractAdapter represents a connection to a database, and provides an
|
59
|
+
# abstract interface for database-specific functionality such as establishing
|
60
|
+
# a connection, escaping values, building the right SQL fragments for +:offset+
|
61
|
+
# and +:limit+ options, etc.
|
62
|
+
#
|
63
|
+
# All the concrete database adapters follow the interface laid down in this class.
|
64
|
+
# {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling#connection] returns an AbstractAdapter object, which
|
65
|
+
# you can use.
|
66
|
+
#
|
67
|
+
# Most of the methods in the adapter are useful during migrations. Most
|
68
|
+
# notably, the instance methods provided by SchemaStatements are very useful.
|
69
|
+
class AbstractAdapter
|
70
|
+
ADAPTER_NAME = "Abstract"
|
71
|
+
include ActiveSupport::Callbacks
|
72
|
+
define_callbacks :checkout, :checkin
|
73
|
+
|
74
|
+
include Quoting, DatabaseStatements, SchemaStatements
|
75
|
+
include DatabaseLimits
|
76
|
+
include QueryCache
|
77
|
+
include Savepoints
|
78
|
+
|
79
|
+
SIMPLE_INT = /\A\d+\z/
|
80
|
+
|
81
|
+
attr_accessor :pool
|
82
|
+
attr_reader :visitor, :owner, :logger, :lock
|
83
|
+
alias :in_use? :owner
|
84
|
+
|
85
|
+
set_callback :checkin, :after, :enable_lazy_transactions!
|
86
|
+
|
87
|
+
def self.type_cast_config_to_integer(config)
|
88
|
+
if config.is_a?(Integer)
|
89
|
+
config
|
90
|
+
elsif SIMPLE_INT.match?(config)
|
91
|
+
config.to_i
|
92
|
+
else
|
93
|
+
config
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.type_cast_config_to_boolean(config)
|
98
|
+
if config == "false"
|
99
|
+
false
|
100
|
+
else
|
101
|
+
config
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.build_read_query_regexp(*parts) # :nodoc:
|
106
|
+
parts = parts.map { |part| /\A[\(\s]*#{part}/i }
|
107
|
+
Regexp.union(*parts)
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.quoted_column_names # :nodoc:
|
111
|
+
@quoted_column_names ||= {}
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.quoted_table_names # :nodoc:
|
115
|
+
@quoted_table_names ||= {}
|
116
|
+
end
|
117
|
+
|
118
|
+
def initialize(connection, logger = nil, config = {}) # :nodoc:
|
119
|
+
super()
|
120
|
+
|
121
|
+
@connection = connection
|
122
|
+
@owner = nil
|
123
|
+
@instrumenter = ActiveSupport::Notifications.instrumenter
|
124
|
+
@logger = logger
|
125
|
+
@config = config
|
126
|
+
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
127
|
+
@idle_since = Concurrent.monotonic_time
|
128
|
+
@visitor = arel_visitor
|
129
|
+
@statements = build_statement_pool
|
130
|
+
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
131
|
+
|
132
|
+
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
133
|
+
@prepared_statement_status = Concurrent::ThreadLocalVar.new(true)
|
134
|
+
@visitor.extend(DetermineIfPreparableVisitor)
|
135
|
+
else
|
136
|
+
@prepared_statement_status = Concurrent::ThreadLocalVar.new(false)
|
137
|
+
end
|
138
|
+
|
139
|
+
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
|
140
|
+
config.fetch(:advisory_locks, true)
|
141
|
+
)
|
142
|
+
end
|
143
|
+
|
144
|
+
def replica?
|
145
|
+
@config[:replica] || false
|
146
|
+
end
|
147
|
+
|
148
|
+
# Determines whether writes are currently being prevents.
|
149
|
+
#
|
150
|
+
# Returns true if the connection is a replica, or if +prevent_writes+
|
151
|
+
# is set to true.
|
152
|
+
def preventing_writes?
|
153
|
+
replica? || ActiveRecord::Base.connection_handler.prevent_writes
|
154
|
+
end
|
155
|
+
|
156
|
+
def migrations_paths # :nodoc:
|
157
|
+
@config[:migrations_paths] || Migrator.migrations_paths
|
158
|
+
end
|
159
|
+
|
160
|
+
def migration_context # :nodoc:
|
161
|
+
MigrationContext.new(migrations_paths, schema_migration)
|
162
|
+
end
|
163
|
+
|
164
|
+
def schema_migration # :nodoc:
|
165
|
+
@schema_migration ||= begin
|
166
|
+
conn = self
|
167
|
+
spec_name = conn.pool.spec.name
|
168
|
+
name = "#{spec_name}::SchemaMigration"
|
169
|
+
|
170
|
+
Class.new(ActiveRecord::SchemaMigration) do
|
171
|
+
define_singleton_method(:name) { name }
|
172
|
+
define_singleton_method(:to_s) { name }
|
173
|
+
|
174
|
+
self.connection_specification_name = spec_name
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def prepared_statements
|
180
|
+
@prepared_statement_status.value
|
181
|
+
end
|
182
|
+
|
183
|
+
class Version
|
184
|
+
include Comparable
|
185
|
+
|
186
|
+
attr_reader :full_version_string
|
187
|
+
|
188
|
+
def initialize(version_string, full_version_string = nil)
|
189
|
+
@version = version_string.split(".").map(&:to_i)
|
190
|
+
@full_version_string = full_version_string
|
191
|
+
end
|
192
|
+
|
193
|
+
def <=>(version_string)
|
194
|
+
@version <=> version_string.split(".").map(&:to_i)
|
195
|
+
end
|
196
|
+
|
197
|
+
def to_s
|
198
|
+
@version.join(".")
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def valid_type?(type) # :nodoc:
|
203
|
+
!native_database_types[type].nil?
|
204
|
+
end
|
205
|
+
|
206
|
+
# this method must only be called while holding connection pool's mutex
|
207
|
+
def lease
|
208
|
+
if in_use?
|
209
|
+
msg = +"Cannot lease connection, "
|
210
|
+
if @owner == Thread.current
|
211
|
+
msg << "it is already leased by the current thread."
|
212
|
+
else
|
213
|
+
msg << "it is already in use by a different thread: #{@owner}. " \
|
214
|
+
"Current thread: #{Thread.current}."
|
215
|
+
end
|
216
|
+
raise ActiveRecordError, msg
|
217
|
+
end
|
218
|
+
|
219
|
+
@owner = Thread.current
|
220
|
+
end
|
221
|
+
|
222
|
+
def schema_cache
|
223
|
+
@pool.get_schema_cache(self)
|
224
|
+
end
|
225
|
+
|
226
|
+
def schema_cache=(cache)
|
227
|
+
cache.connection = self
|
228
|
+
@pool.set_schema_cache(cache)
|
229
|
+
end
|
230
|
+
|
231
|
+
# this method must only be called while holding connection pool's mutex
|
232
|
+
def expire
|
233
|
+
if in_use?
|
234
|
+
if @owner != Thread.current
|
235
|
+
raise ActiveRecordError, "Cannot expire connection, " \
|
236
|
+
"it is owned by a different thread: #{@owner}. " \
|
237
|
+
"Current thread: #{Thread.current}."
|
238
|
+
end
|
239
|
+
|
240
|
+
@idle_since = Concurrent.monotonic_time
|
241
|
+
@owner = nil
|
242
|
+
else
|
243
|
+
raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# this method must only be called while holding connection pool's mutex (and a desire for segfaults)
|
248
|
+
def steal! # :nodoc:
|
249
|
+
if in_use?
|
250
|
+
if @owner != Thread.current
|
251
|
+
pool.send :remove_connection_from_thread_cache, self, @owner
|
252
|
+
|
253
|
+
@owner = Thread.current
|
254
|
+
end
|
255
|
+
else
|
256
|
+
raise ActiveRecordError, "Cannot steal connection, it is not currently leased."
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Seconds since this connection was returned to the pool
|
261
|
+
def seconds_idle # :nodoc:
|
262
|
+
return 0 if in_use?
|
263
|
+
Concurrent.monotonic_time - @idle_since
|
264
|
+
end
|
265
|
+
|
266
|
+
def unprepared_statement
|
267
|
+
@prepared_statement_status.bind(false) { yield }
|
268
|
+
end
|
269
|
+
|
270
|
+
# Returns the human-readable name of the adapter. Use mixed case - one
|
271
|
+
# can always use downcase if needed.
|
272
|
+
def adapter_name
|
273
|
+
self.class::ADAPTER_NAME
|
274
|
+
end
|
275
|
+
|
276
|
+
# Does the database for this adapter exist?
|
277
|
+
def self.database_exists?(config)
|
278
|
+
raise NotImplementedError
|
279
|
+
end
|
280
|
+
|
281
|
+
# Does this adapter support DDL rollbacks in transactions? That is, would
|
282
|
+
# CREATE TABLE or ALTER TABLE get rolled back by a transaction?
|
283
|
+
def supports_ddl_transactions?
|
284
|
+
false
|
285
|
+
end
|
286
|
+
|
287
|
+
def supports_bulk_alter?
|
288
|
+
false
|
289
|
+
end
|
290
|
+
|
291
|
+
# Does this adapter support savepoints?
|
292
|
+
def supports_savepoints?
|
293
|
+
false
|
294
|
+
end
|
295
|
+
|
296
|
+
# Does this adapter support application-enforced advisory locking?
|
297
|
+
def supports_advisory_locks?
|
298
|
+
false
|
299
|
+
end
|
300
|
+
|
301
|
+
# Should primary key values be selected from their corresponding
|
302
|
+
# sequence before the insert statement? If true, next_sequence_value
|
303
|
+
# is called before each insert to set the record's primary key.
|
304
|
+
def prefetch_primary_key?(table_name = nil)
|
305
|
+
false
|
306
|
+
end
|
307
|
+
|
308
|
+
# Does this adapter support index sort order?
|
309
|
+
def supports_index_sort_order?
|
310
|
+
false
|
311
|
+
end
|
312
|
+
|
313
|
+
# Does this adapter support partial indices?
|
314
|
+
def supports_partial_index?
|
315
|
+
false
|
316
|
+
end
|
317
|
+
|
318
|
+
# Does this adapter support expression indices?
|
319
|
+
def supports_expression_index?
|
320
|
+
false
|
321
|
+
end
|
322
|
+
|
323
|
+
# Does this adapter support explain?
|
324
|
+
def supports_explain?
|
325
|
+
false
|
326
|
+
end
|
327
|
+
|
328
|
+
# Does this adapter support setting the isolation level for a transaction?
|
329
|
+
def supports_transaction_isolation?
|
330
|
+
false
|
331
|
+
end
|
332
|
+
|
333
|
+
# Does this adapter support database extensions?
|
334
|
+
def supports_extensions?
|
335
|
+
false
|
336
|
+
end
|
337
|
+
|
338
|
+
# Does this adapter support creating indexes in the same statement as
|
339
|
+
# creating the table?
|
340
|
+
def supports_indexes_in_create?
|
341
|
+
false
|
342
|
+
end
|
343
|
+
|
344
|
+
# Does this adapter support creating foreign key constraints?
|
345
|
+
def supports_foreign_keys?
|
346
|
+
false
|
347
|
+
end
|
348
|
+
|
349
|
+
# Does this adapter support creating invalid constraints?
|
350
|
+
def supports_validate_constraints?
|
351
|
+
false
|
352
|
+
end
|
353
|
+
|
354
|
+
# Does this adapter support creating foreign key constraints
|
355
|
+
# in the same statement as creating the table?
|
356
|
+
def supports_foreign_keys_in_create?
|
357
|
+
supports_foreign_keys?
|
358
|
+
end
|
359
|
+
deprecate :supports_foreign_keys_in_create?
|
360
|
+
|
361
|
+
# Does this adapter support views?
|
362
|
+
def supports_views?
|
363
|
+
false
|
364
|
+
end
|
365
|
+
|
366
|
+
# Does this adapter support materialized views?
|
367
|
+
def supports_materialized_views?
|
368
|
+
false
|
369
|
+
end
|
370
|
+
|
371
|
+
# Does this adapter support datetime with precision?
|
372
|
+
def supports_datetime_with_precision?
|
373
|
+
false
|
374
|
+
end
|
375
|
+
|
376
|
+
# Does this adapter support json data type?
|
377
|
+
def supports_json?
|
378
|
+
false
|
379
|
+
end
|
380
|
+
|
381
|
+
# Does this adapter support metadata comments on database objects (tables, columns, indexes)?
|
382
|
+
def supports_comments?
|
383
|
+
false
|
384
|
+
end
|
385
|
+
|
386
|
+
# Can comments for tables, columns, and indexes be specified in create/alter table statements?
|
387
|
+
def supports_comments_in_create?
|
388
|
+
false
|
389
|
+
end
|
390
|
+
|
391
|
+
# Does this adapter support multi-value insert?
|
392
|
+
def supports_multi_insert?
|
393
|
+
true
|
394
|
+
end
|
395
|
+
deprecate :supports_multi_insert?
|
396
|
+
|
397
|
+
# Does this adapter support virtual columns?
|
398
|
+
def supports_virtual_columns?
|
399
|
+
false
|
400
|
+
end
|
401
|
+
|
402
|
+
# Does this adapter support foreign/external tables?
|
403
|
+
def supports_foreign_tables?
|
404
|
+
false
|
405
|
+
end
|
406
|
+
|
407
|
+
# Does this adapter support optimizer hints?
|
408
|
+
def supports_optimizer_hints?
|
409
|
+
false
|
410
|
+
end
|
411
|
+
|
412
|
+
def supports_lazy_transactions?
|
413
|
+
false
|
414
|
+
end
|
415
|
+
|
416
|
+
def supports_insert_returning?
|
417
|
+
false
|
418
|
+
end
|
419
|
+
|
420
|
+
def supports_insert_on_duplicate_skip?
|
421
|
+
false
|
422
|
+
end
|
423
|
+
|
424
|
+
def supports_insert_on_duplicate_update?
|
425
|
+
false
|
426
|
+
end
|
427
|
+
|
428
|
+
def supports_insert_conflict_target?
|
429
|
+
false
|
430
|
+
end
|
431
|
+
|
432
|
+
# This is meant to be implemented by the adapters that support extensions
|
433
|
+
def disable_extension(name)
|
434
|
+
end
|
435
|
+
|
436
|
+
# This is meant to be implemented by the adapters that support extensions
|
437
|
+
def enable_extension(name)
|
438
|
+
end
|
439
|
+
|
440
|
+
def advisory_locks_enabled? # :nodoc:
|
441
|
+
supports_advisory_locks? && @advisory_locks_enabled
|
442
|
+
end
|
443
|
+
|
444
|
+
# This is meant to be implemented by the adapters that support advisory
|
445
|
+
# locks
|
446
|
+
#
|
447
|
+
# Return true if we got the lock, otherwise false
|
448
|
+
def get_advisory_lock(lock_id) # :nodoc:
|
449
|
+
end
|
450
|
+
|
451
|
+
# This is meant to be implemented by the adapters that support advisory
|
452
|
+
# locks.
|
453
|
+
#
|
454
|
+
# Return true if we released the lock, otherwise false
|
455
|
+
def release_advisory_lock(lock_id) # :nodoc:
|
456
|
+
end
|
457
|
+
|
458
|
+
# A list of extensions, to be filled in by adapters that support them.
|
459
|
+
def extensions
|
460
|
+
[]
|
461
|
+
end
|
462
|
+
|
463
|
+
# A list of index algorithms, to be filled by adapters that support them.
|
464
|
+
def index_algorithms
|
465
|
+
{}
|
466
|
+
end
|
467
|
+
|
468
|
+
# REFERENTIAL INTEGRITY ====================================
|
469
|
+
|
470
|
+
# Override to turn off referential integrity while executing <tt>&block</tt>.
|
471
|
+
def disable_referential_integrity
|
472
|
+
yield
|
473
|
+
end
|
474
|
+
|
475
|
+
# CONNECTION MANAGEMENT ====================================
|
476
|
+
|
477
|
+
# Checks whether the connection to the database is still active. This includes
|
478
|
+
# checking whether the database is actually capable of responding, i.e. whether
|
479
|
+
# the connection isn't stale.
|
480
|
+
def active?
|
481
|
+
end
|
482
|
+
|
483
|
+
# Disconnects from the database if already connected, and establishes a
|
484
|
+
# new connection with the database. Implementors should call super if they
|
485
|
+
# override the default implementation.
|
486
|
+
def reconnect!
|
487
|
+
clear_cache!
|
488
|
+
reset_transaction
|
489
|
+
end
|
490
|
+
|
491
|
+
# Disconnects from the database if already connected. Otherwise, this
|
492
|
+
# method does nothing.
|
493
|
+
def disconnect!
|
494
|
+
clear_cache!
|
495
|
+
reset_transaction
|
496
|
+
end
|
497
|
+
|
498
|
+
# Immediately forget this connection ever existed. Unlike disconnect!,
|
499
|
+
# this will not communicate with the server.
|
500
|
+
#
|
501
|
+
# After calling this method, the behavior of all other methods becomes
|
502
|
+
# undefined. This is called internally just before a forked process gets
|
503
|
+
# rid of a connection that belonged to its parent.
|
504
|
+
def discard!
|
505
|
+
# This should be overridden by concrete adapters.
|
506
|
+
#
|
507
|
+
# Prevent @connection's finalizer from touching the socket, or
|
508
|
+
# otherwise communicating with its server, when it is collected.
|
509
|
+
if schema_cache.connection == self
|
510
|
+
schema_cache.connection = nil
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
# Reset the state of this connection, directing the DBMS to clear
|
515
|
+
# transactions and other connection-related server-side state. Usually a
|
516
|
+
# database-dependent operation.
|
517
|
+
#
|
518
|
+
# The default implementation does nothing; the implementation should be
|
519
|
+
# overridden by concrete adapters.
|
520
|
+
def reset!
|
521
|
+
# this should be overridden by concrete adapters
|
522
|
+
end
|
523
|
+
|
524
|
+
# Clear any caching the database adapter may be doing.
|
525
|
+
def clear_cache!
|
526
|
+
@lock.synchronize { @statements.clear } if @statements
|
527
|
+
end
|
528
|
+
|
529
|
+
# Returns true if its required to reload the connection between requests for development mode.
|
530
|
+
def requires_reloading?
|
531
|
+
false
|
532
|
+
end
|
533
|
+
|
534
|
+
# Checks whether the connection to the database is still active (i.e. not stale).
|
535
|
+
# This is done under the hood by calling #active?. If the connection
|
536
|
+
# is no longer active, then this method will reconnect to the database.
|
537
|
+
def verify!
|
538
|
+
reconnect! unless active?
|
539
|
+
end
|
540
|
+
|
541
|
+
# Provides access to the underlying database driver for this adapter. For
|
542
|
+
# example, this method returns a Mysql2::Client object in case of Mysql2Adapter,
|
543
|
+
# and a PG::Connection object in case of PostgreSQLAdapter.
|
544
|
+
#
|
545
|
+
# This is useful for when you need to call a proprietary method such as
|
546
|
+
# PostgreSQL's lo_* methods.
|
547
|
+
def raw_connection
|
548
|
+
disable_lazy_transactions!
|
549
|
+
@connection
|
550
|
+
end
|
551
|
+
|
552
|
+
def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
|
553
|
+
attribute.eq(value)
|
554
|
+
end
|
555
|
+
|
556
|
+
def case_sensitive_comparison(attribute, value) # :nodoc:
|
557
|
+
attribute.eq(value)
|
558
|
+
end
|
559
|
+
|
560
|
+
def case_insensitive_comparison(attribute, value) # :nodoc:
|
561
|
+
column = column_for_attribute(attribute)
|
562
|
+
|
563
|
+
if can_perform_case_insensitive_comparison_for?(column)
|
564
|
+
attribute.lower.eq(attribute.relation.lower(value))
|
565
|
+
else
|
566
|
+
attribute.eq(value)
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
def can_perform_case_insensitive_comparison_for?(column)
|
571
|
+
true
|
572
|
+
end
|
573
|
+
private :can_perform_case_insensitive_comparison_for?
|
574
|
+
|
575
|
+
# Check the connection back in to the connection pool
|
576
|
+
def close
|
577
|
+
pool.checkin self
|
578
|
+
end
|
579
|
+
|
580
|
+
def column_name_for_operation(operation, node) # :nodoc:
|
581
|
+
visitor.compile(node)
|
582
|
+
end
|
583
|
+
|
584
|
+
def default_index_type?(index) # :nodoc:
|
585
|
+
index.using.nil?
|
586
|
+
end
|
587
|
+
|
588
|
+
# Called by ActiveRecord::InsertAll,
|
589
|
+
# Passed an instance of ActiveRecord::InsertAll::Builder,
|
590
|
+
# This method implements standard bulk inserts for all databases, but
|
591
|
+
# should be overridden by adapters to implement common features with
|
592
|
+
# non-standard syntax like handling duplicates or returning values.
|
593
|
+
def build_insert_sql(insert) # :nodoc:
|
594
|
+
if insert.skip_duplicates? || insert.update_duplicates?
|
595
|
+
raise NotImplementedError, "#{self.class} should define `build_insert_sql` to implement adapter-specific logic for handling duplicates during INSERT"
|
596
|
+
end
|
597
|
+
|
598
|
+
"INSERT #{insert.into} #{insert.values_list}"
|
599
|
+
end
|
600
|
+
|
601
|
+
def get_database_version # :nodoc:
|
602
|
+
end
|
603
|
+
|
604
|
+
def database_version # :nodoc:
|
605
|
+
schema_cache.database_version
|
606
|
+
end
|
607
|
+
|
608
|
+
def check_version # :nodoc:
|
609
|
+
end
|
610
|
+
|
611
|
+
private
|
612
|
+
|
613
|
+
def type_map
|
614
|
+
@type_map ||= Type::TypeMap.new.tap do |mapping|
|
615
|
+
initialize_type_map(mapping)
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
def initialize_type_map(m = type_map)
|
620
|
+
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
621
|
+
register_class_with_limit m, %r(char)i, Type::String
|
622
|
+
register_class_with_limit m, %r(binary)i, Type::Binary
|
623
|
+
register_class_with_limit m, %r(text)i, Type::Text
|
624
|
+
register_class_with_precision m, %r(date)i, Type::Date
|
625
|
+
register_class_with_precision m, %r(time)i, Type::Time
|
626
|
+
register_class_with_precision m, %r(datetime)i, Type::DateTime
|
627
|
+
register_class_with_limit m, %r(float)i, Type::Float
|
628
|
+
register_class_with_limit m, %r(int)i, Type::Integer
|
629
|
+
|
630
|
+
m.alias_type %r(blob)i, "binary"
|
631
|
+
m.alias_type %r(clob)i, "text"
|
632
|
+
m.alias_type %r(timestamp)i, "datetime"
|
633
|
+
m.alias_type %r(numeric)i, "decimal"
|
634
|
+
m.alias_type %r(number)i, "decimal"
|
635
|
+
m.alias_type %r(double)i, "float"
|
636
|
+
|
637
|
+
m.register_type %r(^json)i, Type::Json.new
|
638
|
+
|
639
|
+
m.register_type(%r(decimal)i) do |sql_type|
|
640
|
+
scale = extract_scale(sql_type)
|
641
|
+
precision = extract_precision(sql_type)
|
642
|
+
|
643
|
+
if scale == 0
|
644
|
+
# FIXME: Remove this class as well
|
645
|
+
Type::DecimalWithoutScale.new(precision: precision)
|
646
|
+
else
|
647
|
+
Type::Decimal.new(precision: precision, scale: scale)
|
648
|
+
end
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
def reload_type_map
|
653
|
+
type_map.clear
|
654
|
+
initialize_type_map
|
655
|
+
end
|
656
|
+
|
657
|
+
def register_class_with_limit(mapping, key, klass)
|
658
|
+
mapping.register_type(key) do |*args|
|
659
|
+
limit = extract_limit(args.last)
|
660
|
+
klass.new(limit: limit)
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
664
|
+
def register_class_with_precision(mapping, key, klass)
|
665
|
+
mapping.register_type(key) do |*args|
|
666
|
+
precision = extract_precision(args.last)
|
667
|
+
klass.new(precision: precision)
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
def extract_scale(sql_type)
|
672
|
+
case sql_type
|
673
|
+
when /\((\d+)\)/ then 0
|
674
|
+
when /\((\d+)(,(\d+))\)/ then $3.to_i
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
def extract_precision(sql_type)
|
679
|
+
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
|
680
|
+
end
|
681
|
+
|
682
|
+
def extract_limit(sql_type)
|
683
|
+
$1.to_i if sql_type =~ /\((.*)\)/
|
684
|
+
end
|
685
|
+
|
686
|
+
def translate_exception_class(e, sql, binds)
|
687
|
+
message = "#{e.class.name}: #{e.message}"
|
688
|
+
|
689
|
+
exception = translate_exception(
|
690
|
+
e, message: message, sql: sql, binds: binds
|
691
|
+
)
|
692
|
+
exception.set_backtrace e.backtrace
|
693
|
+
exception
|
694
|
+
end
|
695
|
+
|
696
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
|
697
|
+
@instrumenter.instrument(
|
698
|
+
"sql.active_record",
|
699
|
+
sql: sql,
|
700
|
+
name: name,
|
701
|
+
binds: binds,
|
702
|
+
type_casted_binds: type_casted_binds,
|
703
|
+
statement_name: statement_name,
|
704
|
+
connection_id: object_id,
|
705
|
+
connection: self) do
|
706
|
+
@lock.synchronize do
|
707
|
+
yield
|
708
|
+
end
|
709
|
+
rescue => e
|
710
|
+
raise translate_exception_class(e, sql, binds)
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
def translate_exception(exception, message:, sql:, binds:)
|
715
|
+
# override in derived class
|
716
|
+
case exception
|
717
|
+
when RuntimeError
|
718
|
+
exception
|
719
|
+
else
|
720
|
+
ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
def without_prepared_statement?(binds)
|
725
|
+
!prepared_statements || binds.empty?
|
726
|
+
end
|
727
|
+
|
728
|
+
def column_for(table_name, column_name)
|
729
|
+
column_name = column_name.to_s
|
730
|
+
columns(table_name).detect { |c| c.name == column_name } ||
|
731
|
+
raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
|
732
|
+
end
|
733
|
+
|
734
|
+
def column_for_attribute(attribute)
|
735
|
+
table_name = attribute.relation.name
|
736
|
+
schema_cache.columns_hash(table_name)[attribute.name.to_s]
|
737
|
+
end
|
738
|
+
|
739
|
+
def collector
|
740
|
+
if prepared_statements
|
741
|
+
Arel::Collectors::Composite.new(
|
742
|
+
Arel::Collectors::SQLString.new,
|
743
|
+
Arel::Collectors::Bind.new,
|
744
|
+
)
|
745
|
+
else
|
746
|
+
Arel::Collectors::SubstituteBinds.new(
|
747
|
+
self,
|
748
|
+
Arel::Collectors::SQLString.new,
|
749
|
+
)
|
750
|
+
end
|
751
|
+
end
|
752
|
+
|
753
|
+
def arel_visitor
|
754
|
+
Arel::Visitors::ToSql.new(self)
|
755
|
+
end
|
756
|
+
|
757
|
+
def build_statement_pool
|
758
|
+
end
|
759
|
+
end
|
760
|
+
end
|
761
|
+
end
|