activerecord 5.2.4.2 → 6.0.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (269) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +714 -570
  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 +15 -6
  9. data/lib/active_record/associations.rb +20 -15
  10. data/lib/active_record/associations/association.rb +61 -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 +3 -13
  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 +12 -23
  22. data/lib/active_record/associations/collection_proxy.rb +12 -15
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +2 -10
  25. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  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 +9 -10
  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 +111 -40
  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 +2 -2
  47. data/lib/active_record/base.rb +2 -3
  48. data/lib/active_record/callbacks.rb +5 -19
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +104 -16
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +99 -123
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -8
  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 +132 -53
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +187 -43
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +138 -195
  61. data/lib/active_record/connection_adapters/column.rb +17 -13
  62. data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
  63. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  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 +1 -1
  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 +12 -1
  85. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  86. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
  87. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  88. data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
  89. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  90. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  91. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  92. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
  93. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  94. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +129 -141
  95. data/lib/active_record/connection_handling.rb +155 -26
  96. data/lib/active_record/core.rb +103 -59
  97. data/lib/active_record/counter_cache.rb +4 -29
  98. data/lib/active_record/database_configurations.rb +233 -0
  99. data/lib/active_record/database_configurations/database_config.rb +37 -0
  100. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  101. data/lib/active_record/database_configurations/url_config.rb +79 -0
  102. data/lib/active_record/dynamic_matchers.rb +1 -1
  103. data/lib/active_record/enum.rb +37 -7
  104. data/lib/active_record/errors.rb +15 -7
  105. data/lib/active_record/explain.rb +1 -1
  106. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  107. data/lib/active_record/fixture_set/render_context.rb +17 -0
  108. data/lib/active_record/fixture_set/table_row.rb +153 -0
  109. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  110. data/lib/active_record/fixtures.rb +145 -472
  111. data/lib/active_record/gem_version.rb +4 -4
  112. data/lib/active_record/inheritance.rb +13 -3
  113. data/lib/active_record/insert_all.rb +179 -0
  114. data/lib/active_record/integration.rb +68 -16
  115. data/lib/active_record/internal_metadata.rb +10 -2
  116. data/lib/active_record/locking/optimistic.rb +5 -6
  117. data/lib/active_record/locking/pessimistic.rb +3 -3
  118. data/lib/active_record/log_subscriber.rb +7 -26
  119. data/lib/active_record/middleware/database_selector.rb +75 -0
  120. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  121. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  122. data/lib/active_record/migration.rb +100 -81
  123. data/lib/active_record/migration/command_recorder.rb +50 -6
  124. data/lib/active_record/migration/compatibility.rb +76 -49
  125. data/lib/active_record/model_schema.rb +33 -9
  126. data/lib/active_record/nested_attributes.rb +2 -2
  127. data/lib/active_record/no_touching.rb +7 -0
  128. data/lib/active_record/persistence.rb +228 -24
  129. data/lib/active_record/query_cache.rb +11 -4
  130. data/lib/active_record/querying.rb +32 -20
  131. data/lib/active_record/railtie.rb +80 -43
  132. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  133. data/lib/active_record/railties/controller_runtime.rb +30 -35
  134. data/lib/active_record/railties/databases.rake +199 -46
  135. data/lib/active_record/reflection.rb +32 -30
  136. data/lib/active_record/relation.rb +311 -80
  137. data/lib/active_record/relation/batches.rb +13 -10
  138. data/lib/active_record/relation/calculations.rb +53 -47
  139. data/lib/active_record/relation/delegation.rb +26 -43
  140. data/lib/active_record/relation/finder_methods.rb +23 -27
  141. data/lib/active_record/relation/merger.rb +11 -20
  142. data/lib/active_record/relation/predicate_builder.rb +4 -6
  143. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  144. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  145. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  146. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  147. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  148. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  149. data/lib/active_record/relation/query_attribute.rb +13 -8
  150. data/lib/active_record/relation/query_methods.rb +213 -64
  151. data/lib/active_record/relation/spawn_methods.rb +1 -1
  152. data/lib/active_record/relation/where_clause.rb +14 -10
  153. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  154. data/lib/active_record/result.rb +30 -11
  155. data/lib/active_record/sanitization.rb +32 -40
  156. data/lib/active_record/schema.rb +2 -11
  157. data/lib/active_record/schema_dumper.rb +22 -7
  158. data/lib/active_record/schema_migration.rb +5 -1
  159. data/lib/active_record/scoping.rb +8 -8
  160. data/lib/active_record/scoping/default.rb +4 -5
  161. data/lib/active_record/scoping/named.rb +20 -15
  162. data/lib/active_record/statement_cache.rb +30 -3
  163. data/lib/active_record/store.rb +87 -8
  164. data/lib/active_record/table_metadata.rb +10 -17
  165. data/lib/active_record/tasks/database_tasks.rb +194 -25
  166. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  167. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  168. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  169. data/lib/active_record/test_databases.rb +23 -0
  170. data/lib/active_record/test_fixtures.rb +225 -0
  171. data/lib/active_record/timestamp.rb +39 -25
  172. data/lib/active_record/touch_later.rb +4 -2
  173. data/lib/active_record/transactions.rb +56 -65
  174. data/lib/active_record/translation.rb +1 -1
  175. data/lib/active_record/type.rb +3 -4
  176. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  177. data/lib/active_record/type_caster/connection.rb +15 -14
  178. data/lib/active_record/type_caster/map.rb +1 -4
  179. data/lib/active_record/validations.rb +1 -0
  180. data/lib/active_record/validations/uniqueness.rb +15 -27
  181. data/lib/arel.rb +58 -0
  182. data/lib/arel/alias_predication.rb +9 -0
  183. data/lib/arel/attributes.rb +22 -0
  184. data/lib/arel/attributes/attribute.rb +37 -0
  185. data/lib/arel/collectors/bind.rb +24 -0
  186. data/lib/arel/collectors/composite.rb +31 -0
  187. data/lib/arel/collectors/plain_string.rb +20 -0
  188. data/lib/arel/collectors/sql_string.rb +20 -0
  189. data/lib/arel/collectors/substitute_binds.rb +28 -0
  190. data/lib/arel/crud.rb +42 -0
  191. data/lib/arel/delete_manager.rb +18 -0
  192. data/lib/arel/errors.rb +9 -0
  193. data/lib/arel/expressions.rb +29 -0
  194. data/lib/arel/factory_methods.rb +49 -0
  195. data/lib/arel/insert_manager.rb +49 -0
  196. data/lib/arel/math.rb +45 -0
  197. data/lib/arel/nodes.rb +68 -0
  198. data/lib/arel/nodes/and.rb +32 -0
  199. data/lib/arel/nodes/ascending.rb +23 -0
  200. data/lib/arel/nodes/binary.rb +52 -0
  201. data/lib/arel/nodes/bind_param.rb +36 -0
  202. data/lib/arel/nodes/case.rb +55 -0
  203. data/lib/arel/nodes/casted.rb +50 -0
  204. data/lib/arel/nodes/comment.rb +29 -0
  205. data/lib/arel/nodes/count.rb +12 -0
  206. data/lib/arel/nodes/delete_statement.rb +45 -0
  207. data/lib/arel/nodes/descending.rb +23 -0
  208. data/lib/arel/nodes/equality.rb +18 -0
  209. data/lib/arel/nodes/extract.rb +24 -0
  210. data/lib/arel/nodes/false.rb +16 -0
  211. data/lib/arel/nodes/full_outer_join.rb +8 -0
  212. data/lib/arel/nodes/function.rb +44 -0
  213. data/lib/arel/nodes/grouping.rb +8 -0
  214. data/lib/arel/nodes/in.rb +8 -0
  215. data/lib/arel/nodes/infix_operation.rb +80 -0
  216. data/lib/arel/nodes/inner_join.rb +8 -0
  217. data/lib/arel/nodes/insert_statement.rb +37 -0
  218. data/lib/arel/nodes/join_source.rb +20 -0
  219. data/lib/arel/nodes/matches.rb +18 -0
  220. data/lib/arel/nodes/named_function.rb +23 -0
  221. data/lib/arel/nodes/node.rb +50 -0
  222. data/lib/arel/nodes/node_expression.rb +13 -0
  223. data/lib/arel/nodes/outer_join.rb +8 -0
  224. data/lib/arel/nodes/over.rb +15 -0
  225. data/lib/arel/nodes/regexp.rb +16 -0
  226. data/lib/arel/nodes/right_outer_join.rb +8 -0
  227. data/lib/arel/nodes/select_core.rb +67 -0
  228. data/lib/arel/nodes/select_statement.rb +41 -0
  229. data/lib/arel/nodes/sql_literal.rb +16 -0
  230. data/lib/arel/nodes/string_join.rb +11 -0
  231. data/lib/arel/nodes/table_alias.rb +27 -0
  232. data/lib/arel/nodes/terminal.rb +16 -0
  233. data/lib/arel/nodes/true.rb +16 -0
  234. data/lib/arel/nodes/unary.rb +45 -0
  235. data/lib/arel/nodes/unary_operation.rb +20 -0
  236. data/lib/arel/nodes/unqualified_column.rb +22 -0
  237. data/lib/arel/nodes/update_statement.rb +41 -0
  238. data/lib/arel/nodes/values_list.rb +9 -0
  239. data/lib/arel/nodes/window.rb +126 -0
  240. data/lib/arel/nodes/with.rb +11 -0
  241. data/lib/arel/order_predications.rb +13 -0
  242. data/lib/arel/predications.rb +257 -0
  243. data/lib/arel/select_manager.rb +271 -0
  244. data/lib/arel/table.rb +110 -0
  245. data/lib/arel/tree_manager.rb +72 -0
  246. data/lib/arel/update_manager.rb +34 -0
  247. data/lib/arel/visitors.rb +20 -0
  248. data/lib/arel/visitors/depth_first.rb +204 -0
  249. data/lib/arel/visitors/dot.rb +297 -0
  250. data/lib/arel/visitors/ibm_db.rb +34 -0
  251. data/lib/arel/visitors/informix.rb +62 -0
  252. data/lib/arel/visitors/mssql.rb +157 -0
  253. data/lib/arel/visitors/mysql.rb +83 -0
  254. data/lib/arel/visitors/oracle.rb +159 -0
  255. data/lib/arel/visitors/oracle12.rb +66 -0
  256. data/lib/arel/visitors/postgresql.rb +110 -0
  257. data/lib/arel/visitors/sqlite.rb +39 -0
  258. data/lib/arel/visitors/to_sql.rb +889 -0
  259. data/lib/arel/visitors/visitor.rb +46 -0
  260. data/lib/arel/visitors/where_sql.rb +23 -0
  261. data/lib/arel/window_predications.rb +9 -0
  262. data/lib/rails/generators/active_record/migration.rb +14 -1
  263. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  264. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  265. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  266. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  267. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  268. metadata +110 -25
  269. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
  end
