activerecord 5.2.1.1 → 6.0.1

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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +738 -445
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +4 -2
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +9 -2
  7. data/lib/active_record/aggregations.rb +4 -2
  8. data/lib/active_record/association_relation.rb +18 -9
  9. data/lib/active_record/associations.rb +20 -15
  10. data/lib/active_record/associations/association.rb +69 -20
  11. data/lib/active_record/associations/association_scope.rb +4 -6
  12. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  14. data/lib/active_record/associations/builder/association.rb +14 -18
  15. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  16. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +35 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +15 -29
  22. data/lib/active_record/associations/collection_proxy.rb +19 -48
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +11 -10
  25. data/lib/active_record/associations/has_many_through_association.rb +42 -25
  26. data/lib/active_record/associations/has_one_association.rb +28 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  28. data/lib/active_record/associations/join_dependency.rb +28 -28
  29. data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +39 -31
  32. data/lib/active_record/associations/preloader/association.rb +38 -36
  33. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/attribute_assignment.rb +7 -10
  36. data/lib/active_record/attribute_methods.rb +28 -100
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  38. data/lib/active_record/attribute_methods/dirty.rb +114 -38
  39. data/lib/active_record/attribute_methods/primary_key.rb +15 -22
  40. data/lib/active_record/attribute_methods/query.rb +2 -3
  41. data/lib/active_record/attribute_methods/read.rb +15 -53
  42. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  44. data/lib/active_record/attribute_methods/write.rb +17 -24
  45. data/lib/active_record/attributes.rb +13 -0
  46. data/lib/active_record/autosave_association.rb +27 -13
  47. data/lib/active_record/base.rb +2 -3
  48. data/lib/active_record/callbacks.rb +6 -20
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +140 -27
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +22 -4
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +116 -127
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +26 -11
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +135 -56
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +189 -43
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +151 -198
  61. data/lib/active_record/connection_adapters/column.rb +17 -13
  62. data/lib/active_record/connection_adapters/connection_specification.rb +55 -45
  63. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +9 -4
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  66. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  67. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  68. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  69. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
  70. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  71. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
  72. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  73. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +8 -2
  75. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  76. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  81. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  82. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  83. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  84. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +47 -0
  85. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  86. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +65 -77
  87. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  88. data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql_adapter.rb +172 -74
  90. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  91. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  92. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  93. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -5
  94. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  95. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +131 -143
  96. data/lib/active_record/connection_handling.rb +155 -26
  97. data/lib/active_record/core.rb +104 -59
  98. data/lib/active_record/counter_cache.rb +4 -29
  99. data/lib/active_record/database_configurations.rb +233 -0
  100. data/lib/active_record/database_configurations/database_config.rb +37 -0
  101. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  102. data/lib/active_record/database_configurations/url_config.rb +79 -0
  103. data/lib/active_record/dynamic_matchers.rb +1 -1
  104. data/lib/active_record/enum.rb +38 -7
  105. data/lib/active_record/errors.rb +30 -16
  106. data/lib/active_record/explain.rb +1 -1
  107. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  108. data/lib/active_record/fixture_set/render_context.rb +17 -0
  109. data/lib/active_record/fixture_set/table_row.rb +153 -0
  110. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  111. data/lib/active_record/fixtures.rb +145 -472
  112. data/lib/active_record/gem_version.rb +3 -3
  113. data/lib/active_record/inheritance.rb +13 -3
  114. data/lib/active_record/insert_all.rb +179 -0
  115. data/lib/active_record/integration.rb +68 -16
  116. data/lib/active_record/internal_metadata.rb +10 -2
  117. data/lib/active_record/locking/optimistic.rb +5 -6
  118. data/lib/active_record/locking/pessimistic.rb +3 -3
  119. data/lib/active_record/log_subscriber.rb +7 -26
  120. data/lib/active_record/middleware/database_selector.rb +75 -0
  121. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  122. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  123. data/lib/active_record/migration.rb +100 -81
  124. data/lib/active_record/migration/command_recorder.rb +50 -6
  125. data/lib/active_record/migration/compatibility.rb +91 -64
  126. data/lib/active_record/model_schema.rb +34 -10
  127. data/lib/active_record/nested_attributes.rb +2 -2
  128. data/lib/active_record/no_touching.rb +7 -0
  129. data/lib/active_record/persistence.rb +233 -28
  130. data/lib/active_record/query_cache.rb +11 -4
  131. data/lib/active_record/querying.rb +33 -21
  132. data/lib/active_record/railtie.rb +81 -46
  133. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  134. data/lib/active_record/railties/controller_runtime.rb +30 -35
  135. data/lib/active_record/railties/databases.rake +196 -46
  136. data/lib/active_record/reflection.rb +42 -44
  137. data/lib/active_record/relation.rb +320 -70
  138. data/lib/active_record/relation/batches.rb +13 -10
  139. data/lib/active_record/relation/calculations.rb +67 -57
  140. data/lib/active_record/relation/delegation.rb +48 -35
  141. data/lib/active_record/relation/finder_methods.rb +30 -30
  142. data/lib/active_record/relation/merger.rb +19 -25
  143. data/lib/active_record/relation/predicate_builder.rb +18 -15
  144. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -6
  145. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  146. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  147. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  148. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  149. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  150. data/lib/active_record/relation/query_attribute.rb +17 -10
  151. data/lib/active_record/relation/query_methods.rb +236 -73
  152. data/lib/active_record/relation/spawn_methods.rb +1 -1
  153. data/lib/active_record/relation/where_clause.rb +14 -10
  154. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  155. data/lib/active_record/result.rb +30 -11
  156. data/lib/active_record/sanitization.rb +32 -40
  157. data/lib/active_record/schema.rb +2 -11
  158. data/lib/active_record/schema_dumper.rb +22 -7
  159. data/lib/active_record/schema_migration.rb +5 -1
  160. data/lib/active_record/scoping.rb +8 -8
  161. data/lib/active_record/scoping/default.rb +6 -7
  162. data/lib/active_record/scoping/named.rb +21 -15
  163. data/lib/active_record/statement_cache.rb +32 -5
  164. data/lib/active_record/store.rb +87 -8
  165. data/lib/active_record/table_metadata.rb +10 -17
  166. data/lib/active_record/tasks/database_tasks.rb +195 -26
  167. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  168. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  169. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  170. data/lib/active_record/test_databases.rb +23 -0
  171. data/lib/active_record/test_fixtures.rb +224 -0
  172. data/lib/active_record/timestamp.rb +39 -25
  173. data/lib/active_record/touch_later.rb +4 -2
  174. data/lib/active_record/transactions.rb +57 -66
  175. data/lib/active_record/translation.rb +1 -1
  176. data/lib/active_record/type.rb +3 -4
  177. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  178. data/lib/active_record/type_caster/connection.rb +15 -14
  179. data/lib/active_record/type_caster/map.rb +1 -4
  180. data/lib/active_record/validations.rb +1 -0
  181. data/lib/active_record/validations/uniqueness.rb +15 -27
  182. data/lib/arel.rb +58 -0
  183. data/lib/arel/alias_predication.rb +9 -0
  184. data/lib/arel/attributes.rb +22 -0
  185. data/lib/arel/attributes/attribute.rb +37 -0
  186. data/lib/arel/collectors/bind.rb +24 -0
  187. data/lib/arel/collectors/composite.rb +31 -0
  188. data/lib/arel/collectors/plain_string.rb +20 -0
  189. data/lib/arel/collectors/sql_string.rb +20 -0
  190. data/lib/arel/collectors/substitute_binds.rb +28 -0
  191. data/lib/arel/crud.rb +42 -0
  192. data/lib/arel/delete_manager.rb +18 -0
  193. data/lib/arel/errors.rb +9 -0
  194. data/lib/arel/expressions.rb +29 -0
  195. data/lib/arel/factory_methods.rb +49 -0
  196. data/lib/arel/insert_manager.rb +49 -0
  197. data/lib/arel/math.rb +45 -0
  198. data/lib/arel/nodes.rb +68 -0
  199. data/lib/arel/nodes/and.rb +32 -0
  200. data/lib/arel/nodes/ascending.rb +23 -0
  201. data/lib/arel/nodes/binary.rb +52 -0
  202. data/lib/arel/nodes/bind_param.rb +36 -0
  203. data/lib/arel/nodes/case.rb +55 -0
  204. data/lib/arel/nodes/casted.rb +50 -0
  205. data/lib/arel/nodes/comment.rb +29 -0
  206. data/lib/arel/nodes/count.rb +12 -0
  207. data/lib/arel/nodes/delete_statement.rb +45 -0
  208. data/lib/arel/nodes/descending.rb +23 -0
  209. data/lib/arel/nodes/equality.rb +18 -0
  210. data/lib/arel/nodes/extract.rb +24 -0
  211. data/lib/arel/nodes/false.rb +16 -0
  212. data/lib/arel/nodes/full_outer_join.rb +8 -0
  213. data/lib/arel/nodes/function.rb +44 -0
  214. data/lib/arel/nodes/grouping.rb +8 -0
  215. data/lib/arel/nodes/in.rb +8 -0
  216. data/lib/arel/nodes/infix_operation.rb +80 -0
  217. data/lib/arel/nodes/inner_join.rb +8 -0
  218. data/lib/arel/nodes/insert_statement.rb +37 -0
  219. data/lib/arel/nodes/join_source.rb +20 -0
  220. data/lib/arel/nodes/matches.rb +18 -0
  221. data/lib/arel/nodes/named_function.rb +23 -0
  222. data/lib/arel/nodes/node.rb +50 -0
  223. data/lib/arel/nodes/node_expression.rb +13 -0
  224. data/lib/arel/nodes/outer_join.rb +8 -0
  225. data/lib/arel/nodes/over.rb +15 -0
  226. data/lib/arel/nodes/regexp.rb +16 -0
  227. data/lib/arel/nodes/right_outer_join.rb +8 -0
  228. data/lib/arel/nodes/select_core.rb +67 -0
  229. data/lib/arel/nodes/select_statement.rb +41 -0
  230. data/lib/arel/nodes/sql_literal.rb +16 -0
  231. data/lib/arel/nodes/string_join.rb +11 -0
  232. data/lib/arel/nodes/table_alias.rb +27 -0
  233. data/lib/arel/nodes/terminal.rb +16 -0
  234. data/lib/arel/nodes/true.rb +16 -0
  235. data/lib/arel/nodes/unary.rb +45 -0
  236. data/lib/arel/nodes/unary_operation.rb +20 -0
  237. data/lib/arel/nodes/unqualified_column.rb +22 -0
  238. data/lib/arel/nodes/update_statement.rb +41 -0
  239. data/lib/arel/nodes/values_list.rb +9 -0
  240. data/lib/arel/nodes/window.rb +126 -0
  241. data/lib/arel/nodes/with.rb +11 -0
  242. data/lib/arel/order_predications.rb +13 -0
  243. data/lib/arel/predications.rb +257 -0
  244. data/lib/arel/select_manager.rb +271 -0
  245. data/lib/arel/table.rb +110 -0
  246. data/lib/arel/tree_manager.rb +72 -0
  247. data/lib/arel/update_manager.rb +34 -0
  248. data/lib/arel/visitors.rb +20 -0
  249. data/lib/arel/visitors/depth_first.rb +204 -0
  250. data/lib/arel/visitors/dot.rb +297 -0
  251. data/lib/arel/visitors/ibm_db.rb +34 -0
  252. data/lib/arel/visitors/informix.rb +62 -0
  253. data/lib/arel/visitors/mssql.rb +157 -0
  254. data/lib/arel/visitors/mysql.rb +83 -0
  255. data/lib/arel/visitors/oracle.rb +159 -0
  256. data/lib/arel/visitors/oracle12.rb +66 -0
  257. data/lib/arel/visitors/postgresql.rb +110 -0
  258. data/lib/arel/visitors/sqlite.rb +39 -0
  259. data/lib/arel/visitors/to_sql.rb +889 -0
  260. data/lib/arel/visitors/visitor.rb +46 -0
  261. data/lib/arel/visitors/where_sql.rb +23 -0
  262. data/lib/arel/window_predications.rb +9 -0
  263. data/lib/rails/generators/active_record/migration.rb +14 -1
  264. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  265. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  266. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  267. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  268. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  269. metadata +111 -27
  270. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -75,21 +75,7 @@ module ActiveRecord
