activerecord 4.2.11.3 → 5.0.7.2

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

Potentially problematic release.


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

Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1638 -1132
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +7 -2
  8. data/lib/active_record/aggregations.rb +34 -21
  9. data/lib/active_record/association_relation.rb +7 -4
  10. data/lib/active_record/associations.rb +347 -218
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +22 -10
  13. data/lib/active_record/associations/association_scope.rb +75 -104
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +13 -11
  22. data/lib/active_record/associations/collection_association.rb +85 -69
  23. data/lib/active_record/associations/collection_proxy.rb +104 -46
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +21 -78
  26. data/lib/active_record/associations/has_many_through_association.rb +6 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +38 -22
  29. data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +14 -4
  32. data/lib/active_record/associations/preloader/association.rb +52 -71
  33. data/lib/active_record/associations/preloader/collection_association.rb +0 -7
  34. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +36 -17
  38. data/lib/active_record/associations/singular_association.rb +13 -1
  39. data/lib/active_record/associations/through_association.rb +12 -4
  40. data/lib/active_record/attribute.rb +69 -19
  41. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  42. data/lib/active_record/attribute_assignment.rb +19 -140
  43. data/lib/active_record/attribute_decorators.rb +6 -5
  44. data/lib/active_record/attribute_methods.rb +69 -44
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  46. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  47. data/lib/active_record/attribute_methods/primary_key.rb +16 -3
  48. data/lib/active_record/attribute_methods/query.rb +2 -2
  49. data/lib/active_record/attribute_methods/read.rb +31 -59
  50. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  52. data/lib/active_record/attribute_methods/write.rb +13 -37
  53. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  54. data/lib/active_record/attribute_set.rb +32 -3
  55. data/lib/active_record/attribute_set/builder.rb +42 -16
  56. data/lib/active_record/attributes.rb +199 -81
  57. data/lib/active_record/autosave_association.rb +54 -17
  58. data/lib/active_record/base.rb +32 -23
  59. data/lib/active_record/callbacks.rb +39 -43
  60. data/lib/active_record/coders/json.rb +1 -1
  61. data/lib/active_record/coders/yaml_column.rb +20 -8
  62. data/lib/active_record/collection_cache_key.rb +50 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
  76. data/lib/active_record/connection_adapters/column.rb +28 -43
  77. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  78. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  79. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  80. data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
  81. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  82. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  87. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
  88. data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
  89. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
  90. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
  93. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  99. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  102. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
  116. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  121. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
  122. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  123. data/lib/active_record/connection_handling.rb +37 -14
  124. data/lib/active_record/core.rb +92 -108
  125. data/lib/active_record/counter_cache.rb +13 -24
  126. data/lib/active_record/dynamic_matchers.rb +1 -20
  127. data/lib/active_record/enum.rb +116 -76
  128. data/lib/active_record/errors.rb +87 -48
  129. data/lib/active_record/explain.rb +20 -9
  130. data/lib/active_record/explain_registry.rb +1 -1
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +26 -5
  133. data/lib/active_record/fixtures.rb +77 -41
  134. data/lib/active_record/gem_version.rb +4 -4
  135. data/lib/active_record/inheritance.rb +32 -40
  136. data/lib/active_record/integration.rb +17 -14
  137. data/lib/active_record/internal_metadata.rb +56 -0
  138. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  139. data/lib/active_record/locale/en.yml +3 -2
  140. data/lib/active_record/locking/optimistic.rb +15 -15
  141. data/lib/active_record/locking/pessimistic.rb +1 -1
  142. data/lib/active_record/log_subscriber.rb +48 -24
  143. data/lib/active_record/migration.rb +362 -111
  144. data/lib/active_record/migration/command_recorder.rb +59 -18
  145. data/lib/active_record/migration/compatibility.rb +126 -0
  146. data/lib/active_record/model_schema.rb +270 -73
  147. data/lib/active_record/nested_attributes.rb +58 -29
  148. data/lib/active_record/no_touching.rb +4 -0
  149. data/lib/active_record/null_relation.rb +16 -8
  150. data/lib/active_record/persistence.rb +152 -90
  151. data/lib/active_record/query_cache.rb +18 -23
  152. data/lib/active_record/querying.rb +12 -11
  153. data/lib/active_record/railtie.rb +23 -16
  154. data/lib/active_record/railties/controller_runtime.rb +1 -1
  155. data/lib/active_record/railties/databases.rake +52 -41
  156. data/lib/active_record/readonly_attributes.rb +1 -1
  157. data/lib/active_record/reflection.rb +302 -115
  158. data/lib/active_record/relation.rb +187 -120
  159. data/lib/active_record/relation/batches.rb +141 -36
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  161. data/lib/active_record/relation/calculations.rb +92 -117
  162. data/lib/active_record/relation/delegation.rb +8 -20
  163. data/lib/active_record/relation/finder_methods.rb +173 -89
  164. data/lib/active_record/relation/from_clause.rb +32 -0
  165. data/lib/active_record/relation/merger.rb +16 -42
  166. data/lib/active_record/relation/predicate_builder.rb +120 -107
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  168. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  169. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  170. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  171. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  173. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  175. data/lib/active_record/relation/query_attribute.rb +19 -0
  176. data/lib/active_record/relation/query_methods.rb +308 -244
  177. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  178. data/lib/active_record/relation/spawn_methods.rb +4 -7
  179. data/lib/active_record/relation/where_clause.rb +174 -0
  180. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  181. data/lib/active_record/result.rb +11 -4
  182. data/lib/active_record/runtime_registry.rb +1 -1
  183. data/lib/active_record/sanitization.rb +105 -66
  184. data/lib/active_record/schema.rb +26 -22
  185. data/lib/active_record/schema_dumper.rb +54 -37
  186. data/lib/active_record/schema_migration.rb +11 -14
  187. data/lib/active_record/scoping.rb +34 -16
  188. data/lib/active_record/scoping/default.rb +28 -10
  189. data/lib/active_record/scoping/named.rb +59 -26
  190. data/lib/active_record/secure_token.rb +38 -0
  191. data/lib/active_record/serialization.rb +3 -5
  192. data/lib/active_record/statement_cache.rb +17 -15
  193. data/lib/active_record/store.rb +8 -3
  194. data/lib/active_record/suppressor.rb +58 -0
  195. data/lib/active_record/table_metadata.rb +69 -0
  196. data/lib/active_record/tasks/database_tasks.rb +66 -49
  197. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  198. data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
  199. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  200. data/lib/active_record/timestamp.rb +20 -9
  201. data/lib/active_record/touch_later.rb +63 -0
  202. data/lib/active_record/transactions.rb +139 -57
  203. data/lib/active_record/type.rb +66 -17
  204. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  205. data/lib/active_record/type/date.rb +2 -45
  206. data/lib/active_record/type/date_time.rb +2 -49
  207. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  208. data/lib/active_record/type/internal/timezone.rb +15 -0
  209. data/lib/active_record/type/serialized.rb +15 -14
  210. data/lib/active_record/type/time.rb +10 -16
  211. data/lib/active_record/type/type_map.rb +4 -4
  212. data/lib/active_record/type_caster.rb +7 -0
  213. data/lib/active_record/type_caster/connection.rb +29 -0
  214. data/lib/active_record/type_caster/map.rb +19 -0
  215. data/lib/active_record/validations.rb +33 -32
  216. data/lib/active_record/validations/absence.rb +23 -0
  217. data/lib/active_record/validations/associated.rb +10 -3
  218. data/lib/active_record/validations/length.rb +24 -0
  219. data/lib/active_record/validations/presence.rb +11 -12
  220. data/lib/active_record/validations/uniqueness.rb +33 -33
  221. data/lib/rails/generators/active_record/migration.rb +15 -0
  222. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
  223. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  224. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
  226. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  227. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  228. metadata +58 -34
  229. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  230. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  231. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  232. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  233. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  234. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  235. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  236. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  237. data/lib/active_record/type/big_integer.rb +0 -13
  238. data/lib/active_record/type/binary.rb +0 -50
  239. data/lib/active_record/type/boolean.rb +0 -31
  240. data/lib/active_record/type/decimal.rb +0 -64
  241. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  242. data/lib/active_record/type/decorator.rb +0 -14
  243. data/lib/active_record/type/float.rb +0 -19
  244. data/lib/active_record/type/integer.rb +0 -59
  245. data/lib/active_record/type/mutable.rb +0 -16
  246. data/lib/active_record/type/numeric.rb +0 -36
  247. data/lib/active_record/type/string.rb +0 -40
  248. data/lib/active_record/type/text.rb +0 -11
  249. data/lib/active_record/type/time_value.rb +0 -38
  250. data/lib/active_record/type/unsigned_integer.rb +0 -15
  251. data/lib/active_record/type/value.rb +0 -110
