activerecord 5.0.7 → 5.1.7

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 (219) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -2080
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +28 -28
  6. data/examples/simple.rb +3 -3
  7. data/lib/active_record/aggregations.rb +244 -244
  8. data/lib/active_record/association_relation.rb +5 -5
  9. data/lib/active_record/associations/alias_tracker.rb +10 -11
  10. data/lib/active_record/associations/association.rb +23 -5
  11. data/lib/active_record/associations/association_scope.rb +95 -81
  12. data/lib/active_record/associations/belongs_to_association.rb +7 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +30 -16
  14. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  16. data/lib/active_record/associations/collection_association.rb +36 -205
  17. data/lib/active_record/associations/collection_proxy.rb +132 -63
  18. data/lib/active_record/associations/has_many_association.rb +10 -19
  19. data/lib/active_record/associations/has_many_through_association.rb +12 -4
  20. data/lib/active_record/associations/has_one_association.rb +24 -28
  21. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  22. data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
  23. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  24. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +121 -118
  26. data/lib/active_record/associations/preloader/association.rb +64 -64
  27. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  28. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  29. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  30. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  31. data/lib/active_record/associations/preloader/through_association.rb +41 -41
  32. data/lib/active_record/associations/preloader.rb +94 -94
  33. data/lib/active_record/associations/singular_association.rb +8 -25
  34. data/lib/active_record/associations/through_association.rb +2 -5
  35. data/lib/active_record/associations.rb +1591 -1562
  36. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute_assignment.rb +61 -61
  39. data/lib/active_record/attribute_decorators.rb +35 -13
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +229 -46
  42. data/lib/active_record/attribute_methods/primary_key.rb +74 -73
  43. data/lib/active_record/attribute_methods/read.rb +39 -35
  44. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  46. data/lib/active_record/attribute_methods/write.rb +30 -33
  47. data/lib/active_record/attribute_methods.rb +56 -65
  48. data/lib/active_record/attribute_mutation_tracker.rb +63 -11
  49. data/lib/active_record/attribute_set/builder.rb +27 -33
  50. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  51. data/lib/active_record/attribute_set.rb +9 -6
  52. data/lib/active_record/attributes.rb +22 -22
  53. data/lib/active_record/autosave_association.rb +18 -13
  54. data/lib/active_record/base.rb +24 -22
  55. data/lib/active_record/callbacks.rb +56 -14
  56. data/lib/active_record/coders/yaml_column.rb +9 -11
  57. data/lib/active_record/collection_cache_key.rb +3 -4
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
  70. data/lib/active_record/connection_adapters/column.rb +26 -4
  71. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  72. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  90. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  91. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
  92. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
  97. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  99. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
  108. data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
  110. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
  113. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
  114. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
  115. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
  116. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
  117. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  118. data/lib/active_record/connection_handling.rb +14 -26
  119. data/lib/active_record/core.rb +109 -93
  120. data/lib/active_record/counter_cache.rb +60 -13
  121. data/lib/active_record/define_callbacks.rb +20 -0
  122. data/lib/active_record/dynamic_matchers.rb +80 -79
  123. data/lib/active_record/enum.rb +8 -6
  124. data/lib/active_record/errors.rb +64 -15
  125. data/lib/active_record/explain.rb +1 -2
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +7 -4
  128. data/lib/active_record/fixture_set/file.rb +11 -8
  129. data/lib/active_record/fixtures.rb +66 -53
  130. data/lib/active_record/gem_version.rb +1 -1
  131. data/lib/active_record/inheritance.rb +93 -79
  132. data/lib/active_record/integration.rb +7 -7
  133. data/lib/active_record/internal_metadata.rb +3 -16
  134. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  135. data/lib/active_record/locking/optimistic.rb +69 -74
  136. data/lib/active_record/locking/pessimistic.rb +10 -1
  137. data/lib/active_record/log_subscriber.rb +23 -28
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +100 -47
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/migration.rb +153 -155
  142. data/lib/active_record/model_schema.rb +94 -107
  143. data/lib/active_record/nested_attributes.rb +200 -199
  144. data/lib/active_record/null_relation.rb +11 -34
  145. data/lib/active_record/persistence.rb +65 -50
  146. data/lib/active_record/query_cache.rb +2 -6
  147. data/lib/active_record/querying.rb +3 -4
  148. data/lib/active_record/railtie.rb +16 -17
  149. data/lib/active_record/railties/controller_runtime.rb +6 -2
  150. data/lib/active_record/railties/databases.rake +105 -133
  151. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  152. data/lib/active_record/readonly_attributes.rb +2 -2
  153. data/lib/active_record/reflection.rb +154 -108
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  155. data/lib/active_record/relation/batches.rb +80 -51
  156. data/lib/active_record/relation/calculations.rb +169 -162
  157. data/lib/active_record/relation/delegation.rb +32 -31
  158. data/lib/active_record/relation/finder_methods.rb +197 -231
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  161. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  162. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  163. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  165. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  166. data/lib/active_record/relation/predicate_builder.rb +92 -89
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +255 -293
  169. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  170. data/lib/active_record/relation/spawn_methods.rb +4 -5
  171. data/lib/active_record/relation/where_clause.rb +80 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/relation.rb +93 -119
  174. data/lib/active_record/result.rb +41 -32
  175. data/lib/active_record/runtime_registry.rb +3 -3
  176. data/lib/active_record/sanitization.rb +176 -192
  177. data/lib/active_record/schema.rb +3 -3
  178. data/lib/active_record/schema_dumper.rb +15 -38
  179. data/lib/active_record/schema_migration.rb +8 -4
  180. data/lib/active_record/scoping/default.rb +90 -90
  181. data/lib/active_record/scoping/named.rb +11 -11
  182. data/lib/active_record/scoping.rb +6 -6
  183. data/lib/active_record/secure_token.rb +2 -2
  184. data/lib/active_record/statement_cache.rb +13 -15
  185. data/lib/active_record/store.rb +31 -32
  186. data/lib/active_record/suppressor.rb +2 -1
  187. data/lib/active_record/table_metadata.rb +9 -5
  188. data/lib/active_record/tasks/database_tasks.rb +65 -55
  189. data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
  190. data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
  191. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  192. data/lib/active_record/timestamp.rb +46 -25
  193. data/lib/active_record/touch_later.rb +1 -2
  194. data/lib/active_record/transactions.rb +97 -109
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +13 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/internal/abstract_json.rb +4 -0
  199. data/lib/active_record/type/serialized.rb +14 -8
  200. data/lib/active_record/type/text.rb +9 -0
  201. data/lib/active_record/type/time.rb +0 -1
  202. data/lib/active_record/type/type_map.rb +11 -15
  203. data/lib/active_record/type/unsigned_integer.rb +15 -0
  204. data/lib/active_record/type.rb +17 -13
  205. data/lib/active_record/type_caster/connection.rb +8 -6
  206. data/lib/active_record/type_caster/map.rb +3 -1
  207. data/lib/active_record/type_caster.rb +2 -2
  208. data/lib/active_record/validations/associated.rb +1 -1
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +8 -39
  211. data/lib/active_record/validations.rb +4 -4
  212. data/lib/active_record/version.rb +1 -1
  213. data/lib/active_record.rb +20 -20
  214. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  215. data/lib/rails/generators/active_record/migration.rb +1 -1
  216. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  217. data/lib/rails/generators/active_record.rb +4 -4
  218. metadata +24 -13
  219. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,7 +1,6 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters # :nodoc:
3
3
  module DatabaseLimits
4
-
5
4
  # Returns the maximum length of a table alias.
6
5
  def table_alias_length
7
6
  255
@@ -47,7 +46,7 @@ module ActiveRecord
47
46
  end
48
47
 
49
48
  # Returns the maximum number of elements in an IN (x,y,z) clause.
50
- # nil means no limit.
49
+ # +nil+ means no limit.
51
50
  def in_clause_length
52
51
  nil
53
52
  end
@@ -61,7 +60,6 @@ module ActiveRecord
61
60
  def joins_per_query
62
61
  256
63
62
  end
64
-
65
63
  end
66
64
  end
67
65
  end
@@ -10,19 +10,20 @@ module ActiveRecord
10
10
  def to_sql(arel, binds = [])
11
11
  if arel.respond_to?(:ast)
12
12
  collected = visitor.accept(arel.ast, collector)
13
- collected.compile(binds.dup, self)
13
+ collected.compile(binds, self).freeze
14
14
  else
15
- arel
15
+ arel.dup.freeze
16
16
  end
17
17
  end
18
18
 
19
19
  # This is used in the StatementCache object. It returns an object that
20
20
  # can be used to query the database repeatedly.
21
- def cacheable_query(arel) # :nodoc:
21
+ def cacheable_query(klass, arel) # :nodoc:
22
+ collected = visitor.accept(arel.ast, collector)
22
23
  if prepared_statements