75
75
  # end
76
76
  #
77
77
  # Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is
78
- # run, both +destroy_author+ and +destroy_readers+ are called. Contrast this to the following situation
79
- # where the +before_destroy+ method is overridden:
80
- #
81
- # class Topic < ActiveRecord::Base
82
- # def before_destroy() destroy_author end
83
- # end
84
- #
85
- # class Reply < Topic
86
- # def before_destroy() destroy_readers end
87
- # end
88
- #
89
- # In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
90
- # So, use the callback macros when you want to ensure that a certain callback is called for the entire
91
- # hierarchy, and use the regular overwritable methods when you want to leave it up to each descendant
92
- # to decide whether they want to call +super+ and trigger the inherited callbacks.
78
+ # run, both +destroy_author+ and +destroy_readers+ are called.
93
79
  #
94
80
  # *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
95
81
  # callbacks before specifying the associations. Otherwise, you might trigger the loading of a
@@ -109,7 +95,7 @@ module ActiveRecord
109
95
  #
110
96
  # private
111
97
  # def delete_parents
112
- # self.class.delete_all "parent_id = #{id}"
98
+ # self.class.delete_by(parent_id: id)
113
99
  # end
114
100
  # end
115
101
  #
@@ -142,7 +128,7 @@ module ActiveRecord
142
128
  # end
