activerecord 4.2.11.3 → 5.0.0.beta1

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 (229) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1029 -1349
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record.rb +7 -3
  7. data/lib/active_record/aggregations.rb +35 -25
  8. data/lib/active_record/association_relation.rb +2 -2
  9. data/lib/active_record/associations.rb +305 -204
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +10 -8
  12. data/lib/active_record/associations/association_scope.rb +73 -102
  13. data/lib/active_record/associations/belongs_to_association.rb +20 -32
  14. data/lib/active_record/associations/builder/association.rb +28 -34
  15. data/lib/active_record/associations/builder/belongs_to.rb +41 -18
  16. data/lib/active_record/associations/builder/collection_association.rb +8 -24
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
  18. data/lib/active_record/associations/builder/has_many.rb +4 -4
  19. data/lib/active_record/associations/builder/has_one.rb +10 -5
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -9
  21. data/lib/active_record/associations/collection_association.rb +40 -43
  22. data/lib/active_record/associations/collection_proxy.rb +55 -29
  23. data/lib/active_record/associations/foreign_association.rb +1 -1
  24. data/lib/active_record/associations/has_many_association.rb +20 -71
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -52
  26. data/lib/active_record/associations/has_one_association.rb +12 -5
  27. data/lib/active_record/associations/join_dependency.rb +28 -18
  28. data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
  29. data/lib/active_record/associations/preloader.rb +13 -4
  30. data/lib/active_record/associations/preloader/association.rb +45 -51
  31. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +5 -4
  35. data/lib/active_record/associations/singular_association.rb +6 -0
  36. data/lib/active_record/associations/through_association.rb +11 -3
  37. data/lib/active_record/attribute.rb +61 -17
  38. data/lib/active_record/attribute/user_provided_default.rb +23 -0
  39. data/lib/active_record/attribute_assignment.rb +27 -140
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods.rb +79 -26
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  44. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  45. data/lib/active_record/attribute_methods/query.rb +2 -2
  46. data/lib/active_record/attribute_methods/read.rb +26 -42
  47. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
  49. data/lib/active_record/attribute_methods/write.rb +13 -24
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set.rb +30 -3
  52. data/lib/active_record/attribute_set/builder.rb +6 -4
  53. data/lib/active_record/attributes.rb +194 -81
  54. data/lib/active_record/autosave_association.rb +33 -15
  55. data/lib/active_record/base.rb +30 -18
  56. data/lib/active_record/callbacks.rb +36 -40
  57. data/lib/active_record/coders/yaml_column.rb +20 -8
  58. data/lib/active_record/collection_cache_key.rb +31 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
  70. data/lib/active_record/connection_adapters/column.rb +27 -41
  71. data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  85. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  87. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
  103. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  104. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
  107. data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
  108. data/lib/active_record/connection_handling.rb +5 -5
  109. data/lib/active_record/core.rb +72 -104
  110. data/lib/active_record/counter_cache.rb +9 -20
  111. data/lib/active_record/dynamic_matchers.rb +1 -20
  112. data/lib/active_record/enum.rb +110 -76
  113. data/lib/active_record/errors.rb +72 -47
  114. data/lib/active_record/explain_registry.rb +1 -1
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +19 -4
  117. data/lib/active_record/fixtures.rb +76 -40
  118. data/lib/active_record/gem_version.rb +4 -4
  119. data/lib/active_record/inheritance.rb +27 -40
  120. data/lib/active_record/integration.rb +4 -4
  121. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  122. data/lib/active_record/locale/en.yml +3 -2
  123. data/lib/active_record/locking/optimistic.rb +10 -14
  124. data/lib/active_record/locking/pessimistic.rb +1 -1
  125. data/lib/active_record/log_subscriber.rb +40 -22
  126. data/lib/active_record/migration.rb +304 -133
  127. data/lib/active_record/migration/command_recorder.rb +59 -18
  128. data/lib/active_record/migration/compatibility.rb +90 -0
  129. data/lib/active_record/model_schema.rb +92 -40
  130. data/lib/active_record/nested_attributes.rb +45 -34
  131. data/lib/active_record/null_relation.rb +15 -7
  132. data/lib/active_record/persistence.rb +112 -72
  133. data/lib/active_record/querying.rb +6 -5
  134. data/lib/active_record/railtie.rb +20 -13
  135. data/lib/active_record/railties/controller_runtime.rb +1 -1
  136. data/lib/active_record/railties/databases.rake +47 -38
  137. data/lib/active_record/readonly_attributes.rb +1 -1
  138. data/lib/active_record/reflection.rb +182 -57
  139. data/lib/active_record/relation.rb +152 -100
  140. data/lib/active_record/relation/batches.rb +133 -33
  141. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  142. data/lib/active_record/relation/calculations.rb +80 -101
  143. data/lib/active_record/relation/delegation.rb +6 -19
  144. data/lib/active_record/relation/finder_methods.rb +58 -46
  145. data/lib/active_record/relation/from_clause.rb +32 -0
  146. data/lib/active_record/relation/merger.rb +13 -42
  147. data/lib/active_record/relation/predicate_builder.rb +99 -105
  148. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  149. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
  150. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  151. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  152. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  153. data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
  154. data/lib/active_record/relation/query_attribute.rb +19 -0
  155. data/lib/active_record/relation/query_methods.rb +274 -238
  156. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  157. data/lib/active_record/relation/spawn_methods.rb +3 -6
  158. data/lib/active_record/relation/where_clause.rb +173 -0
  159. data/lib/active_record/relation/where_clause_factory.rb +37 -0
  160. data/lib/active_record/result.rb +4 -3
  161. data/lib/active_record/runtime_registry.rb +1 -1
  162. data/lib/active_record/sanitization.rb +94 -65
  163. data/lib/active_record/schema.rb +23 -22
  164. data/lib/active_record/schema_dumper.rb +33 -22
  165. data/lib/active_record/schema_migration.rb +10 -4
  166. data/lib/active_record/scoping.rb +17 -6
  167. data/lib/active_record/scoping/default.rb +19 -6
  168. data/lib/active_record/scoping/named.rb +39 -28
  169. data/lib/active_record/secure_token.rb +38 -0
  170. data/lib/active_record/serialization.rb +2 -4
  171. data/lib/active_record/statement_cache.rb +15 -13
  172. data/lib/active_record/store.rb +8 -3
  173. data/lib/active_record/suppressor.rb +54 -0
  174. data/lib/active_record/table_metadata.rb +64 -0
  175. data/lib/active_record/tasks/database_tasks.rb +30 -40
  176. data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
  177. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  178. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  179. data/lib/active_record/timestamp.rb +16 -9
  180. data/lib/active_record/touch_later.rb +58 -0
  181. data/lib/active_record/transactions.rb +138 -56
  182. data/lib/active_record/type.rb +66 -17
  183. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  184. data/lib/active_record/type/date.rb +2 -45
  185. data/lib/active_record/type/date_time.rb +2 -49
  186. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  187. data/lib/active_record/type/internal/timezone.rb +15 -0
  188. data/lib/active_record/type/serialized.rb +9 -14
  189. data/lib/active_record/type/time.rb +3 -21
  190. data/lib/active_record/type/type_map.rb +4 -4
  191. data/lib/active_record/type_caster.rb +7 -0
  192. data/lib/active_record/type_caster/connection.rb +29 -0
  193. data/lib/active_record/type_caster/map.rb +19 -0
  194. data/lib/active_record/validations.rb +33 -32
  195. data/lib/active_record/validations/absence.rb +24 -0
  196. data/lib/active_record/validations/associated.rb +10 -3
  197. data/lib/active_record/validations/length.rb +36 -0
  198. data/lib/active_record/validations/presence.rb +12 -12
  199. data/lib/active_record/validations/uniqueness.rb +24 -21
  200. data/lib/rails/generators/active_record/migration.rb +7 -0
  201. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  202. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  203. data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
  204. data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
  205. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  206. metadata +50 -35
  207. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  208. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  209. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  210. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  211. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  212. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  213. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  214. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  215. data/lib/active_record/type/big_integer.rb +0 -13
  216. data/lib/active_record/type/binary.rb +0 -50
  217. data/lib/active_record/type/boolean.rb +0 -31
  218. data/lib/active_record/type/decimal.rb +0 -64
  219. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  220. data/lib/active_record/type/decorator.rb +0 -14
  221. data/lib/active_record/type/float.rb +0 -19
  222. data/lib/active_record/type/integer.rb +0 -59
  223. data/lib/active_record/type/mutable.rb +0 -16
  224. data/lib/active_record/type/numeric.rb +0 -36
  225. data/lib/active_record/type/string.rb +0 -40
  226. data/lib/active_record/type/text.rb +0 -11
  227. data/lib/active_record/type/time_value.rb +0 -38
  228. data/lib/active_record/type/unsigned_integer.rb +0 -15
  229. data/lib/active_record/type/value.rb +0 -110