23
23
 
24
24
  if prepared_statements
25
- sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value
25
+ sql, binds = visitor.compile(arel_or_sql_string.ast, collector)
26
26
 
27
27
  if binds.length > bind_params_length
28
28
  unprepared_statement do
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
  end
32
32
  end
33
33
  else
34
- sql = visitor.accept(arel_or_sql_string.ast, collector).value
34
+ sql = visitor.compile(arel_or_sql_string.ast, collector)
35
35
  end
36
36
  [sql.freeze, binds]
37
37
  else
@@ -45,11 +45,11 @@ module ActiveRecord
45
45
  # can be used to query the database repeatedly.
46
46
  def cacheable_query(klass, arel) # :nodoc:
47
47
  if prepared_statements
48
- sql, binds = visitor.accept(arel.ast, collector).value
48
+ sql, binds = visitor.compile(arel.ast, collector)
49
49
  query = klass.query(sql)
50
50
  else
51
- collector = PartialQueryCollector.new
52
- parts, binds = visitor.accept(arel.ast, collector).value
51
+ collector = klass.partial_query_collector
52
+ parts, binds = visitor.compile(arel.ast, collector)
53
53
  query = klass.partial_query(parts)
54
54
  end
55
55
  [query, binds]
@@ -106,6 +106,11 @@ module ActiveRecord
106
106
  exec_query(sql, name).rows