143
129
  # end
144
130
  #
145
- # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
131
+ # So you specify the object you want to be messaged on a given callback. When that callback is triggered, the object has
146
132
  # a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other
147
133
  # initialization data such as the name of the attribute to work with:
148
134
  #
@@ -332,13 +318,13 @@ module ActiveRecord
332
318
  _run_touch_callbacks { super }
333
319
  end
334
320
 
335
- def increment!(*, touch: nil) # :nodoc:
321
+ def increment!(attribute, by = 1, touch: nil) # :nodoc:
336
322
  touch ? _run_touch_callbacks { super } : super
337
323
  end
338
324
 
339
325
  private
340
326
 
341
- def create_or_update(*)
327
+ def create_or_update(**)
342
328
  _run_save_callbacks { super }
343
329
  end
344
330
 
@@ -346,7 +332,7 @@ module ActiveRecord
346
332
  _run_create_callbacks { super }
347
333
  end
348
334
 
349
- def _update_record(*)
335
+ def _update_record
350
336
  _run_update_callbacks { super }
351
337
  end
352
338
  end
@@ -3,6 +3,7 @@
3
3
  require "thread"
4
4
  require "concurrent/map"
5
5
  require "monitor"
6
+ require "weakref"
6
7
 
7
8
  module ActiveRecord
8
9
  # Raised when a connection could not be obtained within the connection
@@ -19,6 +20,26 @@ module ActiveRecord
19
20
  end
20
21
 
21
22
  module ConnectionAdapters
23
+ module AbstractPool # :nodoc:
24
+ def get_schema_cache(connection)
25
+ @schema_cache ||= SchemaCache.new(connection)
26
+ @schema_cache.connection = connection
27
+ @schema_cache
28
+ end
29
+
30
+ def set_schema_cache(cache)
31
+ @schema_cache = cache
32
+ end
33
+ end
34
+
35
+ class NullPool # :nodoc:
36
+ include ConnectionAdapters::AbstractPool
37
+
38
+ def initialize
39
+ @schema_cache = nil
40
+ end
41
+ end
42
+
22
43
  # Connection pool base class for managing Active Record database
23
44
  # connections.
24
45
  #
@@ -185,14 +206,16 @@ module ActiveRecord
185
206
  def wait_poll(timeout)
186
207
  @num_waiting += 1
187
208
 
188
- t0 = Time.now
209
+ t0 = Concurrent.monotonic_time
189
210
  elapsed = 0