@@ -18,9 +18,9 @@ module ActiveRecord
18
18
  end
19
19
 
20
20
  # 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
21
+ # limit is enforced by \Rails and is less than or equal to
22
+ # #index_name_length. The gap between
23
+ # #index_name_length is to allow internal \Rails
24
24
  # operations to use prefixes in temporary operations.
25
25
  def allowed_index_name_length
26
26
  index_name_length
@@ -27,9 +27,19 @@ module ActiveRecord
27
27
  end
28
28
 
29
29
  # Returns an ActiveRecord::Result instance.
30
- def select_all(arel, name = nil, binds = [])
30
+ def select_all(arel, name = nil, binds = [], preparable: nil)
31
31
  arel, binds = binds_from_relation arel, binds
32
- select(to_sql(arel, binds), name, binds)
32
+ sql = to_sql(arel, binds)
33
+ if !prepared_statements || (arel.is_a?(String) && preparable.nil?)
34
+ preparable = false
35
+ else
36
+ preparable = visitor.preparable
37
+ end
38
+ if prepared_statements && preparable
39
+ select_prepared(sql, name, binds)
40
+ else
41
+ select(sql, name, binds)
42
+ end
33
43
  end
34
44
 
35
45
  # Returns a record hash with the column names as keys and column values
@@ -40,33 +50,39 @@ module ActiveRecord
40
50
 
