activerecord 5.2.6 → 6.0.0.beta1

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.

Files changed (241) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -758
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +2 -1
  7. data/lib/active_record/aggregations.rb +4 -2
  8. data/lib/active_record/associations.rb +16 -12
  9. data/lib/active_record/associations/association.rb +35 -19
  10. data/lib/active_record/associations/association_scope.rb +4 -6
  11. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +14 -50
  14. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  16. data/lib/active_record/associations/collection_association.rb +11 -25
  17. data/lib/active_record/associations/collection_proxy.rb +32 -6
  18. data/lib/active_record/associations/foreign_association.rb +7 -0
  19. data/lib/active_record/associations/has_many_association.rb +1 -1
  20. data/lib/active_record/associations/has_many_through_association.rb +25 -18
  21. data/lib/active_record/associations/has_one_association.rb +28 -30
  22. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  23. data/lib/active_record/associations/join_dependency.rb +15 -20
  24. data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
  25. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  26. data/lib/active_record/associations/preloader.rb +32 -29
  27. data/lib/active_record/associations/preloader/association.rb +1 -2
  28. data/lib/active_record/associations/singular_association.rb +2 -16
  29. data/lib/active_record/attribute_assignment.rb +7 -10
  30. data/lib/active_record/attribute_methods.rb +34 -56
  31. data/lib/active_record/attribute_methods/dirty.rb +64 -26
  32. data/lib/active_record/attribute_methods/primary_key.rb +8 -7
  33. data/lib/active_record/attribute_methods/read.rb +16 -48
  34. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  35. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  36. data/lib/active_record/attribute_methods/write.rb +15 -16
  37. data/lib/active_record/autosave_association.rb +7 -21
  38. data/lib/active_record/base.rb +2 -2
  39. data/lib/active_record/callbacks.rb +3 -17
  40. data/lib/active_record/collection_cache_key.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
  42. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  43. data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
  44. data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
  45. data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
  46. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
  47. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  48. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
  49. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
  50. data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
  51. data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
  52. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
  53. data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
  54. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
  55. data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
  56. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  57. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  58. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
  59. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
  60. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
  61. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -1
  62. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  63. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  64. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  65. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  66. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  67. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  68. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  69. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  70. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
  71. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
  73. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
  74. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
  75. data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
  76. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
  77. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
  78. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
  79. data/lib/active_record/connection_handling.rb +132 -26
  80. data/lib/active_record/core.rb +76 -43
  81. data/lib/active_record/counter_cache.rb +4 -29
  82. data/lib/active_record/database_configurations.rb +184 -0
  83. data/lib/active_record/database_configurations/database_config.rb +37 -0
  84. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  85. data/lib/active_record/database_configurations/url_config.rb +74 -0
  86. data/lib/active_record/enum.rb +22 -7
  87. data/lib/active_record/errors.rb +24 -21
  88. data/lib/active_record/explain.rb +1 -1
  89. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  90. data/lib/active_record/fixture_set/render_context.rb +17 -0
  91. data/lib/active_record/fixture_set/table_row.rb +153 -0
  92. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  93. data/lib/active_record/fixtures.rb +140 -472
  94. data/lib/active_record/gem_version.rb +4 -4
  95. data/lib/active_record/inheritance.rb +12 -2
  96. data/lib/active_record/integration.rb +56 -16
  97. data/lib/active_record/internal_metadata.rb +5 -1
  98. data/lib/active_record/locking/optimistic.rb +2 -2
  99. data/lib/active_record/locking/pessimistic.rb +3 -3
  100. data/lib/active_record/log_subscriber.rb +7 -26
  101. data/lib/active_record/migration.rb +38 -37
  102. data/lib/active_record/migration/command_recorder.rb +35 -5
  103. data/lib/active_record/migration/compatibility.rb +34 -16
  104. data/lib/active_record/model_schema.rb +30 -9
  105. data/lib/active_record/nested_attributes.rb +2 -2
  106. data/lib/active_record/no_touching.rb +7 -0
  107. data/lib/active_record/persistence.rb +18 -7
  108. data/lib/active_record/query_cache.rb +11 -4
  109. data/lib/active_record/querying.rb +19 -11
  110. data/lib/active_record/railtie.rb +71 -42
  111. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  112. data/lib/active_record/railties/controller_runtime.rb +30 -35
  113. data/lib/active_record/railties/databases.rake +94 -43
  114. data/lib/active_record/reflection.rb +60 -44
  115. data/lib/active_record/relation.rb +150 -69
  116. data/lib/active_record/relation/batches.rb +13 -10
  117. data/lib/active_record/relation/calculations.rb +38 -28
  118. data/lib/active_record/relation/delegation.rb +4 -13
  119. data/lib/active_record/relation/finder_methods.rb +12 -25
  120. data/lib/active_record/relation/merger.rb +2 -6
  121. data/lib/active_record/relation/predicate_builder.rb +4 -6
  122. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  123. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  124. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  125. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  126. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  127. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  128. data/lib/active_record/relation/query_attribute.rb +15 -12
  129. data/lib/active_record/relation/query_methods.rb +29 -52
  130. data/lib/active_record/relation/where_clause.rb +4 -0
  131. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  132. data/lib/active_record/result.rb +30 -11
  133. data/lib/active_record/sanitization.rb +2 -39
  134. data/lib/active_record/schema.rb +1 -10
  135. data/lib/active_record/schema_dumper.rb +12 -6
  136. data/lib/active_record/schema_migration.rb +4 -0
  137. data/lib/active_record/scoping.rb +9 -8
  138. data/lib/active_record/scoping/default.rb +10 -3
  139. data/lib/active_record/scoping/named.rb +10 -14
  140. data/lib/active_record/statement_cache.rb +32 -5
  141. data/lib/active_record/store.rb +39 -8
  142. data/lib/active_record/table_metadata.rb +1 -4
  143. data/lib/active_record/tasks/database_tasks.rb +89 -23
  144. data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
  145. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  146. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  147. data/lib/active_record/test_databases.rb +38 -0
  148. data/lib/active_record/test_fixtures.rb +224 -0
  149. data/lib/active_record/timestamp.rb +4 -6
  150. data/lib/active_record/transactions.rb +3 -22
  151. data/lib/active_record/translation.rb +1 -1
  152. data/lib/active_record/type.rb +3 -4
  153. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  154. data/lib/active_record/type_caster/connection.rb +1 -6
  155. data/lib/active_record/type_caster/map.rb +1 -4
  156. data/lib/active_record/validations/uniqueness.rb +13 -25
  157. data/lib/arel.rb +44 -0
  158. data/lib/arel/alias_predication.rb +9 -0
  159. data/lib/arel/attributes.rb +22 -0
  160. data/lib/arel/attributes/attribute.rb +37 -0
  161. data/lib/arel/collectors/bind.rb +24 -0
  162. data/lib/arel/collectors/composite.rb +31 -0
  163. data/lib/arel/collectors/plain_string.rb +20 -0
  164. data/lib/arel/collectors/sql_string.rb +20 -0
  165. data/lib/arel/collectors/substitute_binds.rb +28 -0
  166. data/lib/arel/crud.rb +42 -0
  167. data/lib/arel/delete_manager.rb +18 -0
  168. data/lib/arel/errors.rb +9 -0
  169. data/lib/arel/expressions.rb +29 -0
  170. data/lib/arel/factory_methods.rb +49 -0
  171. data/lib/arel/insert_manager.rb +49 -0
  172. data/lib/arel/math.rb +45 -0
  173. data/lib/arel/nodes.rb +67 -0
  174. data/lib/arel/nodes/and.rb +32 -0
  175. data/lib/arel/nodes/ascending.rb +23 -0
  176. data/lib/arel/nodes/binary.rb +52 -0
  177. data/lib/arel/nodes/bind_param.rb +36 -0
  178. data/lib/arel/nodes/case.rb +55 -0
  179. data/lib/arel/nodes/casted.rb +50 -0
  180. data/lib/arel/nodes/count.rb +12 -0
  181. data/lib/arel/nodes/delete_statement.rb +45 -0
  182. data/lib/arel/nodes/descending.rb +23 -0
  183. data/lib/arel/nodes/equality.rb +18 -0
  184. data/lib/arel/nodes/extract.rb +24 -0
  185. data/lib/arel/nodes/false.rb +16 -0
  186. data/lib/arel/nodes/full_outer_join.rb +8 -0
  187. data/lib/arel/nodes/function.rb +44 -0
  188. data/lib/arel/nodes/grouping.rb +8 -0
  189. data/lib/arel/nodes/in.rb +8 -0
  190. data/lib/arel/nodes/infix_operation.rb +80 -0
  191. data/lib/arel/nodes/inner_join.rb +8 -0
  192. data/lib/arel/nodes/insert_statement.rb +37 -0
  193. data/lib/arel/nodes/join_source.rb +20 -0
  194. data/lib/arel/nodes/matches.rb +18 -0
  195. data/lib/arel/nodes/named_function.rb +23 -0
  196. data/lib/arel/nodes/node.rb +50 -0
  197. data/lib/arel/nodes/node_expression.rb +13 -0
  198. data/lib/arel/nodes/outer_join.rb +8 -0
  199. data/lib/arel/nodes/over.rb +15 -0
  200. data/lib/arel/nodes/regexp.rb +16 -0
  201. data/lib/arel/nodes/right_outer_join.rb +8 -0
  202. data/lib/arel/nodes/select_core.rb +63 -0
  203. data/lib/arel/nodes/select_statement.rb +41 -0
  204. data/lib/arel/nodes/sql_literal.rb +16 -0
  205. data/lib/arel/nodes/string_join.rb +11 -0
  206. data/lib/arel/nodes/table_alias.rb +27 -0
  207. data/lib/arel/nodes/terminal.rb +16 -0
  208. data/lib/arel/nodes/true.rb +16 -0
  209. data/lib/arel/nodes/unary.rb +44 -0
  210. data/lib/arel/nodes/unary_operation.rb +20 -0
  211. data/lib/arel/nodes/unqualified_column.rb +22 -0
  212. data/lib/arel/nodes/update_statement.rb +41 -0
  213. data/lib/arel/nodes/values.rb +16 -0
  214. data/lib/arel/nodes/values_list.rb +24 -0
  215. data/lib/arel/nodes/window.rb +126 -0
  216. data/lib/arel/nodes/with.rb +11 -0
  217. data/lib/arel/order_predications.rb +13 -0
  218. data/lib/arel/predications.rb +257 -0
  219. data/lib/arel/select_manager.rb +271 -0
  220. data/lib/arel/table.rb +110 -0
  221. data/lib/arel/tree_manager.rb +72 -0
  222. data/lib/arel/update_manager.rb +34 -0
  223. data/lib/arel/visitors.rb +20 -0
  224. data/lib/arel/visitors/depth_first.rb +199 -0
  225. data/lib/arel/visitors/dot.rb +292 -0
  226. data/lib/arel/visitors/ibm_db.rb +21 -0
  227. data/lib/arel/visitors/informix.rb +56 -0
  228. data/lib/arel/visitors/mssql.rb +143 -0
  229. data/lib/arel/visitors/mysql.rb +83 -0
  230. data/lib/arel/visitors/oracle.rb +159 -0
  231. data/lib/arel/visitors/oracle12.rb +67 -0
  232. data/lib/arel/visitors/postgresql.rb +116 -0
  233. data/lib/arel/visitors/sqlite.rb +39 -0
  234. data/lib/arel/visitors/to_sql.rb +913 -0
  235. data/lib/arel/visitors/visitor.rb +42 -0
  236. data/lib/arel/visitors/where_sql.rb +23 -0
  237. data/lib/arel/window_predications.rb +9 -0
  238. data/lib/rails/generators/active_record/migration.rb +14 -1
  239. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  240. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  241. metadata +104 -26
