activerecord 4.2.0 → 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 (274) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +640 -928
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -11
  5. data/examples/performance.rb +32 -31
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +264 -247
  8. data/lib/active_record/association_relation.rb +24 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +87 -41
  11. data/lib/active_record/associations/association_scope.rb +106 -132
  12. data/lib/active_record/associations/belongs_to_association.rb +55 -36
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +29 -38
  15. data/lib/active_record/associations/builder/belongs_to.rb +77 -30
  16. data/lib/active_record/associations/builder/collection_association.rb +14 -23
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
  18. data/lib/active_record/associations/builder/has_many.rb +6 -4
  19. data/lib/active_record/associations/builder/has_one.rb +13 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +15 -11
  21. data/lib/active_record/associations/collection_association.rb +145 -266
  22. data/lib/active_record/associations/collection_proxy.rb +242 -138
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +35 -75
  25. data/lib/active_record/associations/has_many_through_association.rb +51 -69
  26. data/lib/active_record/associations/has_one_association.rb +39 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -154
  32. data/lib/active_record/associations/preloader/association.rb +85 -116
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +83 -93
  35. data/lib/active_record/associations/singular_association.rb +27 -40
  36. data/lib/active_record/associations/through_association.rb +48 -23
  37. data/lib/active_record/associations.rb +1732 -1596
  38. data/lib/active_record/attribute_assignment.rb +58 -182
  39. data/lib/active_record/attribute_decorators.rb +39 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -125
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -71
  43. data/lib/active_record/attribute_methods/query.rb +4 -2
  44. data/lib/active_record/attribute_methods/read.rb +45 -63
  45. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
  47. data/lib/active_record/attribute_methods/write.rb +31 -46
  48. data/lib/active_record/attribute_methods.rb +170 -117
  49. data/lib/active_record/attributes.rb +201 -74
  50. data/lib/active_record/autosave_association.rb +118 -45
  51. data/lib/active_record/base.rb +60 -48
  52. data/lib/active_record/callbacks.rb +97 -57
  53. data/lib/active_record/coders/json.rb +3 -1
  54. data/lib/active_record/coders/yaml_column.rb +37 -13
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
  69. data/lib/active_record/connection_adapters/column.rb +50 -41
  70. data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
  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 +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  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 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
  117. data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +40 -27
  128. data/lib/active_record/core.rb +205 -202
  129. data/lib/active_record/counter_cache.rb +80 -37
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +87 -105
  132. data/lib/active_record/enum.rb +136 -90
  133. data/lib/active_record/errors.rb +180 -52
  134. data/lib/active_record/explain.rb +23 -11
  135. data/lib/active_record/explain_registry.rb +4 -2
  136. data/lib/active_record/explain_subscriber.rb +11 -6
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +193 -135
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +148 -112
  141. data/lib/active_record/integration.rb +70 -28
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +92 -98
  146. data/lib/active_record/locking/pessimistic.rb +15 -3
  147. data/lib/active_record/log_subscriber.rb +95 -33
  148. data/lib/active_record/migration/command_recorder.rb +133 -90
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +8 -6
  151. data/lib/active_record/migration.rb +594 -267
  152. data/lib/active_record/model_schema.rb +292 -111
  153. data/lib/active_record/nested_attributes.rb +266 -214
  154. data/lib/active_record/no_touching.rb +8 -2
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +350 -119
  157. data/lib/active_record/query_cache.rb +13 -24
  158. data/lib/active_record/querying.rb +19 -17
  159. data/lib/active_record/railtie.rb +117 -35
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +9 -3
  162. data/lib/active_record/railties/databases.rake +160 -174
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +447 -288
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +204 -55
  167. data/lib/active_record/relation/calculations.rb +259 -244
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +290 -253
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +91 -68
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
  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 +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  179. data/lib/active_record/relation/predicate_builder.rb +118 -92
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +446 -389
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +18 -16
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +287 -339
  187. data/lib/active_record/result.rb +54 -36
  188. data/lib/active_record/runtime_registry.rb +6 -4
  189. data/lib/active_record/sanitization.rb +155 -124
  190. data/lib/active_record/schema.rb +30 -24
  191. data/lib/active_record/schema_dumper.rb +91 -87
  192. data/lib/active_record/schema_migration.rb +19 -19
  193. data/lib/active_record/scoping/default.rb +102 -84
  194. data/lib/active_record/scoping/named.rb +81 -32
  195. data/lib/active_record/scoping.rb +45 -26
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +5 -5
  198. data/lib/active_record/statement_cache.rb +45 -35
  199. data/lib/active_record/store.rb +42 -36
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +136 -95
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
  206. data/lib/active_record/timestamp.rb +70 -38
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +208 -123
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +4 -41
  212. data/lib/active_record/type/date_time.rb +4 -38
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +30 -15
  218. data/lib/active_record/type/text.rb +2 -2
  219. data/lib/active_record/type/time.rb +11 -16
  220. data/lib/active_record/type/type_map.rb +15 -17
  221. data/lib/active_record/type/unsigned_integer.rb +9 -7
  222. data/lib/active_record/type.rb +79 -23
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +13 -4
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +14 -13
  230. data/lib/active_record/validations/uniqueness.rb +41 -32
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +36 -21
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
  237. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
  239. data/lib/rails/generators/active_record/migration.rb +18 -1
  240. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
  242. data/lib/rails/generators/active_record.rb +7 -5
  243. metadata +77 -53
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  251. data/lib/active_record/attribute.rb +0 -149
  252. data/lib/active_record/attribute_set/builder.rb +0 -86
  253. data/lib/active_record/attribute_set.rb +0 -77
  254. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  255. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  256. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  257. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  258. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  259. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  260. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  261. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  262. data/lib/active_record/type/big_integer.rb +0 -13
  263. data/lib/active_record/type/binary.rb +0 -50
  264. data/lib/active_record/type/boolean.rb +0 -30
  265. data/lib/active_record/type/decimal.rb +0 -40
  266. data/lib/active_record/type/decorator.rb +0 -14
  267. data/lib/active_record/type/float.rb +0 -19
  268. data/lib/active_record/type/integer.rb +0 -55
  269. data/lib/active_record/type/mutable.rb +0 -16
  270. data/lib/active_record/type/numeric.rb +0 -36
  271. data/lib/active_record/type/string.rb +0 -36
  272. data/lib/active_record/type/time_value.rb +0 -38
  273. data/lib/active_record/type/value.rb +0 -101
  274. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters # :nodoc:
3
5
  module DatabaseLimits
4
-
5
6
  # Returns the maximum length of a table alias.
6
7
  def table_alias_length
7
8
  255
@@ -18,9 +19,9 @@ module ActiveRecord
18
19
  end
19
20
 
20
21
  # Returns the maximum allowed length for an index name. This
21
- # limit is enforced by rails and Is less than or equal to
22
- # <tt>index_name_length</tt>. The gap between
23
- # <tt>index_name_length</tt> is to allow internal rails
22
+ # limit is enforced by \Rails and is less than or equal to
23
+ # #index_name_length. The gap between
24
+ # #index_name_length is to allow internal \Rails
24
25
  # operations to use prefixes in temporary operations.
25
26
  def allowed_index_name_length
26
27
  index_name_length
@@ -47,7 +48,7 @@ module ActiveRecord
47
48
  end
48
49
 
49
50
  # Returns the maximum number of elements in an IN (x,y,z) clause.
50
- # nil means no limit.
51
+ # +nil+ means no limit.
51
52
  def in_clause_length
52
53
  nil
53
54
  end
@@ -62,6 +63,10 @@ module ActiveRecord
62
63
  256
63
64
  end
64
65
 
66
+ private
67
+ def bind_params_length
68
+ 65535
69
+ end
65
70
  end
66
71
  end
67
72
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters # :nodoc:
3
5
  module DatabaseStatements
@@ -7,29 +9,66 @@ 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.dup, self)
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
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
- def cacheable_query(arel) # :nodoc:
46
+ def cacheable_query(klass, arel) # :nodoc:
22
47
  if prepared_statements
23
- ActiveRecord::StatementCache.query visitor, arel.ast
48
+ sql, binds = visitor.accept(arel.ast, collector).value
49
+ query = klass.query(sql)
24
50
  else
25
- ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector
51
+ collector = PartialQueryCollector.new
52
+ parts, binds = visitor.accept(arel.ast, collector).value
53
+ query = klass.partial_query(parts)
26
54
  end
55
+ [query, binds]
27
56
  end
28
57
 
29
58
  # Returns an ActiveRecord::Result instance.
30
- def select_all(arel, name = nil, binds = [])
31
- arel, binds = binds_from_relation arel, binds
32
- select(to_sql(arel, binds), name, binds)
59
+ def select_all(arel, name = nil, binds = [], preparable: nil)
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
65
+ end
66
+
67
+ if prepared_statements && preparable
68
+ select_prepared(sql, name, binds)
69
+ else
70
+ select(sql, name, binds)
71
+ end
33
72
  end
