activerecord 5.1.5 → 5.2.8.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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +655 -608
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record/aggregations.rb +6 -5
  8. data/lib/active_record/association_relation.rb +7 -5
  9. data/lib/active_record/associations/alias_tracker.rb +19 -27
  10. data/lib/active_record/associations/association.rb +41 -37
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +14 -5
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +2 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +59 -47
  22. data/lib/active_record/associations/collection_proxy.rb +20 -49
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +12 -1
  25. data/lib/active_record/associations/has_many_through_association.rb +36 -30
  26. data/lib/active_record/associations/has_one_association.rb +12 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  28. data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  31. data/lib/active_record/associations/join_dependency.rb +48 -93
  32. data/lib/active_record/associations/preloader/association.rb +45 -61
  33. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  34. data/lib/active_record/associations/preloader.rb +18 -38
  35. data/lib/active_record/associations/singular_association.rb +14 -16
  36. data/lib/active_record/associations/through_association.rb +26 -11
  37. data/lib/active_record/associations.rb +40 -63
  38. data/lib/active_record/attribute_assignment.rb +2 -5
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  41. data/lib/active_record/attribute_methods/dirty.rb +32 -216
  42. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  43. data/lib/active_record/attribute_methods/query.rb +2 -0
  44. data/lib/active_record/attribute_methods/read.rb +9 -3
  45. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  47. data/lib/active_record/attribute_methods/write.rb +21 -9
  48. data/lib/active_record/attribute_methods.rb +65 -24
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +35 -19
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +12 -6
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +15 -1
  55. data/lib/active_record/collection_cache_key.rb +12 -8
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +142 -42
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +110 -173
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -112
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +66 -74
  117. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +82 -95
  126. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  127. data/lib/active_record/connection_handling.rb +4 -2
  128. data/lib/active_record/core.rb +51 -61
  129. data/lib/active_record/counter_cache.rb +20 -15
  130. data/lib/active_record/define_callbacks.rb +5 -3
  131. data/lib/active_record/dynamic_matchers.rb +9 -9
  132. data/lib/active_record/enum.rb +18 -13
  133. data/lib/active_record/errors.rb +60 -15
  134. data/lib/active_record/explain.rb +3 -1
  135. data/lib/active_record/explain_registry.rb +2 -0
  136. data/lib/active_record/explain_subscriber.rb +2 -0
  137. data/lib/active_record/fixture_set/file.rb +2 -0
  138. data/lib/active_record/fixtures.rb +67 -60
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +49 -19
  141. data/lib/active_record/integration.rb +58 -19
  142. data/lib/active_record/internal_metadata.rb +2 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  144. data/lib/active_record/locking/optimistic.rb +30 -42
  145. data/lib/active_record/locking/pessimistic.rb +9 -6
  146. data/lib/active_record/log_subscriber.rb +43 -0
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +47 -9
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/migration.rb +189 -139
  151. data/lib/active_record/model_schema.rb +19 -24
  152. data/lib/active_record/nested_attributes.rb +18 -6
  153. data/lib/active_record/no_touching.rb +3 -1
  154. data/lib/active_record/null_relation.rb +2 -0
  155. data/lib/active_record/persistence.rb +198 -49
  156. data/lib/active_record/query_cache.rb +12 -14
  157. data/lib/active_record/querying.rb +4 -2
  158. data/lib/active_record/railtie.rb +80 -6
  159. data/lib/active_record/railties/console_sandbox.rb +2 -0
  160. data/lib/active_record/railties/controller_runtime.rb +2 -0
  161. data/lib/active_record/railties/databases.rake +46 -36
  162. data/lib/active_record/readonly_attributes.rb +3 -2
  163. data/lib/active_record/reflection.rb +108 -194
  164. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  165. data/lib/active_record/relation/batches.rb +20 -5
  166. data/lib/active_record/relation/calculations.rb +46 -20
  167. data/lib/active_record/relation/delegation.rb +45 -27
  168. data/lib/active_record/relation/finder_methods.rb +77 -78
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +53 -23
  171. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  172. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  173. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  174. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  175. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  176. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  177. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  178. data/lib/active_record/relation/predicate_builder.rb +60 -79
  179. data/lib/active_record/relation/query_attribute.rb +28 -2
  180. data/lib/active_record/relation/query_methods.rb +129 -100
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +4 -2
  183. data/lib/active_record/relation/where_clause.rb +65 -68
  184. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  185. data/lib/active_record/relation.rb +120 -214
  186. data/lib/active_record/result.rb +2 -0
  187. data/lib/active_record/runtime_registry.rb +2 -0
  188. data/lib/active_record/sanitization.rb +129 -121
  189. data/lib/active_record/schema.rb +4 -2
  190. data/lib/active_record/schema_dumper.rb +36 -26
  191. data/lib/active_record/schema_migration.rb +2 -0
  192. data/lib/active_record/scoping/default.rb +8 -9
  193. data/lib/active_record/scoping/named.rb +23 -7
  194. data/lib/active_record/scoping.rb +9 -8
  195. data/lib/active_record/secure_token.rb +2 -0
  196. data/lib/active_record/serialization.rb +2 -0
  197. data/lib/active_record/statement_cache.rb +23 -13
  198. data/lib/active_record/store.rb +3 -1
  199. data/lib/active_record/suppressor.rb +2 -0
  200. data/lib/active_record/table_metadata.rb +12 -3
  201. data/lib/active_record/tasks/database_tasks.rb +26 -15
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  204. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  205. data/lib/active_record/timestamp.rb +13 -6
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +33 -28
  208. data/lib/active_record/translation.rb +2 -0
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +6 -0
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type.rb +4 -1
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +3 -1
  224. data/lib/active_record/type_caster.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +36 -6
  230. data/lib/active_record/validations.rb +2 -0
  231. data/lib/active_record/version.rb +2 -0
  232. data/lib/active_record.rb +11 -4
  233. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  234. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/migration.rb +2 -0
  239. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  240. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  241. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record.rb +3 -1
  243. metadata +26 -40
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  252. data/lib/active_record/attribute.rb +0 -240
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -114
  254. data/lib/active_record/attribute_set/builder.rb +0 -124
  255. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  256. data/lib/active_record/attribute_set.rb +0 -113
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters # :nodoc:
3
5
  module DatabaseStatements