@@ -40,24 +40,6 @@ module ActiveRecord
40
40
  committed? || rolledback?
41
41
  end
42
42
 
43
- def set_state(state)
44
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
45
- The set_state method is deprecated and will be removed in
46
- Rails 6.0. Please use rollback! or commit! to set transaction
47
- state directly.
48
- MSG
49
- case state
50
- when :rolledback
51
- rollback!
52
- when :committed
53
- commit!
54
- when nil
55
- nullify!
56
- else
57
- raise ArgumentError, "Invalid transaction state: #{state}"
58
- end
59
- end
60
-
61
43
  def rollback!
62
44
  @children.each { |c| c.rollback! }
63
45
  @state = :rolledback
@@ -91,13 +73,14 @@ module ActiveRecord
91
73
  end
92
74
 
93
75
  class Transaction #:nodoc:
94
- attr_reader :connection, :state, :records, :savepoint_name
95
- attr_writer :joinable
76
+ attr_reader :connection, :state, :records, :savepoint_name, :isolation_level
96
77
 
97
78
  def initialize(connection, options, run_commit_callbacks: false)
98
79
  @connection = connection
99
80
  @state = TransactionState.new
100
81
  @records = []
82
+ @isolation_level = options[:isolation]
83
+ @materialized = false
101
84
  @joinable = options.fetch(:joinable, true)
