activerecord 4.2.11.3 → 5.0.7.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1638 -1132
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +7 -2
- data/lib/active_record/aggregations.rb +34 -21
- data/lib/active_record/association_relation.rb +7 -4
- data/lib/active_record/associations.rb +347 -218
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +22 -10
- data/lib/active_record/associations/association_scope.rb +75 -104
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +13 -11
- data/lib/active_record/associations/collection_association.rb +85 -69
- data/lib/active_record/associations/collection_proxy.rb +104 -46
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +21 -78
- data/lib/active_record/associations/has_many_through_association.rb +6 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +38 -22
- data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/preloader/association.rb +52 -71
- data/lib/active_record/associations/preloader/collection_association.rb +0 -7
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +36 -17
- data/lib/active_record/associations/singular_association.rb +13 -1
- data/lib/active_record/associations/through_association.rb +12 -4
- data/lib/active_record/attribute.rb +69 -19
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +69 -44
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +16 -3
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +32 -3
- data/lib/active_record/attribute_set/builder.rb +42 -16
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +54 -17
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +92 -108
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +116 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +77 -41
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +17 -14
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +48 -24
- data/lib/active_record/migration.rb +362 -111
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/model_schema.rb +270 -73
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +152 -90
- data/lib/active_record/query_cache.rb +18 -23
- data/lib/active_record/querying.rb +12 -11
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +52 -41
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +302 -115
- data/lib/active_record/relation.rb +187 -120
- data/lib/active_record/relation/batches.rb +141 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +92 -117
- data/lib/active_record/relation/delegation.rb +8 -20
- data/lib/active_record/relation/finder_methods.rb +173 -89
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/result.rb +11 -4
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +105 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +54 -37
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping.rb +34 -16
- data/lib/active_record/scoping/default.rb +28 -10
- data/lib/active_record/scoping/named.rb +59 -26
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +3 -5
- data/lib/active_record/statement_cache.rb +17 -15
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +69 -0
- data/lib/active_record/tasks/database_tasks.rb +66 -49
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +63 -0
- data/lib/active_record/transactions.rb +139 -57
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +33 -33
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +58 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -1,13 +1,10 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module ConnectionAdapters
|
3
3
|
class TransactionState
|
4
|
-
attr_reader :parent
|
5
|
-
|
6
4
|
VALID_STATES = Set.new([:committed, :rolledback, nil])
|
7
5
|
|
8
6
|
def initialize(state = nil)
|
9
7
|
@state = state
|
10
|
-
@parent = nil
|
11
8
|
end
|
12
9
|
|
13
10
|
def finalized?
|
@@ -27,7 +24,7 @@ module ActiveRecord
|
|
27
24
|
end
|
28
25
|
|
29
26
|
def set_state(state)
|
30
|
-
|
27
|
+
unless VALID_STATES.include?(state)
|
31
28
|
raise ArgumentError, "Invalid transaction state: #{state}"
|
32
29
|
end
|
33
30
|
@state = state
|
@@ -36,6 +33,7 @@ module ActiveRecord
|
|
36
33
|
|
37
34
|
class NullTransaction #:nodoc:
|
38
35
|
def initialize; end
|
36
|
+
def state; end
|
39
37
|
def closed?; true; end
|
40
38
|
def open?; false; end
|
41
39
|
def joinable?; false; end
|
@@ -47,11 +45,12 @@ module ActiveRecord
|
|
47
45
|
attr_reader :connection, :state, :records, :savepoint_name
|
48
46
|
attr_writer :joinable
|
49
47
|
|
50
|
-
def initialize(connection, options)
|
48
|
+
def initialize(connection, options, run_commit_callbacks: false)
|
51
49
|
@connection = connection
|
52
50
|
@state = TransactionState.new
|
53
51
|
@records = []
|
54
52
|
@joinable = options.fetch(:joinable, true)
|
53
|
+
@run_commit_callbacks = run_commit_callbacks
|
55
54
|
end
|
56
55
|
|
57
56
|
def add_record(record)
|
@@ -65,16 +64,11 @@ module ActiveRecord
|
|
65
64
|
def rollback_records
|
66
65
|
ite = records.uniq
|
67
66
|
while record = ite.shift
|
68
|
-
|
69
|
-
record.rolledback! full_rollback?
|
70
|
-
rescue => e
|
71
|
-
raise if ActiveRecord::Base.raise_in_transactional_callbacks
|
72
|
-
record.logger.error(e) if record.respond_to?(:logger) && record.logger
|
73
|
-
end
|
67
|
+
record.rolledback!(force_restore_state: full_rollback?)
|
74
68
|
end
|
75
69
|
ensure
|
76
70
|
ite.each do |i|
|
77
|
-
i.rolledback!(full_rollback?, false)
|
71
|
+
i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
|
78
72
|
end
|
79
73
|
end
|
80
74
|
|
@@ -82,20 +76,22 @@ module ActiveRecord
|
|
82
76
|
@state.set_state(:committed)
|
83
77
|
end
|
84
78
|
|
79
|
+
def before_commit_records
|
80
|
+
records.uniq.each(&:before_committed!) if @run_commit_callbacks
|
81
|
+
end
|
82
|
+
|
85
83
|
def commit_records
|
86
84
|
ite = records.uniq
|
87
85
|
while record = ite.shift
|
88
|
-
|
86
|
+
if @run_commit_callbacks
|
89
87
|
record.committed!
|
90
|
-
|
91
|
-
|
92
|
-
record.
|
88
|
+
else
|
89
|
+
# if not running callbacks, only adds the record to the parent transaction
|
90
|
+
record.add_to_transaction
|
93
91
|
end
|
94
92
|
end
|
95
93
|
ensure
|
96
|
-
ite.each
|
97
|
-
i.committed!(false)
|
98
|
-
end
|
94
|
+
ite.each { |i| i.committed!(should_run_callbacks: false) }
|
99
95
|
end
|
100
96
|
|
101
97
|
def full_rollback?; true; end
|
@@ -106,8 +102,8 @@ module ActiveRecord
|
|
106
102
|
|
107
103
|
class SavepointTransaction < Transaction
|
108
104
|
|
109
|
-
def initialize(connection, savepoint_name, options)
|
110
|
-
super(connection, options)
|
105
|
+
def initialize(connection, savepoint_name, options, *args)
|
106
|
+
super(connection, options, *args)
|
111
107
|
if options[:isolation]
|
112
108
|
raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
|
113
109
|
end
|
@@ -117,14 +113,11 @@ module ActiveRecord
|
|
117
113
|
def rollback
|
118
114
|
connection.rollback_to_savepoint(savepoint_name)
|
119
115
|
super
|
120
|
-
rollback_records
|
121
116
|
end
|
122
117
|
|
123
118
|
def commit
|
124
119
|
connection.release_savepoint(savepoint_name)
|
125
120
|
super
|
126
|
-
parent = connection.transaction_manager.current_transaction
|
127
|
-
records.each { |r| parent.add_record(r) }
|
128
121
|
end
|
129
122
|
|
130
123
|
def full_rollback?; false; end
|
@@ -132,7 +125,7 @@ module ActiveRecord
|
|
132
125
|
|
133
126
|
class RealTransaction < Transaction
|
134
127
|
|
135
|
-
def initialize(connection, options)
|
128
|
+
def initialize(connection, options, *args)
|
136
129
|
super
|
137
130
|
if options[:isolation]
|
138
131
|
connection.begin_isolated_db_transaction(options[:isolation])
|
@@ -144,13 +137,11 @@ module ActiveRecord
|
|
144
137
|
def rollback
|
145
138
|
connection.rollback_db_transaction
|
146
139
|
super
|
147
|
-
rollback_records
|
148
140
|
end
|
149
141
|
|
150
142
|
def commit
|
151
143
|
connection.commit_db_transaction
|
152
144
|
super
|
153
|
-
commit_records
|
154
145
|
end
|
155
146
|
end
|
156
147
|
|
@@ -161,29 +152,46 @@ module ActiveRecord
|
|
161
152
|
end
|
162
153
|
|
163
154
|
def begin_transaction(options = {})
|
155
|
+
run_commit_callbacks = !current_transaction.joinable?
|
164
156
|
transaction =
|
165
157
|
if @stack.empty?
|
166
|
-
RealTransaction.new(@connection, options)
|
158
|
+
RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
|
167
159
|
else
|
168
|
-
SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options
|
160
|
+
SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options,
|
161
|
+
run_commit_callbacks: run_commit_callbacks)
|
169
162
|
end
|
163
|
+
|
170
164
|
@stack.push(transaction)
|
171
165
|
transaction
|
172
166
|
end
|
173
167
|
|
174
168
|
def commit_transaction
|
175
|
-
@stack.
|
169
|
+
transaction = @stack.last
|
170
|
+
|
171
|
+
begin
|
172
|
+
transaction.before_commit_records
|
173
|
+
ensure
|
174
|
+
@stack.pop
|
175
|
+
end
|
176
|
+
|
177
|
+
transaction.commit
|
178
|
+
transaction.commit_records
|
176
179
|
end
|
177
180
|
|
178
|
-
def rollback_transaction
|
179
|
-
@stack.pop
|
181
|
+
def rollback_transaction(transaction = nil)
|
182
|
+
transaction ||= @stack.pop
|
183
|
+
transaction.rollback
|
184
|
+
transaction.rollback_records
|
180
185
|
end
|
181
186
|
|
182
187
|
def within_new_transaction(options = {})
|
183
188
|
transaction = begin_transaction options
|
184
189
|
yield
|
185
190
|
rescue Exception => error
|
186
|
-
|
191
|
+
if transaction
|
192
|
+
rollback_transaction
|
193
|
+
after_failure_actions(transaction, error)
|
194
|
+
end
|
187
195
|
raise
|
188
196
|
ensure
|
189
197
|
unless error
|
@@ -193,7 +201,7 @@ module ActiveRecord
|
|
193
201
|
begin
|
194
202
|
commit_transaction
|
195
203
|
rescue Exception
|
196
|
-
transaction
|
204
|
+
rollback_transaction(transaction) unless transaction.state.completed?
|
197
205
|
raise
|
198
206
|
end
|
199
207
|
end
|
@@ -209,7 +217,16 @@ module ActiveRecord
|
|
209
217
|
end
|
210
218
|
|
211
219
|
private
|
220
|
+
|
212
221
|
NULL_TRANSACTION = NullTransaction.new
|
222
|
+
|
223
|
+
# Deallocate invalidated prepared statements outside of the transaction
|
224
|
+
def after_failure_actions(transaction, error)
|
225
|
+
return unless transaction.is_a?(RealTransaction)
|
226
|
+
return unless error.is_a?(ActiveRecord::PreparedStatementCacheExpired)
|
227
|
+
@connection.clear_cache!
|
228
|
+
end
|
229
|
+
|
213
230
|
end
|
214
231
|
end
|
215
232
|
end
|
@@ -1,12 +1,9 @@
|
|
1
|
-
require 'date'
|
2
|
-
require 'bigdecimal'
|
3
|
-
require 'bigdecimal/util'
|
4
1
|
require 'active_record/type'
|
5
|
-
require '
|
2
|
+
require 'active_record/connection_adapters/determine_if_preparable_visitor'
|
6
3
|
require 'active_record/connection_adapters/schema_cache'
|
4
|
+
require 'active_record/connection_adapters/sql_type_metadata'
|
7
5
|
require 'active_record/connection_adapters/abstract/schema_dumper'
|
8
6
|
require 'active_record/connection_adapters/abstract/schema_creation'
|
9
|
-
require 'monitor'
|
10
7
|
require 'arel/collectors/bind'
|
11
8
|
require 'arel/collectors/sql_string'
|
12
9
|
|
@@ -21,15 +18,15 @@ module ActiveRecord
|
|
21
18
|
autoload :IndexDefinition
|
22
19
|
autoload :ColumnDefinition
|
23
20
|
autoload :ChangeColumnDefinition
|
21
|
+
autoload :ForeignKeyDefinition
|
24
22
|
autoload :TableDefinition
|
25
23
|
autoload :Table
|
26
24
|
autoload :AlterTable
|
27
|
-
autoload :
|
25
|
+
autoload :ReferenceDefinition
|
28
26
|
end
|
29
27
|
|
30
28
|
autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
|
31
29
|
autoload :ConnectionHandler
|
32
|
-
autoload :ConnectionManagement
|
33
30
|
end
|
34
31
|
|
35
32
|
autoload_under 'abstract' do
|
@@ -54,28 +51,28 @@ module ActiveRecord
|
|
54
51
|
# related classes form the abstraction layer which makes this possible.
|
55
52
|
# An AbstractAdapter represents a connection to a database, and provides an
|
56
53
|
# abstract interface for database-specific functionality such as establishing
|
57
|
-
# a connection, escaping values, building the right SQL fragments for
|
58
|
-
# and
|
54
|
+
# a connection, escaping values, building the right SQL fragments for +:offset+
|
55
|
+
# and +:limit+ options, etc.
|
59
56
|
#
|
60
57
|
# All the concrete database adapters follow the interface laid down in this class.
|
61
|
-
# ActiveRecord::Base.connection returns an AbstractAdapter object, which
|
58
|
+
# {ActiveRecord::Base.connection}[rdoc-ref:ConnectionHandling#connection] returns an AbstractAdapter object, which
|
62
59
|
# you can use.
|
63
60
|
#
|
64
61
|
# Most of the methods in the adapter are useful during migrations. Most
|
65
|
-
# notably, the instance methods provided by
|
62
|
+
# notably, the instance methods provided by SchemaStatements are very useful.
|
66
63
|
class AbstractAdapter
|
67
|
-
ADAPTER_NAME =
|
64
|
+
ADAPTER_NAME = "Abstract".freeze
|
65
|
+
include ActiveSupport::Callbacks
|
66
|
+
define_callbacks :checkout, :checkin
|
67
|
+
|
68
68
|
include Quoting, DatabaseStatements, SchemaStatements
|
69
69
|
include DatabaseLimits
|
70
70
|
include QueryCache
|
71
|
-
include ActiveSupport::Callbacks
|
72
|
-
include MonitorMixin
|
73
71
|
include ColumnDumper
|
72
|
+
include Savepoints
|
74
73
|
|
75
74
|
SIMPLE_INT = /\A\d+\z/
|
76
75
|
|
77
|
-
define_callbacks :checkout, :checkin
|
78
|
-
|
79
76
|
attr_accessor :visitor, :pool
|
80
77
|
attr_reader :schema_cache, :owner, :logger
|
81
78
|
alias :in_use? :owner
|
@@ -98,17 +95,25 @@ module ActiveRecord
|
|
98
95
|
|
99
96
|
attr_reader :prepared_statements
|
100
97
|
|
101
|
-
def initialize(connection, logger = nil,
|
98
|
+
def initialize(connection, logger = nil, config = {}) # :nodoc:
|
102
99
|
super()
|
103
100
|
|
104
101
|
@connection = connection
|
105
102
|
@owner = nil
|
106
103
|
@instrumenter = ActiveSupport::Notifications.instrumenter
|
107
104
|
@logger = logger
|
108
|
-
@
|
105
|
+
@config = config
|
106
|
+
@pool = nil
|
109
107
|
@schema_cache = SchemaCache.new self
|
110
|
-
@
|
111
|
-
@
|
108
|
+
@quoted_column_names, @quoted_table_names = {}, {}
|
109
|
+
@visitor = arel_visitor
|
110
|
+
|
111
|
+
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
112
|
+
@prepared_statements = true
|
113
|
+
@visitor.extend(DetermineIfPreparableVisitor)
|
114
|
+
else
|
115
|
+
@prepared_statements = false
|
116
|
+
end
|
112
117
|
end
|
113
118
|
|
114
119
|
class Version
|
@@ -125,7 +130,8 @@ module ActiveRecord
|
|
125
130
|
|
126
131
|
class BindCollector < Arel::Collectors::Bind
|
127
132
|
def compile(bvs, conn)
|
128
|
-
|
133
|
+
casted_binds = conn.prepare_binds_for_database(bvs)
|
134
|
+
super(casted_binds.map { |value| conn.quote(value) })
|
129
135
|
end
|
130
136
|
end
|
131
137
|
|
@@ -143,20 +149,32 @@ module ActiveRecord
|
|
143
149
|
end
|
144
150
|
end
|
145
151
|
|
152
|
+
def arel_visitor # :nodoc:
|
153
|
+
Arel::Visitors::ToSql.new(self)
|
154
|
+
end
|
155
|
+
|
146
156
|
def valid_type?(type)
|
147
|
-
|
157
|
+
false
|
148
158
|
end
|
149
159
|
|
150
160
|
def schema_creation
|
151
161
|
SchemaCreation.new self
|
152
162
|
end
|
153
163
|
|
164
|
+
# this method must only be called while holding connection pool's mutex
|
154
165
|
def lease
|
155
|
-
|
156
|
-
|
157
|
-
|
166
|
+
if in_use?
|
167
|
+
msg = 'Cannot lease connection, '
|
168
|
+
if @owner == Thread.current
|
169
|
+
msg << 'it is already leased by the current thread.'
|
170
|
+
else
|
171
|
+
msg << "it is already in use by a different thread: #{@owner}. " <<
|
172
|
+
"Current thread: #{Thread.current}."
|
158
173
|
end
|
174
|
+
raise ActiveRecordError, msg
|
159
175
|
end
|
176
|
+
|
177
|
+
@owner = Thread.current
|
160
178
|
end
|
161
179
|
|
162
180
|
def schema_cache=(cache)
|
@@ -164,8 +182,32 @@ module ActiveRecord
|
|
164
182
|
@schema_cache = cache
|
165
183
|
end
|
166
184
|
|
185
|
+
# this method must only be called while holding connection pool's mutex
|
167
186
|
def expire
|
168
|
-
|
187
|
+
if in_use?
|
188
|
+
if @owner != Thread.current
|
189
|
+
raise ActiveRecordError, "Cannot expire connection, " <<
|
190
|
+
"it is owned by a different thread: #{@owner}. " <<
|
191
|
+
"Current thread: #{Thread.current}."
|
192
|
+
end
|
193
|
+
|
194
|
+
@owner = nil
|
195
|
+
else
|
196
|
+
raise ActiveRecordError, 'Cannot expire connection, it is not currently leased.'
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# this method must only be called while holding connection pool's mutex (and a desire for segfaults)
|
201
|
+
def steal! # :nodoc:
|
202
|
+
if in_use?
|
203
|
+
if @owner != Thread.current
|
204
|
+
pool.send :remove_connection_from_thread_cache, self, @owner
|
205
|
+
|
206
|
+
@owner = Thread.current
|
207
|
+
end
|
208
|
+
else
|
209
|
+
raise ActiveRecordError, 'Cannot steal connection, it is not currently leased.'
|
210
|
+
end
|
169
211
|
end
|
170
212
|
|
171
213
|
def unprepared_statement
|
@@ -207,6 +249,11 @@ module ActiveRecord
|
|
207
249
|
false
|
208
250
|
end
|
209
251
|
|
252
|
+
# Does this adapter support application-enforced advisory locking?
|
253
|
+
def supports_advisory_locks?
|
254
|
+
false
|
255
|
+
end
|
256
|
+
|
210
257
|
# Should primary key values be selected from their corresponding
|
211
258
|
# sequence before the insert statement? If true, next_sequence_value
|
212
259
|
# is called before each insert to set the record's primary key.
|
@@ -224,6 +271,11 @@ module ActiveRecord
|
|
224
271
|
false
|
225
272
|
end
|
226
273
|
|
274
|
+
# Does this adapter support expression indices?
|
275
|
+
def supports_expression_index?
|
276
|
+
false
|
277
|
+
end
|
278
|
+
|
227
279
|
# Does this adapter support explain?
|
228
280
|
def supports_explain?
|
229
281
|
false
|
@@ -255,6 +307,31 @@ module ActiveRecord
|
|
255
307
|
false
|
256
308
|
end
|
257
309
|
|
310
|
+
# Does this adapter support datetime with precision?
|
311
|
+
def supports_datetime_with_precision?
|
312
|
+
false
|
313
|
+
end
|
314
|
+
|
315
|
+
# Does this adapter support json data type?
|
316
|
+
def supports_json?
|
317
|
+
false
|
318
|
+
end
|
319
|
+
|
320
|
+
# Does this adapter support metadata comments on database objects (tables, columns, indexes)?
|
321
|
+
def supports_comments?
|
322
|
+
false
|
323
|
+
end
|
324
|
+
|
325
|
+
# Can comments for tables, columns, and indexes be specified in create/alter table statements?
|
326
|
+
def supports_comments_in_create?
|
327
|
+
false
|
328
|
+
end
|
329
|
+
|
330
|
+
# Does this adapter support multi-value insert?
|
331
|
+
def supports_multi_insert?
|
332
|
+
true
|
333
|
+
end
|
334
|
+
|
258
335
|
# This is meant to be implemented by the adapters that support extensions
|
259
336
|
def disable_extension(name)
|
260
337
|
end
|
@@ -263,6 +340,20 @@ module ActiveRecord
|
|
263
340
|
def enable_extension(name)
|
264
341
|
end
|
265
342
|
|
343
|
+
# This is meant to be implemented by the adapters that support advisory
|
344
|
+
# locks
|
345
|
+
#
|
346
|
+
# Return true if we got the lock, otherwise false
|
347
|
+
def get_advisory_lock(lock_id) # :nodoc:
|
348
|
+
end
|
349
|
+
|
350
|
+
# This is meant to be implemented by the adapters that support advisory
|
351
|
+
# locks.
|
352
|
+
#
|
353
|
+
# Return true if we released the lock, otherwise false
|
354
|
+
def release_advisory_lock(lock_id) # :nodoc:
|
355
|
+
end
|
356
|
+
|
266
357
|
# A list of extensions, to be filled in by adapters that support them.
|
267
358
|
def extensions
|
268
359
|
[]
|
@@ -273,14 +364,6 @@ module ActiveRecord
|
|
273
364
|
{}
|
274
365
|
end
|
275
366
|
|
276
|
-
# QUOTING ==================================================
|
277
|
-
|
278
|
-
# Returns a bind substitution value given a bind +column+
|
279
|
-
# NOTE: The column param is currently being used by the sqlserver-adapter
|
280
|
-
def substitute_at(column, _unused = 0)
|
281
|
-
Arel::Nodes::BindParam.new
|
282
|
-
end
|
283
|
-
|
284
367
|
# REFERENTIAL INTEGRITY ====================================
|
285
368
|
|
286
369
|
# Override to turn off referential integrity while executing <tt>&block</tt>.
|
@@ -334,15 +417,15 @@ module ActiveRecord
|
|
334
417
|
end
|
335
418
|
|
336
419
|
# Checks whether the connection to the database is still active (i.e. not stale).
|
337
|
-
# This is done under the hood by calling
|
420
|
+
# This is done under the hood by calling #active?. If the connection
|
338
421
|
# is no longer active, then this method will reconnect to the database.
|
339
422
|
def verify!(*ignored)
|
340
423
|
reconnect! unless active?
|
341
424
|
end
|
342
425
|
|
343
426
|
# Provides access to the underlying database driver for this adapter. For
|
344
|
-
# example, this method returns a
|
345
|
-
# and a
|
427
|
+
# example, this method returns a Mysql2::Client object in case of Mysql2Adapter,
|
428
|
+
# and a PG::Connection object in case of PostgreSQLAdapter.
|
346
429
|
#
|
347
430
|
# This is useful for when you need to call a proprietary method such as
|
348
431
|
# PostgreSQL's lo_* methods.
|
@@ -350,29 +433,26 @@ module ActiveRecord
|
|
350
433
|
@connection
|
351
434
|
end
|
352
435
|
|
353
|
-
def create_savepoint(name = nil)
|
354
|
-
end
|
355
|
-
|
356
|
-
def release_savepoint(name = nil)
|
357
|
-
end
|
358
|
-
|
359
|
-
def case_sensitive_modifier(node, table_attribute)
|
360
|
-
node
|
361
|
-
end
|
362
|
-
|
363
436
|
def case_sensitive_comparison(table, attribute, column, value)
|
364
|
-
|
365
|
-
|
366
|
-
|
437
|
+
if value.nil?
|
438
|
+
table[attribute].eq(value)
|
439
|
+
else
|
440
|
+
table[attribute].eq(Arel::Nodes::BindParam.new)
|
441
|
+
end
|
367
442
|
end
|
368
443
|
|
369
444
|
def case_insensitive_comparison(table, attribute, column, value)
|
370
|
-
|
445
|
+
if can_perform_case_insensitive_comparison_for?(column)
|
446
|
+
table[attribute].lower.eq(table.lower(Arel::Nodes::BindParam.new))
|
447
|
+
else
|
448
|
+
table[attribute].eq(Arel::Nodes::BindParam.new)
|
449
|
+
end
|
371
450
|
end
|
372
451
|
|
373
|
-
def
|
374
|
-
|
452
|
+
def can_perform_case_insensitive_comparison_for?(column)
|
453
|
+
true
|
375
454
|
end
|
455
|
+
private :can_perform_case_insensitive_comparison_for?
|
376
456
|
|
377
457
|
# Check the connection back in to the connection pool
|
378
458
|
def close
|
@@ -385,8 +465,8 @@ module ActiveRecord
|
|
385
465
|
end
|
386
466
|
end
|
387
467
|
|
388
|
-
def new_column(name, default,
|
389
|
-
Column.new(name, default,
|
468
|
+
def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil) # :nodoc:
|
469
|
+
Column.new(name, default, sql_type_metadata, null, table_name, default_function, collation)
|
390
470
|
end
|
391
471
|
|
392
472
|
def lookup_cast_type(sql_type) # :nodoc:
|
@@ -397,18 +477,36 @@ module ActiveRecord
|
|
397
477
|
visitor.accept(node, collector).value
|
398
478
|
end
|
399
479
|
|
480
|
+
def combine_bind_parameters(
|
481
|
+
from_clause: [],
|
482
|
+
join_clause: [],
|
483
|
+
where_clause: [],
|
484
|
+
having_clause: [],
|
485
|
+
limit: nil,
|
486
|
+
offset: nil
|
487
|
+
) # :nodoc:
|
488
|
+
result = from_clause + join_clause + where_clause + having_clause
|
489
|
+
if limit
|
490
|
+
result << limit
|
491
|
+
end
|
492
|
+
if offset
|
493
|
+
result << offset
|
494
|
+
end
|
495
|
+
result
|
496
|
+
end
|
497
|
+
|
400
498
|
protected
|
401
499
|
|
402
500
|
def initialize_type_map(m) # :nodoc:
|
403
|
-
register_class_with_limit m, %r(boolean)i,
|
404
|
-
register_class_with_limit m, %r(char)i,
|
405
|
-
register_class_with_limit m, %r(binary)i,
|
406
|
-
register_class_with_limit m, %r(text)i,
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
register_class_with_limit m, %r(float)i,
|
411
|
-
register_class_with_limit m, %r(int)i,
|
501
|
+
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
502
|
+
register_class_with_limit m, %r(char)i, Type::String
|
503
|
+
register_class_with_limit m, %r(binary)i, Type::Binary
|
504
|
+
register_class_with_limit m, %r(text)i, Type::Text
|
505
|
+
register_class_with_precision m, %r(date)i, Type::Date
|
506
|
+
register_class_with_precision m, %r(time)i, Type::Time
|
507
|
+
register_class_with_precision m, %r(datetime)i, Type::DateTime
|
508
|
+
register_class_with_limit m, %r(float)i, Type::Float
|
509
|
+
register_class_with_limit m, %r(int)i, Type::Integer
|
412
510
|
|
413
511
|
m.alias_type %r(blob)i, 'binary'
|
414
512
|
m.alias_type %r(clob)i, 'text'
|
@@ -442,6 +540,13 @@ module ActiveRecord
|
|
442
540
|
end
|
443
541
|
end
|
444
542
|
|
543
|
+
def register_class_with_precision(mapping, key, klass) # :nodoc:
|
544
|
+
mapping.register_type(key) do |*args|
|
545
|
+
precision = extract_precision(args.last)
|
546
|
+
klass.new(precision: precision)
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
445
550
|
def extract_scale(sql_type) # :nodoc:
|
446
551
|
case sql_type
|
447
552
|
when /\((\d+)\)/ then 0
|
@@ -474,21 +579,22 @@ module ActiveRecord
|
|
474
579
|
exception
|
475
580
|
end
|
476
581
|
|
477
|
-
def log(sql, name = "SQL", binds = [], statement_name = nil)
|
582
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
|
478
583
|
@instrumenter.instrument(
|
479
584
|
"sql.active_record",
|
480
|
-
:sql
|
481
|
-
:name
|
482
|
-
:
|
483
|
-
:
|
484
|
-
:
|
585
|
+
sql: sql,
|
586
|
+
name: name,
|
587
|
+
binds: binds,
|
588
|
+
type_casted_binds: type_casted_binds,
|
589
|
+
statement_name: statement_name,
|
590
|
+
connection_id: object_id) { yield }
|
485
591
|
rescue => e
|
486
592
|
raise translate_exception_class(e, sql)
|
487
593
|
end
|
488
594
|
|
489
595
|
def translate_exception(exception, message)
|
490
596
|
# override in derived class
|
491
|
-
ActiveRecord::StatementInvalid.new(message
|
597
|
+
ActiveRecord::StatementInvalid.new(message)
|
492
598
|
end
|
493
599
|
|
494
600
|
def without_prepared_statement?(binds)
|