190
211
  loop do
191
- @cond.wait(timeout - elapsed)
212
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
213
+ @cond.wait(timeout - elapsed)
214
+ end
192
215
 
193
216
  return remove if any?
194
217
 
195
- elapsed = Time.now - t0
218
+ elapsed = Concurrent.monotonic_time - t0
196
219
  if elapsed >= timeout
197
220
  msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
198
221
  [timeout, elapsed]
@@ -292,23 +315,59 @@ module ActiveRecord
292
315
  @frequency = frequency
293
316
  end
294
317
 
318
+ @mutex = Mutex.new
319
+ @pools = {}
320
+ @threads = {}
321
+
322
+ class << self
323
+ def register_pool(pool, frequency) # :nodoc:
324
+ @mutex.synchronize do
325
+ unless @threads[frequency]&.alive?
326
+ @threads[frequency] = spawn_thread(frequency)
327
+ end
328
+ @pools[frequency] ||= []
329
+ @pools[frequency] << WeakRef.new(pool)
330
+ end
331
+ end
332
+
333
+ private
334
+
335
+ def spawn_thread(frequency)
336
+ Thread.new(frequency) do |t|
337
+ running = true
338
+ while running
339
+ sleep t
340
+ @mutex.synchronize do
341
+ @pools[frequency].select!(&:weakref_alive?)
342
+ @pools[frequency].each do |p|
343
+ p.reap
344
+ p.flush
345
+ rescue WeakRef::RefError
346
+ end
347
+
348
+ if @pools[frequency].empty?
349
+ @pools.delete(frequency)
350
+ @threads.delete(frequency)
351
+ running = false
352
+ end
353
+ end
354
+ end
355
+ end
356
+ end
357
+ end
358
+
295
359
  def run
296
360
  return unless frequency && frequency > 0
297
- Thread.new(frequency, pool) { |t, p|
298
- loop do
299
- sleep t
300
- p.reap
301
- p.flush
302
- end
303
- }
361
+ self.class.register_pool(pool, frequency)
304
362
  end
305
363
  end
306
364
 
307
365
  include MonitorMixin
308
366
  include QueryCache::ConnectionPoolConfiguration
367
+ include ConnectionAdapters::AbstractPool
309
368
 
310
369
  attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
311
- attr_reader :spec, :connections, :size, :reaper
370
+ attr_reader :spec, :size, :reaper
312
371
 
313
372
  # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
314
373
  # object which describes database connection information (e.g. adapter,
@@ -377,7 +436,7 @@ module ActiveRecord
377
436
  # #connection can be called any number of times; the connection is
378
437
  # held in a cache keyed by a thread.
379
438
  def connection
380
- @thread_cached_conns[connection_cache_key(@lock_thread || Thread.current)] ||= checkout
439
+ @thread_cached_conns[connection_cache_key(current_thread)] ||= checkout
381
440
  end
382
441
 
383
442
  # Returns true if there is an open connection being used for the current thread.
@@ -386,7 +445,7 @@ module ActiveRecord
386
445
  # #connection or #with_connection methods. Connections obtained through
387
446
  # #checkout will not be detected by #active_connection?
388
447
  def active_connection?
389
- @thread_cached_conns[connection_cache_key(Thread.current)]
448
+ @thread_cached_conns[connection_cache_key(current_thread)]
390
449
  end
391
450
 
392
451
  # Signal that the thread is finished with the current connection.
@@ -421,6 +480,21 @@ module ActiveRecord
421
480
  synchronize { @connections.any? }
422
481
  end
423
482
 
483
+ # Returns an array containing the connections currently in the pool.
484
+ # Access to the array does not require synchronization on the pool because
485
+ # the array is newly created and not retained by the pool.
486
+ #
487
+ # However; this method bypasses the ConnectionPool's thread-safe connection
488
+ # access pattern. A returned connection may be owned by another thread,
489
+ # unowned, or by happen-stance owned by the calling thread.
490
+ #
491
+ # Calling methods on a connection without ownership is subject to the
492
+ # thread-safety guarantees of the underlying method. Many of the methods
493
+ # on connection adapter classes are inherently multi-thread unsafe.
494
+ def connections
495
+ synchronize { @connections.dup }
496
+ end
497
+
424
498
  # Disconnects all connections in the pool, and clears the pool.
425
499
  #
426
500
  # Raises:
@@ -576,6 +650,7 @@ module ActiveRecord
576
650
  # or a thread dies unexpectedly.
577
651
  def reap
578
652
  stale_connections = synchronize do
653
+ return unless @connections
579
654
  @connections.select do |conn|
580
655
  conn.in_use? && !conn.owner.alive?
581
656
  end.each do |conn|
@@ -600,6 +675,7 @@ module ActiveRecord
600
675
  return if minimum_idle.nil?
601
676
 
602
677
  idle_connections = synchronize do
678
+ return unless @connections
603
679
  @connections.select do |conn|
604
680
  !conn.in_use? && conn.seconds_idle >= minimum_idle
605
681
  end.each do |conn|
@@ -666,6 +742,10 @@ module ActiveRecord
666
742
  thread
667
743
  end
668
744
 
745
+ def current_thread
746
+ @lock_thread || Thread.current
747
+ end
748
+
669
749
  # Take control of all existing connections so a "group" action such as
670
750
  # reload/disconnect can be performed safely. It is no longer enough to
671
751
  # wrap it in +synchronize+ because some pool's actions are allowed