23
- ActiveRecord::StatementCache.query visitor, arel.ast
24
+ klass.query(collected.value)
24
25
  else
25
- ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector
26
+ klass.partial_query(collected.value)
26
27
  end
27
28
  end
28
29
 
@@ -50,23 +51,31 @@ module ActiveRecord
50
51
 
51
52
  # Returns a single value from a record
52
53
  def select_value(arel, name = nil, binds = [])
53
- arel, binds = binds_from_relation arel, binds
54
- if result = select_rows(to_sql(arel, binds), name, binds).first
55
- result.first
56
- end
54
+ single_value_from_rows(select_rows(arel, name, binds))
57
55
  end
58
56
 
59
57
  # Returns an array of the values of the first column in a select:
60
58
  # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
61
59
  def select_values(arel, name = nil, binds = [])
62
- arel, binds = binds_from_relation arel, binds
63
- select_rows(to_sql(arel, binds), name, binds).map(&:first)
60
+ select_rows(arel, name, binds).map(&:first)
64
61
  end
65
62
 
66
63
  # Returns an array of arrays containing the field values.
67
64
  # Order is the same as that returned by +columns+.
68
- def select_rows(sql, name = nil, binds = [])
69
- exec_query(sql, name, binds).rows
65
+ def select_rows(arel, name = nil, binds = [])
66
+ select_all(arel, name, binds).rows
67
+ end
68
+
69
+ def query_value(sql, name = nil) # :nodoc:
70
+ single_value_from_rows(query(sql, name))
71
+ end
72
+
73
+ def query_values(sql, name = nil) # :nodoc:
74
+ query(sql, name).map(&:first)
75
+ end
76
+
77
+ def query(sql, name = nil) # :nodoc:
78
+ exec_query(sql, name).rows
70
79
  end
71
80
 
72
81
  # Executes the SQL statement in the context of this connection and returns
@@ -81,21 +90,22 @@ module ActiveRecord
81
90
  # Executes +sql+ statement in the context of this connection using
82
91
  # +binds+ as the bind substitutes. +name+ is logged along with
83
92
  # the executed +sql+ statement.
84
- def exec_query(sql, name = 'SQL', binds = [], prepare: false)
93
+ def exec_query(sql, name = "SQL", binds = [], prepare: false)
85
94
  raise NotImplementedError
86
95
  end
87
96
 
88
97
  # Executes insert +sql+ statement in the context of this connection using
89
98
  # +binds+ as the bind substitutes. +name+ is logged along with
90
99
  # the executed +sql+ statement.
91
- def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
100
+ def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
101
+ sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
92
102
  exec_query(sql, name, binds)
93
103
  end
94
104
 
95
105
  # Executes delete +sql+ statement in the context of this connection using
96
106
  # +binds+ as the bind substitutes. +name+ is logged along with