41
51
  # Returns a single value from a record
42
52
  def select_value(arel, name = nil, binds = [])
43
- if result = select_one(arel, name, binds)
44
- result.values.first
53
+ arel, binds = binds_from_relation arel, binds
54
+ if result = select_rows(to_sql(arel, binds), name, binds).first
55
+ result.first
45
56
  end
46
57
  end
47
58
 
48
59
  # Returns an array of the values of the first column in a select:
49
60
  # 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, []
61
+ def select_values(arel, name = nil, binds = [])
62
+ arel, binds = binds_from_relation arel, binds
52
63
  select_rows(to_sql(arel, binds), name, binds).map(&:first)
53
64
  end
54
65
 
55
66
  # Returns an array of arrays containing the field values.
56
67
  # Order is the same as that returned by +columns+.
57
68
  def select_rows(sql, name = nil, binds = [])
69
+ exec_query(sql, name, binds).rows
58
70
  end
59
- undef_method :select_rows
60
71
 
61
- # Executes the SQL statement in the context of this connection.
72
+ # Executes the SQL statement in the context of this connection and returns
73
+ # the raw result from the connection adapter.
74
+ # Note: depending on your database connector, the result returned by this
75
+ # method may be manually memory managed. Consider using the exec_query
76
+ # wrapper instead.
62
77
  def execute(sql, name = nil)
78
+ raise NotImplementedError
63
79
  end
64
- undef_method :execute
65
80
 
66
81
  # Executes +sql+ statement in the context of this connection using
67
82
  # +binds+ as the bind substitutes. +name+ is logged along with
68
83
  # the executed +sql+ statement.
69
- def exec_query(sql, name = 'SQL', binds = [])
84
+ def exec_query(sql, name = 'SQL', binds = [], prepare: false)
85
+ raise NotImplementedError
70
86
  end
71
87
 
72
88
  # Executes insert +sql+ statement in the context of this connection using
@@ -95,7 +111,7 @@ module ActiveRecord
95
111
  exec_query(sql, name, binds)
96
112
  end
97
113
 
98
- # Returns the last auto-generated ID from the affected table.
114
+ # Executes an INSERT query and returns the new record's ID
99
115
  #
100
116
  # +id_value+ will be returned unless the value is nil, in
101
117
  # which case the database will attempt to calculate the last inserted
@@ -104,20 +120,27 @@ module ActiveRecord
104
120
  # If the next id was calculated in advance (as in Oracle), it should be
105
121
  # passed in as +id_value+.
106
122
  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)
123
+ sql, binds, pk, sequence_name = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
124
+ value = exec_insert(sql, name, binds, pk, sequence_name)
109
125
  id_value || last_inserted_id(value)
