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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +657 -2080
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations/alias_tracker.rb +10 -11
- data/lib/active_record/associations/association.rb +23 -5
- data/lib/active_record/associations/association_scope.rb +95 -81
- data/lib/active_record/associations/belongs_to_association.rb +7 -4
- data/lib/active_record/associations/builder/belongs_to.rb +30 -16
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +36 -205
- data/lib/active_record/associations/collection_proxy.rb +132 -63
- data/lib/active_record/associations/has_many_association.rb +10 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -4
- data/lib/active_record/associations/has_one_association.rb +24 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +121 -118
- data/lib/active_record/associations/preloader/association.rb +64 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +41 -41
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +2 -5
- data/lib/active_record/associations.rb +1591 -1562
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +229 -46
- data/lib/active_record/attribute_methods/primary_key.rb +74 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +30 -33
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_mutation_tracker.rb +63 -11
- data/lib/active_record/attribute_set/builder.rb +27 -33
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attributes.rb +22 -22
- data/lib/active_record/autosave_association.rb +18 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +56 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +3 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
- data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
- data/lib/active_record/connection_adapters/column.rb +26 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +109 -93
- data/lib/active_record/counter_cache.rb +60 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +64 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +69 -74
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +23 -28
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +100 -47
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/migration.rb +153 -155
- data/lib/active_record/model_schema.rb +94 -107
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +11 -34
- data/lib/active_record/persistence.rb +65 -50
- data/lib/active_record/query_cache.rb +2 -6
- data/lib/active_record/querying.rb +3 -4
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +105 -133
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +154 -108
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/batches.rb +80 -51
- data/lib/active_record/relation/calculations.rb +169 -162
- data/lib/active_record/relation/delegation.rb +32 -31
- data/lib/active_record/relation/finder_methods.rb +197 -231
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +255 -293
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +80 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/relation.rb +93 -119
- data/lib/active_record/result.rb +41 -32
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +176 -192
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +15 -38
- data/lib/active_record/schema_migration.rb +8 -4
- data/lib/active_record/scoping/default.rb +90 -90
- data/lib/active_record/scoping/named.rb +11 -11
- data/lib/active_record/scoping.rb +6 -6
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +65 -55
- data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
- data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +46 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +97 -109
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +13 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/internal/abstract_json.rb +4 -0
- data/lib/active_record/type/serialized.rb +14 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +20 -20
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/migration.rb +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- data/lib/rails/generators/active_record.rb +4 -4
- metadata +24 -13
- 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
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
23
|
+
def add_table_options!(create_sql, options)
|
24
|
+
add_sql_comment!(super, options[:comment])
|
25
|
+
end
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
36
|
+
if charset = options[:charset]
|
37
|
+
sql << " CHARACTER SET #{charset}"
|
38
|
+
end
|
31
39
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
column_options
|
36
|
-
end
|
40
|
+
if collation = options[:collation]
|
41
|
+
sql << " COLLATE #{collation}"
|
42
|
+
end
|
37
43
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
44
|
-
sql << " COLLATE #{collation}"
|
51
|
+
add_sql_comment!(super, options[:comment])
|
45
52
|
end
|
46
53
|
|
47
|
-
|
48
|
-
|
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
|
-
|
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
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
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
|
-
|
68
|
-
|
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
|
-
|
71
|
-
|
67
|
+
type = :integer
|
68
|
+
options[:limit] ||= 8
|
69
|
+
options[:auto_increment] = true
|
70
|
+
options[:primary_key] = true
|
72
71
|
when /\Aunsigned_(?<type>.+)\z/
|
73
|
-
|
74
|
-
|
72
|
+
type = $~[:type].to_sym
|
73
|
+
options[:unsigned] = true
|
75
74
|
end
|
76
|
-
|
77
|
-
|
78
|
-
column
|
75
|
+
|
76
|
+
super
|
79
77
|
end
|
80
78
|
|
81
79
|
private
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
15
|
+
|
13
16
|
spec
|
14
17
|
end
|
15
18
|
|
16
|
-
def
|
19
|
+
def column_spec_for_primary_key(column)
|
17
20
|
spec = super
|
18
|
-
spec
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
+
def default_primary_key?(column)
|
32
|
+
super && column.auto_increment? && !column.unsigned?
|
33
|
+
end
|
31
34
|
|
32
|
-
|
33
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
5
|
+
undef to_yaml if method_defined?(:to_yaml)
|
6
6
|
|
7
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
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
|
2
|
-
require
|
1
|
+
require "active_record/connection_adapters/abstract_mysql_adapter"
|
2
|
+
require "active_record/connection_adapters/mysql/database_statements"
|
3
3
|
|
4
|
-
gem
|
5
|
-
require
|
6
|
-
raise
|
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
|
18
|
-
|
19
|
-
|
20
|
-
|
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 =
|
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 >=
|
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(:
|
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
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
108
|
+
def connect
|
109
|
+
@connection = Mysql2::Client.new(@config)
|
110
|
+
configure_connection
|
111
|
+
end
|
116
112
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
113
|
+
def configure_connection
|
114
|
+
@connection.query_options.merge!(as: :array)
|
115
|
+
super
|
116
|
+
end
|
121
117
|
|
122
|
-
|
123
|
-
|
124
|
-
|
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,
|
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,]/,
|
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
|
-
|
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
|
93
|
-
# or raising a
|
94
|
-
# Note: the
|
95
|
-
# need it specifically, you
|
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
|
-
|
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 =
|
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 =
|
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
|
-
|
138
|
-
|
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
|
-
|
142
|
-
|
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
|
-
|
173
|
-
|
174
|
-
|
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 <<
|
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 ?
|
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 =
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|