97
107
  # the executed +sql+ statement.
98
- def exec_delete(sql, name, binds)
108
+ def exec_delete(sql, name = nil, binds = [])
99
109
  exec_query(sql, name, binds)
100
110
  end
101
111
 
@@ -107,40 +117,33 @@ module ActiveRecord
107
117
  # Executes update +sql+ statement in the context of this connection using
108
118
  # +binds+ as the bind substitutes. +name+ is logged along with
109
119
  # the executed +sql+ statement.
110
- def exec_update(sql, name, binds)
120
+ def exec_update(sql, name = nil, binds = [])
111
121
  exec_query(sql, name, binds)
112
122
  end
113
123
 
114
124
  # Executes an INSERT query and returns the new record's ID
115
125
  #
116
- # +id_value+ will be returned unless the value is nil, in
126
+ # +id_value+ will be returned unless the value is +nil+, in
117
127
  # which case the database will attempt to calculate the last inserted
118
128
  # id and return that value.
119
129
  #
120
130
  # If the next id was calculated in advance (as in Oracle), it should be
121
131
  # passed in as +id_value+.
122
132
  def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
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)
133
+ value = exec_insert(to_sql(arel, binds), name, binds, pk, sequence_name)
125
134
  id_value || last_inserted_id(value)
126
135
  end
127
136
  alias create insert
128
- alias insert_sql insert
129
- deprecate insert_sql: :insert
130
137
 
131
138
  # Executes the update statement and returns the number of rows affected.
132
139
  def update(arel, name = nil, binds = [])
133
140
  exec_update(to_sql(arel, binds), name, binds)
134
141
  end
135
- alias update_sql update
136
- deprecate update_sql: :update
137
142
 
138
143
  # Executes the delete statement and returns the number of rows affected.
139
144
  def delete(arel, name = nil, binds = [])
140
145
  exec_delete(to_sql(arel, binds), name, binds)
141
146
  end
142
- alias delete_sql delete
143
- deprecate delete_sql: :delete
144
147
 
145
148
  # Returns +true+ when the connection adapter supports prepared statement
146
149
  # caching, otherwise returns +false+
@@ -315,7 +318,7 @@ module ActiveRecord
315
318
  end
316
319
  end
317
320
  key_list = fixture.keys.map { |name| quote_column_name(name) }
318
- value_list = prepare_binds_for_database(binds).map do |value|
321
+ value_list = binds.map(&:value_for_database).map do |value|
319
322
  begin
320
323
  quote(value)
321
324
  rescue TypeError
@@ -323,7 +326,7 @@ module ActiveRecord
323
326
  end
324
327
  end
325
328
 
326
- execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
329
+ execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", "Fixture Insert"
327
330
  end
328
331
 
329
332
  def empty_insert_statement_value
@@ -333,17 +336,12 @@ module ActiveRecord
333
336
  # Sanitizes the given LIMIT parameter in order to prevent SQL injection.
334
337
  #
335
338
  # The +limit+ may be anything that can evaluate to a string via #to_s. It
336
- # should look like an integer, or a comma-delimited list of integers, or
337
- # an Arel SQL literal.
339
+ # should look like an integer, or an Arel SQL literal.
338
340
  #
339
341
  # Returns Integer and Arel::Nodes::SqlLiteral limits as is.
340
- # Returns the sanitized limit parameter, either as an integer, or as a
341
- # string which contains a comma-delimited list of integers.
342
342
  def sanitize_limit(limit)
343
343
  if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
344
344
  limit
345
- elsif limit.to_s.include?(',')
346
- Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
347
345
  else
348
346
  Integer(limit)
349
347
  end
@@ -359,7 +357,7 @@ module ActiveRecord
359
357
  end
360
358
  alias join_to_delete join_to_update
361
359
 
362
- protected
360
+ private
363
361
 
364
362
  # Returns a subquery for the given key using the join information.
365
363
  def subquery_for(key, select)
