activerecord 4.2.11.1 → 5.0.0

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 (246) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1282 -1195
  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 +8 -4
  8. data/lib/active_record/aggregations.rb +35 -24
  9. data/lib/active_record/association_relation.rb +3 -3
  10. data/lib/active_record/associations.rb +317 -209
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +11 -9
  13. data/lib/active_record/associations/association_scope.rb +73 -102
  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 +14 -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 +3 -10
  22. data/lib/active_record/associations/collection_association.rb +49 -41
  23. data/lib/active_record/associations/collection_proxy.rb +67 -27
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +20 -71
  26. data/lib/active_record/associations/has_many_through_association.rb +8 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +29 -19
  29. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  30. data/lib/active_record/associations/preloader.rb +14 -4
  31. data/lib/active_record/associations/preloader/association.rb +46 -52
  32. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  33. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  34. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  35. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  36. data/lib/active_record/associations/singular_association.rb +7 -1
  37. data/lib/active_record/associations/through_association.rb +11 -3
  38. data/lib/active_record/attribute.rb +68 -18
  39. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  40. data/lib/active_record/attribute_assignment.rb +19 -140
  41. data/lib/active_record/attribute_decorators.rb +6 -5
  42. data/lib/active_record/attribute_methods.rb +76 -47
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  44. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  45. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  46. data/lib/active_record/attribute_methods/query.rb +2 -2
  47. data/lib/active_record/attribute_methods/read.rb +31 -59
  48. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  50. data/lib/active_record/attribute_methods/write.rb +13 -37
  51. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  52. data/lib/active_record/attribute_set.rb +30 -3
  53. data/lib/active_record/attribute_set/builder.rb +6 -4
  54. data/lib/active_record/attributes.rb +199 -81
  55. data/lib/active_record/autosave_association.rb +49 -16
  56. data/lib/active_record/base.rb +32 -23
  57. data/lib/active_record/callbacks.rb +39 -43
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +20 -8
  60. data/lib/active_record/collection_cache_key.rb +40 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
  62. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  63. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
  64. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
  65. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
  66. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  67. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  68. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
  69. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  70. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
  71. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  72. data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
  73. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
  74. data/lib/active_record/connection_adapters/column.rb +28 -43
  75. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  76. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  77. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  78. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  79. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  80. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  84. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  85. data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
  86. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  87. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
  88. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -57
  91. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  100. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +37 -14
  121. data/lib/active_record/core.rb +89 -107
  122. data/lib/active_record/counter_cache.rb +13 -24
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +113 -76
  125. data/lib/active_record/errors.rb +87 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +76 -40
  130. data/lib/active_record/gem_version.rb +4 -4
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +15 -15
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration.rb +363 -133
  140. data/lib/active_record/migration/command_recorder.rb +59 -18
  141. data/lib/active_record/migration/compatibility.rb +126 -0
  142. data/lib/active_record/model_schema.rb +129 -41
  143. data/lib/active_record/nested_attributes.rb +58 -29
  144. data/lib/active_record/null_relation.rb +16 -8
  145. data/lib/active_record/persistence.rb +121 -80
  146. data/lib/active_record/query_cache.rb +15 -18
  147. data/lib/active_record/querying.rb +10 -9
  148. data/lib/active_record/railtie.rb +23 -16
  149. data/lib/active_record/railties/controller_runtime.rb +1 -1
  150. data/lib/active_record/railties/databases.rake +69 -46
  151. data/lib/active_record/readonly_attributes.rb +1 -1
  152. data/lib/active_record/reflection.rb +282 -115
  153. data/lib/active_record/relation.rb +176 -116
  154. data/lib/active_record/relation/batches.rb +139 -34
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  156. data/lib/active_record/relation/calculations.rb +79 -108
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +163 -81
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +16 -42
  161. data/lib/active_record/relation/predicate_builder.rb +120 -107
  162. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  163. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  164. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  166. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  167. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  168. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  169. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +308 -244
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +4 -7
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/result.rb +4 -3
  177. data/lib/active_record/runtime_registry.rb +1 -1
  178. data/lib/active_record/sanitization.rb +95 -66
  179. data/lib/active_record/schema.rb +26 -22
  180. data/lib/active_record/schema_dumper.rb +62 -38
  181. data/lib/active_record/schema_migration.rb +11 -14
  182. data/lib/active_record/scoping.rb +32 -15
  183. data/lib/active_record/scoping/default.rb +23 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/secure_token.rb +38 -0
  186. data/lib/active_record/serialization.rb +2 -4
  187. data/lib/active_record/statement_cache.rb +16 -14
  188. data/lib/active_record/store.rb +8 -3
  189. data/lib/active_record/suppressor.rb +58 -0
  190. data/lib/active_record/table_metadata.rb +68 -0
  191. data/lib/active_record/tasks/database_tasks.rb +57 -43
  192. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  193. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  194. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  195. data/lib/active_record/timestamp.rb +20 -9
  196. data/lib/active_record/touch_later.rb +58 -0
  197. data/lib/active_record/transactions.rb +138 -56
  198. data/lib/active_record/type.rb +66 -17
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -45
  201. data/lib/active_record/type/date_time.rb +2 -49
  202. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  203. data/lib/active_record/type/internal/timezone.rb +15 -0
  204. data/lib/active_record/type/serialized.rb +15 -14
  205. data/lib/active_record/type/time.rb +10 -16
  206. data/lib/active_record/type/type_map.rb +4 -4
  207. data/lib/active_record/type_caster.rb +7 -0
  208. data/lib/active_record/type_caster/connection.rb +29 -0
  209. data/lib/active_record/type_caster/map.rb +19 -0
  210. data/lib/active_record/validations.rb +33 -32
  211. data/lib/active_record/validations/absence.rb +23 -0
  212. data/lib/active_record/validations/associated.rb +10 -3
  213. data/lib/active_record/validations/length.rb +24 -0
  214. data/lib/active_record/validations/presence.rb +11 -12
  215. data/lib/active_record/validations/uniqueness.rb +30 -29
  216. data/lib/rails/generators/active_record/migration.rb +7 -0
  217. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  218. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  219. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  220. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  221. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  222. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  223. metadata +59 -34
  224. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  225. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  226. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  227. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  228. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  229. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  231. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  232. data/lib/active_record/type/big_integer.rb +0 -13
  233. data/lib/active_record/type/binary.rb +0 -50
  234. data/lib/active_record/type/boolean.rb +0 -31
  235. data/lib/active_record/type/decimal.rb +0 -64
  236. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  237. data/lib/active_record/type/decorator.rb +0 -14
  238. data/lib/active_record/type/float.rb +0 -19
  239. data/lib/active_record/type/integer.rb +0 -59
  240. data/lib/active_record/type/mutable.rb +0 -16
  241. data/lib/active_record/type/numeric.rb +0 -36
  242. data/lib/active_record/type/string.rb +0 -40
  243. data/lib/active_record/type/text.rb +0 -11
  244. data/lib/active_record/type/time_value.rb +0 -38
  245. data/lib/active_record/type/unsigned_integer.rb +0 -15
  246. 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
