activerecord 5.2.8.1 → 6.1.6.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 (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1255 -596
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +9 -8
  7. data/lib/active_record/association_relation.rb +30 -10
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +100 -41
  10. data/lib/active_record/associations/association_scope.rb +23 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +55 -48
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
  13. data/lib/active_record/associations/builder/association.rb +45 -22
  14. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  15. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -2
  18. data/lib/active_record/associations/builder/has_one.rb +33 -2
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  20. data/lib/active_record/associations/collection_association.rb +44 -34
  21. data/lib/active_record/associations/collection_proxy.rb +25 -21
  22. data/lib/active_record/associations/foreign_association.rb +20 -0
  23. data/lib/active_record/associations/has_many_association.rb +26 -13
  24. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  25. data/lib/active_record/associations/has_one_association.rb +43 -31
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  28. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/preloader/association.rb +69 -43
  31. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/singular_association.rb +3 -17
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/associations.rb +137 -25
  36. data/lib/active_record/attribute_assignment.rb +17 -19
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  38. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  40. data/lib/active_record/attribute_methods/query.rb +4 -8
  41. data/lib/active_record/attribute_methods/read.rb +14 -56
  42. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  44. data/lib/active_record/attribute_methods/write.rb +18 -34
  45. data/lib/active_record/attribute_methods.rb +81 -143
  46. data/lib/active_record/attributes.rb +46 -9
  47. data/lib/active_record/autosave_association.rb +57 -42
  48. data/lib/active_record/base.rb +4 -17
  49. data/lib/active_record/callbacks.rb +158 -43
  50. data/lib/active_record/coders/yaml_column.rb +1 -2
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +211 -90
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  64. data/lib/active_record/connection_adapters/column.rb +30 -12
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +88 -32
  69. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  70. data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
  71. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  72. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  73. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +142 -19
  75. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  77. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -54
  81. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  94. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  96. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  99. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  101. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  102. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  104. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  105. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  106. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
  107. data/lib/active_record/connection_adapters/schema_cache.rb +159 -21
  108. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  109. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  110. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  111. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  112. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  113. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  114. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  115. data/lib/active_record/connection_adapters.rb +52 -0
  116. data/lib/active_record/connection_handling.rb +293 -33
  117. data/lib/active_record/core.rb +333 -98
  118. data/lib/active_record/counter_cache.rb +8 -30
  119. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  120. data/lib/active_record/database_configurations/database_config.rb +80 -0
  121. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  122. data/lib/active_record/database_configurations/url_config.rb +53 -0
  123. data/lib/active_record/database_configurations.rb +273 -0
  124. data/lib/active_record/delegated_type.rb +209 -0
  125. data/lib/active_record/destroy_association_async_job.rb +36 -0
  126. data/lib/active_record/dynamic_matchers.rb +3 -4
  127. data/lib/active_record/enum.rb +108 -36
  128. data/lib/active_record/errors.rb +62 -19
  129. data/lib/active_record/explain.rb +10 -6
  130. data/lib/active_record/explain_subscriber.rb +1 -1
  131. data/lib/active_record/fixture_set/file.rb +10 -17
  132. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  133. data/lib/active_record/fixture_set/render_context.rb +17 -0
  134. data/lib/active_record/fixture_set/table_row.rb +152 -0
  135. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  136. data/lib/active_record/fixtures.rb +200 -481
  137. data/lib/active_record/gem_version.rb +3 -3
  138. data/lib/active_record/inheritance.rb +53 -24
  139. data/lib/active_record/insert_all.rb +212 -0
  140. data/lib/active_record/integration.rb +67 -17
  141. data/lib/active_record/internal_metadata.rb +28 -9
  142. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  143. data/lib/active_record/locking/optimistic.rb +37 -23
  144. data/lib/active_record/locking/pessimistic.rb +9 -5
  145. data/lib/active_record/log_subscriber.rb +35 -35
  146. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  147. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  148. data/lib/active_record/middleware/database_selector.rb +77 -0
  149. data/lib/active_record/migration/command_recorder.rb +96 -44
  150. data/lib/active_record/migration/compatibility.rb +145 -64
  151. data/lib/active_record/migration/join_table.rb +0 -1
  152. data/lib/active_record/migration.rb +206 -157
  153. data/lib/active_record/model_schema.rb +148 -22
  154. data/lib/active_record/nested_attributes.rb +4 -7
  155. data/lib/active_record/no_touching.rb +8 -1
  156. data/lib/active_record/null_relation.rb +0 -1
  157. data/lib/active_record/persistence.rb +267 -59
  158. data/lib/active_record/query_cache.rb +21 -4
  159. data/lib/active_record/querying.rb +40 -23
  160. data/lib/active_record/railtie.rb +116 -59
  161. data/lib/active_record/railties/console_sandbox.rb +2 -4
  162. data/lib/active_record/railties/controller_runtime.rb +30 -35
  163. data/lib/active_record/railties/databases.rake +411 -80
  164. data/lib/active_record/readonly_attributes.rb +4 -0
  165. data/lib/active_record/reflection.rb +109 -93
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  167. data/lib/active_record/relation/batches.rb +44 -35
  168. data/lib/active_record/relation/calculations.rb +157 -90
  169. data/lib/active_record/relation/delegation.rb +35 -50
  170. data/lib/active_record/relation/finder_methods.rb +64 -39
  171. data/lib/active_record/relation/from_clause.rb +5 -1
  172. data/lib/active_record/relation/merger.rb +32 -40
  173. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  174. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  179. data/lib/active_record/relation/predicate_builder.rb +62 -45
  180. data/lib/active_record/relation/query_attribute.rb +13 -8
  181. data/lib/active_record/relation/query_methods.rb +476 -187
  182. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  183. data/lib/active_record/relation/spawn_methods.rb +9 -9
  184. data/lib/active_record/relation/where_clause.rb +115 -62
  185. data/lib/active_record/relation.rb +379 -115
  186. data/lib/active_record/result.rb +64 -38
  187. data/lib/active_record/runtime_registry.rb +2 -2
  188. data/lib/active_record/sanitization.rb +22 -41
  189. data/lib/active_record/schema.rb +2 -11
  190. data/lib/active_record/schema_dumper.rb +54 -9
  191. data/lib/active_record/schema_migration.rb +7 -9
  192. data/lib/active_record/scoping/default.rb +4 -8
  193. data/lib/active_record/scoping/named.rb +17 -24
  194. data/lib/active_record/scoping.rb +8 -9
  195. data/lib/active_record/secure_token.rb +16 -8
  196. data/lib/active_record/serialization.rb +5 -3
  197. data/lib/active_record/signed_id.rb +116 -0
  198. data/lib/active_record/statement_cache.rb +49 -6
  199. data/lib/active_record/store.rb +88 -9
  200. data/lib/active_record/suppressor.rb +2 -2
  201. data/lib/active_record/table_metadata.rb +42 -43
  202. data/lib/active_record/tasks/database_tasks.rb +277 -81
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  206. data/lib/active_record/test_databases.rb +24 -0
  207. data/lib/active_record/test_fixtures.rb +287 -0
  208. data/lib/active_record/timestamp.rb +43 -32
  209. data/lib/active_record/touch_later.rb +23 -22
  210. data/lib/active_record/transactions.rb +62 -118
  211. data/lib/active_record/translation.rb +1 -1
  212. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  213. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  214. data/lib/active_record/type/serialized.rb +6 -3
  215. data/lib/active_record/type/time.rb +10 -0
  216. data/lib/active_record/type/type_map.rb +0 -1
  217. data/lib/active_record/type/unsigned_integer.rb +0 -1
  218. data/lib/active_record/type.rb +10 -5
  219. data/lib/active_record/type_caster/connection.rb +15 -15
  220. data/lib/active_record/type_caster/map.rb +8 -8
  221. data/lib/active_record/validations/associated.rb +1 -2
  222. data/lib/active_record/validations/numericality.rb +35 -0
  223. data/lib/active_record/validations/uniqueness.rb +38 -30
  224. data/lib/active_record/validations.rb +4 -3
  225. data/lib/active_record.rb +13 -12
  226. data/lib/arel/alias_predication.rb +9 -0
  227. data/lib/arel/attributes/attribute.rb +41 -0
  228. data/lib/arel/collectors/bind.rb +29 -0
  229. data/lib/arel/collectors/composite.rb +39 -0
  230. data/lib/arel/collectors/plain_string.rb +20 -0
  231. data/lib/arel/collectors/sql_string.rb +27 -0
  232. data/lib/arel/collectors/substitute_binds.rb +35 -0
  233. data/lib/arel/crud.rb +42 -0
  234. data/lib/arel/delete_manager.rb +18 -0
  235. data/lib/arel/errors.rb +9 -0
  236. data/lib/arel/expressions.rb +29 -0
  237. data/lib/arel/factory_methods.rb +49 -0
  238. data/lib/arel/insert_manager.rb +49 -0
  239. data/lib/arel/math.rb +45 -0
  240. data/lib/arel/nodes/and.rb +32 -0
  241. data/lib/arel/nodes/ascending.rb +23 -0
  242. data/lib/arel/nodes/binary.rb +126 -0
  243. data/lib/arel/nodes/bind_param.rb +44 -0
  244. data/lib/arel/nodes/case.rb +55 -0
  245. data/lib/arel/nodes/casted.rb +62 -0
  246. data/lib/arel/nodes/comment.rb +29 -0
  247. data/lib/arel/nodes/count.rb +12 -0
  248. data/lib/arel/nodes/delete_statement.rb +45 -0
  249. data/lib/arel/nodes/descending.rb +23 -0
  250. data/lib/arel/nodes/equality.rb +15 -0
  251. data/lib/arel/nodes/extract.rb +24 -0
  252. data/lib/arel/nodes/false.rb +16 -0
  253. data/lib/arel/nodes/full_outer_join.rb +8 -0
  254. data/lib/arel/nodes/function.rb +44 -0
  255. data/lib/arel/nodes/grouping.rb +11 -0
  256. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  257. data/lib/arel/nodes/in.rb +15 -0
  258. data/lib/arel/nodes/infix_operation.rb +92 -0
  259. data/lib/arel/nodes/inner_join.rb +8 -0
  260. data/lib/arel/nodes/insert_statement.rb +37 -0
  261. data/lib/arel/nodes/join_source.rb +20 -0
  262. data/lib/arel/nodes/matches.rb +18 -0
  263. data/lib/arel/nodes/named_function.rb +23 -0
  264. data/lib/arel/nodes/node.rb +51 -0
  265. data/lib/arel/nodes/node_expression.rb +13 -0
  266. data/lib/arel/nodes/ordering.rb +27 -0
  267. data/lib/arel/nodes/outer_join.rb +8 -0
  268. data/lib/arel/nodes/over.rb +15 -0
  269. data/lib/arel/nodes/regexp.rb +16 -0
  270. data/lib/arel/nodes/right_outer_join.rb +8 -0
  271. data/lib/arel/nodes/select_core.rb +67 -0
  272. data/lib/arel/nodes/select_statement.rb +41 -0
  273. data/lib/arel/nodes/sql_literal.rb +19 -0
  274. data/lib/arel/nodes/string_join.rb +11 -0
  275. data/lib/arel/nodes/table_alias.rb +31 -0
  276. data/lib/arel/nodes/terminal.rb +16 -0
  277. data/lib/arel/nodes/true.rb +16 -0
  278. data/lib/arel/nodes/unary.rb +44 -0
  279. data/lib/arel/nodes/unary_operation.rb +20 -0
  280. data/lib/arel/nodes/unqualified_column.rb +22 -0
  281. data/lib/arel/nodes/update_statement.rb +41 -0
  282. data/lib/arel/nodes/values_list.rb +9 -0
  283. data/lib/arel/nodes/window.rb +126 -0
  284. data/lib/arel/nodes/with.rb +11 -0
  285. data/lib/arel/nodes.rb +70 -0
  286. data/lib/arel/order_predications.rb +13 -0
  287. data/lib/arel/predications.rb +250 -0
  288. data/lib/arel/select_manager.rb +270 -0
  289. data/lib/arel/table.rb +118 -0
  290. data/lib/arel/tree_manager.rb +72 -0
  291. data/lib/arel/update_manager.rb +34 -0
  292. data/lib/arel/visitors/dot.rb +308 -0
  293. data/lib/arel/visitors/mysql.rb +93 -0
  294. data/lib/arel/visitors/postgresql.rb +120 -0
  295. data/lib/arel/visitors/sqlite.rb +38 -0
  296. data/lib/arel/visitors/to_sql.rb +899 -0
  297. data/lib/arel/visitors/visitor.rb +45 -0
  298. data/lib/arel/visitors.rb +13 -0
  299. data/lib/arel/window_predications.rb +9 -0
  300. data/lib/arel.rb +54 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  303. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  304. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  305. data/lib/rails/generators/active_record/migration.rb +19 -2
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +116 -30
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -3,19 +3,13 @@
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters # :nodoc:
5
5
  module DatabaseLimits
6
- # Returns the maximum length of a table alias.
7
- def table_alias_length
8
- 255
9
- end
10
-
11
- # Returns the maximum length of a column name.
12
- def column_name_length
6
+ def max_identifier_length # :nodoc:
13
7
  64
14
8
  end
15
9
 
16
- # Returns the maximum length of a table name.
17
- def table_name_length
18
- 64
10
+ # Returns the maximum length of a table alias.
11
+ def table_alias_length
12
+ max_identifier_length
19
13
  end
20
14
 
21
15
  # Returns the maximum allowed length for an index name. This
@@ -26,25 +20,11 @@ module ActiveRecord
26
20
  def allowed_index_name_length
27
21
  index_name_length
28
22
  end
23
+ deprecate :allowed_index_name_length
29
24
 
30
25
  # Returns the maximum length of an index name.
31
26
  def index_name_length
32
- 64
33
- end
34
-
35
- # Returns the maximum number of columns per table.
36
- def columns_per_table
37
- 1024
38
- end
39
-
40
- # Returns the maximum number of indexes per table.
41
- def indexes_per_table
42
- 16
43
- end
44
-
45
- # Returns the maximum number of columns in a multicolumn index.
46
- def columns_per_multicolumn_index
47
- 16
27
+ max_identifier_length
48
28
  end
49
29
 
50
30
  # Returns the maximum number of elements in an IN (x,y,z) clause.
@@ -52,16 +32,7 @@ module ActiveRecord
52
32
  def in_clause_length
53
33
  nil
54
34
  end
55
-
56
- # Returns the maximum length of an SQL query.
57
- def sql_query_length
58
- 1048575
59
- end
60
-
61
- # Returns maximum number of joins in a single query.
62
- def joins_per_query
63
- 256
64
- end
35
+ deprecate :in_clause_length
65
36
 
66
37
  private
67
38
  def bind_params_length
@@ -14,29 +14,32 @@ module ActiveRecord
14
14
  sql
15
15
  end
16
16
 
17
- def to_sql_and_binds(arel_or_sql_string, binds = []) # :nodoc:
17
+ def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil) # :nodoc:
18
18
  if arel_or_sql_string.respond_to?(:ast)
