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,66 +1,70 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module MySQL
4
- class SchemaCreation < AbstractAdapter::SchemaCreation
5
- delegate :add_sql_comment!, to: :@conn
6
- private :add_sql_comment!
4
+ class SchemaCreation < AbstractAdapter::SchemaCreation # :nodoc:
5
+ delegate :add_sql_comment!, :mariadb?, to: :@conn
6
+ private :add_sql_comment!, :mariadb?
7
7
 
8
8
  private
9
9
 
10
- def visit_DropForeignKey(name)
11
- "DROP FOREIGN KEY #{name}"
12
- end
10
+ def visit_DropForeignKey(name)
11
+ "DROP FOREIGN KEY #{name}"
12
+ end
13
+
14
+ def visit_AddColumnDefinition(o)
15
+ add_column_position!(super, column_options(o.column))
16
+ end
13
17
 
14
- def visit_ColumnDefinition(o)
15
- o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.unsigned)
16
- super
17
- end
18
+ def visit_ChangeColumnDefinition(o)
19
+ change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}"
20
+ add_column_position!(change_column_sql, column_options(o.column))
21
+ end
18
22
 
19
- def visit_AddColumnDefinition(o)
20
- add_column_position!(super, column_options(o.column))
21
- end
23
+ def add_table_options!(create_sql, options)
24
+ add_sql_comment!(super, options[:comment])
25
+ end
22
26
 
23
- def visit_ChangeColumnDefinition(o)
24
- change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}"
25
- add_column_position!(change_column_sql, column_options(o.column))
26
- end
27
+ def add_column_options!(sql, options)
28
+ # By default, TIMESTAMP columns are NOT NULL, cannot contain NULL values,
29
+ # and assigning NULL assigns the current timestamp. To permit a TIMESTAMP
30
+ # 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
32
+ if /\Atimestamp\b/.match?(options[:column].sql_type) && !options[:primary_key]
33
+ sql << " NULL" unless options[:null] == false || options_include_default?(options)
34
+ end
27
35
 
28
- def add_table_options!(create_sql, options)
29
- add_sql_comment!(super, options[:comment])
30
- end
36
+ if charset = options[:charset]
37
+ sql << " CHARACTER SET #{charset}"
38
+ end
31
39
 
32
- def column_options(o)
33
- column_options = super
34
- column_options[:charset] = o.charset
35
- column_options
36
- end
40
+ if collation = options[:collation]
41
+ sql << " COLLATE #{collation}"
42
+ end
37
43
 
38
- def add_column_options!(sql, options)
39
- if charset = options[:charset]
40
- sql << " CHARACTER SET #{charset}"
41
- end
44
+ if as = options[:as]
45
+ sql << " AS (#{as})"
46
+ if options[:stored]
47
+ sql << (mariadb? ? " PERSISTENT" : " STORED")
48
+ end
49
+ end
42
50
 
43
- if collation = options[:collation]
44
- sql << " COLLATE #{collation}"
51
+ add_sql_comment!(super, options[:comment])
45
52
  end
46
53
 
47
- add_sql_comment!(super, options[:comment])
48
- end
54
+ def add_column_position!(sql, options)
55
+ if options[:first]
56
+ sql << " FIRST"
57
+ elsif options[:after]
58
+ sql << " AFTER #{quote_column_name(options[:after])}"
59
+ end
49
60
 
50
- def add_column_position!(sql, options)
51
- if options[:first]
52
- sql << " FIRST"
53
- elsif options[:after]
54
- sql << " AFTER #{quote_column_name(options[:after])}"
61
+ sql
55
62
  end
56
63
 
57
- sql
58
- end
59
-
60
- def index_in_create(table_name, column_name, options)
61
- index_name, index_type, index_columns, _, _, index_using, comment = @conn.add_index_options(table_name, column_name, options)
62
- add_sql_comment!("#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})", comment)
63
- end
64
+ def index_in_create(table_name, column_name, options)
65
+ 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)
67
+ end
64
68
  end
65
69
  end
66
70
  end