102
85
  @run_commit_callbacks = run_commit_callbacks
103
86
  end
@@ -106,6 +89,14 @@ module ActiveRecord
106
89
  records << record
107
90
  end
108
91
 
92
+ def materialize!
93
+ @materialized = true
94
+ end
95
+
96
+ def materialized?
97
+ @materialized
98
+ end
99
+
109
100
  def rollback_records
110
101
  ite = records.uniq
111
102
  while record = ite.shift
@@ -128,7 +119,7 @@ module ActiveRecord
128
119
  record.committed!
129
120
  else
130
121
  # if not running callbacks, only adds the record to the parent transaction
131
- record.add_to_transaction
122
+ connection.add_transaction_record(record)
132
123
  end
133
124
  end
134
125
  ensure
@@ -142,24 +133,30 @@ module ActiveRecord
142
133
  end
143
134
 
144
135
  class SavepointTransaction < Transaction
145
- def initialize(connection, savepoint_name, parent_transaction, options, *args)
146
- super(connection, options, *args)
136
+ def initialize(connection, savepoint_name, parent_transaction, *args)
137
+ super(connection, *args)
147
138
 
148
139
  parent_transaction.state.add_child(@state)
149
140
 
150
- if options[:isolation]
141
+ if isolation_level
151
142
  raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