34
73
 
35
74
  # Returns a record hash with the column names as keys and column values
@@ -40,46 +79,61 @@ module ActiveRecord
40
79
 
41
80
  # Returns a single value from a record
42
81
  def select_value(arel, name = nil, binds = [])
43
- if result = select_one(arel, name, binds)
44
- result.values.first
45
- end
82
+ single_value_from_rows(select_rows(arel, name, binds))
46
83
  end
47
84
 
48
85
  # Returns an array of the values of the first column in a select:
49
86
  # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
50
- def select_values(arel, name = nil)
51
- arel, binds = binds_from_relation arel, []
52
- select_rows(to_sql(arel, binds), name, binds).map(&:first)
87
+ def select_values(arel, name = nil, binds = [])
88
+ select_rows(arel, name, binds).map(&:first)
53
89
  end
54
90
 
55
91
  # Returns an array of arrays containing the field values.
56
92
  # Order is the same as that returned by +columns+.
57
- def select_rows(sql, name = nil, binds = [])
93
+ def select_rows(arel, name = nil, binds = [])
94
+ select_all(arel, name, binds).rows
95
+ end
96
+
97
+ def query_value(sql, name = nil) # :nodoc:
98
+ single_value_from_rows(query(sql, name))
99
+ end
100
+
101
+ def query_values(sql, name = nil) # :nodoc:
102
+ query(sql, name).map(&:first)
58
103
  end
59
- undef_method :select_rows
60
104
 
61
- # Executes the SQL statement in the context of this connection.
105
+ def query(sql, name = nil) # :nodoc:
106
+ exec_query(sql, name).rows
107
+ end
108
+
109
+ # Executes the SQL statement in the context of this connection and returns
110
+ # the raw result from the connection adapter.
111
+ # Note: depending on your database connector, the result returned by this
112
+ # method may be manually memory managed. Consider using the exec_query
113
+ # wrapper instead.
62
114
  def execute(sql, name = nil)
115
+ raise NotImplementedError
63
116
  end
64
- undef_method :execute
65
117
 
66
118
  # Executes +sql+ statement in the context of this connection using
67
119
  # +binds+ as the bind substitutes. +name+ is logged along with
68
120
  # the executed +sql+ statement.
69
- def exec_query(sql, name = 'SQL', binds = [])
121
+ def exec_query(sql, name = "SQL", binds = [], prepare: false)
122
+ raise NotImplementedError
70
123
  end
71
124
 
72
125
  # Executes insert +sql+ statement in the context of this connection using
73
126
  # +binds+ as the bind substitutes. +name+ is logged along with
74
127
  # the executed +sql+ statement.
75
- def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
128
+ def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
129
+ sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
76
130
  exec_query(sql, name, binds)
77
131
  end
78
132
 
79
133
  # Executes delete +sql+ statement in the context of this connection using
80
134
  # +binds+ as the bind substitutes. +name+ is logged along with
81
135
  # the executed +sql+ statement.
82
- def exec_delete(sql, name, binds)
136
+ def exec_delete(sql, name = nil, binds = [])
83
137
  exec_query(sql, name, binds)
84
138
  end
85
139
 
@@ -91,39 +145,43 @@ module ActiveRecord
91
145
  # Executes update +sql+ statement in the context of this connection using
92
146
  # +binds+ as the bind substitutes. +name+ is logged along with
93
147
  # the executed +sql+ statement.
94
- def exec_update(sql, name, binds)
148
+ def exec_update(sql, name = nil, binds = [])
95
149
  exec_query(sql, name, binds)
96
150
  end
97
151
 
98
- # Returns the last auto-generated ID from the affected table.
152
+ # Executes an INSERT query and returns the new record's ID
99
153
  #
100
- # +id_value+ will be returned unless the value is nil, in
154
+ # +id_value+ will be returned unless the value is +nil+, in
101
155
  # which case the database will attempt to calculate the last inserted
102
156
  # id and return that value.
103
157
  #
104
158
  # If the next id was calculated in advance (as in Oracle), it should be
105
159
  # passed in as +id_value+.
106
160
  def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
107
- sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
108
- value = exec_insert(sql, name, binds, pk, sequence_name)
161
+ sql, binds = to_sql_and_binds(arel, binds)
162
+ value = exec_insert(sql, name, binds, pk, sequence_name)
109
163
  id_value || last_inserted_id(value)
110
164
  end
165
+ alias create insert
111
166
 
112
167
  # Executes the update statement and returns the number of rows affected.