@@ -5,42 +5,32 @@ module ActiveRecord
5
5
  module ConnectionAdapters
6
6
  # An abstract definition of a column in a table.
7
7
  class Column
8
- TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].to_set
9
- FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set
8
+ attr_reader :name, :null, :sql_type_metadata, :default, :default_function, :collation
10
9
 
11
- module Format
12
- ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
13
- ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
14
- end
15
-
16
- attr_reader :name, :cast_type, :null, :sql_type, :default, :default_function
17
-
18
- delegate :type, :precision, :scale, :limit, :klass, :accessor,
19
- :text?, :number?, :binary?, :changed?,
20
- :type_cast_from_user, :type_cast_from_database, :type_cast_for_database,
21
- :type_cast_for_schema,
22
- to: :cast_type
10
+ delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
23
11
 
24
12
  # Instantiates a new column in the table.
25
13
  #
26
- # +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
14
+ # +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int</tt>.
27
15
  # +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
28
- # +cast_type+ is the object used for type casting and type information.
29
- # +sql_type+ is used to extract the column's length, if necessary. For example +60+ in
30
- # <tt>company_name varchar(60)</tt>.
31
- # It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
16
+ # +sql_type_metadata+ is various information about the type of the column
32
17
  # +null+ determines if this column allows +NULL+ values.
