activerecord 5.1.7 → 5.2.0.beta1

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

Potentially problematic release.


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

Files changed (259) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +221 -900
  3. data/README.rdoc +3 -3
  4. data/examples/performance.rb +2 -0
  5. data/examples/simple.rb +2 -0
  6. data/lib/active_record.rb +10 -3
  7. data/lib/active_record/aggregations.rb +2 -0
  8. data/lib/active_record/association_relation.rb +2 -0
  9. data/lib/active_record/associations.rb +13 -42
  10. data/lib/active_record/associations/alias_tracker.rb +17 -17
  11. data/lib/active_record/associations/association.rb +11 -22
  12. data/lib/active_record/associations/association_scope.rb +32 -44
  13. data/lib/active_record/associations/belongs_to_association.rb +6 -4
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -1
  15. data/lib/active_record/associations/builder/association.rb +2 -5
  16. data/lib/active_record/associations/builder/belongs_to.rb +7 -12
  17. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  19. data/lib/active_record/associations/builder/has_many.rb +2 -0
  20. data/lib/active_record/associations/builder/has_one.rb +2 -0
  21. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  22. data/lib/active_record/associations/collection_association.rb +41 -33
  23. data/lib/active_record/associations/collection_proxy.rb +11 -14
  24. data/lib/active_record/associations/foreign_association.rb +2 -0
  25. data/lib/active_record/associations/has_many_association.rb +4 -2
  26. data/lib/active_record/associations/has_many_through_association.rb +4 -2
  27. data/lib/active_record/associations/has_one_association.rb +3 -1
  28. data/lib/active_record/associations/has_one_through_association.rb +3 -1
  29. data/lib/active_record/associations/join_dependency.rb +22 -40
  30. data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
  31. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  32. data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
  33. data/lib/active_record/associations/preloader.rb +17 -37
  34. data/lib/active_record/associations/preloader/association.rb +42 -58
  35. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  36. data/lib/active_record/associations/singular_association.rb +14 -10
  37. data/lib/active_record/associations/through_association.rb +3 -1
  38. data/lib/active_record/attribute_assignment.rb +2 -0
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods.rb +47 -7
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  42. data/lib/active_record/attribute_methods/dirty.rb +25 -214
  43. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  44. data/lib/active_record/attribute_methods/query.rb +2 -0
  45. data/lib/active_record/attribute_methods/read.rb +8 -2
  46. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  48. data/lib/active_record/attribute_methods/write.rb +21 -9
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +5 -11
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +6 -8
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +2 -0
  55. data/lib/active_record/collection_cache_key.rb +10 -5
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +120 -28
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -33
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +13 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +40 -2
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +103 -63
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +62 -90
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +75 -138
  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 +2 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +3 -1
  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 -6
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +91 -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.rb +2 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -11
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -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 +3 -1
  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 +3 -5
  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/quoting.rb +10 -0
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +2 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +11 -7
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +79 -65
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +47 -82
  116. data/lib/active_record/connection_adapters/schema_cache.rb +2 -0
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +19 -2
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  122. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  123. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
  124. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -89
  125. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  126. data/lib/active_record/connection_handling.rb +4 -2
  127. data/lib/active_record/core.rb +27 -57
  128. data/lib/active_record/counter_cache.rb +15 -12
  129. data/lib/active_record/define_callbacks.rb +5 -3
  130. data/lib/active_record/dynamic_matchers.rb +9 -9
  131. data/lib/active_record/enum.rb +15 -13
  132. data/lib/active_record/errors.rb +54 -21
  133. data/lib/active_record/explain.rb +3 -1
  134. data/lib/active_record/explain_registry.rb +2 -0
  135. data/lib/active_record/explain_subscriber.rb +2 -0
  136. data/lib/active_record/fixture_set/file.rb +2 -0
  137. data/lib/active_record/fixtures.rb +40 -24
  138. data/lib/active_record/gem_version.rb +5 -3
  139. data/lib/active_record/inheritance.rb +6 -5
  140. data/lib/active_record/integration.rb +58 -19
  141. data/lib/active_record/internal_metadata.rb +2 -0
  142. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  143. data/lib/active_record/locking/optimistic.rb +31 -20
  144. data/lib/active_record/locking/pessimistic.rb +10 -7
  145. data/lib/active_record/log_subscriber.rb +2 -0
  146. data/lib/active_record/migration.rb +47 -21
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +20 -2
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/model_schema.rb +29 -38
  151. data/lib/active_record/nested_attributes.rb +18 -6
  152. data/lib/active_record/no_touching.rb +3 -1
  153. data/lib/active_record/null_relation.rb +2 -0
  154. data/lib/active_record/persistence.rb +184 -40
  155. data/lib/active_record/query_cache.rb +17 -12
  156. data/lib/active_record/querying.rb +3 -1
  157. data/lib/active_record/railtie.rb +54 -1
  158. data/lib/active_record/railties/console_sandbox.rb +2 -0
  159. data/lib/active_record/railties/controller_runtime.rb +2 -0
  160. data/lib/active_record/railties/databases.rake +41 -28
  161. data/lib/active_record/readonly_attributes.rb +3 -2
  162. data/lib/active_record/reflection.rb +100 -182
  163. data/lib/active_record/relation.rb +61 -193
  164. data/lib/active_record/relation/batches.rb +20 -5
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  166. data/lib/active_record/relation/calculations.rb +40 -23
  167. data/lib/active_record/relation/delegation.rb +10 -27
  168. data/lib/active_record/relation/finder_methods.rb +53 -49
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +22 -19
  171. data/lib/active_record/relation/predicate_builder.rb +42 -79
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +54 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -6
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  179. data/lib/active_record/relation/query_attribute.rb +9 -2
  180. data/lib/active_record/relation/query_methods.rb +80 -69
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +2 -0
  183. data/lib/active_record/relation/where_clause.rb +50 -67
  184. data/lib/active_record/relation/where_clause_factory.rb +4 -46
  185. data/lib/active_record/result.rb +2 -0
  186. data/lib/active_record/runtime_registry.rb +2 -0
  187. data/lib/active_record/sanitization.rb +15 -9
  188. data/lib/active_record/schema.rb +3 -1
  189. data/lib/active_record/schema_dumper.rb +24 -23
  190. data/lib/active_record/schema_migration.rb +2 -0
  191. data/lib/active_record/scoping.rb +9 -8
  192. data/lib/active_record/scoping/default.rb +6 -7
  193. data/lib/active_record/scoping/named.rb +15 -7
  194. data/lib/active_record/secure_token.rb +2 -0
  195. data/lib/active_record/serialization.rb +2 -0
  196. data/lib/active_record/statement_cache.rb +22 -12
  197. data/lib/active_record/store.rb +2 -0
  198. data/lib/active_record/suppressor.rb +2 -0
  199. data/lib/active_record/table_metadata.rb +3 -1
  200. data/lib/active_record/tasks/database_tasks.rb +23 -12
  201. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  202. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  203. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  204. data/lib/active_record/timestamp.rb +5 -12
  205. data/lib/active_record/touch_later.rb +2 -0
  206. data/lib/active_record/transactions.rb +9 -7
  207. data/lib/active_record/translation.rb +2 -0
  208. data/lib/active_record/type.rb +4 -1
  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 +2 -4
  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_caster.rb +2 -0
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +2 -0
  224. data/lib/active_record/validations.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/version.rb +2 -0
  231. data/lib/rails/generators/active_record.rb +3 -1
  232. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  233. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  234. data/lib/rails/generators/active_record/migration.rb +2 -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/model/model_generator.rb +2 -23
  239. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  241. metadata +25 -38
  242. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  243. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  244. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  245. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  246. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  248. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  249. data/lib/active_record/attribute.rb +0 -240
  250. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  251. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  252. data/lib/active_record/attribute_set.rb +0 -113
  253. data/lib/active_record/attribute_set/builder.rb +0 -126
  254. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  255. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  256. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  257. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  258. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  259. 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 DatabaseLimits
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters # :nodoc:
3
5
  module DatabaseStatements