107
107
  end
108
108
 
109
+ # Determines whether the SQL statement is a write query.
110
+ def write_query?(sql)
111
+ raise NotImplementedError
112
+ end
113
+
109
114
  # Executes the SQL statement in the context of this connection and returns
110
115
  # the raw result from the connection adapter.
111
116
  # Note: depending on your database connector, the result returned by this
@@ -126,7 +131,7 @@ module ActiveRecord
126
131
  # +binds+ as the bind substitutes. +name+ is logged along with
127
132
  # the executed +sql+ statement.
128
133
  def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
129
- sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
134
+ sql, binds = sql_for_insert(sql, pk, binds)
130
135
  exec_query(sql, name, binds)
131
136
  end
132
137
 
@@ -137,11 +142,6 @@ module ActiveRecord
137
142
  exec_query(sql, name, binds)
138
143
  end
139
144
 
140
- # Executes the truncate statement.
141
- def truncate(table_name, name = nil)
142
- raise NotImplementedError
143
- end
144
-
145
145
  # Executes update +sql+ statement in the context of this connection using
146
146
  # +binds+ as the bind substitutes. +name+ is logged along with
147
147
  # the executed +sql+ statement.
@@ -149,6 +149,10 @@ module ActiveRecord
149
149
  exec_query(sql, name, binds)
