activerecord 4.2.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1537 -789
- 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/aggregations.rb +37 -23
- data/lib/active_record/association_relation.rb +16 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +23 -9
- data/lib/active_record/associations/association_scope.rb +74 -102
- data/lib/active_record/associations/belongs_to_association.rb +26 -29
- 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 +12 -20
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
- 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 +3 -10
- data/lib/active_record/associations/collection_association.rb +61 -33
- data/lib/active_record/associations/collection_proxy.rb +81 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +15 -45
- data/lib/active_record/associations/has_one_association.rb +13 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
- data/lib/active_record/associations/join_dependency.rb +37 -21
- data/lib/active_record/associations/preloader/association.rb +51 -53
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- 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/through_association.rb +27 -14
- data/lib/active_record/associations/preloader.rb +18 -8
- data/lib/active_record/associations/singular_association.rb +8 -8
- data/lib/active_record/associations/through_association.rb +22 -9
- data/lib/active_record/associations.rb +321 -212
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +79 -15
- data/lib/active_record/attribute_assignment.rb +20 -141
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
- data/lib/active_record/attribute_methods/dirty.rb +51 -81
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
- data/lib/active_record/attribute_methods/write.rb +14 -38
- data/lib/active_record/attribute_methods.rb +70 -45
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +37 -15
- data/lib/active_record/attribute_set.rb +34 -3
- data/lib/active_record/attributes.rb +199 -73
- data/lib/active_record/autosave_association.rb +73 -25
- data/lib/active_record/base.rb +35 -27
- 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 +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
- 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 +125 -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 +26 -177
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -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/type_map_initializer.rb +17 -5
- 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/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- 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 +248 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -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 +150 -209
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +38 -15
- data/lib/active_record/core.rb +109 -114
- data/lib/active_record/counter_cache.rb +14 -25
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +115 -79
- data/lib/active_record/errors.rb +88 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +84 -46
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +27 -25
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +372 -114
- data/lib/active_record/model_schema.rb +128 -38
- data/lib/active_record/nested_attributes.rb +71 -32
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +124 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +28 -19
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +67 -51
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +318 -139
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +80 -102
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +167 -97
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +38 -41
- data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -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/predicate_builder.rb +124 -82
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +323 -257
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -10
- 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/relation.rb +176 -115
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -17
- data/lib/active_record/scoping/default.rb +24 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +59 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
- data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
- 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 +58 -0
- data/lib/active_record/transactions.rb +159 -67
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -41
- data/lib/active_record/type/date_time.rb +2 -38
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +21 -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.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- 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 +29 -18
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +9 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- 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 +60 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- 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 -30
- data/lib/active_record/type/decimal.rb +0 -40
- 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 -55
- 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 -36
- 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 -101
@@ -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,19 +45,16 @@ 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)
|
58
|
-
|
59
|
-
records << record
|
60
|
-
else
|
61
|
-
record.set_transaction_state(@state)
|
62
|
-
end
|
57
|
+
records << record
|
63
58
|
end
|
64
59
|
|
65
60
|
def rollback
|
@@ -69,16 +64,11 @@ module ActiveRecord
|
|
69
64
|
def rollback_records
|
70
65
|
ite = records.uniq
|
71
66
|
while record = ite.shift
|
72
|
-
|
73
|
-
record.rolledback! full_rollback?
|
74
|
-
rescue => e
|
75
|
-
raise if ActiveRecord::Base.raise_in_transactional_callbacks
|
76
|
-
record.logger.error(e) if record.respond_to?(:logger) && record.logger
|
77
|
-
end
|
67
|
+
record.rolledback!(force_restore_state: full_rollback?)
|
78
68
|
end
|
79
69
|
ensure
|
80
70
|
ite.each do |i|
|
81
|
-
i.rolledback!(full_rollback?, false)
|
71
|
+
i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false)
|
82
72
|
end
|
83
73
|
end
|
84
74
|
|
@@ -86,20 +76,22 @@ module ActiveRecord
|
|
86
76
|
@state.set_state(:committed)
|
87
77
|
end
|
88
78
|
|
79
|
+
def before_commit_records
|
80
|
+
records.uniq.each(&:before_committed!) if @run_commit_callbacks
|
81
|
+
end
|
82
|
+
|
89
83
|
def commit_records
|
90
84
|
ite = records.uniq
|
91
85
|
while record = ite.shift
|
92
|
-
|
86
|
+
if @run_commit_callbacks
|
93
87
|
record.committed!
|
94
|
-
|
95
|
-
|
96
|
-
record.
|
88
|
+
else
|
89
|
+
# if not running callbacks, only adds the record to the parent transaction
|
90
|
+
record.add_to_transaction
|
97
91
|
end
|
98
92
|
end
|
99
93
|
ensure
|
100
|
-
ite.each
|
101
|
-
i.committed!(false)
|
102
|
-
end
|
94
|
+
ite.each { |i| i.committed!(should_run_callbacks: false) }
|
103
95
|
end
|
104
96
|
|
105
97
|
def full_rollback?; true; end
|
@@ -110,8 +102,8 @@ module ActiveRecord
|
|
110
102
|
|
111
103
|
class SavepointTransaction < Transaction
|
112
104
|
|
113
|
-
def initialize(connection, savepoint_name, options)
|
114
|
-
super(connection, options)
|
105
|
+
def initialize(connection, savepoint_name, options, *args)
|
106
|
+
super(connection, options, *args)
|
115
107
|
if options[:isolation]
|
116
108
|
raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
|
117
109
|
end
|
@@ -121,14 +113,11 @@ module ActiveRecord
|
|
121
113
|
def rollback
|
122
114
|
connection.rollback_to_savepoint(savepoint_name)
|
123
115
|
super
|
124
|
-
rollback_records
|
125
116
|
end
|
126
117
|
|
127
118
|
def commit
|
128
119
|
connection.release_savepoint(savepoint_name)
|
129
120
|
super
|
130
|
-
parent = connection.transaction_manager.current_transaction
|
131
|
-
records.each { |r| parent.add_record(r) }
|
132
121
|
end
|
133
122
|
|
134
123
|
def full_rollback?; false; end
|
@@ -136,7 +125,7 @@ module ActiveRecord
|
|
136
125
|
|
137
126
|
class RealTransaction < Transaction
|
138
127
|
|
139
|
-
def initialize(connection, options)
|
128
|
+
def initialize(connection, options, *args)
|
140
129
|
super
|
141
130
|
if options[:isolation]
|
142
131
|
connection.begin_isolated_db_transaction(options[:isolation])
|
@@ -148,13 +137,11 @@ module ActiveRecord
|
|
148
137
|
def rollback
|
149
138
|
connection.rollback_db_transaction
|
150
139
|
super
|
151
|
-
rollback_records
|
152
140
|
end
|
153
141
|
|
154
142
|
def commit
|
155
143
|
connection.commit_db_transaction
|
156
144
|
super
|
157
|
-
commit_records
|
158
145
|
end
|
159
146
|
end
|
160
147
|
|
@@ -165,39 +152,56 @@ module ActiveRecord
|
|
165
152
|
end
|
166
153
|
|
167
154
|
def begin_transaction(options = {})
|
155
|
+
run_commit_callbacks = !current_transaction.joinable?
|
168
156
|
transaction =
|
169
157
|
if @stack.empty?
|
170
|
-
RealTransaction.new(@connection, options)
|
158
|
+
RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
|
171
159
|
else
|
172
|
-
SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options
|
160
|
+
SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options,
|
161
|
+
run_commit_callbacks: run_commit_callbacks)
|
173
162
|
end
|
163
|
+
|
174
164
|
@stack.push(transaction)
|
175
165
|
transaction
|
176
166
|
end
|
177
167
|
|
178
168
|
def commit_transaction
|
179
|
-
@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
|
180
179
|
end
|
181
180
|
|
182
|
-
def rollback_transaction
|
183
|
-
@stack.pop
|
181
|
+
def rollback_transaction(transaction = nil)
|
182
|
+
transaction ||= @stack.pop
|
183
|
+
transaction.rollback
|
184
|
+
transaction.rollback_records
|
184
185
|
end
|
185
186
|
|
186
187
|
def within_new_transaction(options = {})
|
187
188
|
transaction = begin_transaction options
|
188
189
|
yield
|
189
190
|
rescue Exception => error
|
190
|
-
|
191
|
+
if transaction
|
192
|
+
rollback_transaction
|
193
|
+
after_failure_actions(transaction, error)
|
194
|
+
end
|
191
195
|
raise
|
192
196
|
ensure
|
193
197
|
unless error
|
194
198
|
if Thread.current.status == 'aborting'
|
195
|
-
rollback_transaction
|
199
|
+
rollback_transaction if transaction
|
196
200
|
else
|
197
201
|
begin
|
198
202
|
commit_transaction
|
199
203
|
rescue Exception
|
200
|
-
transaction
|
204
|
+
rollback_transaction(transaction) unless transaction.state.completed?
|
201
205
|
raise
|
202
206
|
end
|
203
207
|
end
|
@@ -213,7 +217,16 @@ module ActiveRecord
|
|
213
217
|
end
|
214
218
|
|
215
219
|
private
|
220
|
+
|
216
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
|
+
|
217
230
|
end
|
218
231
|
end
|
219
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,23 +51,23 @@ 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
64
|
ADAPTER_NAME = 'Abstract'.freeze
|
68
65
|
include Quoting, DatabaseStatements, SchemaStatements
|
69
66
|
include DatabaseLimits
|
70
67
|
include QueryCache
|
71
68
|
include ActiveSupport::Callbacks
|
72
|
-
include MonitorMixin
|
73
69
|
include ColumnDumper
|
70
|
+
include Savepoints
|
74
71
|
|
75
72
|
SIMPLE_INT = /\A\d+\z/
|
76
73
|
|
@@ -98,22 +95,43 @@ 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
|
117
|
+
end
|
118
|
+
|
119
|
+
class Version
|
120
|
+
include Comparable
|
121
|
+
|
122
|
+
def initialize(version_string)
|
123
|
+
@version = version_string.split('.').map(&:to_i)
|
124
|
+
end
|
125
|
+
|
126
|
+
def <=>(version_string)
|
127
|
+
@version <=> version_string.split('.').map(&:to_i)
|
128
|
+
end
|
112
129
|
end
|
113
130
|
|
114
131
|
class BindCollector < Arel::Collectors::Bind
|
115
132
|
def compile(bvs, conn)
|
116
|
-
|
133
|
+
casted_binds = conn.prepare_binds_for_database(bvs)
|
134
|
+
super(casted_binds.map { |value| conn.quote(value) })
|
117
135
|
end
|
118
136
|
end
|
119
137
|
|
@@ -131,20 +149,32 @@ module ActiveRecord
|
|
131
149
|
end
|
132
150
|
end
|
133
151
|
|
152
|
+
def arel_visitor # :nodoc:
|
153
|
+
Arel::Visitors::ToSql.new(self)
|
154
|
+
end
|
155
|
+
|
134
156
|
def valid_type?(type)
|
135
|
-
|
157
|
+
false
|
136
158
|
end
|
137
159
|
|
138
160
|
def schema_creation
|
139
161
|
SchemaCreation.new self
|
140
162
|
end
|
141
163
|
|
164
|
+
# this method must only be called while holding connection pool's mutex
|
142
165
|
def lease
|
143
|
-
|
144
|
-
|
145
|
-
|
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}."
|
146
173
|
end
|
174
|
+
raise ActiveRecordError, msg
|
147
175
|
end
|
176
|
+
|
177
|
+
@owner = Thread.current
|
148
178
|
end
|
149
179
|
|
150
180
|
def schema_cache=(cache)
|
@@ -152,6 +182,7 @@ module ActiveRecord
|
|
152
182
|
@schema_cache = cache
|
153
183
|
end
|
154
184
|
|
185
|
+
# this method must only be called while holding connection pool's mutex
|
155
186
|
def expire
|
156
187
|
@owner = nil
|
157
188
|
end
|
@@ -195,6 +226,11 @@ module ActiveRecord
|
|
195
226
|
false
|
196
227
|
end
|
197
228
|
|
229
|
+
# Does this adapter support application-enforced advisory locking?
|
230
|
+
def supports_advisory_locks?
|
231
|
+
false
|
232
|
+
end
|
233
|
+
|
198
234
|
# Should primary key values be selected from their corresponding
|
199
235
|
# sequence before the insert statement? If true, next_sequence_value
|
200
236
|
# is called before each insert to set the record's primary key.
|
@@ -212,6 +248,11 @@ module ActiveRecord
|
|
212
248
|
false
|
213
249
|
end
|
214
250
|
|
251
|
+
# Does this adapter support expression indices?
|
252
|
+
def supports_expression_index?
|
253
|
+
false
|
254
|
+
end
|
255
|
+
|
215
256
|
# Does this adapter support explain?
|
216
257
|
def supports_explain?
|
217
258
|
false
|
@@ -243,6 +284,31 @@ module ActiveRecord
|
|
243
284
|
false
|
244
285
|
end
|
245
286
|
|
287
|
+
# Does this adapter support datetime with precision?
|
288
|
+
def supports_datetime_with_precision?
|
289
|
+
false
|
290
|
+
end
|
291
|
+
|
292
|
+
# Does this adapter support json data type?
|
293
|
+
def supports_json?
|
294
|
+
false
|
295
|
+
end
|
296
|
+
|
297
|
+
# Does this adapter support metadata comments on database objects (tables, columns, indexes)?
|
298
|
+
def supports_comments?
|
299
|
+
false
|
300
|
+
end
|
301
|
+
|
302
|
+
# Can comments for tables, columns, and indexes be specified in create/alter table statements?
|
303
|
+
def supports_comments_in_create?
|
304
|
+
false
|
305
|
+
end
|
306
|
+
|
307
|
+
# Does this adapter support multi-value insert?
|
308
|
+
def supports_multi_insert?
|
309
|
+
true
|
310
|
+
end
|
311
|
+
|
246
312
|
# This is meant to be implemented by the adapters that support extensions
|
247
313
|
def disable_extension(name)
|
248
314
|
end
|
@@ -251,6 +317,20 @@ module ActiveRecord
|
|
251
317
|
def enable_extension(name)
|
252
318
|
end
|
253
319
|
|
320
|
+
# This is meant to be implemented by the adapters that support advisory
|
321
|
+
# locks
|
322
|
+
#
|
323
|
+
# Return true if we got the lock, otherwise false
|
324
|
+
def get_advisory_lock(lock_id) # :nodoc:
|
325
|
+
end
|
326
|
+
|
327
|
+
# This is meant to be implemented by the adapters that support advisory
|
328
|
+
# locks.
|
329
|
+
#
|
330
|
+
# Return true if we released the lock, otherwise false
|
331
|
+
def release_advisory_lock(lock_id) # :nodoc:
|
332
|
+
end
|
333
|
+
|
254
334
|
# A list of extensions, to be filled in by adapters that support them.
|
255
335
|
def extensions
|
256
336
|
[]
|
@@ -261,14 +341,6 @@ module ActiveRecord
|
|
261
341
|
{}
|
262
342
|
end
|
263
343
|
|
264
|
-
# QUOTING ==================================================
|
265
|
-
|
266
|
-
# Returns a bind substitution value given a bind +column+
|
267
|
-
# NOTE: The column param is currently being used by the sqlserver-adapter
|
268
|
-
def substitute_at(column, _unused = 0)
|
269
|
-
Arel::Nodes::BindParam.new
|
270
|
-
end
|
271
|
-
|
272
344
|
# REFERENTIAL INTEGRITY ====================================
|
273
345
|
|
274
346
|
# Override to turn off referential integrity while executing <tt>&block</tt>.
|
@@ -322,14 +394,14 @@ module ActiveRecord
|
|
322
394
|
end
|
323
395
|
|
324
396
|
# Checks whether the connection to the database is still active (i.e. not stale).
|
325
|
-
# This is done under the hood by calling
|
397
|
+
# This is done under the hood by calling #active?. If the connection
|
326
398
|
# is no longer active, then this method will reconnect to the database.
|
327
399
|
def verify!(*ignored)
|
328
400
|
reconnect! unless active?
|
329
401
|
end
|
330
402
|
|
331
403
|
# Provides access to the underlying database driver for this adapter. For
|
332
|
-
# example, this method returns a
|
404
|
+
# example, this method returns a Mysql2::Client object in case of Mysql2Adapter,
|
333
405
|
# and a PGconn object in case of PostgreSQLAdapter.
|
334
406
|
#
|
335
407
|
# This is useful for when you need to call a proprietary method such as
|
@@ -338,32 +410,26 @@ module ActiveRecord
|
|
338
410
|
@connection
|
339
411
|
end
|
340
412
|
|
341
|
-
def create_savepoint(name = nil)
|
342
|
-
end
|
343
|
-
|
344
|
-
def rollback_to_savepoint(name = nil)
|
345
|
-
end
|
346
|
-
|
347
|
-
def release_savepoint(name = nil)
|
348
|
-
end
|
349
|
-
|
350
|
-
def case_sensitive_modifier(node, table_attribute)
|
351
|
-
node
|
352
|
-
end
|
353
|
-
|
354
413
|
def case_sensitive_comparison(table, attribute, column, value)
|
355
|
-
|
356
|
-
|
357
|
-
|
414
|
+
if value.nil?
|
415
|
+
table[attribute].eq(value)
|
416
|
+
else
|
417
|
+
table[attribute].eq(Arel::Nodes::BindParam.new)
|
418
|
+
end
|
358
419
|
end
|
359
420
|
|
360
421
|
def case_insensitive_comparison(table, attribute, column, value)
|
361
|
-
|
422
|
+
if can_perform_case_insensitive_comparison_for?(column)
|
423
|
+
table[attribute].lower.eq(table.lower(Arel::Nodes::BindParam.new))
|
424
|
+
else
|
425
|
+
table[attribute].eq(Arel::Nodes::BindParam.new)
|
426
|
+
end
|
362
427
|
end
|
363
428
|
|
364
|
-
def
|
365
|
-
|
429
|
+
def can_perform_case_insensitive_comparison_for?(column)
|
430
|
+
true
|
366
431
|
end
|
432
|
+
private :can_perform_case_insensitive_comparison_for?
|
367
433
|
|
368
434
|
# Check the connection back in to the connection pool
|
369
435
|
def close
|
@@ -376,8 +442,8 @@ module ActiveRecord
|
|
376
442
|
end
|
377
443
|
end
|
378
444
|
|
379
|
-
def new_column(name, default,
|
380
|
-
Column.new(name, default,
|
445
|
+
def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil) # :nodoc:
|
446
|
+
Column.new(name, default, sql_type_metadata, null, table_name, default_function, collation)
|
381
447
|
end
|
382
448
|
|
383
449
|
def lookup_cast_type(sql_type) # :nodoc:
|
@@ -385,21 +451,39 @@ module ActiveRecord
|
|
385
451
|
end
|
386
452
|
|
387
453
|
def column_name_for_operation(operation, node) # :nodoc:
|
388
|
-
node.
|
454
|
+
visitor.accept(node, collector).value
|
455
|
+
end
|
456
|
+
|
457
|
+
def combine_bind_parameters(
|
458
|
+
from_clause: [],
|
459
|
+
join_clause: [],
|
460
|
+
where_clause: [],
|
461
|
+
having_clause: [],
|
462
|
+
limit: nil,
|
463
|
+
offset: nil
|
464
|
+
) # :nodoc:
|
465
|
+
result = from_clause + join_clause + where_clause + having_clause
|
466
|
+
if limit
|
467
|
+
result << limit
|
468
|
+
end
|
469
|
+
if offset
|
470
|
+
result << offset
|
471
|
+
end
|
472
|
+
result
|
389
473
|
end
|
390
474
|
|
391
475
|
protected
|
392
476
|
|
393
477
|
def initialize_type_map(m) # :nodoc:
|
394
|
-
register_class_with_limit m, %r(boolean)i,
|
395
|
-
register_class_with_limit m, %r(char)i,
|
396
|
-
register_class_with_limit m, %r(binary)i,
|
397
|
-
register_class_with_limit m, %r(text)i,
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
register_class_with_limit m, %r(float)i,
|
402
|
-
register_class_with_limit m, %r(int)i,
|
478
|
+
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
479
|
+
register_class_with_limit m, %r(char)i, Type::String
|
480
|
+
register_class_with_limit m, %r(binary)i, Type::Binary
|
481
|
+
register_class_with_limit m, %r(text)i, Type::Text
|
482
|
+
register_class_with_precision m, %r(date)i, Type::Date
|
483
|
+
register_class_with_precision m, %r(time)i, Type::Time
|
484
|
+
register_class_with_precision m, %r(datetime)i, Type::DateTime
|
485
|
+
register_class_with_limit m, %r(float)i, Type::Float
|
486
|
+
register_class_with_limit m, %r(int)i, Type::Integer
|
403
487
|
|
404
488
|
m.alias_type %r(blob)i, 'binary'
|
405
489
|
m.alias_type %r(clob)i, 'text'
|
@@ -433,6 +517,13 @@ module ActiveRecord
|
|
433
517
|
end
|
434
518
|
end
|
435
519
|
|
520
|
+
def register_class_with_precision(mapping, key, klass) # :nodoc:
|
521
|
+
mapping.register_type(key) do |*args|
|
522
|
+
precision = extract_precision(args.last)
|
523
|
+
klass.new(precision: precision)
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
436
527
|
def extract_scale(sql_type) # :nodoc:
|
437
528
|
case sql_type
|
438
529
|
when /\((\d+)\)/ then 0
|
@@ -445,12 +536,21 @@ module ActiveRecord
|
|
445
536
|
end
|
446
537
|
|
447
538
|
def extract_limit(sql_type) # :nodoc:
|
448
|
-
|
539
|
+
case sql_type
|
540
|
+
when /^bigint/i
|
541
|
+
8
|
542
|
+
when /\((.*)\)/
|
543
|
+
$1.to_i
|
544
|
+
end
|
449
545
|
end
|
450
546
|
|
451
547
|
def translate_exception_class(e, sql)
|
452
|
-
|
453
|
-
|
548
|
+
begin
|
549
|
+
message = "#{e.class.name}: #{e.message}: #{sql}"
|
550
|
+
rescue Encoding::CompatibilityError
|
551
|
+
message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
|
552
|
+
end
|
553
|
+
|
454
554
|
exception = translate_exception(e, message)
|
455
555
|
exception.set_backtrace e.backtrace
|
456
556
|
exception
|
@@ -470,7 +570,7 @@ module ActiveRecord
|
|
470
570
|
|
471
571
|
def translate_exception(exception, message)
|
472
572
|
# override in derived class
|
473
|
-
ActiveRecord::StatementInvalid.new(message
|
573
|
+
ActiveRecord::StatementInvalid.new(message)
|
474
574
|
end
|
475
575
|
|
476
576
|
def without_prepared_statement?(binds)
|