@@ -7,30 +9,43 @@ 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
+ sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value
24
+ [sql.freeze, binds || []]
14
25
  else
15
- arel.dup.freeze
26
+ [arel_or_sql_string.dup.freeze, binds]
16
27
  end
17
28
  end
29
+ private :to_sql_and_binds
18
30
 
19
31
  # This is used in the StatementCache object. It returns an object that
20
32
  # can be used to query the database repeatedly.
21
33
  def cacheable_query(klass, arel) # :nodoc:
22
- collected = visitor.accept(arel.ast, collector)
23
34
  if prepared_statements
24
- klass.query(collected.value)
35
+ sql, binds = visitor.accept(arel.ast, collector).value
36
+ query = klass.query(sql)
25
37
  else
26
- klass.partial_query(collected.value)
38
+ collector = PartialQueryCollector.new
39
+ parts, binds = visitor.accept(arel.ast, collector).value
40
+ query = klass.partial_query(parts)
27
41
  end
42
+ [query, binds]
28
43
  end
29
44
 
30
45
  # Returns an ActiveRecord::Result instance.
31
46
  def select_all(arel, name = nil, binds = [], preparable: nil)
32
- arel, binds = binds_from_relation arel, binds
33
- sql = to_sql(arel, binds)
47
+ arel = arel_from_relation(arel)
48
+ sql, binds = to_sql_and_binds(arel, binds)
34
49
  if !prepared_statements || (arel.is_a?(String) && preparable.nil?)
