activerecord 5.1.0 → 5.2.3

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 (261) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +596 -450
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record.rb +11 -4
  8. data/lib/active_record/aggregations.rb +6 -5
  9. data/lib/active_record/association_relation.rb +7 -5
  10. data/lib/active_record/associations.rb +77 -85
  11. data/lib/active_record/associations/alias_tracker.rb +23 -32
  12. data/lib/active_record/associations/association.rb +49 -35
  13. data/lib/active_record/associations/association_scope.rb +55 -55
  14. data/lib/active_record/associations/belongs_to_association.rb +30 -11
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  16. data/lib/active_record/associations/builder/association.rb +4 -7
  17. data/lib/active_record/associations/builder/belongs_to.rb +21 -8
  18. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +2 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +66 -53
  24. data/lib/active_record/associations/collection_proxy.rb +30 -73
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +13 -2
  27. data/lib/active_record/associations/has_many_through_association.rb +37 -19
  28. data/lib/active_record/associations/has_one_association.rb +14 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +52 -96
  31. data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
  32. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  33. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  34. data/lib/active_record/associations/preloader.rb +17 -37
  35. data/lib/active_record/associations/preloader/association.rb +53 -92
  36. data/lib/active_record/associations/preloader/through_association.rb +72 -73
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +27 -12
  39. data/lib/active_record/attribute_assignment.rb +2 -5
  40. data/lib/active_record/attribute_decorators.rb +3 -2
  41. data/lib/active_record/attribute_methods.rb +65 -24
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +33 -216
  44. data/lib/active_record/attribute_methods/primary_key.rb +10 -13
  45. data/lib/active_record/attribute_methods/query.rb +2 -0
  46. data/lib/active_record/attribute_methods/read.rb +9 -3
  47. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  49. data/lib/active_record/attribute_methods/write.rb +22 -19
  50. data/lib/active_record/attributes.rb +7 -6
  51. data/lib/active_record/autosave_association.rb +15 -13
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +12 -6
  54. data/lib/active_record/coders/json.rb +2 -0
  55. data/lib/active_record/coders/yaml_column.rb +2 -0
  56. data/lib/active_record/collection_cache_key.rb +15 -11
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +65 -7
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
  70. data/lib/active_record/connection_adapters/column.rb +4 -2
  71. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  73. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -15
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -23
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +258 -129
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -87
  118. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +90 -96
  127. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  128. data/lib/active_record/connection_handling.rb +4 -2
  129. data/lib/active_record/core.rb +41 -61
  130. data/lib/active_record/counter_cache.rb +20 -15
  131. data/lib/active_record/define_callbacks.rb +5 -3
  132. data/lib/active_record/dynamic_matchers.rb +9 -9
  133. data/lib/active_record/enum.rb +18 -13
  134. data/lib/active_record/errors.rb +60 -15
  135. data/lib/active_record/explain.rb +3 -1
  136. data/lib/active_record/explain_registry.rb +2 -0
  137. data/lib/active_record/explain_subscriber.rb +2 -0
  138. data/lib/active_record/fixture_set/file.rb +2 -0
  139. data/lib/active_record/fixtures.rb +67 -60
  140. data/lib/active_record/gem_version.rb +4 -2
  141. data/lib/active_record/inheritance.rb +49 -19
  142. data/lib/active_record/integration.rb +58 -19
  143. data/lib/active_record/internal_metadata.rb +2 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  145. data/lib/active_record/locking/optimistic.rb +30 -42
  146. data/lib/active_record/locking/pessimistic.rb +10 -7
  147. data/lib/active_record/log_subscriber.rb +46 -4
  148. data/lib/active_record/migration.rb +189 -139
  149. data/lib/active_record/migration/command_recorder.rb +11 -9
  150. data/lib/active_record/migration/compatibility.rb +81 -29
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +74 -58
  153. data/lib/active_record/nested_attributes.rb +18 -6
  154. data/lib/active_record/no_touching.rb +3 -1
  155. data/lib/active_record/null_relation.rb +2 -0
  156. data/lib/active_record/persistence.rb +199 -54
  157. data/lib/active_record/query_cache.rb +8 -10
  158. data/lib/active_record/querying.rb +5 -3
  159. data/lib/active_record/railtie.rb +62 -6
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +2 -0
  162. data/lib/active_record/railties/databases.rake +48 -38
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +137 -207
  165. data/lib/active_record/relation.rb +132 -207
  166. data/lib/active_record/relation/batches.rb +32 -17
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +66 -25
  169. data/lib/active_record/relation/delegation.rb +45 -29
  170. data/lib/active_record/relation/finder_methods.rb +76 -85
  171. data/lib/active_record/relation/from_clause.rb +2 -8
  172. data/lib/active_record/relation/merger.rb +53 -23
  173. data/lib/active_record/relation/predicate_builder.rb +60 -79
  174. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  175. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  176. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  177. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  178. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  179. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  180. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  181. data/lib/active_record/relation/query_attribute.rb +28 -2
  182. data/lib/active_record/relation/query_methods.rb +135 -103
  183. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  184. data/lib/active_record/relation/spawn_methods.rb +4 -2
  185. data/lib/active_record/relation/where_clause.rb +65 -67
  186. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  187. data/lib/active_record/result.rb +2 -0
  188. data/lib/active_record/runtime_registry.rb +2 -0
  189. data/lib/active_record/sanitization.rb +129 -121
  190. data/lib/active_record/schema.rb +4 -2
  191. data/lib/active_record/schema_dumper.rb +36 -26
  192. data/lib/active_record/schema_migration.rb +2 -0
  193. data/lib/active_record/scoping.rb +12 -10
  194. data/lib/active_record/scoping/default.rb +10 -7
  195. data/lib/active_record/scoping/named.rb +40 -12
  196. data/lib/active_record/secure_token.rb +2 -0
  197. data/lib/active_record/serialization.rb +2 -0
  198. data/lib/active_record/statement_cache.rb +22 -12
  199. data/lib/active_record/store.rb +3 -1
  200. data/lib/active_record/suppressor.rb +2 -0
  201. data/lib/active_record/table_metadata.rb +12 -3
  202. data/lib/active_record/tasks/database_tasks.rb +38 -26
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +13 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +32 -27
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type.rb +4 -1
  211. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  212. data/lib/active_record/type/date.rb +2 -0
  213. data/lib/active_record/type/date_time.rb +2 -0
  214. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  215. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  216. data/lib/active_record/type/internal/timezone.rb +2 -0
  217. data/lib/active_record/type/json.rb +30 -0
  218. data/lib/active_record/type/serialized.rb +6 -0
  219. data/lib/active_record/type/text.rb +2 -0
  220. data/lib/active_record/type/time.rb +2 -0
  221. data/lib/active_record/type/type_map.rb +2 -0
  222. data/lib/active_record/type/unsigned_integer.rb +2 -0
  223. data/lib/active_record/type_caster.rb +2 -0
  224. data/lib/active_record/type_caster/connection.rb +2 -0
  225. data/lib/active_record/type_caster/map.rb +3 -1
  226. data/lib/active_record/validations.rb +2 -0
  227. data/lib/active_record/validations/absence.rb +2 -0
  228. data/lib/active_record/validations/associated.rb +2 -0
  229. data/lib/active_record/validations/length.rb +2 -0
  230. data/lib/active_record/validations/presence.rb +2 -0
  231. data/lib/active_record/validations/uniqueness.rb +36 -6
  232. data/lib/active_record/version.rb +2 -0
  233. data/lib/rails/generators/active_record.rb +3 -1
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  236. data/lib/rails/generators/active_record/migration.rb +2 -0
  237. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  238. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  239. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  243. metadata +24 -36
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute.rb +0 -240
  252. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -113
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -124
  256. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # :stopdoc:
3
5
  module ConnectionAdapters
@@ -9,11 +11,11 @@ module ActiveRecord
9
11
 
10
12
  # Instantiates a new column in the table.
11
13
  #
12
- # +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int</tt>.
14
+ # +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id bigint</tt>.
13
15
  # +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
14
16
  # +sql_type_metadata+ is various information about the type of the column
15
17
  # +null+ determines if this column allows +NULL+ values.
16
- def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
18
+ def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil, **)
17
19
  @name = name.freeze
18
20
  @table_name = table_name
19
21
  @sql_type_metadata = sql_type_metadata
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "uri"
2
4
 
3
5
  module ActiveRecord
@@ -181,13 +183,25 @@ module ActiveRecord
181
183
 
182
184
  raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
183
185
 
186
+ # Require the adapter itself and give useful feedback about
187
+ # 1. Missing adapter gems and
188
+ # 2. Adapter gems' missing dependencies.
184
189
  path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter"
185
190
  begin
186
191
  require path_to_adapter
187
- rescue Gem::LoadError => e
188
- raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord)."
189
192
  rescue LoadError => e
190
- raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/database.yml is valid. If you use an adapter other than 'mysql2', 'postgresql' or 'sqlite3' add the necessary adapter gem to the Gemfile.", e.backtrace
193
+ # We couldn't require the adapter itself. Raise an exception that
194
+ # points out config typos and missing gems.
195
+ if e.path == path_to_adapter
196
+ # We can assume that a non-builtin adapter was specified, so it's
197
+ # either misspelled or missing from Gemfile.
198
+ raise LoadError, "Could not load the '#{spec[:adapter]}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
199
+
200
+ # Bubbled up from the adapter require. Prefix the exception message
201
+ # with some guidance about how to address it and reraise.
202
+ else
203
+ raise LoadError, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
204
+ end
191
205
  end