@@ -7,35 +9,61 @@ module ActiveRecord
7
9
  end
8
10
 
9
11
  # Converts an arel AST to SQL
10
- def to_sql(arel, binds = [])
11
- if arel.respond_to?(:ast)
12
- collected = visitor.accept(arel.ast, collector)
13
- collected.compile(binds, self).freeze
12
+ def to_sql(arel_or_sql_string, binds = [])
13
+ sql, _ = to_sql_and_binds(arel_or_sql_string, binds)
14
+ sql
15
+ end
16
+
17
+ def to_sql_and_binds(arel_or_sql_string, binds = []) # :nodoc:
18
+ if arel_or_sql_string.respond_to?(:ast)
19
+ unless binds.empty?
20
+ raise "Passing bind parameters with an arel AST is forbidden. " \
21
+ "The values must be stored on the AST directly"
22
+ end
23
+
24
+ if prepared_statements
25
+ sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value
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.accept(arel_or_sql_string.ast, collector).value
35
+ end
36
+ [sql.freeze, binds]
14
37
  else
15
- arel.dup.freeze
38
+ visitor.preparable = false if prepared_statements
39
+ [arel_or_sql_string.dup.freeze, binds]
16
40
  end
17
41
  end
42
+ private :to_sql_and_binds
18
43
 
19
44
  # This is used in the StatementCache object. It returns an object that
20
45
  # can be used to query the database repeatedly.