150
150
  end
151
151
 
152
+ def exec_insert_all(sql, name) # :nodoc:
153
+ exec_query(sql, name)
154
+ end
155
+
152
156
  # Executes an INSERT query and returns the new record's ID
153
157
  #
154
158
  # +id_value+ will be returned unless the value is +nil+, in
@@ -176,12 +180,22 @@ module ActiveRecord
176
180
  exec_delete(sql, name, binds)
177
181
  end
178
182
 
179
- # Returns +true+ when the connection adapter supports prepared statement
180
- # caching, otherwise returns +false+
181
- def supports_statement_cache? # :nodoc:
182
- 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
183
198
  end
184
- deprecate :supports_statement_cache?
185
199
 
186
200
  # Runs the given block in a database transaction, and returns the result
187
201
  # of the block.
@@ -272,7 +286,9 @@ module ActiveRecord
272
286
 
273
287
  attr_reader :transaction_manager #:nodoc:
274
288
 
275
- 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
276
292
 
277
293
  def transaction_open?
278
294
  current_transaction.open?
@@ -337,68 +353,30 @@ module ActiveRecord
337
353
 
338
354
  # Inserts the given fixture into the table. Overridden in adapters that require
339
355
  # something beyond a simple insert (eg. Oracle).
340
- # 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.
341
357
  # We keep this method to provide fallback
342
358
  # for databases like sqlite that do not support bulk inserts.
343
359
  def insert_fixture(fixture, table_name)
344
- fixture = fixture.stringify_keys
345
-
346
- columns = schema_cache.columns_hash(table_name)
347
- binds = fixture.map do |name, value|
348
- if column = columns[name]
349
- type = lookup_cast_type_from_column(column)
350
- Relation::QueryAttribute.new(name, value, type)
351
- else
352
- raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
353
- end
354
- end
355
-
356
- table = Arel::Table.new(table_name)
357
-
358
- values = binds.map do |bind|
359
- value = with_yaml_fallback(bind.value_for_database)
360
- [table[bind.name], value]
361
- end
362
-
363
- manager = Arel::InsertManager.new
364
- manager.into(table)
365
- manager.insert(values)
366
- execute manager.to_sql, "Fixture Insert"
367
- end
368
-
369
- # Inserts a set of fixtures into the table. Overridden in adapters that require
370
- # something beyond a simple insert (eg. Oracle).
371
- def insert_fixtures(fixtures, table_name)
372
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
373
- `insert_fixtures` is deprecated and will be removed in the next version of Rails.
374
- Consider using `insert_fixtures_set` for performance improvement.
375
- MSG
376
- return if fixtures.empty?
377
-
378
- execute(build_fixture_sql(fixtures, table_name), "Fixtures Insert")
360
+ execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
379
361
  end