@@ -378,11 +376,15 @@ module ActiveRecord
378
376
  end
379
377
 
380
378
  def sql_for_insert(sql, pk, id_value, sequence_name, binds)
381
- [sql, binds, pk, sequence_name]
379
+ [sql, binds]
382
380
  end
383
381
 
384
382
  def last_inserted_id(result)
385
- row = result.rows.first
383
+ single_value_from_rows(result.rows)
384
+ end
385
+
386
+ def single_value_from_rows(rows)
387
+ row = rows.first
386
388
  row && row.first
387
389
  end
388
390
 
@@ -46,7 +46,7 @@ module ActiveRecord
46
46
 
47
47
  def initialize(*)
48
48
  super
49
- @query_cache = Hash.new { |h,sql| h[sql] = {} }
49
+ @query_cache = Hash.new { |h, sql| h[sql] = {} }
50
50
  @query_cache_enabled = false
51
51
  end
52
52
 
@@ -83,14 +83,16 @@ module ActiveRecord
83
83
  # the same SQL query and repeatedly return the same result each time, silently
84
84
  # undermining the randomness you were expecting.
85
85
  def clear_query_cache
86
- @query_cache.clear
86
+ @lock.synchronize do
87
+ @query_cache.clear
88
+ end
87
89
  end
88
90
 
89
91
  def select_all(arel, name = nil, binds = [], preparable: nil)
90
92
  if @query_cache_enabled && !locked?(arel)
91
93
  arel, binds = binds_from_relation arel, binds
92
94
  sql = to_sql(arel, binds)
93
- cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) }
95
+ cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
94
96
  else
95
97
  super
96
98
  end
@@ -98,33 +100,36 @@ module ActiveRecord
98
100
 
99
101
  private
100
102
 
101
- def cache_sql(sql, binds)
102
- result =
103
- if @query_cache[sql].key?(binds)
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
- )
112
- @query_cache[sql][binds]
113
- else
114
- @query_cache[sql][binds] = yield
103
+ def cache_sql(sql, name, binds)
104
+ @lock.synchronize do
105
+ result =
106
+ if @query_cache[sql].key?(binds)
107
+ ActiveSupport::Notifications.instrument(
108
+ "sql.active_record",
109
+ sql: sql,
110
+ binds: binds,
111
+ type_casted_binds: -> { type_casted_binds(binds) },
112
+ name: name,
113
+ connection_id: object_id,
114
+ cached: true,
115
+ )
116
+ @query_cache[sql][binds]
117
+ else
118
+ @query_cache[sql][binds] = yield
119
+ end
120
+ result.dup
115
121
  end
116
- result.dup
117
- end
122
+ end
118
123
 
119
- # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
120
- # queries should not be cached.
121
- def locked?(arel)
122
- arel.respond_to?(:locked) && arel.locked
123
- end
124
+ # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
125
+ # queries should not be cached.
126
+ def locked?(arel)
127
+ arel.respond_to?(:locked) && arel.locked
128
+ end
124
129
 
125
- def configure_query_cache!
126
- enable_query_cache! if pool.query_cache_enabled
127
- end
130
+ def configure_query_cache!
131
+ enable_query_cache! if pool.query_cache_enabled
132
+ end
128
133
  end
129
134
  end
130
135
  end
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/big_decimal/conversions'
1
+ require "active_support/core_ext/big_decimal/conversions"
2
2
  require "active_support/multibyte/chars"
3
3
 
4
4
  module ActiveRecord
@@ -6,18 +6,20 @@ module ActiveRecord
6
6
  module Quoting
7
7
  # Quotes the column value to help prevent
8
8
  # {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
9
- def quote(value, column = nil)
10
- # records are quoted as their primary key
11
- return value.quoted_id if value.respond_to?(:quoted_id)
9
+ def quote(value)
10
+ value = id_value_for_database(value) if value.is_a?(Base)
12
11
 