21
46
  def cacheable_query(klass, arel) # :nodoc:
22
- collected = visitor.accept(arel.ast, collector)
23
47
  if prepared_statements
24
- klass.query(collected.value)
48
+ sql, binds = visitor.accept(arel.ast, collector).value
49
+ query = klass.query(sql)
25
50
  else
26
- klass.partial_query(collected.value)
51
+ collector = PartialQueryCollector.new
52
+ parts, binds = visitor.accept(arel.ast, collector).value
53
+ query = klass.partial_query(parts)
27
54
  end
55
+ [query, binds]
28
56
  end
29
57
 
30
58
  # Returns an ActiveRecord::Result instance.
31
59
  def select_all(arel, name = nil, binds = [], preparable: nil)
32
- arel, binds = binds_from_relation arel, binds
33
- sql = to_sql(arel, binds)
34
- if !prepared_statements || (arel.is_a?(String) && preparable.nil?)
35
- preparable = false
36
- else
37
- preparable = visitor.preparable
60
+ 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
38
65
  end
66
+
39
67
  if prepared_statements && preparable
40
68
  select_prepared(sql, name, binds)
41
69
  else
@@ -130,26 +158,30 @@ module ActiveRecord
130
158
  # If the next id was calculated in advance (as in Oracle), it should be
131
159
  # passed in as +id_value+.
132
160
  def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
133
- value = exec_insert(to_sql(arel, binds), name, binds, pk, sequence_name)
161
+ sql, binds = to_sql_and_binds(arel, binds)
162
+ value = exec_insert(sql, name, binds, pk, sequence_name)
134
163
  id_value || last_inserted_id(value)
135
164
  end
136
165
  alias create insert
137
166
 
138
167
  # Executes the update statement and returns the number of rows affected.
139
168
  def update(arel, name = nil, binds = [])
140
- exec_update(to_sql(arel, binds), name, binds)
169
+ sql, binds = to_sql_and_binds(arel, binds)
170
+ exec_update(sql, name, binds)
141
171
  end
142
172
 
143
173
  # Executes the delete statement and returns the number of rows affected.
144
174
  def delete(arel, name = nil, binds = [])
145
- exec_delete(to_sql(arel, binds), name, binds)
175
+ sql, binds = to_sql_and_binds(arel, binds)
176
+ exec_delete(sql, name, binds)
146
177
  end
147
178
 
148
179
  # Returns +true+ when the connection adapter supports prepared statement
149
180
  # caching, otherwise returns +false+
150
- def supports_statement_cache?
151
- false
181
+ def supports_statement_cache? # :nodoc:
182
+ true
152
183
  end
184
+ deprecate :supports_statement_cache?
153
185
 
154
186
  # Runs the given block in a database transaction, and returns the result
155
187
  # of the block.
@@ -162,7 +194,7 @@ module ActiveRecord
162
194
  #
163
195
  # In order to get around this problem, #transaction will emulate the effect
164
196
  # of nested transactions, by using savepoints:
165
- # http://dev.mysql.com/doc/refman/5.7/en/savepoint.html
197
+ # https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
166
198
  # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
167
199
  # supports savepoints.
168
200
  #
@@ -214,7 +246,7 @@ module ActiveRecord
214
246
  # You should consult the documentation for your database to understand the
215
247
  # semantics of these different levels:
216
248
  #
217
- # * http://www.postgresql.org/docs/current/static/transaction-iso.html
249
+ # * https://www.postgresql.org/docs/current/static/transaction-iso.html
218
250
  # * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
219
251
  #
220
252
  # An ActiveRecord::TransactionIsolationError will be raised if:
@@ -305,6 +337,9 @@ module ActiveRecord
305
337
 
306
338
  # Inserts the given fixture into the table. Overridden in adapters that require
307
339
  # something beyond a simple insert (eg. Oracle).