110
126
  end
127
+ alias create insert
128
+ alias insert_sql insert
129
+ deprecate insert_sql: :insert
111
130
 
112
131
  # Executes the update statement and returns the number of rows affected.
113
132
  def update(arel, name = nil, binds = [])
114
133
  exec_update(to_sql(arel, binds), name, binds)
115
134
  end
135
+ alias update_sql update
136
+ deprecate update_sql: :update
116
137
 
117
138
  # Executes the delete statement and returns the number of rows affected.
118
139
  def delete(arel, name = nil, binds = [])
119
140
  exec_delete(to_sql(arel, binds), name, binds)
120
141
  end
142
+ alias delete_sql delete
143
+ deprecate delete_sql: :delete
121
144
 
122
145
  # Returns +true+ when the connection adapter supports prepared statement
123
146
  # caching, otherwise returns +false+
@@ -136,7 +159,7 @@ module ActiveRecord
136
159
  #
137
160
  # In order to get around this problem, #transaction will emulate the effect
138
161
  # of nested transactions, by using savepoints:
139
- # http://dev.mysql.com/doc/refman/5.0/en/savepoint.html
162
+ # http://dev.mysql.com/doc/refman/5.7/en/savepoint.html
140
163
  # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
141
164
  # supports savepoints.
142
165
  #
@@ -188,29 +211,25 @@ module ActiveRecord
188
211
  # You should consult the documentation for your database to understand the
189
212
  # semantics of these different levels:
190
213
  #
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
214
+ # * http://www.postgresql.org/docs/current/static/transaction-iso.html
215
+ # * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
193
216
  #
194
- # An <tt>ActiveRecord::TransactionIsolationError</tt> will be raised if:
217
+ # An ActiveRecord::TransactionIsolationError will be raised if:
195
218
  #
196
219
  # * The adapter does not support setting the isolation level
197
220
  # * You are joining an existing open transaction
198
221
  # * You are creating a nested (savepoint) transaction
199
222
  #
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]
223
+ # The mysql2 and postgresql adapters support setting the transaction
224
+ # isolation level.
225
+ def transaction(requires_new: nil, isolation: nil, joinable: true)
226
+ if !requires_new && current_transaction.joinable?
227
+ if isolation
209
228
  raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
210
229
  end
211
230
  yield
212
231
  else
213
- transaction_manager.within_new_transaction(options) { yield }
232
+ transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
214
233
  end
215
234
  rescue ActiveRecord::Rollback
216
235
  # rollbacks are silently swallowed
@@ -225,7 +244,7 @@ module ActiveRecord
225
244
  end
226
245
 
227
246
  def reset_transaction #:nodoc:
228
- @transaction_manager = TransactionManager.new(self)
247
+ @transaction_manager = ConnectionAdapters::TransactionManager.new(self)
229
248
  end
230
249
 
231
250
  # Register a record with the current transaction so that its after_commit and after_rollback callbacks
@@ -272,9 +291,6 @@ module ActiveRecord
272
291
  exec_rollback_to_savepoint(name)
273
292
  end
274
293
 
275
- def exec_rollback_to_savepoint(name = nil) #:nodoc:
276
- end
277
-
278
294
  def default_sequence_name(table, column)
279
295
  nil
280
296
  end
@@ -288,17 +304,24 @@ module ActiveRecord
288
304
  # something beyond a simple insert (eg. Oracle).
289
305
  def insert_fixture(fixture, table_name)
290
306
  fixture = fixture.stringify_keys
291
- columns = schema_cache.columns_hash(table_name)
292
307
 
293
- key_list = []
294
- value_list = fixture.map do |name, value|
308
+ columns = schema_cache.columns_hash(table_name)
309
+ binds = fixture.map do |name, value|
295
310
  if column = columns[name]
296
- key_list << quote_column_name(name)
297
- quote(value, column)
311
+ type = lookup_cast_type_from_column(column)
312
+ Relation::QueryAttribute.new(name, value, type)
298
313
  else
299
314
  raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
300
315
  end
301
316
  end
317
+ key_list = fixture.keys.map { |name| quote_column_name(name) }
318
+ value_list = prepare_binds_for_database(binds).map do |value|
319
+ begin
320
+ quote(value)
321
+ rescue TypeError
322
+ quote(YAML.dump(value))
323
+ end
324
+ end
302
325
 