19
19
  unless binds.empty?
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
23
 
24
+ collector = collector()
25
+
24
26
  if prepared_statements
25
- sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value
27
+ collector.preparable = true
28
+ sql, binds = visitor.compile(arel_or_sql_string.ast, collector)
26
29
 
27
30
  if binds.length > bind_params_length
28
31
  unprepared_statement do
29
- sql, binds = to_sql_and_binds(arel_or_sql_string)
30
- visitor.preparable = false
32
+ return to_sql_and_binds(arel_or_sql_string)
31
33
  end
32
34
  end
35
+ preparable = collector.preparable
33
36
  else
34
- sql = visitor.accept(arel_or_sql_string.ast, collector).value
37
+ sql = visitor.compile(arel_or_sql_string.ast, collector)
35
38
  end
36
- [sql.freeze, binds]
39
+ [sql.freeze, binds, preparable]
37
40
  else
38
- visitor.preparable = false if prepared_statements
39
- [arel_or_sql_string.dup.freeze, binds]
41
+ arel_or_sql_string = arel_or_sql_string.dup.freeze unless arel_or_sql_string.frozen?
42
+ [arel_or_sql_string, binds, preparable]
40
43
  end
41
44
  end
42
45
  private :to_sql_and_binds
@@ -45,11 +48,11 @@ module ActiveRecord
45
48
  # can be used to query the database repeatedly.