340
+ # Most of adapters should implement `insert_fixtures` that leverages bulk SQL insert.
341
+ # We keep this method to provide fallback
342
+ # for databases like sqlite that do not support bulk inserts.
308
343
  def insert_fixture(fixture, table_name)
309
344
  fixture = fixture.stringify_keys
310
345
 
@@ -317,16 +352,50 @@ module ActiveRecord
317
352
  raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
318
353
  end
319
354
  end
320
- key_list = fixture.keys.map { |name| quote_column_name(name) }
321
- value_list = binds.map(&:value_for_database).map do |value|
322
- begin
323
- quote(value)
324
- rescue TypeError
325
- quote(YAML.dump(value))
326
- 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]
327
361
  end
328
362
 
329
- execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", "Fixture Insert"
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")
379
+ end
380
+
381
+ 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?
396
+ end
397
+ end
398
+ end
330
399
  end
331
400
 
332
401
  def empty_insert_statement_value
@@ -358,6 +427,44 @@ module ActiveRecord
358
427
  alias join_to_delete join_to_update
359
428
 
360
429
  private
430
+ def default_insert_value(column)
431
+ Arel.sql("DEFAULT")
432
+ end
433
+
434
+ def build_fixture_sql(fixtures, table_name)
435
+ columns = schema_cache.columns_hash(table_name)
436
+
437
+ values = fixtures.map do |fixture|
438
+ fixture = fixture.stringify_keys
439
+
440
+ unknown_columns = fixture.keys - columns.keys
441
+ if unknown_columns.any?
442
+ raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
443
+ end
444
+
445
+ columns.map do |name, column|
446
+ if fixture.key?(name)
447
+ type = lookup_cast_type_from_column(column)
448
+ bind = Relation::QueryAttribute.new(name, fixture[name], type)
449
+ with_yaml_fallback(bind.value_for_database)
450
+ else
451
+ default_insert_value(column)
452
+ end
453
+ end
454
+ end
455
+
456
+ table = Arel::Table.new(table_name)
457
+ manager = Arel::InsertManager.new
458
+ manager.into(table)
459
+ columns.each_key { |column| manager.columns << table[column] }
460
+ manager.values = manager.create_values_list(values)
461
+
462
+ manager.to_sql
463
+ end
464
+
465
+ def combine_multi_statements(total_sql)
466
+ total_sql.join(";\n")
467
+ end
361
468
 
362
469
  # Returns a subquery for the given key using the join information.
363
470
  def subquery_for(key, select)
@@ -388,11 +495,45 @@ module ActiveRecord
388
495
  row && row.first
389
496
  end
390
497
 
391
- def binds_from_relation(relation, binds)
392
- if relation.is_a?(Relation) && binds.empty?
393
- relation, binds = relation.arel, relation.bound_attributes
498
+ def arel_from_relation(relation)
499
+ if relation.is_a?(Relation)
500
+ relation.arel
501
+ else
502
+ relation
503
+ end
504
+ 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]
394
536
  end
395
- [relation, binds]
396
537
  end
397
538
  end
398
539
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/map"
4
+
1
5
  module ActiveRecord
2
6
  module ConnectionAdapters # :nodoc:
3
7
  module QueryCache
@@ -28,17 +32,17 @@ module ActiveRecord
28
32
  end
29
33
 
30
34
  def enable_query_cache!
31
- @query_cache_enabled[connection_cache_key(Thread.current)] = true
35
+ @query_cache_enabled[connection_cache_key(current_thread)] = true
32
36
  connection.enable_query_cache! if active_connection?
33
37
  end
34
38
 
35
39
  def disable_query_cache!
36
- @query_cache_enabled.delete connection_cache_key(Thread.current)
40
+ @query_cache_enabled.delete connection_cache_key(current_thread)
37
41
  connection.disable_query_cache! if active_connection?
38
42
  end
39
43
 