303
326
  execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
304
327
  end
@@ -329,18 +352,12 @@ module ActiveRecord
329
352
  # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
330
353
  # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
331
354
  # an UPDATE statement, so in the MySQL adapters we redefine this to do that.
332
- def join_to_update(update, select) #:nodoc:
333
- key = update.key
355
+ def join_to_update(update, select, key) # :nodoc:
334
356
  subselect = subquery_for(key, select)
335
357
 
336
358
  update.where key.in(subselect)
337
359
  end
338
-
339
- def join_to_delete(delete, select, key) #:nodoc:
340
- subselect = subquery_for(key, select)
341
-
342
- delete.where key.in(subselect)
343
- end
360
+ alias join_to_delete join_to_update
344
361
 
345
362
  protected
346
363
 
@@ -353,28 +370,15 @@ module ActiveRecord
353
370
 
354
371
  # Returns an ActiveRecord::Result instance.
355
372
  def select(sql, name = nil, binds = [])
356
- exec_query(sql, name, binds)
357
- end
358
-
359
-
360
- # Returns the last auto-generated ID from the affected table.
361
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
362
- execute(sql, name)
363
- id_value
364
- end
365
-
366
- # Executes the update statement and returns the number of rows affected.
367
- def update_sql(sql, name = nil)
368
- execute(sql, name)
373
+ exec_query(sql, name, binds, prepare: false)
369
374
  end
370
375
 
371
- # Executes the delete statement and returns the number of rows affected.
372
- def delete_sql(sql, name = nil)
373
- update_sql(sql, name)
376
+ def select_prepared(sql, name = nil, binds = [])
377
+ exec_query(sql, name, binds, prepare: true)
374
378
  end
375
379
 
376
380
  def sql_for_insert(sql, pk, id_value, sequence_name, binds)
377
- [sql, binds]
381
+ [sql, binds, pk, sequence_name]
378
382
  end
379
383
 
380
384
  def last_inserted_id(result)
@@ -384,7 +388,7 @@ module ActiveRecord
384
388
 
385
389
  def binds_from_relation(relation, binds)
386
390
  if relation.is_a?(Relation) && binds.empty?
387
- relation, binds = relation.arel, relation.bind_values
391
+ relation, binds = relation.arel, relation.bound_attributes
388
392
  end
389
393
  [relation, binds]
390
394
  end
@@ -4,6 +4,9 @@ module ActiveRecord
4
4
  class << self
5
5
  def included(base) #:nodoc:
6
6
  dirties_query_cache base, :insert, :update, :delete, :rollback_to_savepoint, :rollback_db_transaction
7
+
8
+ base.set_callback :checkout, :after, :configure_query_cache!
9
+ base.set_callback :checkin, :after, :disable_query_cache!
7
10
  end
8
11
 
9
12
  def dirties_query_cache(base, *method_names)
@@ -18,6 +21,27 @@ module ActiveRecord
18
21
  end
19
22
  end
20
23
 
24
+ module ConnectionPoolConfiguration
25
+ def initialize(*)
26
+ super
27
+ @query_cache_enabled = Concurrent::Map.new { false }
28
+ end
29
+
30
+ def enable_query_cache!
31
+ @query_cache_enabled[connection_cache_key(Thread.current)] = true
32
+ connection.enable_query_cache! if active_connection?
33
+ end
34
+
35
+ def disable_query_cache!
36
+ @query_cache_enabled.delete connection_cache_key(Thread.current)
37
+ connection.disable_query_cache! if active_connection?
38
+ end
39
+
40
+ def query_cache_enabled
41
+ @query_cache_enabled[connection_cache_key(Thread.current)]
42
+ end
43
+ end
44
+
21
45
  attr_reader :query_cache, :query_cache_enabled
22
46
 
23
47
  def initialize(*)
@@ -41,6 +65,7 @@ module ActiveRecord
41
65
 
42
66
  def disable_query_cache!
43
67
  @query_cache_enabled = false
68
+ clear_query_cache
44
69
  end
45
70
 
46
71
  # Disable the query cache within the block.
@@ -61,11 +86,11 @@ module ActiveRecord
61
86
  @query_cache.clear
62
87
  end
63
88
 