@@ -3,7 +3,7 @@ module ActiveRecord
3
3
  module MySQL
4
4
  module ColumnMethods
5
5
  def primary_key(name, type = :primary_key, **options)
6
- options[:auto_increment] = true if type == :bigint && !options.key?(:default)
6
+ options[:auto_increment] = true if [:integer, :bigint].include?(type) && !options.key?(:default)
7
7
  super
8
8
  end
9
9
 
@@ -56,33 +56,30 @@ module ActiveRecord
56
56
  end
57
57
  end
58
58
 
59
- class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
60
- attr_accessor :charset, :unsigned
61
- end
62
-
63
59
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
64
60
  include ColumnMethods
65
61
 
66
- def new_column_definition(name, type, options) # :nodoc:
67
- column = super
68
- case column.type
62
+ def new_column_definition(name, type, **options) # :nodoc:
63
+ case type
64
+ when :virtual
65
+ type = options[:type]
69
66
  when :primary_key
70
- column.type = :integer
71
- column.auto_increment = true
67
+ type = :integer
68
+ options[:limit] ||= 8
69
+ options[:auto_increment] = true
70
+ options[:primary_key] = true
72
71
  when /\Aunsigned_(?<type>.+)\z/
73
- column.type = $~[:type].to_sym
74
- column.unsigned = true
72
+ type = $~[:type].to_sym
73
+ options[:unsigned] = true
75
74
  end
76
- column.unsigned ||= options[:unsigned]
77
- column.charset = options[:charset]
78
- column
75
+
76
+ super
79
77
  end
80
78
 
81
79
  private
82
-
83
- def create_column_definition(name, type)
84
- MySQL::ColumnDefinition.new(name, type)
85
- end
80
+ def aliased_types(name, fallback)
81
+ fallback
82
+ end
86
83
  end
87
84
 
88
85
  class Table < ActiveRecord::ConnectionAdapters::Table
@@ -1,21 +1,24 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module MySQL
4
- module ColumnDumper
5
- def column_spec_for_primary_key(column)
6
- if column.bigint?
7
- spec = { id: :bigint.inspect }
8
- spec[:default] = schema_default(column) || 'nil' unless column.auto_increment?
9
- else
10
- spec = super
4
+ module ColumnDumper # :nodoc:
5
+ def prepare_column_options(column)
6
+ spec = super
7
+ spec[:unsigned] = "true" if column.unsigned?
8
+ spec[:auto_increment] = "true" if column.auto_increment?
9
+
10
+ if supports_virtual_columns? && column.virtual?
11
+ spec[:as] = extract_expression_for_virtual_column(column)
12
+ spec[:stored] = "true" if /\b(?:STORED|PERSISTENT)\b/.match?(column.extra)
13
+ spec = { type: schema_type(column).inspect }.merge!(spec)
11
14
  end
12
- spec[:unsigned] = 'true' if column.unsigned?
15
+
13
16
  spec
14
17
  end
15
18
 
16
- def prepare_column_options(column)
19
+ def column_spec_for_primary_key(column)
17
20
  spec = super
18
- spec[:unsigned] = 'true' if column.unsigned?
21
+ spec.delete(:auto_increment) if column.type == :integer && column.auto_increment?
19
22
  spec
20
23
  end
21
24
 
@@ -25,29 +28,52 @@ module ActiveRecord
25
28
 
26
29
  private
27
30
 
28
- def default_primary_key?(column)
29
- super && column.auto_increment?
30
- end
31
+ def default_primary_key?(column)
32
+ super && column.auto_increment? && !column.unsigned?
33
+ end
31
34
 
32
- def schema_type(column)
33
- if column.sql_type == 'tinyblob'
34
- :blob
35
- else
36
- super
35
+ def explicit_primary_key_default?(column)
36
+ column.type == :integer && !column.auto_increment?
37
37
  end
38
- end
39
38
 