33
- def initialize(name, default, cast_type, sql_type = nil, null = true)
34
- @name = name.freeze
35
- @cast_type = cast_type
36
- @sql_type = sql_type
37
- @null = null
38
- @default = default
39
- @default_function = nil
18
+ def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation = nil)
19
+ @name = name.freeze
20
+ @sql_type_metadata = sql_type_metadata
21
+ @null = null
22
+ @default = default
23
+ @default_function = default_function
24
+ @collation = collation
25
+ @table_name = nil
40
26
  end
41
27
 
42
28
  def has_default?
43
- !default.nil?
29
+ !default.nil? || default_function
30
+ end
31
+
32
+ def bigint?
33
+ /bigint/ === sql_type
44
34
  end
45
35
 
46
36
  # Returns the human name of the column name.
@@ -51,19 +41,9 @@ module ActiveRecord
51
41
  Base.human_attribute_name(@name)
52
42
  end
53
43
 
54
- def with_type(type)
55
- dup.tap do |clone|
56
- clone.instance_variable_set('@cast_type', type)
57
- end
58
- end
59
-
60
44
  def ==(other)
61
- other.name == name &&
62
- other.default == default &&
63
- other.cast_type == cast_type &&
64
- other.sql_type == sql_type &&
65
- other.null == null &&
66
- other.default_function == default_function
45
+ other.is_a?(Column) &&
46
+ attributes_for_hash == other.attributes_for_hash
67
47
  end
68
48
  alias :eql? :==
69
49
 
@@ -71,10 +51,16 @@ module ActiveRecord
71
51
  attributes_for_hash.hash
72
52
  end
73
53
 
74
- private
54
+ protected
75
55
 
76
56
  def attributes_for_hash
77
- [self.class, name, default, cast_type, sql_type, null, default_function]
57
+ [self.class, name, default, sql_type_metadata, null, default_function, collation]
58
+ end
59
+ end
60
+
61
+ class NullColumn < Column
62
+ def initialize(name)
63
+ super(name, nil)
78
64
  end
79
65
  end
80
66
  end
@@ -1,5 +1,4 @@
1
1
  require 'uri'
2
- require 'active_support/core_ext/string/filters'
3
2
 
4
3
  module ActiveRecord
5
4
  module ConnectionAdapters
@@ -176,7 +175,7 @@ module ActiveRecord
176
175
  rescue Gem::LoadError => e
177
176
  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)."
178
177
  rescue LoadError => e
179
- 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 'mysql', 'mysql2', 'postgresql' or 'sqlite3' add the necessary adapter gem to the Gemfile.", e.backtrace
178
+ 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
180
179
  end
181
180
 
182
181
  adapter_method = "#{spec[:adapter]}_connection"
@@ -210,30 +209,12 @@ module ActiveRecord
210
209
  when Symbol
211
210
  resolve_symbol_connection spec
212
211
  when String
213
- resolve_string_connection spec
212
+ resolve_url_connection spec
214
213
  when Hash