40
44
  def query_cache_enabled
41
- @query_cache_enabled[connection_cache_key(Thread.current)]
45
+ @query_cache_enabled[connection_cache_key(current_thread)]
42
46
  end
43
47
  end
44
48
 
@@ -90,8 +94,13 @@ module ActiveRecord
90
94
 
91
95
  def select_all(arel, name = nil, binds = [], preparable: nil)
92
96
  if @query_cache_enabled && !locked?(arel)
93
- arel, binds = binds_from_relation arel, binds
94
- sql = to_sql(arel, binds)
97
+ 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
103
+
95
104
  cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
96
105
  else
97
106
  super
@@ -124,6 +133,7 @@ module ActiveRecord
124
133
  # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
125
134
  # queries should not be cached.
126
135
  def locked?(arel)
136
+ arel = arel.arel if arel.is_a?(Relation)
127
137
  arel.respond_to?(:locked) && arel.locked
128
138
  end
129
139
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/big_decimal/conversions"
2
4
  require "active_support/multibyte/chars"
3
5
 
@@ -5,21 +7,12 @@ module ActiveRecord
5
7
  module ConnectionAdapters # :nodoc:
6
8
  module Quoting
7
9
  # Quotes the column value to help prevent
8
- # {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
10
+ # {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
9
11
  def quote(value)
10
12
  value = id_value_for_database(value) if value.is_a?(Base)
11
13
 
12
- if value.respond_to?(:quoted_id)
13
- at = value.method(:quoted_id).source_location
14
- at &&= " at %s:%d" % at
15
-
16
- owner = value.method(:quoted_id).owner.to_s
17
- klass = value.class.to_s
18
- klass += "(#{owner})" unless owner == klass
19
-
20
- ActiveSupport::Deprecation.warn \
21
- "Defining #quoted_id is deprecated and will be ignored in Rails 5.2. (defined on #{klass}#{at})"
22
- return value.quoted_id
14
+ if value.respond_to?(:value_for_database)
15
+ value = value.value_for_database
23
16
  end
24
17
 
25
18
  _quote(value)
@@ -31,10 +24,6 @@ module ActiveRecord
31
24
  def type_cast(value, column = nil)
32
25
  value = id_value_for_database(value) if value.is_a?(Base)
33
26
 
34
- if value.respond_to?(:quoted_id) && value.respond_to?(:id)
35
- return value.id
36
- end
37
-
38
27
  if column
39
28
  value = type_cast_from_column(column, value)
40
29
  end
@@ -68,17 +57,6 @@ module ActiveRecord
68
57
  lookup_cast_type(column.sql_type)
69
58
  end
70
59
 
71
- def fetch_type_metadata(sql_type)
72
- cast_type = lookup_cast_type(sql_type)
73
- SqlTypeMetadata.new(
74
- sql_type: sql_type,
75
- type: cast_type.type,
76
- limit: cast_type.limit,
77
- precision: cast_type.precision,
78
- scale: cast_type.scale,
79
- )
80
- end
81
-
82
60
  # Quotes a string, escaping any ' (single quote) and \ (backslash)
83
61
  # characters.
84
62
  def quote_string(s)
@@ -117,19 +95,19 @@ module ActiveRecord
117
95
  end
118
96
 
119
97
  def quoted_true
120
- "'t'".freeze
98
+ "TRUE".freeze
121
99
  end
122
100
 
123
101
  def unquoted_true
124
- "t".freeze
102
+ true
125
103
  end
126
104
 
127
105
  def quoted_false
128
- "'f'".freeze
106
+ "FALSE".freeze
129
107
  end
130
108
 
131
109
  def unquoted_false
132
- "f".freeze
110
+ false
133
111
  end
134
112
 
135
113
  # Quote date/time values for use in SQL input. Includes microseconds
@@ -152,7 +130,8 @@ module ActiveRecord
152
130
  end
153
131
 