@@ -684,13 +764,13 @@ module ActiveRecord
684
764
  end
685
765
 
686
766
  newly_checked_out = []
687
- timeout_time = Time.now + (@checkout_timeout * 2)
767
+ timeout_time = Concurrent.monotonic_time + (@checkout_timeout * 2)
688
768
 
689
769
  @available.with_a_bias_for(Thread.current) do
690
770
  loop do
691
771
  synchronize do
692
772
  return if collected_conns.size == @connections.size && @now_connecting == 0
693
- remaining_timeout = timeout_time - Time.now
773
+ remaining_timeout = timeout_time - Concurrent.monotonic_time
694
774
  remaining_timeout = 0 if remaining_timeout < 0
695
775
  conn = checkout_for_exclusive_access(remaining_timeout)
696
776
  collected_conns << conn
@@ -729,7 +809,7 @@ module ActiveRecord
729
809
  # this block can't be easily moved into attempt_to_checkout_all_existing_connections's
730
810
  # rescue block, because doing so would put it outside of synchronize section, without
731
811
  # being in a critical section thread_report might become inaccurate
732
- msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds".dup
812
+ msg = +"could not obtain ownership of all database connections in #{checkout_timeout} seconds"
733
813
 
734
814
  thread_report = []
735
815
  @connections.each do |conn|
@@ -807,7 +887,7 @@ module ActiveRecord
807
887
 
808
888
  def new_connection
809
889
  Base.send(spec.adapter_method, spec.config).tap do |conn|
810
- conn.schema_cache = schema_cache.dup if schema_cache
890
+ conn.check_version
811
891
  end
812
892
  end
813
893
 
@@ -913,6 +993,16 @@ module ActiveRecord
913
993
  # about the model. The model needs to pass a specification name to the handler,
914
994
  # in order to look up the correct connection pool.
915
995
  class ConnectionHandler
996
+ def self.create_owner_to_pool # :nodoc:
997
+ Concurrent::Map.new(initial_capacity: 2) do |h, k|
998
+ # Discard the parent's connection pools immediately; we have no need
999
+ # of them
1000
+ discard_unowned_pools(h)
1001
+
1002
+ h[k] = Concurrent::Map.new(initial_capacity: 2)
1003
+ end
1004
+ end
1005
+
916
1006
  def self.unowned_pool_finalizer(pid_map) # :nodoc:
917
1007
  lambda do |_|
918
1008
  discard_unowned_pools(pid_map)
@@ -927,19 +1017,33 @@ module ActiveRecord
927
1017
 
928
1018
  def initialize
929
1019
  # These caches are keyed by spec.name (ConnectionSpecification#name).
930
- @owner_to_pool = Concurrent::Map.new(initial_capacity: 2) do |h, k|
931
- # Discard the parent's connection pools immediately; we have no need
932
- # of them
933
- ConnectionHandler.discard_unowned_pools(h)
934
-
935
- h[k] = Concurrent::Map.new(initial_capacity: 2)
936
- end
1020
+ @owner_to_pool = ConnectionHandler.create_owner_to_pool
937
1021
 
938
1022
  # Backup finalizer: if the forked child never needed a pool, the above
939
1023
  # early discard has not occurred
940
1024
  ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
941
1025
  end
942
1026
 
1027
+ def prevent_writes # :nodoc:
1028
+ Thread.current[:prevent_writes]
1029
+ end
1030
+
1031
+ def prevent_writes=(prevent_writes) # :nodoc:
1032
+ Thread.current[:prevent_writes] = prevent_writes
1033
+ end
1034
+
1035
+ # Prevent writing to the database regardless of role.
1036
+ #
1037
+ # In some cases you may want to prevent writes to the database
1038
+ # even if you are on a database that can write. `while_preventing_writes`
1039
+ # will prevent writes to the database for the duration of the block.
1040
+ def while_preventing_writes(enabled = true)
1041
+ original, self.prevent_writes = self.prevent_writes, enabled
1042
+ yield
1043
+ ensure
1044
+ self.prevent_writes = original
1045
+ end
1046
+
943
1047
  def connection_pool_list
944
1048
  owner_to_pool.values.compact
945
1049
  end
@@ -1004,15 +1108,24 @@ module ActiveRecord
1004
1108
  # for (not necessarily the current class).
1005
1109
  def retrieve_connection(spec_name) #:nodoc:
1006
1110
  pool = retrieve_connection_pool(spec_name)
1007
- raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found." unless pool
1111
+
1112
+ unless pool
1113
+ # multiple database application
1114
+ if ActiveRecord::Base.connection_handler != ActiveRecord::Base.default_connection_handler
1115
+ raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found for the '#{ActiveRecord::Base.current_role}' role."
1116
+ else
1117
+ raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found."
1118
+ end
1119
+ end
1120
+
1008
1121
  pool.connection
1009
1122
  end
1010
1123
 
1011
1124
  # Returns true if a connection that's accessible to this class has
1012
1125
  # already been opened.
1013
1126
  def connected?(spec_name)
1014
- conn = retrieve_connection_pool(spec_name)
1015
- conn && conn.connected?
1127
+ pool = retrieve_connection_pool(spec_name)
1128
+ pool && pool.connected?
1016
1129
  end
1017
1130
 
1018
1131
  # Remove the connection for this class. This will close the active
@@ -1,22 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/deprecation"
4
+
3
5
  module ActiveRecord
4
6
  module ConnectionAdapters # :nodoc:
5
7
  module DatabaseLimits
8
+ def max_identifier_length # :nodoc:
9
+ 64
10
+ end
11
+
6
12
  # Returns the maximum length of a table alias.
7
13
  def table_alias_length
8
- 255
14
+ max_identifier_length
9
15
  end
10
16
 
11
17
  # Returns the maximum length of a column name.
12
18
  def column_name_length
13
- 64
19
+ max_identifier_length
14
20
  end
21
+ deprecate :column_name_length
15
22
 
16
23
  # Returns the maximum length of a table name.
17
24
  def table_name_length
18
- 64
25
+ max_identifier_length
19
26
  end
27
+ deprecate :table_name_length
20
28
 
21
29
  # Returns the maximum allowed length for an index name. This
22
30
  # limit is enforced by \Rails and is less than or equal to
@@ -29,23 +37,26 @@ module ActiveRecord
29
37
 
30
38
  # Returns the maximum length of an index name.
31
39
  def index_name_length
32
- 64
40
+ max_identifier_length
33
41
  end
34
42
 
35
43
  # Returns the maximum number of columns per table.
36
44
  def columns_per_table
37
45
  1024
38
46
  end
47
+ deprecate :columns_per_table
39
48
 
40
49
  # Returns the maximum number of indexes per table.
41
50
  def indexes_per_table
42
51
  16
43
52
  end
53
+ deprecate :indexes_per_table
44
54
 
45
55
  # Returns the maximum number of columns in a multicolumn index.
46
56
  def columns_per_multicolumn_index
47
57
  16
48
58
  end
59
+ deprecate :columns_per_multicolumn_index
49
60
 
50
61
  # Returns the maximum number of elements in an IN (x,y,z) clause.
51
62
  # +nil+ means no limit.
@@ -57,11 +68,18 @@ module ActiveRecord
57
68
  def sql_query_length
58
69
  1048575
59
70
  end
71
+ deprecate :sql_query_length
60
72
 
61
73
  # Returns maximum number of joins in a single query.
62
74
  def joins_per_query
63
75
  256
64
76
  end
77
+ deprecate :joins_per_query
78
+
79
+ private
80
+ def bind_params_length
81
+ 65535
82
+ end
65
83
  end
66
84
  end
67
85
  end
@@ -20,9 +20,22 @@ module ActiveRecord
20
20
  raise "Passing bind parameters with an arel AST is forbidden. " \
21
21
  "The values must be stored on the AST directly"
22
22
  end
23
- sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value
24
- [sql.freeze, binds || []]
23
+
24
+ if prepared_statements
25
+ sql, binds = visitor.compile(arel_or_sql_string.ast, collector)
26
+
27
+ if binds.length > bind_params_length
28
+ unprepared_statement do
29
+ sql, binds = to_sql_and_binds(arel_or_sql_string)
30
+ visitor.preparable = false
31
+ end
32
+ end
33
+ else
34
+ sql = visitor.compile(arel_or_sql_string.ast, collector)
35
+ end
36
+ [sql.freeze, binds]
25
37
  else
38
+ visitor.preparable = false if prepared_statements
26
39
  [arel_or_sql_string.dup.freeze, binds]
27
40
  end
28
41
  end
@@ -32,11 +45,11 @@ module ActiveRecord
32
45
  # can be used to query the database repeatedly.
33
46
  def cacheable_query(klass, arel) # :nodoc:
34
47
  if prepared_statements
35
- sql, binds = visitor.accept(arel.ast, collector).value
48
+ sql, binds = visitor.compile(arel.ast, collector)
36
49
  query = klass.query(sql)
37
50
  else
38
- collector = PartialQueryCollector.new
39
- parts, binds = visitor.accept(arel.ast, collector).value
51
+ collector = klass.partial_query_collector
52
+ parts, binds = visitor.compile(arel.ast, collector)
40
53
  query = klass.partial_query(parts)
41
54
  end
42
55
  [query, binds]
@@ -46,11 +59,11 @@ module ActiveRecord
46
59
  def select_all(arel, name = nil, binds = [], preparable: nil)
47
60
  arel = arel_from_relation(arel)
48
61
  sql, binds = to_sql_and_binds(arel, binds)
49
- if !prepared_statements || (arel.is_a?(String) && preparable.nil?)
50
- preparable = false
51
- else
52
- preparable = visitor.preparable
62
+
63
+ if preparable.nil?
64
+ preparable = prepared_statements ? visitor.preparable : false
53
65
  end
66
+
54
67
  if prepared_statements && preparable
55
68
  select_prepared(sql, name, binds)
56
69
  else
@@ -93,6 +106,11 @@ module ActiveRecord
93
106
  exec_query(sql, name).rows
94
107
  end
95
108
 
109
+ # Determines whether the SQL statement is a write query.
110
+ def write_query?(sql)
111
+ raise NotImplementedError
112
+ end
113
+
96
114
  # Executes the SQL statement in the context of this connection and returns
97
115
  # the raw result from the connection adapter.
98
116
  # Note: depending on your database connector, the result returned by this
@@ -113,7 +131,7 @@ module ActiveRecord
113
131
  # +binds+ as the bind substitutes. +name+ is logged along with
114
132
  # the executed +sql+ statement.
115
133
  def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
116
- sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
134
+ sql, binds = sql_for_insert(sql, pk, binds)
117
135
  exec_query(sql, name, binds)
118
136
  end
119
137
 