152
143
  end
153
- connection.create_savepoint(@savepoint_name = savepoint_name)
144
+
145
+ @savepoint_name = savepoint_name
146
+ end
147
+
148
+ def materialize!
149
+ connection.create_savepoint(savepoint_name)
150
+ super
154
151
  end
155
152
 
156
153
  def rollback
157
- connection.rollback_to_savepoint(savepoint_name)
154
+ connection.rollback_to_savepoint(savepoint_name) if materialized?
158
155
  @state.rollback!
159
156
  end
160
157
 
161
158
  def commit
162
- connection.release_savepoint(savepoint_name)
159
+ connection.release_savepoint(savepoint_name) if materialized?
163
160
  @state.commit!
164
161
  end
165
162
 
@@ -167,22 +164,23 @@ module ActiveRecord
167
164
  end
168
165
 
169
166
  class RealTransaction < Transaction
170
- def initialize(connection, options, *args)
171
- super
172
- if options[:isolation]
173
- connection.begin_isolated_db_transaction(options[:isolation])
167
+ def materialize!
168
+ if isolation_level
169
+ connection.begin_isolated_db_transaction(isolation_level)
174
170
  else
175
171
  connection.begin_db_transaction
176
172
  end
173
+
174
+ super
177
175
  end
178
176
 
179
177
  def rollback
180
- connection.rollback_db_transaction
178
+ connection.rollback_db_transaction if materialized?
181
179
  @state.full_rollback!
182
180
  end
183
181
 
184
182
  def commit
185
- connection.commit_db_transaction
183
+ connection.commit_db_transaction if materialized?
186
184
  @state.full_commit!
187
185
  end
188
186
  end
@@ -191,6 +189,9 @@ module ActiveRecord
191
189
  def initialize(connection)
192
190
  @stack = []
193
191
  @connection = connection
192
+ @has_unmaterialized_transactions = false
193
+ @materializing_transactions = false
194
+ @lazy_transactions_enabled = true
194
195
  end
195
196
 
196
197
  def begin_transaction(options = {})
@@ -204,11 +205,41 @@ module ActiveRecord
204
205
  run_commit_callbacks: run_commit_callbacks)
205
206
  end
206
207
 