46
49
  def cacheable_query(klass, arel) # :nodoc:
47
50
  if prepared_statements
48
- sql, binds = visitor.accept(arel.ast, collector).value
51
+ sql, binds = visitor.compile(arel.ast, collector)
49
52
  query = klass.query(sql)
50
53
  else
51
- collector = PartialQueryCollector.new
52
- parts, binds = visitor.accept(arel.ast, collector).value
54
+ collector = klass.partial_query_collector
55
+ parts, binds = visitor.compile(arel.ast, collector)
53
56
  query = klass.partial_query(parts)
54
57
  end
55
58
  [query, binds]
@@ -58,17 +61,15 @@ module ActiveRecord
58
61
  # Returns an ActiveRecord::Result instance.
59
62
  def select_all(arel, name = nil, binds = [], preparable: nil)
60
63
  arel = arel_from_relation(arel)
61
- sql, binds = to_sql_and_binds(arel, binds)
62
-
63
- if preparable.nil?
64
- preparable = prepared_statements ? visitor.preparable : false
65
- end
64
+ sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
66
65
 
67
66
  if prepared_statements && preparable
68
67
  select_prepared(sql, name, binds)
69
68
  else
70
69
  select(sql, name, binds)
71
70
  end
71
+ rescue ::RangeError
72
+ ActiveRecord::Result.new([], [])
72
73
  end