13
- if column
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)
12
+ if value.respond_to?(:quoted_id)
13
+ at = value.method(:quoted_id).source_location
14
+ at &&= " at %s:%d" % at
15
+
16
+ owner = value.method(:quoted_id).owner.to_s
17
+ klass = value.class.to_s
18
+ klass += "(#{owner})" unless owner == klass
19
+
20
+ ActiveSupport::Deprecation.warn \
21
+ "Defining #quoted_id is deprecated and will be ignored in Rails 5.2. (defined on #{klass}#{at})"
22
+ return value.quoted_id
21
23
  end
22
24
 
23
25
  _quote(value)
@@ -27,6 +29,8 @@ module ActiveRecord
27
29
  # SQLite does not understand dates, so this method will convert a Date
28
30
  # to a String.
29
31
  def type_cast(value, column = nil)
32
+ value = id_value_for_database(value) if value.is_a?(Base)
33
+
30
34
  if value.respond_to?(:quoted_id) && value.respond_to?(:id)
31
35
  return value.id
32
36
  end
@@ -117,7 +121,7 @@ module ActiveRecord
117
121
  end
118
122
 
119
123
  def unquoted_true
120
- 't'.freeze
124
+ "t".freeze
121
125
  end
122
126
 
123
127
  def quoted_false
@@ -125,7 +129,7 @@ module ActiveRecord
125
129
  end
126
130
 
127
131
  def unquoted_false
128
- 'f'.freeze
132
+ "f".freeze
129
133
  end
130
134
 
131
135
  # Quote date/time values for use in SQL input. Includes microseconds
@@ -148,11 +152,12 @@ module ActiveRecord
148
152
  end
149
153
 
150
154
  def quoted_time(value) # :nodoc:
151
- quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, '')
155
+ value = value.change(year: 2000, month: 1, day: 1)
156
+ quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "")
152
157
  end
153
158
 
154
- def prepare_binds_for_database(binds) # :nodoc:
155
- binds.map(&:value_for_database)
159
+ def quoted_binary(value) # :nodoc:
160
+ "'#{quote_string(value.to_s)}'"
156
161
  end
157
162
 
158
163
  def type_casted_binds(binds) # :nodoc:
@@ -164,44 +169,50 @@ module ActiveRecord
164
169
  end
165
170
 
166
171
  private
172
+ def id_value_for_database(value)
173
+ if primary_key = value.class.primary_key
174
+ value.instance_variable_get(:@attributes)[primary_key].value_for_database
175
+ end
176
+ end
167
177
 
168
- def types_which_need_no_typecasting
169
- [nil, Numeric, String]
170
- end
171
-
172
- def _quote(value)
173
- case value
174
- when String, ActiveSupport::Multibyte::Chars, Type::Binary::Data
175
- "'#{quote_string(value.to_s)}'"
176
- when true then quoted_true
177
- when false then quoted_false
178
- when nil then "NULL"
179
- # BigDecimals need to be put in a non-normalized form and quoted.
180
- when BigDecimal then value.to_s('F')
181
- when Numeric, ActiveSupport::Duration then value.to_s
182
- when Type::Time::Value then "'#{quoted_time(value)}'"
183
- when Date, Time then "'#{quoted_date(value)}'"
184
- when Symbol then "'#{quote_string(value.to_s)}'"
185
- when Class then "'#{value}'"
186
- else raise TypeError, "can't quote #{value.class.name}"
178
+ def types_which_need_no_typecasting
179
+ [nil, Numeric, String]
187
180
  end
188
- end
189
181
 