208
+ transaction.materialize! unless @connection.supports_lazy_transactions? && lazy_transactions_enabled?
207
209
  @stack.push(transaction)
210
+ @has_unmaterialized_transactions = true if @connection.supports_lazy_transactions?
208
211
  transaction
209
212
  end
210
213
  end
211
214
 
215
+ def disable_lazy_transactions!
216
+ materialize_transactions
217
+ @lazy_transactions_enabled = false
218
+ end
219
+
220
+ def enable_lazy_transactions!
221
+ @lazy_transactions_enabled = true
222
+ end
223
+
224
+ def lazy_transactions_enabled?
225
+ @lazy_transactions_enabled
226
+ end
227
+
228
+ def materialize_transactions
229
+ return if @materializing_transactions
230
+ return unless @has_unmaterialized_transactions
231
+
232
+ @connection.lock.synchronize do
233
+ begin
234
+ @materializing_transactions = true
235
+ @stack.each { |t| t.materialize! unless t.materialized? }
236
+ ensure
237
+ @materializing_transactions = false
238
+ end
239
+ @has_unmaterialized_transactions = false
240
+ end
241
+ end
242
+
212
243
  def commit_transaction
213
244
  @connection.lock.synchronize do
214
245
  transaction = @stack.last
@@ -234,26 +265,24 @@ module ActiveRecord
234
265
 
235
266
  def within_new_transaction(options = {})
236
267
  @connection.lock.synchronize do
237
- begin
238
- transaction = begin_transaction options
239
- yield
240
- rescue Exception => error
241
- if transaction
268
+ transaction = begin_transaction options
269
+ yield
270
+ rescue Exception => error
271
+ if transaction
272
+ rollback_transaction
273
+ after_failure_actions(transaction, error)
274
+ end
275
+ raise
276
+ ensure
277
+ if !error && transaction
278
+ if Thread.current.status == "aborting"
242
279
  rollback_transaction
243
- after_failure_actions(transaction, error)
244
- end
245
- raise
246
- ensure
247
- unless error
248
- if Thread.current.status == "aborting"
249
- rollback_transaction if transaction
250
- else
251
- begin
252
- commit_transaction if transaction
253
- rescue Exception
254
- rollback_transaction(transaction) unless transaction.state.completed?
255
- raise
256
- end
280
+ else
281
+ begin
282
+ commit_transaction
283
+ rescue Exception
284
+ rollback_transaction(transaction) unless transaction.state.completed?
285
+ raise
257
286
  end
258
287
  end
259
288
  end
@@ -6,6 +6,7 @@ require "active_record/connection_adapters/sql_type_metadata"
6
6
  require "active_record/connection_adapters/abstract/schema_dumper"
7
7
  require "active_record/connection_adapters/abstract/schema_creation"
8
8
  require "active_support/concurrency/load_interlock_aware_monitor"
9
+ require "active_support/deprecation"
9
10
  require "arel/collectors/bind"
10
11
  require "arel/collectors/composite"
11
12
  require "arel/collectors/sql_string"
@@ -65,7 +66,7 @@ module ActiveRecord
65
66
  # Most of the methods in the adapter are useful during migrations. Most
66
67
  # notably, the instance methods provided by SchemaStatements are very useful.
67
68
  class AbstractAdapter
68
- ADAPTER_NAME = "Abstract".freeze
69
+ ADAPTER_NAME = "Abstract"
69
70
  include ActiveSupport::Callbacks
70
71
  define_callbacks :checkout, :checkin
71
72
 
@@ -76,14 +77,19 @@ module ActiveRecord
76
77
 
77
78
  SIMPLE_INT = /\A\d+\z/
78
79
 
79
- attr_accessor :visitor, :pool
80
- attr_reader :schema_cache, :owner, :logger, :prepared_statements, :lock
80
+ attr_writer :visitor
81
+ deprecate :visitor=
82
+
83
+ attr_accessor :pool
84
+ attr_reader :schema_cache, :visitor, :owner, :logger, :lock, :prepared_statements, :prevent_writes
81
85
  alias :in_use? :owner
82
86
 
87
+ set_callback :checkin, :after, :enable_lazy_transactions!
88
+
83
89
  def self.type_cast_config_to_integer(config)