73
74
 
74
75
  # Returns a record hash with the column names as keys and column values
@@ -106,6 +107,11 @@ module ActiveRecord
106
107
  exec_query(sql, name).rows
107
108
  end
108
109
 
110
+ # Determines whether the SQL statement is a write query.
111
+ def write_query?(sql)
112
+ raise NotImplementedError
113
+ end
114
+
109
115
  # Executes the SQL statement in the context of this connection and returns
110
116
  # the raw result from the connection adapter.
111
117
  # Note: depending on your database connector, the result returned by this
@@ -126,7 +132,7 @@ module ActiveRecord
126
132
  # +binds+ as the bind substitutes. +name+ is logged along with
127
133
  # the executed +sql+ statement.
128
134
  def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
129
- sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
135
+ sql, binds = sql_for_insert(sql, pk, binds)
130
136
  exec_query(sql, name, binds)
131
137
  end
132
138
 
@@ -137,11 +143,6 @@ module ActiveRecord
137
143
  exec_query(sql, name, binds)
138
144
  end
139
145
 
140
- # Executes the truncate statement.
141
- def truncate(table_name, name = nil)
142
- raise NotImplementedError
143
- end
144
-
145
146
  # Executes update +sql+ statement in the context of this connection using
146
147
  # +binds+ as the bind substitutes. +name+ is logged along with