113
168
  def update(arel, name = nil, binds = [])
114
- exec_update(to_sql(arel, binds), name, binds)
169
+ sql, binds = to_sql_and_binds(arel, binds)
170
+ exec_update(sql, name, binds)
115
171
  end
116
172
 
117
173
  # Executes the delete statement and returns the number of rows affected.
118
174
  def delete(arel, name = nil, binds = [])
119
- exec_delete(to_sql(arel, binds), name, binds)
175
+ sql, binds = to_sql_and_binds(arel, binds)
176
+ exec_delete(sql, name, binds)
120
177
  end
121
178
 
122
179
  # Returns +true+ when the connection adapter supports prepared statement
123
180
  # caching, otherwise returns +false+
124
- def supports_statement_cache?
125
- false
181
+ def supports_statement_cache? # :nodoc:
182
+ true
126
183
  end
184
+ deprecate :supports_statement_cache?
127
185
 
128
186
  # Runs the given block in a database transaction, and returns the result
129
187
  # of the block.
@@ -136,7 +194,7 @@ module ActiveRecord
136
194
  #
137
195
  # In order to get around this problem, #transaction will emulate the effect
138
196
  # of nested transactions, by using savepoints:
139
- # http://dev.mysql.com/doc/refman/5.0/en/savepoint.html
197
+ # https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
140
198
  # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
141
199
  # supports savepoints.
142
200
  #
@@ -188,29 +246,25 @@ module ActiveRecord
188
246
  # You should consult the documentation for your database to understand the
189
247
  # semantics of these different levels:
190
248
  #
191
- # * http://www.postgresql.org/docs/9.1/static/transaction-iso.html
192
- # * https://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
249
+ # * https://www.postgresql.org/docs/current/static/transaction-iso.html
250
+ # * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
193
251
  #
194
- # An <tt>ActiveRecord::TransactionIsolationError</tt> will be raised if:
252
+ # An ActiveRecord::TransactionIsolationError will be raised if:
195
253
  #
196
254
  # * The adapter does not support setting the isolation level
197
255
  # * You are joining an existing open transaction
198
256
  # * You are creating a nested (savepoint) transaction
199
257
  #
200
- # The mysql, mysql2 and postgresql adapters support setting the transaction
201
- # isolation level. However, support is disabled for MySQL versions below 5,
202
- # because they are affected by a bug[http://bugs.mysql.com/bug.php?id=39170]
203
- # which means the isolation level gets persisted outside the transaction.
204
- def transaction(options = {})
205
- options.assert_valid_keys :requires_new, :joinable, :isolation
206
-
207
- if !options[:requires_new] && current_transaction.joinable?
208
- if options[:isolation]
258
+ # The mysql2 and postgresql adapters support setting the transaction
259
+ # isolation level.
260
+ def transaction(requires_new: nil, isolation: nil, joinable: true)
261
+ if !requires_new && current_transaction.joinable?
262
+ if isolation
209
263
  raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
210
264
  end
211
265
  yield
212
266
  else
213
- transaction_manager.within_new_transaction(options) { yield }
267
+ transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
214
268
  end
215
269
  rescue ActiveRecord::Rollback
216
270
  # rollbacks are silently swallowed
@@ -225,7 +279,7 @@ module ActiveRecord
225
279
  end
226
280
 
227
281
  def reset_transaction #:nodoc:
228
- @transaction_manager = TransactionManager.new(self)
282
+ @transaction_manager = ConnectionAdapters::TransactionManager.new(self)
229
283
  end
230
284
 
231
285
  # Register a record with the current transaction so that its after_commit and after_rollback callbacks
@@ -234,6 +288,10 @@ module ActiveRecord
234
288
  current_transaction.add_record(record)
235
289
  end
236
290
 
291
+ def transaction_state
292
+ current_transaction.state
293
+ end
294
+
237
295
  # Begins the transaction (and turns off auto-committing).
238
296
  def begin_db_transaction() end
239
297
 
@@ -258,7 +316,15 @@ module ActiveRecord
258
316
 
259
317
  # Rolls back the transaction (and turns on auto-committing). Must be
260
318
  # done if the transaction block raises an exception or returns false.
261
- def rollback_db_transaction() end
319
+ def rollback_db_transaction
320
+ exec_rollback_db_transaction
321
+ end
322
+
323
+ def exec_rollback_db_transaction() end #:nodoc:
324
+
325
+ def rollback_to_savepoint(name = nil)
326
+ exec_rollback_to_savepoint(name)
327
+ end
262
328
 