215
214
  resolve_hash_connection spec
216
215
  end
217
216
  end
218
217
 
219
- def resolve_string_connection(spec)
220
- # Rails has historically accepted a string to mean either
221
- # an environment key or a URL spec, so we have deprecated
222
- # this ambiguous behaviour and in the future this function
223
- # can be removed in favor of resolve_url_connection.
224
- if configurations.key?(spec) || spec !~ /:/
225
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
226
- Passing a string to ActiveRecord::Base.establish_connection for a
227
- configuration lookup is deprecated, please pass a symbol
228
- (#{spec.to_sym.inspect}) instead.
229
- MSG
230
-
231
- resolve_symbol_connection(spec)
232
- else
233
- resolve_url_connection(spec)
234
- end
235
- end
236
-
237
218
  # Takes the environment such as +:production+ or +:development+.
238
219
  # This requires that the @configurations was initialized with a key that
239
220
  # matches.
@@ -0,0 +1,22 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module DetermineIfPreparableVisitor
4
+ attr_reader :preparable
5
+
6
+ def accept(*)
7
+ @preparable = true
8
+ super
9
+ end
10
+
11
+ def visit_Arel_Nodes_In(*)
12
+ @preparable = false
13
+ super
14
+ end
15
+
16
+ def visit_Arel_Nodes_SqlLiteral(*)
17
+ @preparable = false
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,57 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module MySQL
4
+ class SchemaCreation < AbstractAdapter::SchemaCreation
5
+ private
6
+
7
+ def visit_DropForeignKey(name)
8
+ "DROP FOREIGN KEY #{name}"
9
+ end
10
+
11
+ def visit_ColumnDefinition(o)
12
+ o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.unsigned)
13
+ super
14
+ end
15
+
16
+ def visit_AddColumnDefinition(o)
17
+ add_column_position!(super, column_options(o.column))
18
+ end
19
+
20
+ def visit_ChangeColumnDefinition(o)
21
+ change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}"
22
+ add_column_position!(change_column_sql, column_options(o.column))
23
+ end
24
+
25
+ def column_options(o)
26
+ column_options = super
27
+ column_options[:charset] = o.charset
28
+ column_options
29
+ end
30
+
31
+ def add_column_options!(sql, options)
32
+ if options[:charset]
33
+ sql << " CHARACTER SET #{options[:charset]}"
34
+ end
35
+ if options[:collation]
36
+ sql << " COLLATE #{options[:collation]}"
37
+ end
38
+ super
39
+ end
40
+
41
+ def add_column_position!(sql, options)
42
+ if options[:first]
43
+ sql << " FIRST"
44
+ elsif options[:after]
45
+ sql << " AFTER #{quote_column_name(options[:after])}"
46
+ end
47
+ sql
48
+ end
49
+
50
+ def index_in_create(table_name, column_name, options)
51
+ index_name, index_type, index_columns, _, _, index_using = @conn.add_index_options(table_name, column_name, options)
52
+ "#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns}) "
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,69 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module MySQL
4
+ module ColumnMethods
5
+ def primary_key(name, type = :primary_key, **options)
6
+ options[:auto_increment] = true if type == :bigint && !options.key?(:default)
7
+ super
8
+ end
9
+
10
+ def blob(*args, **options)
11
+ args.each { |name| column(name, :blob, options) }
12
+ end
13
+
14
+ def json(*args, **options)
15
+ args.each { |name| column(name, :json, options) }
16
+ end
17
+
18
+ def unsigned_integer(*args, **options)
19
+ args.each { |name| column(name, :unsigned_integer, options) }
20
+ end
21
+
22
+ def unsigned_bigint(*args, **options)
23
+ args.each { |name| column(name, :unsigned_bigint, options) }
24
+ end
25
+
26
+ def unsigned_float(*args, **options)
27
+ args.each { |name| column(name, :unsigned_float, options) }
28
+ end
29
+
30
+ def unsigned_decimal(*args, **options)
31
+ args.each { |name| column(name, :unsigned_decimal, options) }
32
+ end
33
+ end
34
+
35
+ class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
36
+ attr_accessor :charset, :unsigned
37
+ end
38
+
39
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
40
+ include ColumnMethods
41
+
42
+ def new_column_definition(name, type, options) # :nodoc:
43
+ column = super
44
+ case column.type
45
+ when :primary_key
46
+ column.type = :integer
47
+ column.auto_increment = true
48
+ when /\Aunsigned_(?<type>.+)\z/
49
+ column.type = $~[:type].to_sym
50
+ column.unsigned = true
51
+ end
52
+ column.unsigned ||= options[:unsigned]
53
+ column.charset = options[:charset]
54
+ column
55
+ end
56
+
57
+ private
58
+
59
+ def create_column_definition(name, type)
60
+ MySQL::ColumnDefinition.new(name, type)
61
+ end
62
+ end
63
+
64
+ class Table < ActiveRecord::ConnectionAdapters::Table
65
+ include ColumnMethods
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,59 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module MySQL
4
+ module ColumnDumper
5
+ def column_spec_for_primary_key(column)
6
+ spec = {}
7
+ if column.bigint?
8
+ spec[:id] = ':bigint'
9
+ spec[:default] = schema_default(column) || 'nil' unless column.auto_increment?
10
+ spec[:unsigned] = 'true' if column.unsigned?
11
+ elsif column.auto_increment?
12
+ spec[:unsigned] = 'true' if column.unsigned?
13
+ return if spec.empty?
14
+ else
15
+ spec[:id] = column.type.inspect
16
+ spec.merge!(prepare_column_options(column).delete_if { |key, _| [:name, :type, :null].include?(key) })
17
+ end
18
+ spec
19
+ end
20
+
21
+ def prepare_column_options(column)
22
+ spec = super
23
+ spec[:unsigned] = 'true' if column.unsigned?
24
+ spec
25
+ end
26
+
27
+ def migration_keys
28
+ super + [:unsigned]
29
+ end
30
+
31
+ private
32
+
33
+ def schema_type(column)
34
+ if column.sql_type == 'tinyblob'
35
+ 'blob'
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ def schema_limit(column)
42
+ super unless column.type == :boolean
43
+ end
44
+
45
+ def schema_precision(column)
46
+ super unless /time/ === column.sql_type && column.precision == 0
47
+ end
48
+
49
+ def schema_collation(column)
50
+ if column.collation && table_name = column.instance_variable_get(:@table_name)
51
+ @table_collation_cache ||= {}
52
+ @table_collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE '#{table_name}'")["Collation"]
53
+ column.collation.inspect if column.collation != @table_collation_cache[table_name]
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,6 +1,6 @@
1
1
  require 'active_record/connection_adapters/abstract_mysql_adapter'