147
148
  # the executed +sql+ statement.
@@ -149,6 +150,14 @@ module ActiveRecord
149
150
  exec_query(sql, name, binds)
150
151
  end
151
152
 
153
+ def exec_insert_all(sql, name) # :nodoc:
154
+ exec_query(sql, name)
155
+ end
156
+
157
+ def explain(arel, binds = []) # :nodoc:
158
+ raise NotImplementedError
159
+ end
160
+
152
161
  # Executes an INSERT query and returns the new record's ID
153
162
  #
154
163
  # +id_value+ will be returned unless the value is +nil+, in
@@ -176,27 +185,53 @@ module ActiveRecord
176
185
  exec_delete(sql, name, binds)
177
186
  end
178
187
 
179
- # Returns +true+ when the connection adapter supports prepared statement
180
- # caching, otherwise returns +false+
181
- def supports_statement_cache? # :nodoc:
182
- true
188
+ # Executes the truncate statement.
189
+ def truncate(table_name, name = nil)
190
+ execute(build_truncate_statement(table_name), name)
191
+ end
192
+
193
+ def truncate_tables(*table_names) # :nodoc:
194
+ table_names -= [schema_migration.table_name, InternalMetadata.table_name]
195
+
196
+ return if table_names.empty?
197
+
198
+ with_multi_statements do
199
+ disable_referential_integrity do
200
+ statements = build_truncate_statements(table_names)
201
+ execute_batch(statements, "Truncate Tables")
202
+ end
203
+ end
183
204
  end