192
206
 
193
207
  adapter_method = "#{spec[:adapter]}_connection"
@@ -1,15 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module DetermineIfPreparableVisitor
4
- attr_reader :preparable
6
+ attr_accessor :preparable
5
7
 
6
8
  def accept(*)
7
9
  @preparable = true
8
10
  super
9
11
  end
10
12
 
11
- def visit_Arel_Nodes_In(*)
13
+ def visit_Arel_Nodes_In(o, collector)
12
14
  @preparable = false
15
+
16
+ if Array === o.right && !o.right.empty?
17
+ o.right.delete_if do |bind|
18
+ if Arel::Nodes::BindParam === bind && Relation::QueryAttribute === bind.value
19
+ !bind.value.boundable?
20
+ end
21
+ end
22
+ end
23
+
13
24
  super
14
25
  end
15
26
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module MySQL
@@ -1,25 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module MySQL
4
6
  module DatabaseStatements
5
7
  # Returns an ActiveRecord::Result instance.
6
- def select_all(arel, name = nil, binds = [], preparable: nil) # :nodoc:
8
+ def select_all(*) # :nodoc:
7
9
  result = if ExplainRegistry.collect? && prepared_statements
8
10
  unprepared_statement { super }
9
11
  else
10
12
  super
11
13
  end
12
- @connection.next_result while @connection.more_results?
14
+ discard_remaining_results
13
15
  result
14
16
  end
15
17
 
16
- # Returns an array of arrays containing the field values.
17
- # Order is the same as that returned by +columns+.
18
- def select_rows(arel, name = nil, binds = []) # :nodoc:
19
- select_result(arel, name, binds) do |result|
20
- @connection.next_result while @connection.more_results?
21
- result.to_a
22
- end
18
+ def query(sql, name = nil) # :nodoc:
19
+ execute(sql, name).to_a
23
20
  end
24
21
 
25
22
  # Executes the SQL statement in the context of this connection.
@@ -53,18 +50,51 @@ module ActiveRecord
53
50
  alias :exec_update :exec_delete
54
51
 
55
52
  private
53
+ def default_insert_value(column)
54
+ Arel.sql("DEFAULT") unless column.auto_increment?
55
+ end
56
56
 
57
57
  def last_inserted_id(result)
58
58
  @connection.last_id
59
59
  end
60
60
 
61
- def select_result(arel, name, binds)
62
- arel, binds = binds_from_relation(arel, binds)
63
- sql = to_sql(arel, binds)
64
- if without_prepared_statement?(binds)
65
- execute_and_free(sql, name) { |result| yield result }
61
+ def discard_remaining_results
62
+ @connection.next_result while @connection.more_results?
63
+ end
64
+
65
+ def supports_set_server_option?
66
+ @connection.respond_to?(:set_server_option)
67
+ end
68
+
69
+ def multi_statements_enabled?(flags)
70
+ if flags.is_a?(Array)
71
+ flags.include?("MULTI_STATEMENTS")
66
72
  else