64
- def select_all(arel, name = nil, binds = [])
89
+ def select_all(arel, name = nil, binds = [], preparable: nil)
65
90
  if @query_cache_enabled && !locked?(arel)
66
91
  arel, binds = binds_from_relation arel, binds
67
92
  sql = to_sql(arel, binds)
68
- cache_sql(sql, binds) { super(sql, name, binds) }
93
+ cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
69
94
  else
70
95
  super
71
96
  end
@@ -76,8 +101,14 @@ module ActiveRecord
76
101
  def cache_sql(sql, binds)
77
102
  result =
78
103
  if @query_cache[sql].key?(binds)
79
- ActiveSupport::Notifications.instrument("sql.active_record",
80
- :sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id)
104
+ ActiveSupport::Notifications.instrument(
105
+ "sql.active_record",
106
+ sql: sql,
107
+ binds: binds,
108
+ type_casted_binds: -> { type_casted_binds(binds) },
109
+ name: "CACHE",
110
+ connection_id: object_id,
111
+ )
81
112
  @query_cache[sql][binds]
82
113
  else
83
114
  @query_cache[sql][binds] = yield
@@ -90,6 +121,10 @@ module ActiveRecord
90
121
  def locked?(arel)
91
122
  arel.respond_to?(:locked) && arel.locked
92
123
  end
124
+
125
+ def configure_query_cache!
126
+ enable_query_cache! if pool.query_cache_enabled
127
+ end
93
128
  end
94
129
  end
95
130
  end
@@ -11,7 +11,13 @@ module ActiveRecord
11
11
  return value.quoted_id if value.respond_to?(:quoted_id)
12
12
 
13
13
  if column
14
- value = column.cast_type.type_cast_for_database(value)
14
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
15
+ Passing a column to `quote` has been deprecated. It is only used
16
+ for type casting, which should be handled elsewhere. See
17
+ https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11
18
+ for more information.
19
+ MSG
20
+ value = type_cast_from_column(column, value)
15
21
  end
16
22
 
17
23
  _quote(value)
@@ -20,13 +26,13 @@ module ActiveRecord
20
26
  # Cast a +value+ to a type that the database understands. For example,
21
27
  # SQLite does not understand dates, so this method will convert a Date
22
28
  # to a String.
23
- def type_cast(value, column)
29
+ def type_cast(value, column = nil)
24
30
  if value.respond_to?(:quoted_id) && value.respond_to?(:id)
25
31
  return value.id
26
32
  end
27
33
 
28
34
  if column
29
- value = column.cast_type.type_cast_for_database(value)
35
+ value = type_cast_from_column(column, value)
30
36
  end
31
37
 
32
38
  _type_cast(value)
@@ -35,15 +41,49 @@ module ActiveRecord
35
41
  raise TypeError, "can't cast #{value.class}#{to_type}"
36
42
  end
37
43
 
44
+ # If you are having to call this function, you are likely doing something
45
+ # wrong. The column does not have sufficient type information if the user
46
+ # provided a custom type on the class level either explicitly (via
47
+ # Attributes::ClassMethods#attribute) or implicitly (via
48
+ # AttributeMethods::Serialization::ClassMethods#serialize, +time_zone_aware_attributes+).
49
+ # In almost all cases, the sql type should only be used to change quoting behavior, when the primitive to
50
+ # represent the type doesn't sufficiently reflect the differences
51
+ # (varchar vs binary) for example. The type used to get this primitive
52
+ # should have been provided before reaching the connection adapter.
53
+ def type_cast_from_column(column, value) # :nodoc:
54
+ if column
55
+ type = lookup_cast_type_from_column(column)
56
+ type.serialize(value)
57
+ else
58
+ value
59
+ end
60
+ end
61
+
62
+ # See docs for #type_cast_from_column
63
+ def lookup_cast_type_from_column(column) # :nodoc:
64
+ lookup_cast_type(column.sql_type)
65
+ end
66
+
67
+ def fetch_type_metadata(sql_type)
68
+ cast_type = lookup_cast_type(sql_type)
69
+ SqlTypeMetadata.new(
70
+ sql_type: sql_type,
71
+ type: cast_type.type,
72
+ limit: cast_type.limit,
73
+ precision: cast_type.precision,
74
+ scale: cast_type.scale,
75
+ )
76
+ end
77
+
38
78
  # Quotes a string, escaping any ' (single quote) and \ (backslash)