184
- deprecate :supports_statement_cache?
185
205
 
186
206
  # Runs the given block in a database transaction, and returns the result
187
207
  # of the block.
188
208
  #
189
209
  # == Nested transactions support
190
210
  #
211
+ # #transaction calls can be nested. By default, this makes all database
212
+ # statements in the nested transaction block become part of the parent
213
+ # transaction. For example, the following behavior may be surprising:
214
+ #
215
+ # ActiveRecord::Base.transaction do
216
+ # Post.create(title: 'first')
217
+ # ActiveRecord::Base.transaction do
218
+ # Post.create(title: 'second')
219
+ # raise ActiveRecord::Rollback
220
+ # end
221
+ # end
222
+ #
223
+ # This creates both "first" and "second" posts. Reason is the
224
+ # ActiveRecord::Rollback exception in the nested block does not issue a
225
+ # ROLLBACK. Since these exceptions are captured in transaction blocks,
226
+ # the parent block does not see it and the real transaction is committed.
227
+ #
191
228
  # Most databases don't support true nested transactions. At the time of
192
229
  # writing, the only database that supports true nested transactions that
193
230
  # we're aware of, is MS-SQL.
194
231
  #
195
232
  # In order to get around this problem, #transaction will emulate the effect
196
233
  # of nested transactions, by using savepoints:
197
- # https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
198
- # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
199
- # supports savepoints.
234
+ # https://dev.mysql.com/doc/refman/en/savepoint.html.
200
235
  #
201
236
  # It is safe to call this method if a database transaction is already open,
202
237
  # i.e. if #transaction is called within another #transaction block. In case
@@ -208,6 +243,24 @@ module ActiveRecord
208
243
  # - However, if +:requires_new+ is set, the block will be wrapped in a
209
244
  # database savepoint acting as a sub-transaction.
210
245
  #
246
+ # In order to get a ROLLBACK for the nested transaction you may ask for a
247
+ # real sub-transaction by passing <tt>requires_new: true</tt>.
248
+ # If anything goes wrong, the database rolls back to the beginning of
249
+ # the sub-transaction without rolling back the parent transaction.
250
+ # If we add it to the previous example:
251
+ #
252
+ # ActiveRecord::Base.transaction do
253
+ # Post.create(title: 'first')
254
+ # ActiveRecord::Base.transaction(requires_new: true) do
255
+ # Post.create(title: 'second')
256
+ # raise ActiveRecord::Rollback
257
+ # end
258
+ # end
259
+ #
260
+ # only post with title "first" is created.
261
+ #
262
+ # See ActiveRecord::Transactions to learn more.
263
+ #
211
264
  # === Caveats
212
265
  #
213
266
  # MySQL doesn't support DDL transactions. If you perform a DDL operation,
@@ -247,7 +300,7 @@ module ActiveRecord
247
300
  # semantics of these different levels:
248
301
  #
249
302
  # * https://www.postgresql.org/docs/current/static/transaction-iso.html
250
- # * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
303
+ # * https://dev.mysql.com/doc/refman/en/set-transaction.html
251
304
  #
252
305
  # An ActiveRecord::TransactionIsolationError will be raised if:
253
306
  #
@@ -272,7 +325,16 @@ module ActiveRecord
272
325
 
273
326
  attr_reader :transaction_manager #:nodoc:
274
327
 