40
- def schema_precision(column)
41
- super unless /time/ === column.sql_type && column.precision == 0
42
- end
39
+ def schema_type(column)
40
+ case column.sql_type
41
+ when /\Atimestamp\b/
42
+ :timestamp
43
+ when "tinyblob"
44
+ :blob
45
+ else
46
+ super
47
+ end
48
+ end
43
49
 
44
- def schema_collation(column)
45
- if column.collation && table_name = column.table_name
46
- @table_collation_cache ||= {}
47
- @table_collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE '#{table_name}'")["Collation"]
48
- column.collation.inspect if column.collation != @table_collation_cache[table_name]
50
+ def schema_precision(column)
51
+ super unless /\A(?:date)?time(?:stamp)?\b/.match?(column.sql_type) && column.precision == 0
52
+ end
53
+
54
+ def schema_collation(column)
55
+ if column.collation && table_name = column.table_name
56
+ @table_collation_cache ||= {}
57
+ @table_collation_cache[table_name] ||= exec_query("SHOW TABLE STATUS LIKE #{quote(table_name)}", "SCHEMA").first["Collation"]
58
+ column.collation.inspect if column.collation != @table_collation_cache[table_name]
59
+ end
60
+ end
61
+
62
+ def extract_expression_for_virtual_column(column)
63
+ if mariadb? && version < "10.2.5"
64
+ create_table_info = create_table_info(column.table_name)
65
+ if %r/#{quote_column_name(column.name)} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info
66
+ $~[:expression].inspect
67
+ end
68
+ else
69
+ scope = quoted_scope(column.table_name)
70
+ sql = "SELECT generation_expression FROM information_schema.columns" \
71
+ " WHERE table_schema = #{scope[:schema]}" \
72
+ " AND table_name = #{scope[:name]}" \
73
+ " AND column_name = #{quote(column.name)}"
74
+ query_value(sql, "SCHEMA").inspect
75
+ end
49
76
  end
50
- end
51
77
  end
52
78
  end
53
79
  end
@@ -0,0 +1,43 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module MySQL
4
+ module SchemaStatements # :nodoc:
5
+ def internal_string_options_for_primary_key
6
+ super.tap do |options|
7
+ if CHARSETS_OF_4BYTES_MAXLEN.include?(charset) && (mariadb? || version < "8.0.0")
8
+ options[:collation] = collation.sub(/\A[^_]+/, "utf8")
9
+ end
10
+ end
11
+ end
12
+
13
+ private
14
+ CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"]
15
+
16
+ def data_source_sql(name = nil, type: nil)
17
+ scope = quoted_scope(name, type: type)
18
+
19
+ sql = "SELECT table_name FROM information_schema.tables"
20
+ sql << " WHERE table_schema = #{scope[:schema]}"
21
+ sql << " AND table_name = #{scope[:name]}" if scope[:name]
22
+ sql << " AND table_type = #{scope[:type]}" if scope[:type]
23
+ sql
24
+ end
25
+
26
+ def quoted_scope(name = nil, type: nil)
27
+ schema, name = extract_schema_qualified_name(name)
28
+ scope = {}
29
+ scope[:schema] = schema ? quote(schema) : "database()"
30
+ scope[:name] = quote(name) if name
31
+ scope[:type] = quote(type) if type
32
+ scope
33
+ end
34
+
35
+ def extract_schema_qualified_name(string)
36
+ schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/)
37
+ schema, name = nil, schema unless name
38
+ [schema, name]
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -2,13 +2,14 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module MySQL
4
4
  class TypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc:
5
- attr_reader :extra, :strict
5
+ undef to_yaml if method_defined?(:to_yaml)
6
6
 
7
- def initialize(type_metadata, extra: "", strict: false)
7
+ attr_reader :extra
8
+
9
+ def initialize(type_metadata, extra: "")
8
10
  super(type_metadata)
9
11
  @type_metadata = type_metadata
10
12
  @extra = extra
11
- @strict = strict
12
13
  end
13
14
 
14
15
  def ==(other)
@@ -23,9 +24,9 @@ module ActiveRecord
23
24
 
24
25
  protected
25
26
 