190
- def _type_cast(value)
191
- case value
192
- when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
193
- value.to_s
194
- when true then unquoted_true
195
- when false then unquoted_false
196
- # BigDecimals need to be put in a non-normalized form and quoted.
197
- when BigDecimal then value.to_s('F')
198
- when Type::Time::Value then quoted_time(value)
199
- when Date, Time then quoted_date(value)
200
- when *types_which_need_no_typecasting
201
- value
202
- else raise TypeError
182
+ def _quote(value)
183
+ case value
184
+ when String, ActiveSupport::Multibyte::Chars
185
+ "'#{quote_string(value.to_s)}'"
186
+ when true then quoted_true
187
+ when false then quoted_false
188
+ when nil then "NULL"
189
+ # BigDecimals need to be put in a non-normalized form and quoted.
190
+ when BigDecimal then value.to_s("F")
191
+ when Numeric, ActiveSupport::Duration then value.to_s
192
+ when Type::Binary::Data then quoted_binary(value)
193
+ when Type::Time::Value then "'#{quoted_time(value)}'"
194
+ when Date, Time then "'#{quoted_date(value)}'"
195
+ when Symbol then "'#{quote_string(value.to_s)}'"
196
+ when Class then "'#{value}'"
197
+ else raise TypeError, "can't quote #{value.class.name}"
198
+ end
199
+ end
200
+
201
+ def _type_cast(value)
202
+ case value
203
+ when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
204
+ value.to_s
205
+ when true then unquoted_true
206
+ when false then unquoted_false
207
+ # BigDecimals need to be put in a non-normalized form and quoted.
208
+ when BigDecimal then value.to_s("F")
209
+ when Type::Time::Value then quoted_time(value)
210
+ when Date, Time then quoted_date(value)
211
+ when *types_which_need_no_typecasting
212
+ value
213
+ else raise TypeError
214
+ end
203
215
  end
204
- end
205
216
  end
206
217
  end
207
218
  end
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/string/strip'
1
+ require "active_support/core_ext/string/strip"
2
2
 
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
@@ -15,21 +15,21 @@ module ActiveRecord
15
15
  end
16
16
 
17
17
  delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
18
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options, to: :@conn
18
+ :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options, to: :@conn
19
19
  private :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
20
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options
20
+ :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options
21
21
 
22
22
  private
23
23
 
24
24
  def visit_AlterTable(o)
25
25
  sql = "ALTER TABLE #{quote_table_name(o.name)} "
26
- sql << o.adds.map { |col| accept col }.join(' ')
27
- sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(' ')
28
- sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(' ')
26
+ sql << o.adds.map { |col| accept col }.join(" ")
27
+ sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
28
+ sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
29
29
  end
30
30
 
31
31
  def visit_ColumnDefinition(o)
32
- o.sql_type ||= type_to_sql(o.type, o.limit, o.precision, o.scale)
32
+ o.sql_type = type_to_sql(o.type, o.options)
33
33
  column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
34
34
  add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
35
35
  column_sql
@@ -49,7 +49,7 @@ module ActiveRecord
49
49
  statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
50
50
  end
51
51
 
52
- if supports_foreign_keys?
52
+ if supports_foreign_keys_in_create?
53
53
  statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
54
54
  end
55
55
 
@@ -60,7 +60,7 @@ module ActiveRecord
60
60
  end
61
61
 
62
62
  def visit_PrimaryKeyDefinition(o)
63
- "PRIMARY KEY (#{o.name.join(', ')})"
63
+ "PRIMARY KEY (#{o.name.map { |name| quote_column_name(name) }.join(', ')})"
64
64
  end
65
65
 
66
66
  def visit_ForeignKeyDefinition(o)
@@ -96,17 +96,7 @@ module ActiveRecord
96
96
  end
97
97
 
98
98
  def column_options(o)
99
- column_options = {}
100
- column_options[:null] = o.null unless o.null.nil?
101
- column_options[:default] = o.default unless o.default.nil?
102
- column_options[:column] = o
103
- column_options[:first] = o.first
104
- column_options[:after] = o.after
105
- column_options[:auto_increment] = o.auto_increment
106
- column_options[:primary_key] = o.primary_key
107
- column_options[:collation] = o.collation
108
- column_options[:comment] = o.comment
109
- column_options
99
+ o.options.merge(column: o)
110
100
  end
111
101
 
112
102
  def add_column_options!(sql, options)