@@ -124,11 +142,6 @@ module ActiveRecord
124
142
  exec_query(sql, name, binds)
125
143
  end
126
144
 
127
- # Executes the truncate statement.
128
- def truncate(table_name, name = nil)
129
- raise NotImplementedError
130
- end
131
-
132
145
  # Executes update +sql+ statement in the context of this connection using
133
146
  # +binds+ as the bind substitutes. +name+ is logged along with
134
147
  # the executed +sql+ statement.
@@ -136,6 +149,10 @@ module ActiveRecord
136
149
  exec_query(sql, name, binds)
137
150
  end
138
151
 
152
+ def exec_insert_all(sql, name) # :nodoc:
153
+ exec_query(sql, name)
154
+ end
155
+
139
156
  # Executes an INSERT query and returns the new record's ID
140
157
  #
141
158
  # +id_value+ will be returned unless the value is +nil+, in
@@ -163,12 +180,22 @@ module ActiveRecord
163
180
  exec_delete(sql, name, binds)
164
181
  end
165
182
 
166
- # Returns +true+ when the connection adapter supports prepared statement
167
- # caching, otherwise returns +false+
168
- def supports_statement_cache? # :nodoc:
169
- true
183
+ # Executes the truncate statement.
184
+ def truncate(table_name, name = nil)
185
+ execute(build_truncate_statements(table_name), name)
186
+ end
187
+
188
+ def truncate_tables(*table_names) # :nodoc:
189
+ return if table_names.empty?
190
+
191
+ with_multi_statements do
192
+ disable_referential_integrity do
193
+ Array(build_truncate_statements(*table_names)).each do |sql|
194
+ execute_batch(sql, "Truncate Tables")
195
+ end
196
+ end
197
+ end
170
198
  end
171
- deprecate :supports_statement_cache?
172
199
 
173
200
  # Runs the given block in a database transaction, and returns the result
174
201
  # of the block.
@@ -259,7 +286,9 @@ module ActiveRecord
259
286
 
260
287
  attr_reader :transaction_manager #:nodoc:
261
288
 
262
- delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction, :commit_transaction, :rollback_transaction, to: :transaction_manager
289
+ delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
290
+ :commit_transaction, :rollback_transaction, :materialize_transactions,
291
+ :disable_lazy_transactions!, :enable_lazy_transactions!, to: :transaction_manager
263
292
 
264
293
  def transaction_open?
265
294
  current_transaction.open?
@@ -324,68 +353,30 @@ module ActiveRecord
324
353
 
325
354
  # Inserts the given fixture into the table. Overridden in adapters that require
326
355
  # something beyond a simple insert (eg. Oracle).
327
- # Most of adapters should implement `insert_fixtures` that leverages bulk SQL insert.
356
+ # Most of adapters should implement `insert_fixtures_set` that leverages bulk SQL insert.
328
357
  # We keep this method to provide fallback
329
358
  # for databases like sqlite that do not support bulk inserts.
330
359
  def insert_fixture(fixture, table_name)
331
- fixture = fixture.stringify_keys
332
-
333
- columns = schema_cache.columns_hash(table_name)
334
- binds = fixture.map do |name, value|
335
- if column = columns[name]
336
- type = lookup_cast_type_from_column(column)
337
- Relation::QueryAttribute.new(name, value, type)
338
- else
339
- raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
340
- end
341
- end
342
-
343
- table = Arel::Table.new(table_name)
344
-
345
- values = binds.map do |bind|
346
- value = with_yaml_fallback(bind.value_for_database)
347
- [table[bind.name], value]
348
- end
349
-
350
- manager = Arel::InsertManager.new
351
- manager.into(table)
352
- manager.insert(values)
353
- execute manager.to_sql, "Fixture Insert"
354
- end
355
-
356
- # Inserts a set of fixtures into the table. Overridden in adapters that require
357
- # something beyond a simple insert (eg. Oracle).
358
- def insert_fixtures(fixtures, table_name)
359
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
360
- `insert_fixtures` is deprecated and will be removed in the next version of Rails.
361
- Consider using `insert_fixtures_set` for performance improvement.
362
- MSG
363
- return if fixtures.empty?
364
-
365
- execute(build_fixture_sql(fixtures, table_name), "Fixtures Insert")
360
+ execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
366
361
  end
367
362
 
368
363
  def insert_fixtures_set(fixture_set, tables_to_delete = [])
369
- fixture_inserts = fixture_set.map do |table_name, fixtures|
370
- next if fixtures.empty?
371
-
372
- build_fixture_sql(fixtures, table_name)
373
- end.compact
374
-
375
- table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name table}".dup }
376
- total_sql = Array.wrap(combine_multi_statements(table_deletes + fixture_inserts))
377
-
378
- disable_referential_integrity do
379
- transaction(requires_new: true) do
380
- total_sql.each do |sql|
381
- execute sql, "Fixtures Load"
382
- yield if block_given?
364
+ fixture_inserts = build_fixture_statements(fixture_set)
365
+ table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
366
+ total_sql = Array(combine_multi_statements(table_deletes + fixture_inserts))
367
+
368
+ with_multi_statements do
369
+ disable_referential_integrity do
370
+ transaction(requires_new: true) do
371
+ total_sql.each do |sql|
372
+ execute_batch(sql, "Fixtures Load")
373
+ end
383
374
  end
384
375
  end
385
376
  end
386
377
  end
387
378
 