380
362
 
381
363
  def insert_fixtures_set(fixture_set, tables_to_delete = [])
382
- fixture_inserts = fixture_set.map do |table_name, fixtures|
383
- next if fixtures.empty?
384
-
385
- build_fixture_sql(fixtures, table_name)
386
- end.compact
387
-
388
- table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name table}".dup }
389
- total_sql = Array.wrap(combine_multi_statements(table_deletes + fixture_inserts))
390
-
391
- disable_referential_integrity do
392
- transaction(requires_new: true) do
393
- total_sql.each do |sql|
394
- execute sql, "Fixtures Load"
395
- 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
396
374
  end
397
375
  end
398
376
  end
399
377
  end
400
378
 
401
- def empty_insert_statement_value
379
+ def empty_insert_statement_value(primary_key = nil)
402
380
  "DEFAULT VALUES"
403
381
  end
404
382
 
@@ -416,25 +394,33 @@ module ActiveRecord
416
394
  end
417
395
  end
418
396
 
419
- # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
420
- # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
421
- # an UPDATE statement, so in the MySQL adapters we redefine this to do that.
422
- def join_to_update(update, select, key) # :nodoc:
423
- subselect = subquery_for(key, select)
424
-
425
- 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
426
406
  end
427
- alias join_to_delete join_to_update
428
407
 
429
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
+
430
416
  def default_insert_value(column)
431
- Arel.sql("DEFAULT")
417
+ DEFAULT_INSERT_VALUE
432
418
  end
433
419
 
434
420
  def build_fixture_sql(fixtures, table_name)
435
421
  columns = schema_cache.columns_hash(table_name)
436
422
 
437
- values = fixtures.map do |fixture|
423
+ values_list = fixtures.map do |fixture|
438
424
  fixture = fixture.stringify_keys
439
425
 
440
426
  unknown_columns = fixture.keys - columns.keys
@@ -445,8 +431,7 @@ module ActiveRecord
445
431
  columns.map do |name, column|
446
432
  if fixture.key?(name)
447
433
  type = lookup_cast_type_from_column(column)
448
- bind = Relation::QueryAttribute.new(name, fixture[name], type)
449
- with_yaml_fallback(bind.value_for_database)
434
+ with_yaml_fallback(type.serialize(fixture[name]))
450
435
  else
451
436
  default_insert_value(column)
452
437
  end
@@ -456,21 +441,45 @@ module ActiveRecord
456
441
  table = Arel::Table.new(table_name)
457
442
  manager = Arel::InsertManager.new
458
443
  manager.into(table)
459
- columns.each_key { |column| manager.columns << table[column] }
460
- manager.values = manager.create_values_list(values)
461
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)
462
460
  manager.to_sql
463
461
  end
464
462
 
465
- def combine_multi_statements(total_sql)
466
- 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)
467
475
  end
468
476
 
469
- # Returns a subquery for the given key using the join information.
470
- def subquery_for(key, select)
471
- subselect = select.clone
472
- subselect.projections = [key]
473
- subselect
477
+ def with_multi_statements
478
+ yield
479
+ end
480
+
481
+ def combine_multi_statements(total_sql)
482
+ total_sql.join(";\n")
474
483
  end
475
484
 
476
485
  # Returns an ActiveRecord::Result instance.
@@ -482,7 +491,7 @@ module ActiveRecord
482
491
  exec_query(sql, name, binds, prepare: true)
483
492
  end
484
493
 
485
- def sql_for_insert(sql, pk, id_value, sequence_name, binds)
494
+ def sql_for_insert(sql, pk, binds)
486
495
  [sql, binds]
487
496
  end
488
497
 
@@ -502,39 +511,6 @@ module ActiveRecord
502
511
  relation
503
512
  end
504
513
  end