67
- exec_stmt_and_free(sql, name, binds, cache_stmt: true) { |_, result| yield result }
73
+ (flags & Mysql2::Client::MULTI_STATEMENTS) != 0
74
+ end
75
+ end
76
+
77
+ def with_multi_statements
78
+ previous_flags = @config[:flags]
79
+
80
+ unless multi_statements_enabled?(previous_flags)
81
+ if supports_set_server_option?
82
+ @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
83
+ else
84
+ @config[:flags] = Mysql2::Client::MULTI_STATEMENTS
85
+ reconnect!
86
+ end
87
+ end
88
+
89
+ yield
90
+ ensure
91
+ unless multi_statements_enabled?(previous_flags)
92
+ if supports_set_server_option?
93
+ @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
94
+ else
95
+ @config[:flags] = previous_flags
96
+ reconnect!
97
+ end
68
98
  end
69
99
  end
70
100
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module MySQL
@@ -1,9 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module MySQL
4
6
  module Quoting # :nodoc:
5
- QUOTED_TRUE, QUOTED_FALSE = "1".freeze, "0".freeze
6
-
7
7
  def quote_column_name(name)
8
8
  @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`".freeze
9
9
  end
@@ -12,18 +12,10 @@ module ActiveRecord
12
12
  @quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
13
13
  end
14
14
 
15
- def quoted_true
16
- QUOTED_TRUE
17
- end
18
-
19
15
  def unquoted_true
20
16
  1
21
17
  end
22
18
 
23
- def quoted_false
24
- QUOTED_FALSE
25
- end
26
-
27
19
  def unquoted_false
28
20
  0
29
21
  end
@@ -39,6 +31,13 @@ module ActiveRecord
39
31
  def quoted_binary(value)
40
32
  "x'#{value.hex}'"
41
33
  end
34
+
35
+ def _type_cast(value)
36
+ case value
37
+ when Date, Time then value
38
+ else super
39
+ end
40
+ end
42
41
  end
43
42
  end
44
43
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module MySQL
@@ -16,7 +18,7 @@ module ActiveRecord
16
18
  end
17
19
 
18
20
  def visit_ChangeColumnDefinition(o)
19
- change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}"
21
+ change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}".dup
20
22
  add_column_position!(change_column_sql, column_options(o.column))
21
23
  end
22
24
 
@@ -28,7 +30,7 @@ module ActiveRecord
28
30
  # By default, TIMESTAMP columns are NOT NULL, cannot contain NULL values,
29
31
  # and assigning NULL assigns the current timestamp. To permit a TIMESTAMP
30
32
  # column to contain NULL, explicitly declare it with the NULL attribute.
31
- # See http://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html
33
+ # See https://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html
32
34
  if /\Atimestamp\b/.match?(options[:column].sql_type) && !options[:primary_key]
33
35
  sql << " NULL" unless options[:null] == false || options_include_default?(options)
34
36
  end
@@ -63,7 +65,7 @@ module ActiveRecord
63
65
 
64
66
  def index_in_create(table_name, column_name, options)
65
67
  index_name, index_type, index_columns, _, _, index_using, comment = @conn.add_index_options(table_name, column_name, options)
66
- add_sql_comment!("#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})", comment)
68
+ add_sql_comment!("#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})".dup, comment)
67
69
  end
68
70
  end
69
71
  end
@@ -1,12 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module MySQL
4
6
  module ColumnMethods
5
- def primary_key(name, type = :primary_key, **options)
6
- options[:auto_increment] = true if [:integer, :bigint].include?(type) && !options.key?(:default)
7
- super
8
- end
9
-
10
7
  def blob(*args, **options)
11
8
  args.each { |name| column(name, :blob, options) }
12
9
  end
@@ -35,10 +32,6 @@ module ActiveRecord
35
32
  args.each { |name| column(name, :longtext, options) }
36
33
  end
37
34
 
38
- def json(*args, **options)
39
- args.each { |name| column(name, :json, options) }
40
- end
41
-
42
35
  def unsigned_integer(*args, **options)
43
36
  args.each { |name| column(name, :unsigned_integer, options) }
44
37
  end
@@ -66,7 +59,6 @@ module ActiveRecord
66
59
  when :primary_key
67
60
  type = :integer
68
61
  options[:limit] ||= 8
69
- options[:auto_increment] = true
70
62
  options[:primary_key] = true
71
63
  when /\Aunsigned_(?<type>.+)\z/
72
64
  type = $~[:type].to_sym
@@ -80,6 +72,11 @@ module ActiveRecord
80
72
  def aliased_types(name, fallback)
81
73
  fallback
82
74
  end
75
+
76
+ def integer_like_primary_key_type(type, options)
77
+ options[:auto_increment] = true
78
+ type
79
+ end
83
80
  end
84
81
 
85
82
  class Table < ActiveRecord::ConnectionAdapters::Table
@@ -1,25 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module MySQL
4
- module ColumnDumper # :nodoc:
5
- def prepare_column_options(column)
6
- spec = super
7
- spec[:unsigned] = "true" if column.unsigned?
8
-
9
- if supports_virtual_columns? && column.virtual?
10
- spec[:as] = extract_expression_for_virtual_column(column)
11
- spec[:stored] = "true" if /\b(?:STORED|PERSISTENT)\b/.match?(column.extra)
12
- spec = { type: schema_type(column).inspect }.merge!(spec)
13
- end
6
+ class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc:
7
+ private
8
+ def prepare_column_options(column)
9
+ spec = super
10
+ spec[:unsigned] = "true" if column.unsigned?
11
+ spec[:auto_increment] = "true" if column.auto_increment?
14
12
 
15
- spec
16
- end
13
+ if @connection.supports_virtual_columns? && column.virtual?
14
+ spec[:as] = extract_expression_for_virtual_column(column)
15
+ spec[:stored] = "true" if /\b(?:STORED|PERSISTENT)\b/.match?(column.extra)
16
+ spec = { type: schema_type(column).inspect }.merge!(spec)
17
+ end
17
18
 
18
- def migration_keys
19
- super + [:unsigned]
20
- end
19
+ spec
20
+ end
21
21
 
22
- private
22
+ def column_spec_for_primary_key(column)
23
+ spec = super
24
+ spec.delete(:auto_increment) if column.type == :integer && column.auto_increment?
25
+ spec
26
+ end
23
27
 
24
28
  def default_primary_key?(column)
25
29
  super && column.auto_increment? && !column.unsigned?
@@ -47,24 +51,27 @@ module ActiveRecord
47
51
  def schema_collation(column)
48
52
  if column.collation && table_name = column.table_name
49
53
  @table_collation_cache ||= {}
50
- @table_collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE '#{table_name}'")["Collation"]
54
+ @table_collation_cache[table_name] ||=
55
+ @connection.exec_query("SHOW TABLE STATUS LIKE #{@connection.quote(table_name)}", "SCHEMA").first["Collation"]
51
56
  column.collation.inspect if column.collation != @table_collation_cache[table_name]
52
57
  end
53
58
  end
54
59
 
55
60
  def extract_expression_for_virtual_column(column)
56
- if mariadb?
57
- create_table_info = create_table_info(column.table_name)
58
- if %r/#{quote_column_name(column.name)} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info
61
+ if @connection.mariadb? && @connection.version < "10.2.5"
62
+ create_table_info = @connection.send(:create_table_info, column.table_name)
63
+ column_name = @connection.quote_column_name(column.name)
64
+ if %r/#{column_name} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info
59
65
  $~[:expression].inspect
60
66
  end
61
67
  else
62
- scope = quoted_scope(column.table_name)
68
+ scope = @connection.send(:quoted_scope, column.table_name)
69
+ column_name = @connection.quote(column.name)
63
70
  sql = "SELECT generation_expression FROM information_schema.columns" \
64
71
  " WHERE table_schema = #{scope[:schema]}" \
65
72
  " AND table_name = #{scope[:name]}" \
66
- " AND column_name = #{quote(column.name)}"
67
- select_value(sql, "SCHEMA").inspect
73
+ " AND column_name = #{column_name}"
74
+ @connection.query_value(sql, "SCHEMA").inspect
68
75
  end
69
76
  end
70
77
  end
@@ -1,7 +1,56 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module MySQL
4
6
  module SchemaStatements # :nodoc:
7
+ # Returns an array of indexes for the given table.
8
+ def indexes(table_name)
9
+ indexes = []
10
+ current_index = nil
11
+ execute_and_free("SHOW KEYS FROM #{quote_table_name(table_name)}", "SCHEMA") do |result|
12
+ each_hash(result) do |row|
13
+ if current_index != row[:Key_name]
14
+ next if row[:Key_name] == "PRIMARY" # skip the primary key
15
+ current_index = row[:Key_name]
16
+
17
+ mysql_index_type = row[:Index_type].downcase.to_sym
18
+ case mysql_index_type
19
+ when :fulltext, :spatial
20
+ index_type = mysql_index_type
21
+ when :btree, :hash
22
+ index_using = mysql_index_type
23
+ end
24
+
25
+ indexes << [
26
+ row[:Table],
27
+ row[:Key_name],
28
+ row[:Non_unique].to_i == 0,
29
+ [],
30
+ lengths: {},
31
+ orders: {},
32
+ type: index_type,
33
+ using: index_using,
34
+ comment: row[:Index_comment].presence
35
+ ]
36
+ end
37
+
38
+ indexes.last[-2] << row[:Column_name]
39
+ indexes.last[-1][:lengths].merge!(row[:Column_name] => row[:Sub_part].to_i) if row[:Sub_part]
40
+ indexes.last[-1][:orders].merge!(row[:Column_name] => :desc) if row[:Collation] == "D"
41
+ end
42
+ end
43
+
44
+ indexes.map { |index| IndexDefinition.new(*index) }
45
+ end
46
+
47
+ def remove_column(table_name, column_name, type = nil, options = {})
48
+ if foreign_key_exists?(table_name, column: column_name)
49
+ remove_foreign_key(table_name, column: column_name)
50
+ end
51
+ super
52
+ end
53
+
5
54
  def internal_string_options_for_primary_key
6
55
  super.tap do |options|
7
56
  if CHARSETS_OF_4BYTES_MAXLEN.include?(charset) && (mariadb? || version < "8.0.0")
@@ -10,13 +59,69 @@ module ActiveRecord
10
59
  end
11
60
  end
12
61
 
62
+ def update_table_definition(table_name, base)
63
+ MySQL::Table.new(table_name, base)
64
+ end
65
+
66
+ def create_schema_dumper(options)
67
+ MySQL::SchemaDumper.create(self, options)
68
+ end
69
+
13
70
  private
14
71
  CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"]
15
72
 
73
+ def schema_creation
74
+ MySQL::SchemaCreation.new(self)
75
+ end
76
+
77
+ def create_table_definition(*args)
78
+ MySQL::TableDefinition.new(*args)
79
+ end
80
+
81
+ def new_column_from_field(table_name, field)
82
+ type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
83
+ if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(field[:Default])
84
+ default, default_function = nil, field[:Default]
85
+ else
86
+ default, default_function = field[:Default], nil
87
+ end
88
+
89
+ MySQL::Column.new(
90
+ field[:Field],
91
+ default,
92
+ type_metadata,
93
+ field[:Null] == "YES",
94
+ table_name,
95
+ default_function,
96
+ field[:Collation],
97
+ comment: field[:Comment].presence
98
+ )
99
+ end
100
+
101
+ def fetch_type_metadata(sql_type, extra = "")
102
+ MySQL::TypeMetadata.new(super(sql_type), extra: extra)
103
+ end
104
+
105
+ def extract_foreign_key_action(specifier)
106
+ super unless specifier == "RESTRICT"
107
+ end
108
+
109
+ def add_index_length(quoted_columns, **options)
110
+ lengths = options_for_index_columns(options[:length])
111
+ quoted_columns.each do |name, column|
112
+ column << "(#{lengths[name]})" if lengths[name].present?
113
+ end
114
+ end
115
+
116
+ def add_options_for_index_columns(quoted_columns, **options)
117
+ quoted_columns = add_index_length(quoted_columns, options)
118
+ super
119
+ end
120
+
16
121
  def data_source_sql(name = nil, type: nil)
17
122
  scope = quoted_scope(name, type: type)
18
123
 
19
- sql = "SELECT table_name FROM information_schema.tables"
124
+ sql = "SELECT table_name FROM information_schema.tables".dup
20
125
  sql << " WHERE table_schema = #{scope[:schema]}"
21
126
  sql << " AND table_name = #{scope[:name]}" if scope[:name]
22
127
  sql << " AND table_type = #{scope[:type]}" if scope[:type]