35
50
  preparable = false
36
51
  else
@@ -130,26 +145,30 @@ module ActiveRecord
130
145
  # If the next id was calculated in advance (as in Oracle), it should be
131
146
  # passed in as +id_value+.
132
147
  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)
148
+ sql, binds = to_sql_and_binds(arel, binds)
149
+ value = exec_insert(sql, name, binds, pk, sequence_name)
134
150
  id_value || last_inserted_id(value)
135
151
  end
136
152
  alias create insert
137
153
 
138
154
  # Executes the update statement and returns the number of rows affected.
139
155
  def update(arel, name = nil, binds = [])
140
- exec_update(to_sql(arel, binds), name, binds)
156
+ sql, binds = to_sql_and_binds(arel, binds)
157
+ exec_update(sql, name, binds)
141
158
  end
142
159
 
143
160
  # Executes the delete statement and returns the number of rows affected.
144
161
  def delete(arel, name = nil, binds = [])
145
- exec_delete(to_sql(arel, binds), name, binds)
162
+ sql, binds = to_sql_and_binds(arel, binds)
163
+ exec_delete(sql, name, binds)
146
164
  end
147
165
 
148
166
  # Returns +true+ when the connection adapter supports prepared statement
149
167
  # caching, otherwise returns +false+
150
- def supports_statement_cache?
151
- false
168
+ def supports_statement_cache? # :nodoc:
169
+ true
152
170
  end
171
+ deprecate :supports_statement_cache?
153
172
 
154
173
  # Runs the given block in a database transaction, and returns the result
155
174
  # of the block.
@@ -162,7 +181,7 @@ module ActiveRecord
162
181
  #
163
182
  # In order to get around this problem, #transaction will emulate the effect
164
183
  # of nested transactions, by using savepoints:
165
- # http://dev.mysql.com/doc/refman/5.7/en/savepoint.html
184
+ # https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
166
185
  # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
167
186
  # supports savepoints.
168
187
  #
@@ -214,7 +233,7 @@ module ActiveRecord
214
233
  # You should consult the documentation for your database to understand the
215
234
  # semantics of these different levels:
216
235
  #