39
79
  # characters.
40
80
  def quote_string(s)
41
- s.gsub(/\\/, '\&\&').gsub(/'/, "''") # ' (for ruby-mode)
81
+ s.gsub('\\'.freeze, '\&\&'.freeze).gsub("'".freeze, "''".freeze) # ' (for ruby-mode)
42
82
  end
43
83
 
44
84
  # Quotes the column name. Defaults to no quoting.
45
85
  def quote_column_name(column_name)
46
- column_name
86
+ column_name.to_s
47
87
  end
48
88
 
49
89
  # Quotes the table name. Defaults to column name quoting.
@@ -54,7 +94,7 @@ module ActiveRecord
54
94
  # Override to return the quoted table name for assignment. Defaults to
55
95
  # table quoting.
56
96
  #
57
- # This works for mysql and mysql2 where table.column can be used to
97
+ # This works for mysql2 where table.column can be used to
58
98
  # resolve ambiguity.
59
99
  #
60
100
  # We override this in the sqlite3 and postgresql adapters to use only
@@ -63,22 +103,33 @@ module ActiveRecord
63
103
  quote_table_name("#{table}.#{attr}")
64
104
  end
65
105
 
106
+ def quote_default_expression(value, column) # :nodoc:
107
+ if value.is_a?(Proc)
108
+ value.call
109
+ else
110
+ value = lookup_cast_type(column.sql_type).serialize(value)
111
+ quote(value)
112
+ end
113
+ end
114
+
66
115
  def quoted_true
67
- "'t'"
116
+ "'t'".freeze
68
117
  end
69
118
 
70
119
  def unquoted_true
71
- 't'
120
+ 't'.freeze
72
121
  end
73
122
 
74
123
  def quoted_false
75
- "'f'"
124
+ "'f'".freeze
76
125
  end
77
126
 
78
127
  def unquoted_false
79
- 'f'
128
+ 'f'.freeze
80
129
  end
81
130
 
131
+ # Quote date/time values for use in SQL input. Includes microseconds
132
+ # if the value is a Time responding to usec.
82
133
  def quoted_date(value)
83
134
  if value.acts_like?(:time)
84
135
  zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
@@ -88,7 +139,28 @@ module ActiveRecord
88
139
  end
89
140
  end
90
141
 
91
- value.to_s(:db)
142
+ result = value.to_s(:db)
143
+ if value.respond_to?(:usec) && value.usec > 0
144
+ "#{result}.#{sprintf("%06d", value.usec)}"
145
+ else
146
+ result
147
+ end
148
+ end
149
+
150
+ def quoted_time(value) # :nodoc:
151
+ quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, '')
152
+ end
153
+
154
+ def prepare_binds_for_database(binds) # :nodoc:
155
+ binds.map(&:value_for_database)
156
+ end
157
+
158
+ def type_casted_binds(binds) # :nodoc:
159
+ if binds.first.is_a?(Array)
160
+ binds.map { |column, value| type_cast(value, column) }
161
+ else
162
+ binds.map { |attr| type_cast(attr.value_for_database) }
163
+ end
92
164
  end
93
165
 
94
166
  private
@@ -107,11 +179,11 @@ module ActiveRecord
107
179
  # BigDecimals need to be put in a non-normalized form and quoted.
108
180
  when BigDecimal then value.to_s('F')
109
181
  when Numeric, ActiveSupport::Duration then value.to_s
182
+ when Type::Time::Value then "'#{quoted_time(value)}'"
110
183
  when Date, Time then "'#{quoted_date(value)}'"
111
184
  when Symbol then "'#{quote_string(value.to_s)}'"
112
185
  when Class then "'#{value}'"
113
- else
114
- "'#{quote_string(YAML.dump(value))}'"
186
+ else raise TypeError, "can't quote #{value.class.name}"
115
187
  end
116
188
  end
117
189
 
@@ -123,6 +195,7 @@ module ActiveRecord
123
195
  when false then unquoted_false
124
196
  # BigDecimals need to be put in a non-normalized form and quoted.
125
197
  when BigDecimal then value.to_s('F')
198
+ when Type::Time::Value then quoted_time(value)
126
199
  when Date, Time then quoted_date(value)
127
200
  when *types_which_need_no_typecasting
128
201
  value