154
132
  def quoted_time(value) # :nodoc:
155
- quoted_date(value).sub(/\A2000-01-01 /, "")
133
+ value = value.change(year: 2000, month: 1, day: 1)
134
+ quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "")
156
135
  end
157
136
 
158
137
  def quoted_binary(value) # :nodoc:
@@ -168,6 +147,10 @@ module ActiveRecord
168
147
  end
169
148
 
170
149
  private
150
+ def lookup_cast_type(sql_type)
151
+ type_map.lookup(sql_type)
152
+ end
153
+
171
154
  def id_value_for_database(value)
172
155
  if primary_key = value.class.primary_key
173
156
  value.instance_variable_get(:@attributes)[primary_key].value_for_database
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module Savepoints
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/strip"
2
4
 
3
5
  module ActiveRecord
@@ -22,7 +24,7 @@ module ActiveRecord
22
24
  private
23
25
 
24
26
  def visit_AlterTable(o)
25
- sql = "ALTER TABLE #{quote_table_name(o.name)} "
27
+ sql = "ALTER TABLE #{quote_table_name(o.name)} ".dup
26
28
  sql << o.adds.map { |col| accept col }.join(" ")
27
29
  sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
28
30
  sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
@@ -30,17 +32,17 @@ module ActiveRecord
30
32
 
31
33
  def visit_ColumnDefinition(o)
32
34
  o.sql_type = type_to_sql(o.type, o.options)
33
- column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
35
+ column_sql = "#{quote_column_name(o.name)} #{o.sql_type}".dup
34
36
  add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
35
37
  column_sql
36
38
  end
37
39
 
38
40
  def visit_AddColumnDefinition(o)
39
- "ADD #{accept(o.column)}"
41
+ "ADD #{accept(o.column)}".dup
40
42
  end
41
43
 
42
44
  def visit_TableDefinition(o)
43
- create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
45
+ create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} ".dup
44
46
 
45
47
  statements = o.columns.map { |c| accept c }
46
48
  statements << accept(o.primary_keys) if o.primary_keys
@@ -55,7 +57,7 @@ module ActiveRecord
55
57
 
56
58
  create_sql << "(#{statements.join(', ')})" if statements.present?
57
59
  add_table_options!(create_sql, table_options(o))
58
- create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
60
+ create_sql << " AS #{to_sql(o.as)}" if o.as
59
61
  create_sql
60
62
  end
61
63
 
@@ -93,6 +95,7 @@ module ActiveRecord
93
95
  if options_sql = options[:options]
94
96
  create_sql << " #{options_sql}"
95
97
  end
98
+ create_sql
96
99
  end
97
100
 
98
101
  def column_options(o)
@@ -114,6 +117,11 @@ module ActiveRecord
114
117
  sql
115
118
  end
116
119
 
120
+ def to_sql(sql)
121
+ sql = sql.to_sql if sql.respond_to?(:to_sql)
122
+ sql
123
+ end
124
+
117
125
  def foreign_key_in_create(from_table, to_table, options)
118
126
  options = foreign_key_options(from_table, to_table, options)
119
127
  accept ForeignKeyDefinition.new(from_table, to_table, options)
@@ -133,5 +141,6 @@ module ActiveRecord
133
141
  end
134
142
  end
135
143
  end
144
+ SchemaCreation = AbstractAdapter::SchemaCreation # :nodoc:
136
145
  end
137
146
  end
@@ -1,9 +1,47 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters #:nodoc:
3
5
  # Abstract representation of an index definition on a table. Instances of
4
6
  # this type are typically created and returned by methods in database