217
- # * http://www.postgresql.org/docs/current/static/transaction-iso.html
236
+ # * https://www.postgresql.org/docs/current/static/transaction-iso.html
218
237
  # * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
219
238
  #
220
239
  # An ActiveRecord::TransactionIsolationError will be raised if:
@@ -305,6 +324,9 @@ module ActiveRecord
305
324
 
306
325
  # Inserts the given fixture into the table. Overridden in adapters that require
307
326
  # something beyond a simple insert (eg. Oracle).
327
+ # Most of adapters should implement `insert_fixtures` that leverages bulk SQL insert.
328
+ # We keep this method to provide fallback
329
+ # for databases like sqlite that do not support bulk inserts.
308
330
  def insert_fixture(fixture, table_name)
309
331
  fixture = fixture.stringify_keys
310
332
 
@@ -317,16 +339,52 @@ module ActiveRecord
317
339
  raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
318
340
  end
319
341
  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))
342
+
343
+ table = Arel::Table.new(table_name)
344
+
345
+ values = binds.map do |bind|
346
+ value = with_yaml_fallback(bind.value_for_database)
347
+ [table[bind.name], value]
348
+ end
349
+
350
+ manager = Arel::InsertManager.new
351
+ manager.into(table)
352
+ manager.insert(values)
353
+ execute manager.to_sql, "Fixture Insert"
354
+ end
355
+
356
+ # Inserts a set of fixtures into the table. Overridden in adapters that require
357
+ # something beyond a simple insert (eg. Oracle).
358
+ def insert_fixtures(fixtures, table_name)
359
+ return if fixtures.empty?
360
+
361
+ columns = schema_cache.columns_hash(table_name)
362
+
363
+ values = fixtures.map do |fixture|
364
+ fixture = fixture.stringify_keys
365
+
366
+ unknown_columns = fixture.keys - columns.keys
367
+ if unknown_columns.any?
368
+ raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
369
+ end
370
+
371
+ columns.map do |name, column|
372
+ if fixture.key?(name)
373
+ type = lookup_cast_type_from_column(column)
374
+ bind = Relation::QueryAttribute.new(name, fixture[name], type)
375
+ with_yaml_fallback(bind.value_for_database)
376
+ else
377
+ Arel.sql("DEFAULT")
378
+ end
326
379
  end
327
380
  end
328
381
 
329
- execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", "Fixture Insert"
382
+ table = Arel::Table.new(table_name)
383
+ manager = Arel::InsertManager.new
384
+ manager.into(table)
385
+ columns.each_key { |column| manager.columns << table[column] }
386
+ manager.values = manager.create_values_list(values)
387
+ execute manager.to_sql, "Fixtures Insert"
330
388
  end
331
389
 
332
390
  def empty_insert_statement_value
@@ -388,11 +446,45 @@ module ActiveRecord
388
446
  row && row.first
389
447
  end
390
448
 
391
- def binds_from_relation(relation, binds)
392
- if relation.is_a?(Relation) && binds.empty?
393
- relation, binds = relation.arel, relation.bound_attributes
449
+ def arel_from_relation(relation)
450
+ if relation.is_a?(Relation)
451
+ relation.arel
452
+ else
453
+ relation
454
+ end
455
+ end
456
+
457
+ # Fixture value is quoted by Arel, however scalar values
458
+ # are not quotable. In this case we want to convert
459
+ # the column value to YAML.
460
+ def with_yaml_fallback(value)
461
+ if value.is_a?(Hash) || value.is_a?(Array)
462
+ YAML.dump(value)
463
+ else
464
+ value
465
+ end
466
+ end
467
+
468
+ class PartialQueryCollector
469
+ def initialize
470
+ @parts = []
471
+ @binds = []
472
+ end
473
+
474
+ def <<(str)
475
+ @parts << str
476
+ self
477
+ end
478
+
479
+ def add_bind(obj)
480
+ @binds << obj
481
+ @parts << Arel::Nodes::BindParam.new(1)
482
+ self
483
+ end
484
+
485
+ def value
486
+ [@parts, @binds]
394
487
  end