2
2
 
3
- gem 'mysql2', '>= 0.3.13', '< 0.6.0'
3
+ gem 'mysql2', '>= 0.3.18', '< 0.5'
4
4
  require 'mysql2'
5
5
 
6
6
  module ActiveRecord
@@ -10,17 +10,16 @@ module ActiveRecord
10
10
  config = config.symbolize_keys
11
11
 
12
12
  config[:username] = 'root' if config[:username].nil?
13
-
13
+ config[:flags] ||= 0
14
14
  if Mysql2::Client.const_defined? :FOUND_ROWS
15
- config[:flags] = Mysql2::Client::FOUND_ROWS
15
+ config[:flags] |= Mysql2::Client::FOUND_ROWS
16
16
  end
17
17
 
18
18
  client = Mysql2::Client.new(config)
19
- options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
20
- ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
19
+ ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config)
21
20
  rescue Mysql2::Error => error
22
21
  if error.message.include?("Unknown database")
23
- raise ActiveRecord::NoDatabaseError.new(error.message, error)
22
+ raise ActiveRecord::NoDatabaseError
24
23
  else
25
24
  raise
26
25
  end
@@ -37,17 +36,8 @@ module ActiveRecord
37
36
  configure_connection
38
37
  end
39
38
 
40
- MAX_INDEX_LENGTH_FOR_UTF8MB4 = 191
41
- def initialize_schema_migrations_table
42
- if charset == 'utf8mb4'
43
- ActiveRecord::SchemaMigration.create_table(MAX_INDEX_LENGTH_FOR_UTF8MB4)
44
- else
45
- ActiveRecord::SchemaMigration.create_table
46
- end
47
- end
48
-
49
- def supports_explain?
50
- true
39
+ def supports_json?
40
+ version >= '5.7.8'
51
41
  end
52
42
 
53
43
  # HELPER METHODS ===========================================
@@ -79,6 +69,7 @@ module ActiveRecord
79
69
  #++
80
70
 
81
71
  def active?
72
+ return false unless @connection
82
73
  @connection.ping
83
74
  end
84
75
 