505
-
506
- # Fixture value is quoted by Arel, however scalar values
507
- # are not quotable. In this case we want to convert
508
- # the column value to YAML.
509
- def with_yaml_fallback(value)
510
- if value.is_a?(Hash) || value.is_a?(Array)
511
- YAML.dump(value)
512
- else
513
- value
514
- end
515
- end
516
-
517
- class PartialQueryCollector
518
- def initialize
519
- @parts = []
520
- @binds = []
521
- end
522
-
523
- def <<(str)
524
- @parts << str
525
- self
526
- end
527
-
528
- def add_bind(obj)
529
- @binds << obj
530
- @parts << Arel::Nodes::BindParam.new(1)
531
- self
532
- end
533
-
534
- def value
535
- [@parts, @binds]
536
- end
537
- end
538
514
  end
539
515
  end
540
516
  end
@@ -7,7 +7,8 @@ module ActiveRecord
7
7
  module QueryCache
8
8
  class << self
9
9
  def included(base) #:nodoc:
10
- dirties_query_cache base, :insert, :update, :delete, :rollback_to_savepoint, :rollback_db_transaction
10
+ dirties_query_cache base, :insert, :update, :delete, :truncate, :truncate_tables,
11
+ :rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
11
12
 
12
13
  base.set_callback :checkout, :after, :configure_query_cache!
13
14
  base.set_callback :checkin, :after, :disable_query_cache!
@@ -17,7 +18,7 @@ module ActiveRecord
17
18
  method_names.each do |method_name|
18
19
  base.class_eval <<-end_code, __FILE__, __LINE__ + 1
19
20
  def #{method_name}(*)
20
- clear_query_cache if @query_cache_enabled
21
+ ActiveRecord::Base.clear_query_caches_for_current_thread if @query_cache_enabled
21
22
  super
22
23
  end
23
24
  end_code
@@ -115,12 +116,7 @@ module ActiveRecord
115
116
  if @query_cache[sql].key?(binds)
116
117
  ActiveSupport::Notifications.instrument(
117
118
  "sql.active_record",
118
- sql: sql,
119
- binds: binds,
120
- type_casted_binds: -> { type_casted_binds(binds) },
121
- name: name,
122
- connection_id: object_id,
123
- cached: true,
119
+ cache_notification_info(sql, name, binds)
124
120
  )
125
121
  @query_cache[sql][binds]
126
122
  else
@@ -130,6 +126,20 @@ module ActiveRecord
130
126
  end
131
127
  end
132
128
 
129
+ # Database adapters can override this method to
130
+ # provide custom cache information.
131
+ def cache_notification_info(sql, name, binds)
132
+ {
133
+ sql: sql,
134
+ binds: binds,
135
+ type_casted_binds: -> { type_casted_binds(binds) },
136
+ name: name,
137
+ connection_id: object_id,
138
+ connection: self,
139
+ cached: true
140
+ }
141
+ end
142
+
133
143
  # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
134
144
  # queries should not be cached.
135
145
  def locked?(arel)
@@ -60,7 +60,7 @@ module ActiveRecord
60
60
  # Quotes a string, escaping any ' (single quote) and \ (backslash)
61
61
  # characters.
62
62
  def quote_string(s)
63
- s.gsub('\\'.freeze, '\&\&'.freeze).gsub("'".freeze, "''".freeze) # ' (for ruby-mode)
63
+ s.gsub('\\', '\&\&').gsub("'", "''") # ' (for ruby-mode)
64
64
  end
65
65
 
66
66
  # Quotes the column name. Defaults to no quoting.
@@ -95,7 +95,7 @@ module ActiveRecord
95
95
  end
96
96
 
97
97
  def quoted_true
98
- "TRUE".freeze
98
+ "TRUE"
99
99
  end
100
100
 
101
101
  def unquoted_true
@@ -103,7 +103,7 @@ module ActiveRecord
103
103
  end
104
104
 
105
105
  def quoted_false
106
- "FALSE".freeze
106
+ "FALSE"
107
107
  end
108
108
 
109
109
  def unquoted_false
@@ -138,15 +138,72 @@ module ActiveRecord
138
138
  "'#{quote_string(value.to_s)}'"
139
139
  end
140
140
 