263
329
  def default_sequence_name(table, column)
264
330
  nil
@@ -271,16 +337,65 @@ module ActiveRecord
271
337
 
272
338
  # Inserts the given fixture into the table. Overridden in adapters that require
273
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.
274
343
  def insert_fixture(fixture, table_name)
344
+ fixture = fixture.stringify_keys
345
+
275
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
276
355
 
277
- key_list = []
278
- value_list = fixture.map do |name, value|
279
- key_list << quote_column_name(name)
280
- quote(value, columns[name])
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]
281
361
  end
282
362
 
283
- 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
284
399
  end
285
400
 
286
401
  def empty_insert_statement_value
@@ -290,17 +405,12 @@ module ActiveRecord
290
405
  # Sanitizes the given LIMIT parameter in order to prevent SQL injection.
291
406
  #
292
407
  # The +limit+ may be anything that can evaluate to a string via #to_s. It
293
- # should look like an integer, or a comma-delimited list of integers, or
294
- # an Arel SQL literal.
408
+ # should look like an integer, or an Arel SQL literal.
295
409
  #
296
410
  # Returns Integer and Arel::Nodes::SqlLiteral limits as is.
297
- # Returns the sanitized limit parameter, either as an integer, or as a
298
- # string which contains a comma-delimited list of integers.
299
411
  def sanitize_limit(limit)
300
412
  if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
301
413
  limit
302
- elsif limit.to_s.include?(',')
303
- Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
304
414
  else
305
415
  Integer(limit)
306
416
  end
@@ -309,20 +419,52 @@ module ActiveRecord
309
419
  # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
310
420
  # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
311
421
  # an UPDATE statement, so in the MySQL adapters we redefine this to do that.
312
- def join_to_update(update, select) #:nodoc:
313
- key = update.key
422
+ def join_to_update(update, select, key) # :nodoc:
314
423
  subselect = subquery_for(key, select)
315
424
 
316
425
  update.where key.in(subselect)
317
426
  end
427
+ alias join_to_delete join_to_update
318
428
 
319
- def join_to_delete(delete, select, key) #:nodoc:
320
- subselect = subquery_for(key, select)
429
+ private
430
+ def default_insert_value(column)
431
+ Arel.sql("DEFAULT")
432
+ end
321
433
 
322
- delete.where key.in(subselect)
323
- end
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)
324
461
 
325
- protected
462
+ manager.to_sql
463
+ end
464
+
465
+ def combine_multi_statements(total_sql)
466
+ total_sql.join(";\n")
467
+ end
326
468
 
327
469
  # Returns a subquery for the given key using the join information.
328
470
  def subquery_for(key, select)
@@ -333,40 +475,65 @@ module ActiveRecord
333
475
 
334
476
  # Returns an ActiveRecord::Result instance.
335
477
  def select(sql, name = nil, binds = [])
336
- exec_query(sql, name, binds)
478
+ exec_query(sql, name, binds, prepare: false)
337
479
  end
338
480
 
481
+ def select_prepared(sql, name = nil, binds = [])
482
+ exec_query(sql, name, binds, prepare: true)
483
+ end
339
484
 
340
- # Returns the last auto-generated ID from the affected table.
341
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
342
- execute(sql, name)
343
- id_value
485
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
486
+ [sql, binds]
344
487
  end
345
488
 
346
- # Executes the update statement and returns the number of rows affected.
347
- def update_sql(sql, name = nil)
348
- execute(sql, name)
489
+ def last_inserted_id(result)
490
+ single_value_from_rows(result.rows)
349
491
  end
350
492
 
351
- # Executes the delete statement and returns the number of rows affected.
352
- def delete_sql(sql, name = nil)
353
- update_sql(sql, name)
493
+ def single_value_from_rows(rows)
494
+ row = rows.first
495
+ row && row.first
354
496
  end
355
497
 
356
- def sql_for_insert(sql, pk, id_value, sequence_name, binds)
357
- [sql, binds]
498
+ def arel_from_relation(relation)
499
+ if relation.is_a?(Relation)
500
+ relation.arel
501
+ else
502
+ relation
503
+ end
358
504
  end
359
505
 
360
- def last_inserted_id(result)
361
- row = result.rows.first
362
- row && row.first
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
363
515
  end
364
516
 
365
- def binds_from_relation(relation, binds)
366
- if relation.is_a?(Relation) && binds.empty?
367
- relation, binds = relation.arel, relation.bind_values
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]
368
536
  end
369
- [relation, binds]
370
537
  end
371
538
  end
372
539
  end