@@ -93,87 +84,16 @@ module ActiveRecord
93
84
  # Otherwise, this method does nothing.
94
85
  def disconnect!
95
86
  super
96
- @connection.close
87
+ unless @connection.nil?
88
+ @connection.close
89
+ @connection = nil
90
+ end
97
91
  end
98
92
 
99
93
  #--
100
94
  # DATABASE STATEMENTS ======================================
101
95
  #++
102
96
 
103
- def explain(arel, binds = [])
104
- sql = "EXPLAIN #{to_sql(arel, binds.dup)}"
105
- start = Time.now
106
- result = exec_query(sql, 'EXPLAIN', binds)
107
- elapsed = Time.now - start
108
-
109
- ExplainPrettyPrinter.new.pp(result, elapsed)
110
- end
111
-
112
- class ExplainPrettyPrinter # :nodoc:
113
- # Pretty prints the result of a EXPLAIN in a way that resembles the output of the
114
- # MySQL shell:
115
- #
116
- # +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
117
- # | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
118
- # +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
119
- # | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
120
- # | 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
121
- # +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
122
- # 2 rows in set (0.00 sec)
123
- #
124
- # This is an exercise in Ruby hyperrealism :).
125
- def pp(result, elapsed)
126
- widths = compute_column_widths(result)
127
- separator = build_separator(widths)
128
-
129
- pp = []
130
-
131
- pp << separator
132
- pp << build_cells(result.columns, widths)
133
- pp << separator
134
-
135
- result.rows.each do |row|
136
- pp << build_cells(row, widths)
137
- end
138
-
139
- pp << separator
140
- pp << build_footer(result.rows.length, elapsed)
141
-
142
- pp.join("\n") + "\n"
143
- end
144
-
145
- private
146
-
147
- def compute_column_widths(result)
148
- [].tap do |widths|
149
- result.columns.each_with_index do |column, i|
150
- cells_in_column = [column] + result.rows.map {|r| r[i].nil? ? 'NULL' : r[i].to_s}
151
- widths << cells_in_column.map(&:length).max
152
- end
153
- end
154
- end
155
-
156
- def build_separator(widths)
157
- padding = 1
158
- '+' + widths.map {|w| '-' * (w + (padding*2))}.join('+') + '+'
159
- end
160
-
161
- def build_cells(items, widths)
162
- cells = []
163
- items.each_with_index do |item, i|
164
- item = 'NULL' if item.nil?
165
- justifier = item.is_a?(Numeric) ? 'rjust' : 'ljust'
166
- cells << item.to_s.send(justifier, widths[i])
167
- end
168
- '| ' + cells.join(' | ') + ' |'
169
- end
170
-
171
- def build_footer(nrows, elapsed)
172
- rows_label = nrows == 1 ? 'row' : 'rows'
173
- "#{nrows} #{rows_label} in set (%.2f sec)" % elapsed
174
- end
175
- end
176
-
177
97
  # FIXME: re-enable the following once a "better" query_cache solution is in core
178
98
  #
179
99
  # The overrides below perform much better than the originals in AbstractAdapter
@@ -205,20 +125,25 @@ module ActiveRecord
205
125
  # Returns an array of arrays containing the field values.
206
126
  # Order is the same as that returned by +columns+.
207
127
  def select_rows(sql, name = nil, binds = [])
208
- execute(sql, name).to_a
128
+ result = execute(sql, name)
129
+ @connection.next_result while @connection.more_results?
130
+ result.to_a
209
131
  end
210
132
 
211
133
  # Executes the SQL statement in the context of this connection.
212
134
  def execute(sql, name = nil)
213
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
214
- # made since we established the connection
215
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
135
+ if @connection
136
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
137
+ # made since we established the connection
138
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
139
+ end
216
140
 
217
141
  super
218
142
  end
219
143
 
220
- def exec_query(sql, name = 'SQL', binds = [])
144
+ def exec_query(sql, name = 'SQL', binds = [], prepare: false)
221
145
  result = execute(sql, name)
146
+ @connection.next_result while @connection.more_results?
222
147
  ActiveRecord::Result.new(result.fields, result.to_a)
223
148
  end
224
149
 
@@ -259,10 +184,6 @@ module ActiveRecord
259
184
  def full_version
260
185
  @full_version ||= @connection.server_info[:version]
261
186
  end
262
-
263
- def set_field_encoding field_name
264
- field_name
265
- end
266
187
  end
267
188
  end
268
189
  end