275
- delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction, :commit_transaction, :rollback_transaction, to: :transaction_manager
328
+ delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
329
+ :commit_transaction, :rollback_transaction, :materialize_transactions,
330
+ :disable_lazy_transactions!, :enable_lazy_transactions!, to: :transaction_manager
331
+
332
+ def mark_transaction_written_if_write(sql) # :nodoc:
333
+ transaction = current_transaction
334
+ if transaction.open?
335
+ transaction.written ||= write_query?(sql)
336
+ end
337
+ end
276
338
 
277
339
  def transaction_open?
278
340
  current_transaction.open?
@@ -284,12 +346,8 @@ module ActiveRecord
284
346
 
285
347
  # Register a record with the current transaction so that its after_commit and after_rollback callbacks
286
348
  # can be called.
287
- def add_transaction_record(record)
288
- current_transaction.add_record(record)
289
- end
290
-
291
- def transaction_state
292
- current_transaction.state
349
+ def add_transaction_record(record, ensure_finalize = true)
350
+ current_transaction.add_record(record, ensure_finalize)
293
351
  end
294
352
 
295
353
  # Begins the transaction (and turns off auto-committing).
@@ -336,69 +394,29 @@ module ActiveRecord
336
394
  end
337
395
 
338
396
  # Inserts the given fixture into the table. Overridden in adapters that require
339
- # something beyond a simple insert (eg. Oracle).
340
- # Most of adapters should implement `insert_fixtures` that leverages bulk SQL insert.
397
+ # something beyond a simple insert (e.g. Oracle).
398
+ # Most of adapters should implement +insert_fixtures_set+ that leverages bulk SQL insert.
341
399
  # We keep this method to provide fallback
342
400
  # for databases like sqlite that do not support bulk inserts.
343
401
  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")
402
+ execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
379
403
  end
380
404
 
381
405
  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?
406
+ fixture_inserts = build_fixture_statements(fixture_set)
407
+ table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
408
+ statements = table_deletes + fixture_inserts
409
+
410
+ with_multi_statements do
411
+ disable_referential_integrity do
412
+ transaction(requires_new: true) do
413
+ execute_batch(statements, "Fixtures Load")
396
414
  end
397
415
  end
398
416
  end
399
417
  end
400
418
 
401
- def empty_insert_statement_value
419
+ def empty_insert_statement_value(primary_key = nil)
402
420
  "DEFAULT VALUES"
403
421
  end
404
422
 
@@ -416,25 +434,35 @@ module ActiveRecord
416
434
  end
417
435
  end
418
436
 
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)
437
+ # Fixture value is quoted by Arel, however scalar values
438
+ # are not quotable. In this case we want to convert
439
+ # the column value to YAML.
440
+ def with_yaml_fallback(value) # :nodoc:
441
+ if value.is_a?(Hash) || value.is_a?(Array)
442
+ YAML.dump(value)
443
+ else
444
+ value
445
+ end
426
446
  end
427
- alias join_to_delete join_to_update
428
447
 
429
448
  private
449
+ def execute_batch(statements, name = nil)
450
+ statements.each do |statement|
451
+ execute(statement, name)
452
+ end
453
+ end
454
+
455
+ DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
456
+ private_constant :DEFAULT_INSERT_VALUE
457
+
430
458
  def default_insert_value(column)
431
- Arel.sql("DEFAULT")
459
+ DEFAULT_INSERT_VALUE
432
460
  end
433
461
 
434
462
  def build_fixture_sql(fixtures, table_name)
435
463
  columns = schema_cache.columns_hash(table_name)
436
464
 
437
- values = fixtures.map do |fixture|
465
+ values_list = fixtures.map do |fixture|
438
466
  fixture = fixture.stringify_keys
439
467
 
440
468
  unknown_columns = fixture.keys - columns.keys
@@ -445,8 +473,7 @@ module ActiveRecord
445
473
  columns.map do |name, column|
446
474
  if fixture.key?(name)
447
475
  type = lookup_cast_type_from_column(column)
448
- bind = Relation::QueryAttribute.new(name, fixture[name], type)
449
- with_yaml_fallback(bind.value_for_database)
476
+ with_yaml_fallback(type.serialize(fixture[name]))
450
477
  else
451
478
  default_insert_value(column)
452
479
  end
