activerecord 5.2.6 → 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 +609 -622
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations/association.rb +52 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- 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 +6 -21
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +24 -28
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +40 -32
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations.rb +19 -14
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +5 -9
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +94 -16
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +180 -47
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- 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 +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -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 +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -141
- data/lib/active_record/connection_handling.rb +149 -27
- data/lib/active_record/core.rb +100 -60
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- 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 +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +196 -46
- data/lib/active_record/reflection.rb +32 -30
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +53 -47
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +13 -26
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +189 -63
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +310 -80
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping/default.rb +4 -5
- data/lib/active_record/scoping/named.rb +19 -15
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +57 -66
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +9 -2
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +51 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- 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/migration.rb +14 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +108 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -35,13 +35,39 @@ module ActiveRecord
|
|
35
35
|
]
|
36
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
if row[:Expression]
|
39
|
+
expression = row[:Expression]
|
40
|
+
expression = +"(#{expression})" unless expression.start_with?("(")
|
41
|
+
indexes.last[-2] << expression
|
42
|
+
indexes.last[-1][:expressions] ||= {}
|
43
|
+
indexes.last[-1][:expressions][expression] = expression
|
44
|
+
indexes.last[-1][:orders][expression] = :desc if row[:Collation] == "D"
|
45
|
+
else
|
46
|
+
indexes.last[-2] << row[:Column_name]
|
47
|
+
indexes.last[-1][:lengths][row[:Column_name]] = row[:Sub_part].to_i if row[:Sub_part]
|
48
|
+
indexes.last[-1][:orders][row[:Column_name]] = :desc if row[:Collation] == "D"
|
49
|
+
end
|
41
50
|
end
|
42
51
|
end
|
43
52
|
|
44
|
-
indexes.map
|
53
|
+
indexes.map do |index|
|
54
|
+
options = index.last
|
55
|
+
|
56
|
+
if expressions = options.delete(:expressions)
|
57
|
+
orders = options.delete(:orders)
|
58
|
+
lengths = options.delete(:lengths)
|
59
|
+
|
60
|
+
columns = index[-2].map { |name|
|
61
|
+
[ name.to_sym, expressions[name] || +quote_column_name(name) ]
|
62
|
+
}.to_h
|
63
|
+
|
64
|
+
index[-2] = add_options_for_index_columns(
|
65
|
+
columns, order: orders, length: lengths
|
66
|
+
).values.join(", ")
|
67
|
+
end
|
68
|
+
|
69
|
+
IndexDefinition.new(*index)
|
70
|
+
end
|
45
71
|
end
|
46
72
|
|
47
73
|
def remove_column(table_name, column_name, type = nil, options = {})
|
@@ -51,9 +77,13 @@ module ActiveRecord
|
|
51
77
|
super
|
52
78
|
end
|
53
79
|
|
80
|
+
def create_table(table_name, options: default_row_format, **)
|
81
|
+
super
|
82
|
+
end
|
83
|
+
|
54
84
|
def internal_string_options_for_primary_key
|
55
85
|
super.tap do |options|
|
56
|
-
if CHARSETS_OF_4BYTES_MAXLEN.include?(charset)
|
86
|
+
if !row_format_dynamic_by_default? && CHARSETS_OF_4BYTES_MAXLEN.include?(charset)
|
57
87
|
options[:collation] = collation.sub(/\A[^_]+/, "utf8")
|
58
88
|
end
|
59
89
|
end
|
@@ -67,23 +97,76 @@ module ActiveRecord
|
|
67
97
|
MySQL::SchemaDumper.create(self, options)
|
68
98
|
end
|
69
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
|
+
|
70
128
|
private
|
71
129
|
CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"]
|
72
130
|
|
131
|
+
def row_format_dynamic_by_default?
|
132
|
+
if mariadb?
|
133
|
+
database_version >= "10.2.2"
|
134
|
+
else
|
135
|
+
database_version >= "5.7.9"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def default_row_format
|
140
|
+
return if row_format_dynamic_by_default?
|
141
|
+
|
142
|
+
unless defined?(@default_row_format)
|
143
|
+
if query_value("SELECT @@innodb_file_per_table = 1 AND @@innodb_file_format = 'Barracuda'") == 1
|
144
|
+
@default_row_format = "ROW_FORMAT=DYNAMIC"
|
145
|
+
else
|
146
|
+
@default_row_format = nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
@default_row_format
|
151
|
+
end
|
152
|
+
|
73
153
|
def schema_creation
|
74
154
|
MySQL::SchemaCreation.new(self)
|
75
155
|
end
|
76
156
|
|
77
157
|
def create_table_definition(*args)
|
78
|
-
MySQL::TableDefinition.new(*args)
|
158
|
+
MySQL::TableDefinition.new(self, *args)
|
79
159
|
end
|
80
160
|
|
81
161
|
def new_column_from_field(table_name, field)
|
82
162
|
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
default, default_function =
|
163
|
+
default, default_function = field[:Default], nil
|
164
|
+
|
165
|
+
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
166
|
+
default, default_function = nil, default
|
167
|
+
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
168
|
+
default = +"(#{default})" unless default.start_with?("(")
|
169
|
+
default, default_function = nil, default
|
87
170
|
end
|
88
171
|
|
89
172
|
MySQL::Column.new(
|
@@ -91,9 +174,8 @@ module ActiveRecord
|
|
91
174
|
default,
|
92
175
|
type_metadata,
|
93
176
|
field[:Null] == "YES",
|
94
|
-
table_name,
|
95
177
|
default_function,
|
96
|
-
field[:Collation],
|
178
|
+
collation: field[:Collation],
|
97
179
|
comment: field[:Comment].presence
|
98
180
|
)
|
99
181
|
end
|
@@ -121,7 +203,7 @@ module ActiveRecord
|
|
121
203
|
def data_source_sql(name = nil, type: nil)
|
122
204
|
scope = quoted_scope(name, type: type)
|
123
205
|
|
124
|
-
sql = "SELECT table_name FROM information_schema.tables"
|
206
|
+
sql = +"SELECT table_name FROM information_schema.tables"
|
125
207
|
sql << " WHERE table_schema = #{scope[:schema]}"
|
126
208
|
sql << " AND table_name = #{scope[:name]}" if scope[:name]
|
127
209
|
sql << " AND table_type = #{scope[:type]}" if scope[:type]
|
@@ -142,6 +224,40 @@ module ActiveRecord
|
|
142
224
|
schema, name = nil, schema unless name
|
143
225
|
[schema, name]
|
144
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
|
145
261
|
end
|
146
262
|
end
|
147
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
|
@@ -3,18 +3,20 @@
|
|
3
3
|
require "active_record/connection_adapters/abstract_mysql_adapter"
|
4
4
|
require "active_record/connection_adapters/mysql/database_statements"
|
5
5
|
|
6
|
-
gem "mysql2", ">= 0.4.4"
|
6
|
+
gem "mysql2", ">= 0.4.4"
|
7
7
|
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
|
14
16
|
config[:flags] ||= 0
|
15
17
|
|
16
18
|
if config[:flags].kind_of? Array
|
17
|
-
config[:flags].push "FOUND_ROWS"
|
19
|
+
config[:flags].push "FOUND_ROWS"
|
18
20
|
else
|
19
21
|
config[:flags] |= Mysql2::Client::FOUND_ROWS
|
20
22
|
end
|
@@ -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
|
@@ -32,18 +34,24 @@ module ActiveRecord
|
|
32
34
|
|
33
35
|
module ConnectionAdapters
|
34
36
|
class Mysql2Adapter < AbstractMysqlAdapter
|
35
|
-
ADAPTER_NAME = "Mysql2"
|
37
|
+
ADAPTER_NAME = "Mysql2"
|
36
38
|
|
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?
|
@@ -58,6 +66,10 @@ module ActiveRecord
|
|
58
66
|
true
|
59
67
|
end
|
60
68
|
|
69
|
+
def supports_lazy_transactions?
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
61
73
|
# HELPER METHODS ===========================================
|
62
74
|
|
63
75
|
def each_hash(result) # :nodoc:
|
@@ -105,6 +117,7 @@ module ActiveRecord
|
|
105
117
|
end
|
106
118
|
|
107
119
|
def discard! # :nodoc:
|
120
|
+
super
|
108
121
|
@connection.automatic_close = false
|
109
122
|
@connection = nil
|
110
123
|
end
|
@@ -117,12 +130,16 @@ module ActiveRecord
|
|
117
130
|
end
|
118
131
|
|
119
132
|
def configure_connection
|
120
|
-
@connection.query_options
|
133
|
+
@connection.query_options[:as] = :array
|
121
134
|
super
|
122
135
|
end
|
123
136
|
|
124
137
|
def full_version
|
125
|
-
|
138
|
+
schema_cache.database_version.full_version_string
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_full_version
|
142
|
+
@connection.server_info[:version]
|
126
143
|
end
|
127
144
|
end
|
128
145
|
end
|
@@ -2,43 +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
|
-
protected
|
24
|
-
attr_reader :max_identifier_length
|
25
13
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if over_length > 0
|
31
|
-
column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
|
32
|
-
over_length -= column_name.length - column_name_length
|
33
|
-
column_name = column_name[0, column_name_length - [over_length, 0].min]
|
34
|
-
end
|
14
|
+
def serial?
|
15
|
+
@serial
|
16
|
+
end
|
35
17
|
|
36
|
-
|
37
|
-
|
38
|
-
|
18
|
+
def array
|
19
|
+
sql_type_metadata.sql_type.end_with?("[]")
|
20
|
+
end
|
21
|
+
alias :array? :array
|
39
22
|
|
40
|
-
|
23
|
+
def sql_type
|
24
|
+
super.sub(/\[\]\z/, "")
|
41
25
|
end
|
26
|
+
end
|
42
27
|
end
|
28
|
+
PostgreSQLColumn = PostgreSQL::Column # :nodoc:
|
43
29
|
end
|
44
30
|
end
|
@@ -58,6 +58,8 @@ module ActiveRecord
|
|
58
58
|
|
59
59
|
# Queries the database and returns the results in an Array-like object
|
60
60
|
def query(sql, name = nil) #:nodoc:
|
61
|
+
materialize_transactions
|
62
|
+
|
61
63
|
log(sql, name) do
|
62
64
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
63
65
|
result_as_array @connection.async_exec(sql)
|
@@ -65,11 +67,24 @@ module ActiveRecord
|
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
70
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback) # :nodoc:
|
71
|
+
private_constant :READ_QUERY
|
72
|
+
|
73
|
+
def write_query?(sql) # :nodoc:
|
74
|
+
!READ_QUERY.match?(sql)
|
75
|
+
end
|
76
|
+
|
68
77
|
# Executes an SQL statement, returning a PG::Result object on success
|
69
78
|
# or raising a PG::Error exception otherwise.
|
70
79
|
# Note: the PG::Result object is manually memory managed; if you don't
|
71
80
|
# need it specifically, you may want consider the <tt>exec_query</tt> wrapper.
|
72
81
|
def execute(sql, name = nil)
|
82
|
+
if preventing_writes? && write_query?(sql)
|
83
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
84
|
+
end
|
85
|
+
|
86
|
+
materialize_transactions
|
87
|
+
|
73
88
|
log(sql, name) do
|
74
89
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
75
90
|
@connection.async_exec(sql)
|
@@ -95,7 +110,7 @@ module ActiveRecord
|
|
95
110
|
end
|
96
111
|
alias :exec_update :exec_delete
|
97
112
|
|
98
|
-
def sql_for_insert(sql, pk,
|
113
|
+
def sql_for_insert(sql, pk, binds) # :nodoc:
|
99
114
|
if pk.nil?
|
100
115
|
# Extract the table from the insert sql. Yuck.
|
101
116
|
table_ref = extract_table_ref_from_insert_sql(sql)
|
@@ -149,6 +164,10 @@ module ActiveRecord
|
|
149
164
|
end
|
150
165
|
|
151
166
|
private
|
167
|
+
def build_truncate_statements(*table_names)
|
168
|
+
"TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"
|
169
|
+
end
|
170
|
+
|
152
171
|
# Returns the current ID of a table's sequence.
|
153
172
|
def last_insert_id_result(sequence_name)
|
154
173
|
exec_query("SELECT currval(#{quote(sequence_name)})", "SQL")
|
@@ -43,10 +43,7 @@ module ActiveRecord
|
|
43
43
|
/\A[0-9A-F]*\Z/i.match?(value)
|
44
44
|
end
|
45
45
|
|
46
|
-
|
47
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
48
|
-
protected
|
49
|
-
|
46
|
+
private
|
50
47
|
attr_reader :value
|
51
48
|
end
|
52
49
|
end
|
@@ -26,9 +26,9 @@ module ActiveRecord
|
|
26
26
|
|
27
27
|
value = value.sub(/^\((.+)\)$/, '-\1') # (4)
|
28
28
|
case value
|
29
|
-
when /^-?\D
|
29
|
+
when /^-?\D*[\d,]+\.\d{2}$/ # (1)
|
30
30
|
value.gsub!(/[^-\d.]/, "")
|
31
|
-
when /^-?\D
|
31
|
+
when /^-?\D*[\d.]+,\d{2}$/ # (2)
|
32
32
|
value.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
|
33
33
|
end
|
34
34
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/array/extract"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module ConnectionAdapters
|
5
7
|
module PostgreSQL
|
@@ -16,12 +18,12 @@ module ActiveRecord
|
|
16
18
|
|
17
19
|
def run(records)
|
18
20
|
nodes = records.reject { |row| @store.key? row["oid"].to_i }
|
19
|
-
mapped
|
20
|
-
ranges
|
21
|
-
enums
|
22
|
-
domains
|
23
|
-
arrays
|
24
|
-
composites
|
21
|
+
mapped = nodes.extract! { |row| @store.key? row["typname"] }
|
22
|
+
ranges = nodes.extract! { |row| row["typtype"] == "r" }
|
23
|
+
enums = nodes.extract! { |row| row["typtype"] == "e" }
|
24
|
+
domains = nodes.extract! { |row| row["typtype"] == "d" }
|
25
|
+
arrays = nodes.extract! { |row| row["typinput"] == "array_in" }
|
26
|
+
composites = nodes.extract! { |row| row["typelem"].to_i != 0 }
|
25
27
|
|
26
28
|
mapped.each { |row| register_mapped_type(row) }
|
27
29
|
enums.each { |row| register_enum_type(row) }
|
@@ -34,7 +36,7 @@ module ActiveRecord
|
|
34
36
|
def query_conditions_for_initial_load
|
35
37
|
known_type_names = @store.keys.map { |n| "'#{n}'" }
|
36
38
|
known_type_types = %w('r' 'e' 'd')
|
37
|
-
|
39
|
+
<<~SQL % [known_type_names.join(", "), known_type_types.join(", ")]
|
38
40
|
WHERE
|
39
41
|
t.typname IN (%s)
|
40
42
|
OR t.typtype IN (%s)
|
@@ -30,7 +30,7 @@ module ActiveRecord
|
|
30
30
|
# - "schema.name".table_name
|
31
31
|
# - "schema.name"."table.name"
|
32
32
|
def quote_table_name(name) # :nodoc:
|
33
|
-
|
33
|
+
self.class.quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
|
34
34
|
end
|
35
35
|
|
36
36
|
# Quotes schema names for use in SQL queries.
|
@@ -44,7 +44,7 @@ module ActiveRecord
|
|
44
44
|
|
45
45
|
# Quotes column names for use in SQL queries.
|
46
46
|
def quote_column_name(name) # :nodoc:
|
47
|
-
|
47
|
+
self.class.quoted_column_names[name] ||= PG::Connection.quote_ident(super).freeze
|
48
48
|
end
|
49
49
|
|
50
50
|
# Quote date/time values for use in SQL input.
|
@@ -78,6 +78,43 @@ module ActiveRecord
|
|
78
78
|
type_map.lookup(column.oid, column.fmod, column.sql_type)
|
79
79
|
end
|
80
80
|
|
81
|
+
def column_name_matcher
|
82
|
+
COLUMN_NAME
|
83
|
+
end
|
84
|
+
|
85
|
+
def column_name_with_order_matcher
|
86
|
+
COLUMN_NAME_WITH_ORDER
|
87
|
+
end
|
88
|
+
|
89
|
+
COLUMN_NAME = /
|
90
|
+
\A
|
91
|
+
(
|
92
|
+
(?:
|
93
|
+
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
94
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
|
95
|
+
)
|
96
|
+
(?:\s+AS\s+(?:\w+|"\w+"))?
|
97
|
+
)
|
98
|
+
(?:\s*,\s*\g<1>)*
|
99
|
+
\z
|
100
|
+
/ix
|
101
|
+
|
102
|
+
COLUMN_NAME_WITH_ORDER = /
|
103
|
+
\A
|
104
|
+
(
|
105
|
+
(?:
|
106
|
+
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
107
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
|
108
|
+
)
|
109
|
+
(?:\s+ASC|\s+DESC)?
|
110
|
+
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
111
|
+
)
|
112
|
+
(?:\s*,\s*\g<1>)*
|
113
|
+
\z
|
114
|
+
/ix
|
115
|
+
|
116
|
+
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
117
|
+
|
81
118
|
private
|
82
119
|
def lookup_cast_type(sql_type)
|
83
120
|
super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i)
|
@@ -93,11 +130,11 @@ module ActiveRecord
|
|
93
130
|
elsif value.hex?
|
94
131
|
"X'#{value}'"
|
95
132
|
end
|
96
|
-
when
|
97
|
-
if value.
|
98
|
-
"'#{value}'"
|
99
|
-
else
|
133
|
+
when Numeric
|
134
|
+
if value.finite?
|
100
135
|
super
|
136
|
+
else
|
137
|
+
"'#{value}'"
|
101
138
|
end
|
102
139
|
when OID::Array::Data
|
103
140
|
_quote(encode_array(value))
|
@@ -138,7 +175,7 @@ module ActiveRecord
|
|
138
175
|
end
|
139
176
|
|
140
177
|
def encode_range(range)
|
141
|
-
"[#{type_cast_range_value(range.
|
178
|
+
"[#{type_cast_range_value(range.begin)},#{type_cast_range_value(range.end)}#{range.exclude_end? ? ')' : ']'}"
|
142
179
|
end
|
143
180
|
|
144
181
|
def determine_encoding_of_strings_in_array(value)
|