26
- def attributes_for_hash
27
- [self.class, @type_metadata, extra, strict]
28
- end
27
+ def attributes_for_hash
28
+ [self.class, @type_metadata, extra]
29
+ end
29
30
  end
30
31
  end
31
32
  end
@@ -1,25 +1,21 @@
1
- require 'active_record/connection_adapters/abstract_mysql_adapter'
2
- require 'active_record/connection_adapters/mysql/database_statements'
1
+ require "active_record/connection_adapters/abstract_mysql_adapter"
2
+ require "active_record/connection_adapters/mysql/database_statements"
3
3
 
4
- gem 'mysql2', '>= 0.3.18', '< 0.6.0'
5
- require 'mysql2'
6
- raise 'mysql2 0.4.3 is not supported. Please upgrade to 0.4.4+' if Mysql2::VERSION == '0.4.3'
4
+ gem "mysql2", ">= 0.3.18", "< 0.6.0"
5
+ require "mysql2"
6
+ raise "mysql2 0.4.3 is not supported. Please upgrade to 0.4.4+" if Mysql2::VERSION == "0.4.3"
7
7
 
8
8
  module ActiveRecord
9
9
  module ConnectionHandling # :nodoc:
10
10
  # Establishes a connection to the database that's used by all Active Record objects.
11
11
  def mysql2_connection(config)
12
12
  config = config.symbolize_keys
13
-
14
- config[:username] = 'root' if config[:username].nil?
15
13
  config[:flags] ||= 0
16
14
 
17
- if Mysql2::Client.const_defined? :FOUND_ROWS
18
- if config[:flags].kind_of? Array
19
- config[:flags].push "FOUND_ROWS".freeze
20
- else
21
- config[:flags] |= Mysql2::Client::FOUND_ROWS
22
- end
15
+ if config[:flags].kind_of? Array
16
+ config[:flags].push "FOUND_ROWS".freeze
17
+ else
18
+ config[:flags] |= Mysql2::Client::FOUND_ROWS
23
19
  end
24
20
 
25
21
  client = Mysql2::Client.new(config)
@@ -35,7 +31,7 @@ module ActiveRecord
35
31
 
36
32
  module ConnectionAdapters
37
33
  class Mysql2Adapter < AbstractMysqlAdapter
38
- ADAPTER_NAME = 'Mysql2'.freeze
34
+ ADAPTER_NAME = "Mysql2".freeze
39
35
 
40
36
  include MySQL::DatabaseStatements
41
37
 
@@ -46,7 +42,7 @@ module ActiveRecord
46
42
  end
47
43
 
48
44
  def supports_json?
49
- !mariadb? && version >= '5.7.8'
45
+ !mariadb? && version >= "5.7.8"
50
46
  end
51
47
 
52
48
  def supports_comments?
@@ -65,7 +61,7 @@ module ActiveRecord
65
61
 
66
62
  def each_hash(result) # :nodoc:
67
63
  if block_given?
68
- result.each(:as => :hash, :symbolize_keys => true) do |row|
64
+ result.each(as: :hash, symbolize_keys: true) do |row|
69
65
  yield row
70
66
  end
71
67
  else
@@ -109,19 +105,19 @@ module ActiveRecord
109
105
 
110
106
  private
111
107
 
112
- def connect
113
- @connection = Mysql2::Client.new(@config)
114
- configure_connection
115
- end
108
+ def connect
109
+ @connection = Mysql2::Client.new(@config)
110
+ configure_connection
111
+ end
116
112
 
117
- def configure_connection
118
- @connection.query_options.merge!(:as => :array)
119
- super
120
- end
113
+ def configure_connection
114
+ @connection.query_options.merge!(as: :array)
115
+ super
116
+ end
121
117
 
122
- def full_version
123
- @full_version ||= @connection.server_info[:version]
124
- end
118
+ def full_version
119
+ @full_version ||= @connection.server_info[:version]
120
+ end
125
121
  end
126
122
  end
127
123
  end
@@ -4,35 +4,7 @@ module ActiveRecord
4
4
  module DatabaseStatements