84
90
  if config.is_a?(Integer)
85
91
  config
86
- elsif config =~ SIMPLE_INT
92
+ elsif SIMPLE_INT.match?(config)
87
93
  config.to_i
88
94
  else
89
95
  config
@@ -98,6 +104,11 @@ module ActiveRecord
98
104
  end
99
105
  end
100
106
 
107
+ def self.build_read_query_regexp(*parts) # :nodoc:
108
+ parts = parts.map { |part| /\A\s*#{part}/i }
109
+ Regexp.union(*parts)
110
+ end
111
+
101
112
  def initialize(connection, logger = nil, config = {}) # :nodoc:
102
113
  super()
103
114
 
@@ -110,6 +121,7 @@ module ActiveRecord
110
121
  @idle_since = Concurrent.monotonic_time
111
122
  @schema_cache = SchemaCache.new self
112
123
  @quoted_column_names, @quoted_table_names = {}, {}
124
+ @prevent_writes = false
113
125
  @visitor = arel_visitor
114
126
  @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
115
127
 
@@ -119,6 +131,36 @@ module ActiveRecord
119
131
  else
120
132
  @prepared_statements = false
121
133
  end
134
+
135
+ @advisory_locks_enabled = self.class.type_cast_config_to_boolean(
136
+ config.fetch(:advisory_locks, true)
137
+ )
138
+
139
+ check_version
140
+ end
141
+
142
+ def replica?
143
+ @config[:replica] || false
144
+ end
145
+
146
+ # Determines whether writes are currently being prevents.
147
+ #
148
+ # Returns true if the connection is a replica, or if +prevent_writes+
149
+ # is set to true.
150
+ def preventing_writes?
151
+ replica? || prevent_writes
152
+ end
153
+
154
+ # Prevent writing to the database regardless of role.
155
+ #
156
+ # In some cases you may want to prevent writes to the database
157
+ # even if you are on a database that can write. `while_preventing_writes`
158
+ # will prevent writes to the database for the duration of the block.
159
+ def while_preventing_writes
160
+ original, @prevent_writes = @prevent_writes, true
161
+ yield
162
+ ensure
163
+ @prevent_writes = original
122
164
  end
123
165
 
124
166
  def migrations_paths # :nodoc:
@@ -139,6 +181,10 @@ module ActiveRecord
139
181
  def <=>(version_string)
140
182
  @version <=> version_string.split(".").map(&:to_i)
141
183
  end
184
+
185
+ def to_s
186
+ @version.join(".")
187
+ end
142
188
  end
143
189
 
144
190
  def valid_type?(type) # :nodoc:
@@ -148,7 +194,7 @@ module ActiveRecord
148
194
  # this method must only be called while holding connection pool's mutex
149
195
  def lease
150
196
  if in_use?
151
- msg = "Cannot lease connection, ".dup
197
+ msg = +"Cannot lease connection, "
152
198
  if @owner == Thread.current
153
199
  msg << "it is already leased by the current thread."
154
200
  else
@@ -298,6 +344,11 @@ module ActiveRecord
298
344
  false
299
345
  end
300
346
 
347
+ # Does this adapter support materialized views?
348
+ def supports_materialized_views?
349
+ false
350
+ end
351
+
301
352
  # Does this adapter support datetime with precision?
302
353
  def supports_datetime_with_precision?
303
354
  false
@@ -322,6 +373,7 @@ module ActiveRecord
322
373
  def supports_multi_insert?
323
374
  true
324
375
  end
376
+ deprecate :supports_multi_insert?
325
377
 
326
378
  # Does this adapter support virtual columns?
327
379
  def supports_virtual_columns?
@@ -333,6 +385,10 @@ module ActiveRecord
333
385
  false
334
386
  end
335
387
 
388
+ def supports_lazy_transactions?
389
+ false
390
+ end
391
+
336
392
  # This is meant to be implemented by the adapters that support extensions
337
393
  def disable_extension(name)
338
394
  end
@@ -341,6 +397,10 @@ module ActiveRecord
341
397
  def enable_extension(name)
342
398
  end
343
399
 
400
+ def advisory_locks_enabled? # :nodoc:
401
+ supports_advisory_locks? && @advisory_locks_enabled
402
+ end
403
+
344
404
  # This is meant to be implemented by the adapters that support advisory
345
405
  # locks
346
406
  #
@@ -444,18 +504,21 @@ module ActiveRecord
444
504
  # This is useful for when you need to call a proprietary method such as
445
505
  # PostgreSQL's lo_* methods.
446
506
  def raw_connection
507
+ disable_lazy_transactions!
447
508
  @connection
448
509
  end
449
510
 
450
- def case_sensitive_comparison(table, attribute, column, value) # :nodoc:
451
- table[attribute].eq(value)
511
+ def case_sensitive_comparison(attribute, value) # :nodoc:
512
+ attribute.eq(value)
452
513
  end
453
514
 
454
- def case_insensitive_comparison(table, attribute, column, value) # :nodoc:
515
+ def case_insensitive_comparison(attribute, value) # :nodoc:
516
+ column = column_for_attribute(attribute)
517
+
455
518
  if can_perform_case_insensitive_comparison_for?(column)
456
- table[attribute].lower.eq(table.lower(value))
519
+ attribute.lower.eq(attribute.relation.lower(value))
457
520
  else
458
- table[attribute].eq(value)
521
+ attribute.eq(value)
459
522
  end
460
523
  end
461
524
 
@@ -470,11 +533,7 @@ module ActiveRecord
470
533
  end
471
534
 
472
535
  def column_name_for_operation(operation, node) # :nodoc:
473
- column_name_from_arel_node(node)
474
- end
475
-
476
- def column_name_from_arel_node(node) # :nodoc:
477
- visitor.accept(node, Arel::Collectors::SQLString.new).value
536
+ visitor.compile(node)
478
537
  end
479
538
 
480
539
  def default_index_type?(index) # :nodoc:
@@ -482,6 +541,9 @@ module ActiveRecord
482
541
  end
483
542
 
484
543
  private
544
+ def check_version
545
+ end
546
+
485
547
  def type_map
486
548
  @type_map ||= Type::TypeMap.new.tap do |mapping|
487
549
  initialize_type_map(mapping)
@@ -555,14 +617,12 @@ module ActiveRecord
555
617
  $1.to_i if sql_type =~ /\((.*)\)/
556
618
  end
557
619
 
558
- def translate_exception_class(e, sql)
559
- begin
560
- message = "#{e.class.name}: #{e.message}: #{sql}"
561
- rescue Encoding::CompatibilityError
562
- message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
563
- end
620
+ def translate_exception_class(e, sql, binds)
621
+ message = "#{e.class.name}: #{e.message}"
564
622
 
565
- exception = translate_exception(e, message)
623
+ exception = translate_exception(
624
+ e, message: message, sql: sql, binds: binds
625
+ )
566
626
  exception.set_backtrace e.backtrace
567
627
  exception
568
628
  end
@@ -575,24 +635,23 @@ module ActiveRecord
575
635
  binds: binds,
576
636
  type_casted_binds: type_casted_binds,
577
637
  statement_name: statement_name,
578
- connection_id: object_id) do
579
- begin
580
- @lock.synchronize do
581
- yield
582
- end
583
- rescue => e
584
- raise translate_exception_class(e, sql)
638
+ connection_id: object_id,
639
+ connection: self) do
640
+ @lock.synchronize do
641
+ yield
585
642
  end
643
+ rescue => e
644
+ raise translate_exception_class(e, sql, binds)
586
645
  end
587
646
  end
588
647
 
589
- def translate_exception(exception, message)
648
+ def translate_exception(exception, message:, sql:, binds:)
590
649
  # override in derived class
591
650
  case exception
592
651
  when RuntimeError
593
652
  exception
594
653
  else
595
- ActiveRecord::StatementInvalid.new(message)
654
+ ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
596
655
  end
597
656
  end
598
657
 
@@ -606,6 +665,11 @@ module ActiveRecord
606
665
  raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
607
666
  end
608
667
 
668
+ def column_for_attribute(attribute)
669
+ table_name = attribute.relation.name
670
+ schema_cache.columns_hash(table_name)[attribute.name.to_s]
671
+ end
672
+
609
673
  def collector
610
674
  if prepared_statements
611
675
  Arel::Collectors::Composite.new(