5
- # adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
6
- IndexDefinition = Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using, :comment) #:nodoc:
7
+ # adapters. e.g. ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#indexes
8
+ class IndexDefinition # :nodoc:
9
+ attr_reader :table, :name, :unique, :columns, :lengths, :orders, :opclasses, :where, :type, :using, :comment
10
+
11
+ def initialize(
12
+ table, name,
13
+ unique = false,
14
+ columns = [],
15
+ lengths: {},
16
+ orders: {},
17
+ opclasses: {},
18
+ where: nil,
19
+ type: nil,
20
+ using: nil,
21
+ comment: nil
22
+ )
23
+ @table = table
24
+ @name = name
25
+ @unique = unique
26
+ @columns = columns
27
+ @lengths = concise_options(lengths)
28
+ @orders = concise_options(orders)
29
+ @opclasses = concise_options(opclasses)
30
+ @where = where
31
+ @type = type
32
+ @using = using
33
+ @comment = comment
34
+ end
35
+
36
+ private
37
+ def concise_options(options)
38
+ if columns.size == options.size && options.values.uniq.size == 1
39
+ options.values.first
40
+ else
41
+ options
42
+ end
43
+ end
44
+ end
7
45
 
8
46
  # Abstract representation of a column definition. Instances of this type
9
47
  # are typically created by methods in TableDefinition, and added to the
@@ -58,6 +96,11 @@ module ActiveRecord
58
96
  options[:primary_key] != default_primary_key
59
97
  end
60
98
 
99
+ def validate?
100
+ options.fetch(:validate, true)
101
+ end
102
+ alias validated? validate?
103
+
61
104
  def defined_for?(to_table_ord = nil, to_table: nil, **options)
62
105
  if to_table_ord
63
106
  self.to_table == to_table_ord.to_s
@@ -177,6 +220,7 @@ module ActiveRecord
177
220
  :decimal,
178
221
  :float,
179
222
  :integer,
223
+ :json,
180
224
  :string,
181
225
  :text,
182
226
  :time,
@@ -369,6 +413,9 @@ module ActiveRecord
369
413
  alias :belongs_to :references
370
414
 
371
415
  def new_column_definition(name, type, **options) # :nodoc:
416
+ if integer_like_primary_key?(type, options)
417
+ type = integer_like_primary_key_type(type, options)
418
+ end
372
419
  type = aliased_types(type.to_s, type)
373
420
  options[:primary_key] ||= type == :primary_key
374
421
  options[:null] = false if options[:primary_key]
@@ -383,6 +430,14 @@ module ActiveRecord
383
430
  def aliased_types(name, fallback)
384
431
  "timestamp" == name ? :datetime : fallback
385
432
  end
433
+
434
+ def integer_like_primary_key?(type, options)
435
+ options[:primary_key] && [:integer, :bigint].include?(type) && !options.key?(:default)
436
+ end
437
+
438
+ def integer_like_primary_key_type(type, options)
439
+ type
440
+ end
386
441
  end
387
442
 
388
443
  class AlterTable # :nodoc:
@@ -443,6 +498,9 @@ module ActiveRecord
443
498
  # t.date
444
499
  # t.binary
445
500
  # t.boolean
501
+ # t.foreign_key
502
+ # t.json
503
+ # t.virtual
446
504
  # t.remove
447
505
  # t.remove_references
448
506
  # t.remove_belongs_to
@@ -607,19 +665,19 @@ module ActiveRecord
607
665
 
608
666
  # Adds a foreign key.
609
667
  #
610
- # t.foreign_key(:authors)
668
+ # t.foreign_key(:authors)
611
669
  #
612
670
  # See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
613
- def foreign_key(*args) # :nodoc:
671
+ def foreign_key(*args)
614
672
  @base.add_foreign_key(name, *args)
615
673
  end
616
674
 
617
675
  # Checks to see if a foreign key exists.
618
676
  #
619
- # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
677
+ # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
620
678
  #
621
679
  # See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
622
- def foreign_key_exists?(*args) # :nodoc:
680
+ def foreign_key_exists?(*args)
623
681
  @base.foreign_key_exists?(name, *args)
624
682
  end
625
683
  end