@@ -456,21 +483,48 @@ module ActiveRecord
456
483
  table = Arel::Table.new(table_name)
457
484
  manager = Arel::InsertManager.new
458
485
  manager.into(table)
459
- columns.each_key { |column| manager.columns << table[column] }
460
- manager.values = manager.create_values_list(values)
461
486
 
462
- manager.to_sql
487
+ if values_list.size == 1
488
+ values = values_list.shift
489
+ new_values = []
490
+ columns.each_key.with_index { |column, i|
491
+ unless values[i].equal?(DEFAULT_INSERT_VALUE)
492
+ new_values << values[i]
493
+ manager.columns << table[column]
494
+ end
495
+ }
496
+ values_list << new_values
497
+ else
498
+ columns.each_key { |column| manager.columns << table[column] }
499
+ end
500
+
501
+ manager.values = manager.create_values_list(values_list)
502
+ visitor.compile(manager.ast)
463
503
  end
464
504
 
465
- def combine_multi_statements(total_sql)
466
- total_sql.join(";\n")
505
+ def build_fixture_statements(fixture_set)
506
+ fixture_set.map do |table_name, fixtures|
507
+ next if fixtures.empty?
508
+ build_fixture_sql(fixtures, table_name)
509
+ end.compact
510
+ end
511
+
512
+ def build_truncate_statement(table_name)
513
+ "TRUNCATE TABLE #{quote_table_name(table_name)}"
514
+ end
515
+
516
+ def build_truncate_statements(table_names)
517
+ table_names.map do |table_name|
518
+ build_truncate_statement(table_name)
519
+ end
467
520
  end
468
521
 
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
522
+ def with_multi_statements
523
+ yield
524
+ end
525
+
526
+ def combine_multi_statements(total_sql)
527
+ total_sql.join(";\n")
474
528
  end
475
529
 
476
530
  # Returns an ActiveRecord::Result instance.
@@ -482,7 +536,7 @@ module ActiveRecord
482
536
  exec_query(sql, name, binds, prepare: true)
483
537
  end
484
538
 
485
- def sql_for_insert(sql, pk, id_value, sequence_name, binds)
539
+ def sql_for_insert(sql, pk, binds)
486
540
  [sql, binds]
487
541
  end
488
542
 
@@ -502,39 +556,6 @@ module ActiveRecord
502
556
  relation
503
557
  end
504
558
  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
559
  end
539
560
  end
540
561
  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, :create, :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
21
22
  super
22
23
  end
23
24
  end_code
@@ -95,11 +96,7 @@ module ActiveRecord
95
96
  def select_all(arel, name = nil, binds = [], preparable: nil)
96
97
  if @query_cache_enabled && !locked?(arel)
97
98
  arel = arel_from_relation(arel)
98
- sql, binds = to_sql_and_binds(arel, binds)
99
-
100
- if preparable.nil?
101
- preparable = prepared_statements ? visitor.preparable : false
102
- end
99
+ sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
103
100
 
104
101
  cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
105
102
  else
@@ -108,19 +105,13 @@ module ActiveRecord
108
105
  end
109
106
 
110
107
  private
111
-
112
108
  def cache_sql(sql, name, binds)
113
109
  @lock.synchronize do
114
110
  result =
115
111
  if @query_cache[sql].key?(binds)
116
112
  ActiveSupport::Notifications.instrument(
117
113
  "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,
114
+ cache_notification_info(sql, name, binds)
124
115
  )
125
116
  @query_cache[sql][binds]
126
117
  else
@@ -130,6 +121,19 @@ module ActiveRecord
130
121
  end
131
122
  end
132
123
 
124
+ # Database adapters can override this method to
125
+ # provide custom cache information.
126
+ def cache_notification_info(sql, name, binds)
127
+ {
128
+ sql: sql,
129
+ binds: binds,
130
+ type_casted_binds: -> { type_casted_binds(binds) },
131
+ name: name,
132
+ connection: self,
133
+ cached: true
134
+ }
135
+ end
136
+
133
137
  # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
134
138
  # queries should not be cached.
135
139
  def locked?(arel)