395
- [relation, binds]
396
488
  end
397
489
  end
398
490
  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
@@ -90,8 +94,8 @@ 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)
95
99
  cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
96
100
  else
97
101
  super
@@ -124,6 +128,7 @@ module ActiveRecord
124
128
  # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
125
129
  # queries should not be cached.
126
130
  def locked?(arel)
131
+ arel = arel.arel if arel.is_a?(Relation)
127
132
  arel.respond_to?(:locked) && arel.locked
128
133
  end
129
134
 
@@ -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,8 +130,7 @@ module ActiveRecord
152
130
  end
153
131
 
154
132
  def quoted_time(value) # :nodoc:
155
- value = value.change(year: 2000, month: 1, day: 1)
156
- quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "")
133
+ quoted_date(value).sub(/\A2000-01-01 /, "")
157
134
  end
158
135
 
159
136
  def quoted_binary(value) # :nodoc:
@@ -169,6 +146,10 @@ module ActiveRecord
169
146
  end
170
147
 
171
148
  private
149
+ def lookup_cast_type(sql_type)
150
+ type_map.lookup(sql_type)
151
+ end
152
+
172
153
  def id_value_for_database(value)
173
154
  if primary_key = value.class.primary_key
174
155
  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
 
@@ -114,6 +116,11 @@ module ActiveRecord
114
116
  sql
115
117
  end
116
118
 
119
+ def to_sql(sql)
120
+ sql = sql.to_sql if sql.respond_to?(:to_sql)
121
+ sql
122
+ end
123
+
117
124
  def foreign_key_in_create(from_table, to_table, options)
118
125
  options = foreign_key_options(from_table, to_table, options)
119
126
  accept ForeignKeyDefinition.new(from_table, to_table, options)
@@ -133,5 +140,6 @@ module ActiveRecord
133
140
  end
134
141
  end
135
142
  end
143
+ SchemaCreation = AbstractAdapter::SchemaCreation # :nodoc:
136
144
  end
137
145
  end
@@ -1,9 +1,36 @@
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, :where, :type, :using, :comment
10
+
11
+ def initialize(
12
+ table, name,
13
+ unique = false,
14
+ columns = [],
15
+ lengths: {},
16
+ orders: {},
17
+ where: nil,
18
+ type: nil,
19
+ using: nil,
20
+ comment: nil
21
+ )
22
+ @table = table
23
+ @name = name
24
+ @unique = unique
25
+ @columns = columns
26
+ @lengths = lengths
27
+ @orders = orders
28
+ @where = where
29
+ @type = type
30
+ @using = using
31
+ @comment = comment
32
+ end
33
+ end
7
34
 
8
35
  # Abstract representation of a column definition. Instances of this type
9
36
  # are typically created by methods in TableDefinition, and added to the
@@ -369,6 +396,9 @@ module ActiveRecord
369
396
  alias :belongs_to :references
370
397
 
371
398
  def new_column_definition(name, type, **options) # :nodoc:
399
+ if integer_like_primary_key?(type, options)
400
+ type = integer_like_primary_key_type(type, options)
401
+ end
372
402
  type = aliased_types(type.to_s, type)
373
403
  options[:primary_key] ||= type == :primary_key
374
404
  options[:null] = false if options[:primary_key]
@@ -383,6 +413,14 @@ module ActiveRecord
383
413
  def aliased_types(name, fallback)
384
414
  "timestamp" == name ? :datetime : fallback
385
415
  end
416
+
417
+ def integer_like_primary_key?(type, options)
418
+ options[:primary_key] && [:integer, :bigint].include?(type) && !options.key?(:default)
419
+ end
420
+
421
+ def integer_like_primary_key_type(type, options)
422
+ type
423
+ end
386
424
  end
387
425
 
388
426
  class AlterTable # :nodoc: