activerecord 6.0.0.beta1 → 6.0.0
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 +4 -4
- data/CHANGELOG.md +455 -9
- data/README.rdoc +3 -1
- data/lib/active_record/associations/association.rb +18 -1
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +5 -2
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +5 -6
- data/lib/active_record/associations/collection_proxy.rb +13 -42
- data/lib/active_record/associations/has_many_association.rb +1 -9
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +21 -7
- data/lib/active_record/associations/join_dependency.rb +10 -9
- data/lib/active_record/associations/preloader/association.rb +37 -34
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +11 -6
- data/lib/active_record/associations.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +47 -14
- data/lib/active_record/attribute_methods/primary_key.rb +7 -15
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +3 -9
- data/lib/active_record/attribute_methods/write.rb +6 -12
- data/lib/active_record/attribute_methods.rb +3 -53
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +15 -5
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/callbacks.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +124 -23
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +101 -70
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +11 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +51 -40
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +95 -30
- data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +108 -39
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +93 -134
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +1 -1
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +66 -5
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -3
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +98 -89
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +47 -63
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +91 -24
- data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +69 -118
- data/lib/active_record/connection_handling.rb +32 -16
- data/lib/active_record/core.rb +27 -20
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +21 -16
- data/lib/active_record/database_configurations.rb +99 -50
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +15 -0
- data/lib/active_record/errors.rb +18 -13
- data/lib/active_record/fixtures.rb +11 -6
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +13 -1
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +3 -4
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +72 -63
- data/lib/active_record/migration.rb +62 -44
- data/lib/active_record/persistence.rb +212 -19
- data/lib/active_record/querying.rb +18 -14
- data/lib/active_record/railtie.rb +9 -1
- data/lib/active_record/railties/collection_cache_association_loading.rb +3 -3
- data/lib/active_record/railties/databases.rake +124 -25
- data/lib/active_record/reflection.rb +18 -32
- data/lib/active_record/relation/calculations.rb +40 -44
- data/lib/active_record/relation/delegation.rb +23 -31
- data/lib/active_record/relation/finder_methods.rb +13 -13
- data/lib/active_record/relation/merger.rb +11 -16
- data/lib/active_record/relation/query_attribute.rb +5 -3
- data/lib/active_record/relation/query_methods.rb +217 -68
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +10 -10
- data/lib/active_record/relation.rb +184 -35
- data/lib/active_record/sanitization.rb +33 -4
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +10 -1
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping/default.rb +7 -15
- data/lib/active_record/scoping/named.rb +10 -2
- data/lib/active_record/scoping.rb +6 -7
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +9 -13
- data/lib/active_record/tasks/database_tasks.rb +109 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
- data/lib/active_record/test_databases.rb +1 -16
- data/lib/active_record/test_fixtures.rb +2 -2
- data/lib/active_record/timestamp.rb +35 -19
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +55 -45
- data/lib/active_record/type_caster/connection.rb +16 -10
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -1
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes/and.rb +1 -1
- data/lib/arel/nodes/case.rb +1 -1
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/select_core.rb +16 -12
- data/lib/arel/nodes/unary.rb +1 -0
- data/lib/arel/nodes/values_list.rb +2 -17
- data/lib/arel/nodes.rb +2 -1
- data/lib/arel/select_manager.rb +10 -10
- data/lib/arel/visitors/depth_first.rb +7 -2
- data/lib/arel/visitors/dot.rb +7 -2
- data/lib/arel/visitors/ibm_db.rb +13 -0
- data/lib/arel/visitors/informix.rb +6 -0
- data/lib/arel/visitors/mssql.rb +15 -1
- data/lib/arel/visitors/oracle12.rb +4 -5
- data/lib/arel/visitors/postgresql.rb +4 -10
- data/lib/arel/visitors/to_sql.rb +107 -131
- data/lib/arel/visitors/visitor.rb +9 -5
- data/lib/arel.rb +7 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +17 -13
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
module ConnectionAdapters
|
6
6
|
# An abstract definition of a column in a table.
|
7
7
|
class Column
|
8
|
-
attr_reader :name, :default, :sql_type_metadata, :null, :
|
8
|
+
attr_reader :name, :default, :sql_type_metadata, :null, :default_function, :collation, :comment
|
9
9
|
|
10
10
|
delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
|
11
11
|
|
@@ -15,9 +15,8 @@ module ActiveRecord
|
|
15
15
|
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
|
16
16
|
# +sql_type_metadata+ is various information about the type of the column
|
17
17
|
# +null+ determines if this column allows +NULL+ values.
|
18
|
-
def initialize(name, default, sql_type_metadata = nil, null = true,
|
18
|
+
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, **)
|
19
19
|
@name = name.freeze
|
20
|
-
@table_name = table_name
|
21
20
|
@sql_type_metadata = sql_type_metadata
|
22
21
|
@null = null
|
23
22
|
@default = default
|
@@ -44,7 +43,6 @@ module ActiveRecord
|
|
44
43
|
|
45
44
|
def init_with(coder)
|
46
45
|
@name = coder["name"]
|
47
|
-
@table_name = coder["table_name"]
|
48
46
|
@sql_type_metadata = coder["sql_type_metadata"]
|
49
47
|
@null = coder["null"]
|
50
48
|
@default = coder["default"]
|
@@ -55,7 +53,6 @@ module ActiveRecord
|
|
55
53
|
|
56
54
|
def encode_with(coder)
|
57
55
|
coder["name"] = @name
|
58
|
-
coder["table_name"] = @table_name
|
59
56
|
coder["sql_type_metadata"] = @sql_type_metadata
|
60
57
|
coder["null"] = @null
|
61
58
|
coder["default"] = @default
|
@@ -66,19 +63,26 @@ module ActiveRecord
|
|
66
63
|
|
67
64
|
def ==(other)
|
68
65
|
other.is_a?(Column) &&
|
69
|
-
|
66
|
+
name == other.name &&
|
67
|
+
default == other.default &&
|
68
|
+
sql_type_metadata == other.sql_type_metadata &&
|
69
|
+
null == other.null &&
|
70
|
+
default_function == other.default_function &&
|
71
|
+
collation == other.collation &&
|
72
|
+
comment == other.comment
|
70
73
|
end
|
71
74
|
alias :eql? :==
|
72
75
|
|
73
76
|
def hash
|
74
|
-
|
77
|
+
Column.hash ^
|
78
|
+
name.hash ^
|
79
|
+
default.hash ^
|
80
|
+
sql_type_metadata.hash ^
|
81
|
+
null.hash ^
|
82
|
+
default_function.hash ^
|
83
|
+
collation.hash ^
|
84
|
+
comment.hash
|
75
85
|
end
|
76
|
-
|
77
|
-
protected
|
78
|
-
|
79
|
-
def attributes_for_hash
|
80
|
-
[self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
|
81
|
-
end
|
82
86
|
end
|
83
87
|
|
84
88
|
class NullColumn < Column
|
@@ -222,7 +222,7 @@ module ActiveRecord
|
|
222
222
|
when Hash
|
223
223
|
resolve_hash_connection config_or_env
|
224
224
|
else
|
225
|
-
|
225
|
+
raise TypeError, "Invalid type for configuration. Expected Symbol, String, or Hash. Got #{config_or_env.inspect}"
|
226
226
|
end
|
227
227
|
end
|
228
228
|
|
@@ -3,9 +3,9 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
5
|
module DetermineIfPreparableVisitor
|
6
|
-
|
6
|
+
attr_accessor :preparable
|
7
7
|
|
8
|
-
def accept(
|
8
|
+
def accept(object, collector)
|
9
9
|
@preparable = true
|
10
10
|
super
|
11
11
|
end
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
20
20
|
super
|
21
21
|
end
|
22
22
|
|
23
|
-
def visit_Arel_Nodes_SqlLiteral(
|
23
|
+
def visit_Arel_Nodes_SqlLiteral(o, collector)
|
24
24
|
@preparable = false
|
25
25
|
super
|
26
26
|
end
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
11
11
|
else
|
12
12
|
super
|
13
13
|
end
|
14
|
-
|
14
|
+
@connection.abandon_results!
|
15
15
|
result
|
16
16
|
end
|
17
17
|
|
@@ -61,7 +61,9 @@ module ActiveRecord
|
|
61
61
|
|
62
62
|
def exec_delete(sql, name = nil, binds = [])
|
63
63
|
if without_prepared_statement?(binds)
|
64
|
-
|
64
|
+
@lock.synchronize do
|
65
|
+
execute_and_free(sql, name) { @connection.affected_rows }
|
66
|
+
end
|
65
67
|
else
|
66
68
|
exec_stmt_and_free(sql, name, binds) { |stmt| stmt.affected_rows }
|
67
69
|
end
|
@@ -69,22 +71,31 @@ module ActiveRecord
|
|
69
71
|
alias :exec_update :exec_delete
|
70
72
|
|
71
73
|
private
|
74
|
+
def execute_batch(sql, name = nil)
|
75
|
+
super
|
76
|
+
@connection.abandon_results!
|
77
|
+
end
|
78
|
+
|
72
79
|
def default_insert_value(column)
|
73
|
-
|
80
|
+
super unless column.auto_increment?
|
74
81
|
end
|
75
82
|
|
76
83
|
def last_inserted_id(result)
|
77
84
|
@connection.last_id
|
78
85
|
end
|
79
86
|
|
80
|
-
def discard_remaining_results
|
81
|
-
@connection.abandon_results!
|
82
|
-
end
|
83
|
-
|
84
87
|
def supports_set_server_option?
|
85
88
|
@connection.respond_to?(:set_server_option)
|
86
89
|
end
|
87
90
|
|
91
|
+
def build_truncate_statements(*table_names)
|
92
|
+
if table_names.size == 1
|
93
|
+
super.first
|
94
|
+
else
|
95
|
+
super
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
88
99
|
def multi_statements_enabled?(flags)
|
89
100
|
if flags.is_a?(Array)
|
90
101
|
flags.include?("MULTI_STATEMENTS")
|
@@ -117,6 +128,33 @@ module ActiveRecord
|
|
117
128
|
end
|
118
129
|
end
|
119
130
|
|
131
|
+
def combine_multi_statements(total_sql)
|
132
|
+
total_sql.each_with_object([]) do |sql, total_sql_chunks|
|
133
|
+
previous_packet = total_sql_chunks.last
|
134
|
+
if max_allowed_packet_reached?(sql, previous_packet)
|
135
|
+
total_sql_chunks << +sql
|
136
|
+
else
|
137
|
+
previous_packet << ";\n"
|
138
|
+
previous_packet << sql
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def max_allowed_packet_reached?(current_packet, previous_packet)
|
144
|
+
if current_packet.bytesize > max_allowed_packet
|
145
|
+
raise ActiveRecordError,
|
146
|
+
"Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
|
147
|
+
elsif previous_packet.nil?
|
148
|
+
true
|
149
|
+
else
|
150
|
+
(current_packet.bytesize + previous_packet.bytesize + 2) > max_allowed_packet
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def max_allowed_packet
|
155
|
+
@max_allowed_packet ||= show_variable("max_allowed_packet")
|
156
|
+
end
|
157
|
+
|
120
158
|
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
|
121
159
|
if preventing_writes? && write_query?(sql)
|
122
160
|
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
@@ -5,11 +5,11 @@ module ActiveRecord
|
|
5
5
|
module MySQL
|
6
6
|
module Quoting # :nodoc:
|
7
7
|
def quote_column_name(name)
|
8
|
-
|
8
|
+
self.class.quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
|
9
9
|
end
|
10
10
|
|
11
11
|
def quote_table_name(name)
|
12
|
-
|
12
|
+
self.class.quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
|
13
13
|
end
|
14
14
|
|
15
15
|
def unquoted_true
|
@@ -32,12 +32,49 @@ module ActiveRecord
|
|
32
32
|
"x'#{value.hex}'"
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
def column_name_matcher
|
36
|
+
COLUMN_NAME
|
37
|
+
end
|
38
|
+
|
39
|
+
def column_name_with_order_matcher
|
40
|
+
COLUMN_NAME_WITH_ORDER
|
40
41
|
end
|
42
|
+
|
43
|
+
COLUMN_NAME = /
|
44
|
+
\A
|
45
|
+
(
|
46
|
+
(?:
|
47
|
+
# `table_name`.`column_name` | function(one or no argument)
|
48
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
|
49
|
+
)
|
50
|
+
(?:\s+AS\s+(?:\w+|`\w+`))?
|
51
|
+
)
|
52
|
+
(?:\s*,\s*\g<1>)*
|
53
|
+
\z
|
54
|
+
/ix
|
55
|
+
|
56
|
+
COLUMN_NAME_WITH_ORDER = /
|
57
|
+
\A
|
58
|
+
(
|
59
|
+
(?:
|
60
|
+
# `table_name`.`column_name` | function(one or no argument)
|
61
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
|
62
|
+
)
|
63
|
+
(?:\s+ASC|\s+DESC)?
|
64
|
+
)
|
65
|
+
(?:\s*,\s*\g<1>)*
|
66
|
+
\z
|
67
|
+
/ix
|
68
|
+
|
69
|
+
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
70
|
+
|
71
|
+
private
|
72
|
+
def _type_cast(value)
|
73
|
+
case value
|
74
|
+
when Date, Time then value
|
75
|
+
else super
|
76
|
+
end
|
77
|
+
end
|
41
78
|
end
|
42
79
|
end
|
43
80
|
end
|
@@ -4,48 +4,56 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module MySQL
|
6
6
|
module ColumnMethods
|
7
|
-
|
8
|
-
args.each { |name| column(name, :blob, options) }
|
9
|
-
end
|
7
|
+
extend ActiveSupport::Concern
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
##
|
10
|
+
# :method: blob
|
11
|
+
# :call-seq: blob(*names, **options)
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
##
|
14
|
+
# :method: tinyblob
|
15
|
+
# :call-seq: tinyblob(*names, **options)
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
##
|
18
|
+
# :method: mediumblob
|
19
|
+
# :call-seq: mediumblob(*names, **options)
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
##
|
22
|
+
# :method: longblob
|
23
|
+
# :call-seq: longblob(*names, **options)
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
##
|
26
|
+
# :method: tinytext
|
27
|
+
# :call-seq: tinytext(*names, **options)
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
##
|
30
|
+
# :method: mediumtext
|
31
|
+
# :call-seq: mediumtext(*names, **options)
|
34
32
|
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
##
|
34
|
+
# :method: longtext
|
35
|
+
# :call-seq: longtext(*names, **options)
|
38
36
|
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
##
|
38
|
+
# :method: unsigned_integer
|
39
|
+
# :call-seq: unsigned_integer(*names, **options)
|
42
40
|
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
##
|
42
|
+
# :method: unsigned_bigint
|
43
|
+
# :call-seq: unsigned_bigint(*names, **options)
|
44
|
+
|
45
|
+
##
|
46
|
+
# :method: unsigned_float
|
47
|
+
# :call-seq: unsigned_float(*names, **options)
|
48
|
+
|
49
|
+
##
|
50
|
+
# :method: unsigned_decimal
|
51
|
+
# :call-seq: unsigned_decimal(*names, **options)
|
46
52
|
|
47
|
-
|
48
|
-
|
53
|
+
included do
|
54
|
+
define_column_methods :blob, :tinyblob, :mediumblob, :longblob,
|
55
|
+
:tinytext, :mediumtext, :longtext, :unsigned_integer, :unsigned_bigint,
|
56
|
+
:unsigned_float, :unsigned_decimal
|
49
57
|
end
|
50
58
|
end
|
51
59
|
|
@@ -10,6 +10,10 @@ module ActiveRecord
|
|
10
10
|
spec[:unsigned] = "true" if column.unsigned?
|
11
11
|
spec[:auto_increment] = "true" if column.auto_increment?
|
12
12
|
|
13
|
+
if /\A(?<size>tiny|medium|long)(?:text|blob)/ =~ column.sql_type
|
14
|
+
spec = { size: size.to_sym.inspect }.merge!(spec)
|
15
|
+
end
|
16
|
+
|
13
17
|
if @connection.supports_virtual_columns? && column.virtual?
|
14
18
|
spec[:as] = extract_expression_for_virtual_column(column)
|
15
19
|
spec[:stored] = "true" if /\b(?:STORED|PERSISTENT)\b/.match?(column.extra)
|
@@ -37,19 +41,23 @@ module ActiveRecord
|
|
37
41
|
case column.sql_type
|
38
42
|
when /\Atimestamp\b/
|
39
43
|
:timestamp
|
40
|
-
when
|
41
|
-
|
44
|
+
when /\A(?:enum|set)\b/
|
45
|
+
column.sql_type
|
42
46
|
else
|
43
47
|
super
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
51
|
+
def schema_limit(column)
|
52
|
+
super unless /\A(?:enum|set|(?:tiny|medium|long)?(?:text|blob))\b/.match?(column.sql_type)
|
53
|
+
end
|
54
|
+
|
47
55
|
def schema_precision(column)
|
48
56
|
super unless /\A(?:date)?time(?:stamp)?\b/.match?(column.sql_type) && column.precision == 0
|
49
57
|
end
|
50
58
|
|
51
59
|
def schema_collation(column)
|
52
|
-
if column.collation
|
60
|
+
if column.collation
|
53
61
|
@table_collation_cache ||= {}
|
54
62
|
@table_collation_cache[table_name] ||=
|
55
63
|
@connection.exec_query("SHOW TABLE STATUS LIKE #{@connection.quote(table_name)}", "SCHEMA").first["Collation"]
|
@@ -58,14 +66,14 @@ module ActiveRecord
|
|
58
66
|
end
|
59
67
|
|
60
68
|
def extract_expression_for_virtual_column(column)
|
61
|
-
if @connection.mariadb? && @connection.
|
62
|
-
create_table_info = @connection.send(:create_table_info,
|
69
|
+
if @connection.mariadb? && @connection.database_version < "10.2.5"
|
70
|
+
create_table_info = @connection.send(:create_table_info, table_name)
|
63
71
|
column_name = @connection.quote_column_name(column.name)
|
64
72
|
if %r/#{column_name} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info
|
65
73
|
$~[:expression].inspect
|
66
74
|
end
|
67
75
|
else
|
68
|
-
scope = @connection.send(:quoted_scope,
|
76
|
+
scope = @connection.send(:quoted_scope, table_name)
|
69
77
|
column_name = @connection.quote(column.name)
|
70
78
|
sql = "SELECT generation_expression FROM information_schema.columns" \
|
71
79
|
" WHERE table_schema = #{scope[:schema]}" \
|
@@ -97,14 +97,42 @@ module ActiveRecord
|
|
97
97
|
MySQL::SchemaDumper.create(self, options)
|
98
98
|
end
|
99
99
|
|
100
|
+
# Maps logical Rails types to MySQL-specific data types.
|
101
|
+
def type_to_sql(type, limit: nil, precision: nil, scale: nil, size: limit_to_size(limit, type), unsigned: nil, **)
|
102
|
+
sql =
|
103
|
+
case type.to_s
|
104
|
+
when "integer"
|
105
|
+
integer_to_sql(limit)
|
106
|
+
when "text"
|
107
|
+
type_with_size_to_sql("text", size)
|
108
|
+
when "blob"
|
109
|
+
type_with_size_to_sql("blob", size)
|
110
|
+
when "binary"
|
111
|
+
if (0..0xfff) === limit
|
112
|
+
"varbinary(#{limit})"
|
113
|
+
else
|
114
|
+
type_with_size_to_sql("blob", size)
|
115
|
+
end
|
116
|
+
else
|
117
|
+
super
|
118
|
+
end
|
119
|
+
|
120
|
+
sql = "#{sql} unsigned" if unsigned && type != :primary_key
|
121
|
+
sql
|
122
|
+
end
|
123
|
+
|
124
|
+
def table_alias_length
|
125
|
+
256 # https://dev.mysql.com/doc/refman/8.0/en/identifiers.html
|
126
|
+
end
|
127
|
+
|
100
128
|
private
|
101
129
|
CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"]
|
102
130
|
|
103
131
|
def row_format_dynamic_by_default?
|
104
132
|
if mariadb?
|
105
|
-
|
133
|
+
database_version >= "10.2.2"
|
106
134
|
else
|
107
|
-
|
135
|
+
database_version >= "5.7.9"
|
108
136
|
end
|
109
137
|
end
|
110
138
|
|
@@ -127,7 +155,7 @@ module ActiveRecord
|
|
127
155
|
end
|
128
156
|
|
129
157
|
def create_table_definition(*args)
|
130
|
-
MySQL::TableDefinition.new(*args)
|
158
|
+
MySQL::TableDefinition.new(self, *args)
|
131
159
|
end
|
132
160
|
|
133
161
|
def new_column_from_field(table_name, field)
|
@@ -146,9 +174,8 @@ module ActiveRecord
|
|
146
174
|
default,
|
147
175
|
type_metadata,
|
148
176
|
field[:Null] == "YES",
|
149
|
-
table_name,
|
150
177
|
default_function,
|
151
|
-
field[:Collation],
|
178
|
+
collation: field[:Collation],
|
152
179
|
comment: field[:Comment].presence
|
153
180
|
)
|
154
181
|
end
|
@@ -197,6 +224,40 @@ module ActiveRecord
|
|
197
224
|
schema, name = nil, schema unless name
|
198
225
|
[schema, name]
|
199
226
|
end
|
227
|
+
|
228
|
+
def type_with_size_to_sql(type, size)
|
229
|
+
case size&.to_s
|
230
|
+
when nil, "tiny", "medium", "long"
|
231
|
+
"#{size}#{type}"
|
232
|
+
else
|
233
|
+
raise ArgumentError,
|
234
|
+
"#{size.inspect} is invalid :size value. Only :tiny, :medium, and :long are allowed."
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def limit_to_size(limit, type)
|
239
|
+
case type.to_s
|
240
|
+
when "text", "blob", "binary"
|
241
|
+
case limit
|
242
|
+
when 0..0xff; "tiny"
|
243
|
+
when nil, 0x100..0xffff; nil
|
244
|
+
when 0x10000..0xffffff; "medium"
|
245
|
+
when 0x1000000..0xffffffff; "long"
|
246
|
+
else raise ArgumentError, "No #{type} type has byte size #{limit}"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def integer_to_sql(limit)
|
252
|
+
case limit
|
253
|
+
when 1; "tinyint"
|
254
|
+
when 2; "smallint"
|
255
|
+
when 3; "mediumint"
|
256
|
+
when nil, 4; "int"
|
257
|
+
when 5..8; "bigint"
|
258
|
+
else raise ArgumentError, "No integer type has byte size #{limit}. Use a decimal with scale 0 instead."
|
259
|
+
end
|
260
|
+
end
|
200
261
|
end
|
201
262
|
end
|
202
263
|
end
|
@@ -10,25 +10,21 @@ module ActiveRecord
|
|
10
10
|
|
11
11
|
def initialize(type_metadata, extra: "")
|
12
12
|
super(type_metadata)
|
13
|
-
@type_metadata = type_metadata
|
14
13
|
@extra = extra
|
15
14
|
end
|
16
15
|
|
17
16
|
def ==(other)
|
18
|
-
other.is_a?(
|
19
|
-
|
17
|
+
other.is_a?(TypeMetadata) &&
|
18
|
+
__getobj__ == other.__getobj__ &&
|
19
|
+
extra == other.extra
|
20
20
|
end
|
21
21
|
alias eql? ==
|
22
22
|
|
23
23
|
def hash
|
24
|
-
|
24
|
+
TypeMetadata.hash ^
|
25
|
+
__getobj__.hash ^
|
26
|
+
extra.hash
|
25
27
|
end
|
26
|
-
|
27
|
-
protected
|
28
|
-
|
29
|
-
def attributes_for_hash
|
30
|
-
[self.class, @type_metadata, extra]
|
31
|
-
end
|
32
28
|
end
|
33
29
|
end
|
34
30
|
end
|
@@ -8,6 +8,8 @@ require "mysql2"
|
|
8
8
|
|
9
9
|
module ActiveRecord
|
10
10
|
module ConnectionHandling # :nodoc:
|
11
|
+
ER_BAD_DB_ERROR = 1049
|
12
|
+
|
11
13
|
# Establishes a connection to the database that's used by all Active Record objects.
|
12
14
|
def mysql2_connection(config)
|
13
15
|
config = config.symbolize_keys
|
@@ -22,7 +24,7 @@ module ActiveRecord
|
|
22
24
|
client = Mysql2::Client.new(config)
|
23
25
|
ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config)
|
24
26
|
rescue Mysql2::Error => error
|
25
|
-
if error.
|
27
|
+
if error.error_number == ER_BAD_DB_ERROR
|
26
28
|
raise ActiveRecord::NoDatabaseError
|
27
29
|
else
|
28
30
|
raise
|
@@ -37,13 +39,19 @@ module ActiveRecord
|
|
37
39
|
include MySQL::DatabaseStatements
|
38
40
|
|
39
41
|
def initialize(connection, logger, connection_options, config)
|
40
|
-
|
41
|
-
|
42
|
+
superclass_config = config.reverse_merge(prepared_statements: false)
|
43
|
+
super(connection, logger, connection_options, superclass_config)
|
42
44
|
configure_connection
|
43
45
|
end
|
44
46
|
|
47
|
+
def self.database_exists?(config)
|
48
|
+
!!ActiveRecord::Base.mysql2_connection(config)
|
49
|
+
rescue ActiveRecord::NoDatabaseError
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
45
53
|
def supports_json?
|
46
|
-
!mariadb? &&
|
54
|
+
!mariadb? && database_version >= "5.7.8"
|
47
55
|
end
|
48
56
|
|
49
57
|
def supports_comments?
|
@@ -109,6 +117,7 @@ module ActiveRecord
|
|
109
117
|
end
|
110
118
|
|
111
119
|
def discard! # :nodoc:
|
120
|
+
super
|
112
121
|
@connection.automatic_close = false
|
113
122
|
@connection = nil
|
114
123
|
end
|
@@ -126,7 +135,11 @@ module ActiveRecord
|
|
126
135
|
end
|
127
136
|
|
128
137
|
def full_version
|
129
|
-
|
138
|
+
schema_cache.database_version.full_version_string
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_full_version
|
142
|
+
@connection.server_info[:version]
|
130
143
|
end
|
131
144
|
end
|
132
145
|
end
|
@@ -2,42 +2,29 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
alias :array? :array
|
5
|
+
module PostgreSQL
|
6
|
+
class Column < ConnectionAdapters::Column # :nodoc:
|
7
|
+
delegate :oid, :fmod, to: :sql_type_metadata
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def serial?
|
16
|
-
return unless default_function
|
17
|
-
|
18
|
-
if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
|
19
|
-
sequence_name_from_parts(table_name, name, suffix) == sequence_name
|
9
|
+
def initialize(*, serial: nil, **)
|
10
|
+
super
|
11
|
+
@serial = serial
|
20
12
|
end
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
attr_reader :max_identifier_length
|
25
13
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
if over_length > 0
|
30
|
-
column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
|
31
|
-
over_length -= column_name.length - column_name_length
|
32
|
-
column_name = column_name[0, column_name_length - [over_length, 0].min]
|
33
|
-
end
|
14
|
+
def serial?
|
15
|
+
@serial
|
16
|
+
end
|
34
17
|
|
35
|
-
|
36
|
-
|
37
|
-
|
18
|
+
def array
|
19
|
+
sql_type_metadata.sql_type.end_with?("[]")
|
20
|
+
end
|
21
|
+
alias :array? :array
|
38
22
|
|
39
|
-
|
23
|
+
def sql_type
|
24
|
+
super.sub(/\[\]\z/, "")
|
40
25
|
end
|
26
|
+
end
|
41
27
|
end
|
28
|
+
PostgreSQLColumn = PostgreSQL::Column # :nodoc:
|
42
29
|
end
|
43
30
|
end
|