5
5
  def explain(arel, binds = [])
6
6
  sql = "EXPLAIN #{to_sql(arel, binds)}"
7
- PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
8
- end
9
-
10
- def select_value(arel, name = nil, binds = [])
11
- arel, binds = binds_from_relation arel, binds
12
- sql = to_sql(arel, binds)
13
- execute_and_clear(sql, name, binds) do |result|
14
- result.getvalue(0, 0) if result.ntuples > 0 && result.nfields > 0
15
- end
16
- end
17
-
18
- def select_values(arel, name = nil, binds = [])
19
- arel, binds = binds_from_relation arel, binds
20
- sql = to_sql(arel, binds)
21
- execute_and_clear(sql, name, binds) do |result|
22
- if result.nfields > 0
23
- result.column_values(0)
24
- else
25
- []
26
- end
27
- end
28
- end
29
-
30
- # Executes a SELECT query and returns an array of rows. Each row is an
31
- # array of field values.
32
- def select_rows(sql, name = nil, binds = [])
33
- execute_and_clear(sql, name, binds) do |result|
34
- result.values
35
- end
7
+ PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", binds))
36
8
  end
37
9
 
38
10
  # The internal PostgreSQL identifier of the money data type.
@@ -74,9 +46,9 @@ module ActiveRecord
74
46
  # (2) $12.345.678,12
75
47
  case data
76
48
  when /^-?\D+[\d,]+\.\d{2}$/ # (1)
77
- data.gsub!(/[^-\d.]/, '')
49
+ data.gsub!(/[^-\d.]/, "")
78
50
  when /^-?\D+[\d.]+,\d{2}$/ # (2)
79
- data.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
51
+ data.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
80
52
  end
81
53
  end
82
54
  end
@@ -85,21 +57,25 @@ module ActiveRecord
85
57
  # Queries the database and returns the results in an Array-like object
86
58
  def query(sql, name = nil) #:nodoc:
87
59
  log(sql, name) do
88
- result_as_array @connection.async_exec(sql)
60
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
61
+ result_as_array @connection.async_exec(sql)
62
+ end
89
63
  end
90
64
  end
91
65
 
92
- # Executes an SQL statement, returning a PGresult object on success
93
- # or raising a PGError exception otherwise.
94
- # Note: the PGresult object is manually memory managed; if you don't
95
- # need it specifically, you many want consider the exec_query wrapper.
66
+ # Executes an SQL statement, returning a PG::Result object on success
67
+ # or raising a PG::Error exception otherwise.
68
+ # Note: the PG::Result object is manually memory managed; if you don't
69
+ # need it specifically, you may want consider the <tt>exec_query</tt> wrapper.
96
70
  def execute(sql, name = nil)
97
71
  log(sql, name) do
98
- @connection.async_exec(sql)
72
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
73
+ @connection.async_exec(sql)
74
+ end
99
75
  end
100
76
  end
101
77
 
102
- def exec_query(sql, name = 'SQL', binds = [], prepare: false)
78
+ def exec_query(sql, name = "SQL", binds = [], prepare: false)
103
79
  execute_and_clear(sql, name, binds, prepare: prepare) do |result|
104
80
  types = {}
105
81
  fields = result.fields
@@ -112,8 +88,8 @@ module ActiveRecord
112
88
  end
113
89
  end
114
90
 
115
- def exec_delete(sql, name = 'SQL', binds = [])
116
- execute_and_clear(sql, name, binds) {|result| result.cmd_tuples }
91
+ def exec_delete(sql, name = nil, binds = [])
92
+ execute_and_clear(sql, name, binds) { |result| result.cmd_tuples }
117
93
  end
118
94
  alias :exec_update :exec_delete
119
95
 
@@ -124,26 +100,29 @@ module ActiveRecord
124
100
  pk = primary_key(table_ref) if table_ref
125
101
  end
126
102
 
127
- pk = suppress_composite_primary_key(pk)
128
-
129
- if pk && use_insert_returning?
103
+ if pk = suppress_composite_primary_key(pk)
130
104
  sql = "#{sql} RETURNING #{quote_column_name(pk)}"