@@ -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
@@ -61,11 +61,11 @@ module ActiveRecord
61
61
  @query_cache.clear
62
62
  end
63
63
 
64
- def select_all(arel, name = nil, binds = [])
64
+ def select_all(arel, name = nil, binds = [], preparable: nil)
65
65
  if @query_cache_enabled && !locked?(arel)
66
66
  arel, binds = binds_from_relation arel, binds
67
67
  sql = to_sql(arel, binds)
68
- cache_sql(sql, binds) { super(sql, name, binds) }
68
+ cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
69
69
  else
70
70
  super
71
71
  end
@@ -1,5 +1,4 @@
1
1
  require 'active_support/core_ext/big_decimal/conversions'
2
- require "active_support/multibyte/chars"
3
2
 
4
3
  module ActiveRecord
5
4
  module ConnectionAdapters # :nodoc:
@@ -11,7 +10,13 @@ module ActiveRecord
11
10
  return value.quoted_id if value.respond_to?(:quoted_id)
12
11
 
13
12
  if column
14
- value = column.cast_type.type_cast_for_database(value)
13
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
14
+ Passing a column to `quote` has been deprecated. It is only used
15
+ for type casting, which should be handled elsewhere. See
16
+ https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11
17
+ for more information.
18
+ MSG
19
+ value = type_cast_from_column(column, value)
15
20
  end
16
21
 
17
22
  _quote(value)
@@ -20,13 +25,13 @@ module ActiveRecord
20
25
  # Cast a +value+ to a type that the database understands. For example,
21
26
  # SQLite does not understand dates, so this method will convert a Date
22
27
  # to a String.
23
- def type_cast(value, column)
28
+ def type_cast(value, column = nil)
24
29
  if value.respond_to?(:quoted_id) && value.respond_to?(:id)
25
30
  return value.id
26
31
  end
27
32
 
28
33
  if column
29
- value = column.cast_type.type_cast_for_database(value)
34
+ value = type_cast_from_column(column, value)
30
35
  end
31
36
 
32
37
  _type_cast(value)
@@ -35,15 +40,49 @@ module ActiveRecord
35
40
  raise TypeError, "can't cast #{value.class}#{to_type}"
36
41
  end
37
42
 