141
- def type_casted_binds(binds) # :nodoc:
142
- if binds.first.is_a?(Array)
143
- binds.map { |column, value| type_cast(value, column) }
144
- else
145
- binds.map { |attr| type_cast(attr.value_for_database) }
146
- end
141
+ def sanitize_as_sql_comment(value) # :nodoc:
142
+ value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
143
+ end
144
+
145
+ def column_name_matcher # :nodoc:
146
+ COLUMN_NAME
147
147
  end
148
148
 
149
+ def column_name_with_order_matcher # :nodoc:
150
+ COLUMN_NAME_WITH_ORDER
151
+ end
152
+
153
+ # Regexp for column names (with or without a table name prefix).
154
+ # Matches the following:
155
+ #
156
+ # "#{table_name}.#{column_name}"
157
+ # "#{column_name}"
158
+ COLUMN_NAME = /
159
+ \A
160
+ (
161
+ (?:
162
+ # table_name.column_name | function(one or no argument)
163
+ ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
164
+ )
165
+ (?:\s+AS\s+\w+)?
166
+ )
167
+ (?:\s*,\s*\g<1>)*
168
+ \z
169
+ /ix
170
+
171
+ # Regexp for column names with order (with or without a table name prefix,
172
+ # with or without various order modifiers). Matches the following:
173
+ #
174
+ # "#{table_name}.#{column_name}"
175
+ # "#{table_name}.#{column_name} #{direction}"
176
+ # "#{table_name}.#{column_name} #{direction} NULLS FIRST"
177
+ # "#{table_name}.#{column_name} NULLS LAST"
178
+ # "#{column_name}"
179
+ # "#{column_name} #{direction}"
180
+ # "#{column_name} #{direction} NULLS FIRST"
181
+ # "#{column_name} NULLS LAST"
182
+ COLUMN_NAME_WITH_ORDER = /
183
+ \A
184
+ (
185
+ (?:
186
+ # table_name.column_name | function(one or no argument)
187
+ ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
188
+ )
189
+ (?:\s+ASC|\s+DESC)?
190
+ (?:\s+NULLS\s+(?:FIRST|LAST))?
191
+ )
192
+ (?:\s*,\s*\g<1>)*
193
+ \z
194
+ /ix
195
+
196
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
197
+
149
198
  private
199
+ def type_casted_binds(binds)
200
+ if binds.first.is_a?(Array)
201
+ binds.map { |column, value| type_cast(value, column) }
202
+ else
203
+ binds.map { |attr| type_cast(attr.value_for_database) }
204
+ end
205
+ end
206
+
150
207
  def lookup_cast_type(sql_type)
151
208
  type_map.lookup(sql_type)
152
209
  end
@@ -157,13 +214,9 @@ module ActiveRecord
157
214
  end
158
215
  end
159
216
 
160
- def types_which_need_no_typecasting
161
- [nil, Numeric, String]
162
- end
163
-
164
217
  def _quote(value)
165
218
  case value
166
- when String, ActiveSupport::Multibyte::Chars
219
+ when String, Symbol, ActiveSupport::Multibyte::Chars
167
220
  "'#{quote_string(value.to_s)}'"
168
221
  when true then quoted_true
169
222
  when false then quoted_false
@@ -174,7 +227,6 @@ module ActiveRecord
174
227
  when Type::Binary::Data then quoted_binary(value)
175
228
  when Type::Time::Value then "'#{quoted_time(value)}'"
176
229
  when Date, Time then "'#{quoted_date(value)}'"
177
- when Symbol then "'#{quote_string(value.to_s)}'"
178
230
  when Class then "'#{value}'"
179
231
  else raise TypeError, "can't quote #{value.class.name}"
180
232
  end
@@ -188,10 +240,9 @@ module ActiveRecord
188
240
  when false then unquoted_false
189
241
  # BigDecimals need to be put in a non-normalized form and quoted.
190
242
  when BigDecimal then value.to_s("F")
243
+ when nil, Numeric, String then value
191
244
  when Type::Time::Value then quoted_time(value)
192
245
  when Date, Time then quoted_date(value)
193
- when *types_which_need_no_typecasting
194
- value
195
246
  else raise TypeError
196
247
  end
197
248
  end