131
105
  end
132
106
 
133
107
  super
134
108
  end
109
+ private :sql_for_insert
135
110
 
136
- def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
137
- val = exec_query(sql, name, binds)
138
- if !use_insert_returning? && pk
111
+ def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
112
+ if use_insert_returning? || pk == false
113
+ super
114
+ else
115
+ result = exec_query(sql, name, binds)
139
116
  unless sequence_name
140
117
  table_ref = extract_table_ref_from_insert_sql(sql)
141
- sequence_name = default_sequence_name(table_ref, pk)
142
- return val unless sequence_name
118
+ if table_ref
119
+ pk = primary_key(table_ref) if pk.nil?
120
+ pk = suppress_composite_primary_key(pk)
121
+ sequence_name = default_sequence_name(table_ref, pk)
122
+ end
123
+ return result unless sequence_name
143
124
  end
144
125
  last_insert_id_result(sequence_name)
145
- else
146
- val
147
126
  end
148
127
  end
149
128
 
@@ -169,9 +148,9 @@ module ActiveRecord
169
148
 
170
149
  private
171
150
 
172
- def suppress_composite_primary_key(pk)
173
- pk unless pk.is_a?(Array)
174
- end
151
+ def suppress_composite_primary_key(pk)
152
+ pk unless pk.is_a?(Array)
153
+ end
175
154
  end
176
155
  end
177
156
  end
@@ -26,12 +26,12 @@ module ActiveRecord
26
26
  pp = []
27
27
 
28
28
  pp << header.center(width).rstrip
29
- pp << '-' * width
29
+ pp << "-" * width
30
30
 
31
- pp += lines.map {|line| " #{line}"}
31
+ pp += lines.map { |line| " #{line}" }
32
32
 
33
33
  nrows = result.rows.length
34
- rows_label = nrows == 1 ? 'row' : 'rows'
34
+ rows_label = nrows == 1 ? "row" : "rows"
35
35
  pp << "(#{nrows} #{rows_label})"
36
36
 
37
37
  pp.join("\n") + "\n"
@@ -8,9 +8,9 @@ module ActiveRecord
8
8
  Data = Struct.new(:encoder, :values) # :nodoc:
9
9
 
10
10
  attr_reader :subtype, :delimiter
11
- delegate :type, :user_input_in_time_zone, :limit, to: :subtype
11
+ delegate :type, :user_input_in_time_zone, :limit, :precision, :scale, to: :subtype
12
12
 
13
- def initialize(subtype, delimiter = ',')
13
+ def initialize(subtype, delimiter = ",")
14
14
  @subtype = subtype
15
15
  @delimiter = delimiter
16
16
 
@@ -31,7 +31,13 @@ module ActiveRecord
31
31
 
32
32
  def cast(value)
33
33
  if value.is_a?(::String)
34
- value = @pg_decoder.decode(value)
34
+ value = begin
35
+ @pg_decoder.decode(value)
36
+ rescue TypeError
37
+ # malformed array string is treated as [], will raise in PG 2.0 gem
38
+ # this keeps a consistent implementation
39
+ []
40
+ end
35
41
  end
36
42
  type_cast_array(value, :cast)
37
43
  end
@@ -64,15 +70,19 @@ module ActiveRecord
64
70
  deserialize(raw_old_value) != new_value
65
71
  end
66
72
 
73
+ def force_equality?(value)
74
+ value.is_a?(::Array)
75
+ end
76
+
67
77
  private
68
78
 
69
- def type_cast_array(value, method)
70
- if value.is_a?(::Array)
71
- value.map { |item| type_cast_array(item, method) }
72
- else
73
- @subtype.public_send(method, value)
79
+ def type_cast_array(value, method)
80
+ if value.is_a?(::Array)
81
+ value.map { |item| type_cast_array(item, method) }
82
+ else
83
+ @subtype.public_send(method, value)
84
+ end
74
85
  end
75
- end
76
86
  end
77
87
  end
78
88
  end