43
+ # If you are having to call this function, you are likely doing something
44
+ # wrong. The column does not have sufficient type information if the user
45
+ # provided a custom type on the class level either explicitly (via
46
+ # Attributes::ClassMethods#attribute) or implicitly (via
47
+ # AttributeMethods::Serialization::ClassMethods#serialize, +time_zone_aware_attributes+).
48
+ # In almost all cases, the sql type should only be used to change quoting behavior, when the primitive to
49
+ # represent the type doesn't sufficiently reflect the differences
50
+ # (varchar vs binary) for example. The type used to get this primitive
51
+ # should have been provided before reaching the connection adapter.
52
+ def type_cast_from_column(column, value) # :nodoc:
53
+ if column
54
+ type = lookup_cast_type_from_column(column)
55
+ type.serialize(value)
56
+ else
57
+ value
58
+ end
59
+ end
60
+
61
+ # See docs for #type_cast_from_column
62
+ def lookup_cast_type_from_column(column) # :nodoc:
63
+ lookup_cast_type(column.sql_type)
64
+ end
65
+
66
+ def fetch_type_metadata(sql_type)
67
+ cast_type = lookup_cast_type(sql_type)
68
+ SqlTypeMetadata.new(
69
+ sql_type: sql_type,
70
+ type: cast_type.type,
71
+ limit: cast_type.limit,
72
+ precision: cast_type.precision,
73
+ scale: cast_type.scale,
74
+ )
75
+ end
76
+
38
77
  # Quotes a string, escaping any ' (single quote) and \ (backslash)
39
78
  # characters.
40
79
  def quote_string(s)
41
- s.gsub(/\\/, '\&\&').gsub(/'/, "''") # ' (for ruby-mode)
80
+ s.gsub('\\'.freeze, '\&\&'.freeze).gsub("'".freeze, "''".freeze) # ' (for ruby-mode)
42
81
  end
43
82
 
44
83
  # Quotes the column name. Defaults to no quoting.
45
84
  def quote_column_name(column_name)
46
- column_name
85
+ column_name.to_s
47
86
  end
48
87
 
49
88
  # Quotes the table name. Defaults to column name quoting.
@@ -54,7 +93,7 @@ module ActiveRecord
54
93
  # Override to return the quoted table name for assignment. Defaults to
55
94
  # table quoting.
56
95
  #
57
- # This works for mysql and mysql2 where table.column can be used to
96
+ # This works for mysql2 where table.column can be used to
58
97
  # resolve ambiguity.
59
98
  #
60
99
  # We override this in the sqlite3 and postgresql adapters to use only
@@ -63,6 +102,15 @@ module ActiveRecord
63
102
  quote_table_name("#{table}.#{attr}")
64
103
  end
65
104
 
105
+ def quote_default_expression(value, column) # :nodoc:
106
+ if value.is_a?(Proc)
107
+ value.call
108
+ else
109
+ value = lookup_cast_type(column.sql_type).serialize(value)
110
+ quote(value)
111
+ end
112
+ end
113
+
66
114
  def quoted_true
67
115
  "'t'"
68
116
  end
@@ -79,6 +127,8 @@ module ActiveRecord
79
127
  'f'
80
128
  end
81
129
 
130
+ # Quote date/time values for use in SQL input. Includes microseconds
131
+ # if the value is a Time responding to usec.
82
132
  def quoted_date(value)
83
133
  if value.acts_like?(:time)
84
134
  zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
@@ -88,7 +138,20 @@ module ActiveRecord
88
138
  end
89
139
  end
90
140
 
91
- value.to_s(:db)
141
+ result = value.to_s(:db)
142
+ if value.respond_to?(:usec) && value.usec > 0
143
+ "#{result}.#{sprintf("%06d", value.usec)}"
144
+ else
145
+ result
146
+ end
147
+ end
148
+
149
+ def quoted_time(value) # :nodoc:
150
+ quoted_date(value).sub(/\A2000-01-01 /, '')
151
+ end
152
+
153
+ def prepare_binds_for_database(binds) # :nodoc:
154
+ binds.map(&:value_for_database)
92
155
  end
93
156
 
94
157
  private
@@ -107,11 +170,11 @@ module ActiveRecord
107
170
  # BigDecimals need to be put in a non-normalized form and quoted.
108
171
  when BigDecimal then value.to_s('F')
109
172
  when Numeric, ActiveSupport::Duration then value.to_s
173
+ when Type::Time::Value then "'#{quoted_time(value)}'"
110
174
  when Date, Time then "'#{quoted_date(value)}'"
111
175
  when Symbol then "'#{quote_string(value.to_s)}'"
112
176
  when Class then "'#{value}'"
113
- else
114
- "'#{quote_string(YAML.dump(value))}'"
177
+ else raise TypeError, "can't quote #{value.class.name}"
115
178
  end
116
179
  end
117
180
 
@@ -123,6 +186,7 @@ module ActiveRecord
123
186
  when false then unquoted_false
124
187
  # BigDecimals need to be put in a non-normalized form and quoted.
125
188
  when BigDecimal then value.to_s('F')
189
+ when Type::Time::Value then quoted_time(value)
126
190
  when Date, Time then quoted_date(value)
127
191
  when *types_which_need_no_typecasting
128
192
  value
@@ -1,8 +1,8 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
- module Savepoints #:nodoc:
4
- def supports_savepoints?
5
- true
3
+ module Savepoints
4
+ def current_savepoint_name
5
+ current_transaction.savepoint_name
6
6
  end
7
7
 
8
8
  def create_savepoint(name = current_savepoint_name)