388
- def empty_insert_statement_value
379
+ def empty_insert_statement_value(primary_key = nil)
389
380
  "DEFAULT VALUES"
390
381
  end
391
382
 
@@ -403,25 +394,33 @@ module ActiveRecord
403
394
  end
404
395
  end
405
396
 
406
- # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
407
- # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
408
- # an UPDATE statement, so in the MySQL adapters we redefine this to do that.
409
- def join_to_update(update, select, key) # :nodoc:
410
- subselect = subquery_for(key, select)
411
-
412
- update.where key.in(subselect)
397
+ # Fixture value is quoted by Arel, however scalar values
398
+ # are not quotable. In this case we want to convert
399
+ # the column value to YAML.
400
+ def with_yaml_fallback(value) # :nodoc:
401
+ if value.is_a?(Hash) || value.is_a?(Array)
402
+ YAML.dump(value)
403
+ else
404
+ value
405
+ end
413
406
  end
414
- alias join_to_delete join_to_update
415
407
 
416
408
  private
409
+ def execute_batch(sql, name = nil)
410
+ execute(sql, name)
411
+ end
412
+
413
+ DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
414
+ private_constant :DEFAULT_INSERT_VALUE
415
+
417
416
  def default_insert_value(column)
418
- Arel.sql("DEFAULT")
417
+ DEFAULT_INSERT_VALUE
419
418
  end
420
419
 
421
420
  def build_fixture_sql(fixtures, table_name)
422
421
  columns = schema_cache.columns_hash(table_name)
423
422
 
424
- values = fixtures.map do |fixture|
423
+ values_list = fixtures.map do |fixture|
425
424
  fixture = fixture.stringify_keys
426
425
 
427
426
  unknown_columns = fixture.keys - columns.keys
@@ -432,8 +431,7 @@ module ActiveRecord
432
431
  columns.map do |name, column|
433
432
  if fixture.key?(name)
434
433
  type = lookup_cast_type_from_column(column)
435
- bind = Relation::QueryAttribute.new(name, fixture[name], type)
436
- with_yaml_fallback(bind.value_for_database)
434
+ with_yaml_fallback(type.serialize(fixture[name]))
437
435
  else
438
436
  default_insert_value(column)
439
437
  end
@@ -443,21 +441,45 @@ module ActiveRecord
443
441
  table = Arel::Table.new(table_name)
444
442
  manager = Arel::InsertManager.new
445
443
  manager.into(table)
446
- columns.each_key { |column| manager.columns << table[column] }
447
- manager.values = manager.create_values_list(values)
448
444
 
445
+ if values_list.size == 1
446
+ values = values_list.shift
447
+ new_values = []
448
+ columns.each_key.with_index { |column, i|
449
+ unless values[i].equal?(DEFAULT_INSERT_VALUE)
450
+ new_values << values[i]
451
+ manager.columns << table[column]
452
+ end
453
+ }
454
+ values_list << new_values
455
+ else
456
+ columns.each_key { |column| manager.columns << table[column] }
457
+ end
458
+
459
+ manager.values = manager.create_values_list(values_list)
449
460
  manager.to_sql
450
461
  end
451
462
 
452
- def combine_multi_statements(total_sql)
453
- total_sql.join(";\n")
463
+ def build_fixture_statements(fixture_set)
464
+ fixture_set.map do |table_name, fixtures|
465
+ next if fixtures.empty?
466
+ build_fixture_sql(fixtures, table_name)
467
+ end.compact
468
+ end
469
+
470
+ def build_truncate_statements(*table_names)
471
+ truncate_tables = table_names.map do |table_name|
472
+ "TRUNCATE TABLE #{quote_table_name(table_name)}"
473
+ end
474
+ combine_multi_statements(truncate_tables)
454
475
  end
455
476
 
456
- # Returns a subquery for the given key using the join information.
457
- def subquery_for(key, select)
458
- subselect = select.clone
459
- subselect.projections = [key]
460
- subselect
477
+ def with_multi_statements
478
+ yield
479
+ end
480
+
481
+ def combine_multi_statements(total_sql)
482
+ total_sql.join(";\n")
461
483
  end
462
484
 
463
485
  # Returns an ActiveRecord::Result instance.
@@ -469,7 +491,7 @@ module ActiveRecord
469
491
  exec_query(sql, name, binds, prepare: true)
470
492
  end
471
493
 
472
- def sql_for_insert(sql, pk, id_value, sequence_name, binds)
494
+ def sql_for_insert(sql, pk, binds)
473
495
  [sql, binds]
474
496
  end
475
497
 
@@ -489,39 +511,6 @@ module ActiveRecord
489
511
  relation
490
512
  end
491
513
  end
492
-
493
- # Fixture value is quoted by Arel, however scalar values
494
- # are not quotable. In this case we want to convert
495
- # the column value to YAML.
496
- def with_yaml_fallback(value)
497
- if value.is_a?(Hash) || value.is_a?(Array)
498
- YAML.dump(value)
499
- else
500
- value
501
- end
502
- end
503
-
504
- class PartialQueryCollector
505
- def initialize
506
- @parts = []
507
- @binds = []
508
- end
509
-
510
- def <<(str)
511
- @parts << str
512
- self
513
- end
514
-
515
- def add_bind(obj)
516
- @binds << obj
517
- @parts << Arel::Nodes::BindParam.new(1)
518
- self
519
- end
520
-
521
- def value
522
- [@parts, @binds]
523
- end
524
- end
525
514
  end
526
515
  end
527
516
  end