activerecord 5.2.3 → 6.0.0.rc2
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 +605 -554
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +19 -14
- 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 +5 -15
- 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 +18 -25
- 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.rb +24 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +39 -31
- 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/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- 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/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +15 -5
- 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 +111 -19
- 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 +20 -11
- 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 +172 -41
- 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 +24 -7
- 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/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 +127 -143
- 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.rb +204 -0
- 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/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +28 -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 +140 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +180 -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.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +90 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +87 -76
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- 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 +193 -46
- data/lib/active_record/reflection.rb +42 -44
- data/lib/active_record/relation.rb +310 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +58 -49
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +14 -27
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- 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/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +182 -68
- 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/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.rb +8 -8
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +19 -15
- data/lib/active_record/statement_cache.rb +32 -5
- 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 +159 -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 +38 -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 +56 -65
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- 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/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -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.rb +68 -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/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.rb +20 -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/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- 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/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +109 -27
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -6,6 +6,7 @@ require "active_record/connection_adapters/sql_type_metadata"
|
|
6
6
|
require "active_record/connection_adapters/abstract/schema_dumper"
|
7
7
|
require "active_record/connection_adapters/abstract/schema_creation"
|
8
8
|
require "active_support/concurrency/load_interlock_aware_monitor"
|
9
|
+
require "active_support/deprecation"
|
9
10
|
require "arel/collectors/bind"
|
10
11
|
require "arel/collectors/composite"
|
11
12
|
require "arel/collectors/sql_string"
|
@@ -65,7 +66,7 @@ module ActiveRecord
|
|
65
66
|
# Most of the methods in the adapter are useful during migrations. Most
|
66
67
|
# notably, the instance methods provided by SchemaStatements are very useful.
|
67
68
|
class AbstractAdapter
|
68
|
-
ADAPTER_NAME = "Abstract"
|
69
|
+
ADAPTER_NAME = "Abstract"
|
69
70
|
include ActiveSupport::Callbacks
|
70
71
|
define_callbacks :checkout, :checkin
|
71
72
|
|
@@ -76,14 +77,16 @@ module ActiveRecord
|
|
76
77
|
|
77
78
|
SIMPLE_INT = /\A\d+\z/
|
78
79
|
|
79
|
-
attr_accessor :
|
80
|
-
attr_reader :
|
80
|
+
attr_accessor :pool
|
81
|
+
attr_reader :visitor, :owner, :logger, :lock, :prepared_statements
|
81
82
|
alias :in_use? :owner
|
82
83
|
|
84
|
+
set_callback :checkin, :after, :enable_lazy_transactions!
|
85
|
+
|
83
86
|
def self.type_cast_config_to_integer(config)
|
84
87
|
if config.is_a?(Integer)
|
85
88
|
config
|
86
|
-
elsif config
|
89
|
+
elsif SIMPLE_INT.match?(config)
|
87
90
|
config.to_i
|
88
91
|
else
|
89
92
|
config
|
@@ -98,6 +101,19 @@ module ActiveRecord
|
|
98
101
|
end
|
99
102
|
end
|
100
103
|
|
104
|
+
def self.build_read_query_regexp(*parts) # :nodoc:
|
105
|
+
parts = parts.map { |part| /\A[\(\s]*#{part}/i }
|
106
|
+
Regexp.union(*parts)
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.quoted_column_names # :nodoc:
|
110
|
+
@quoted_column_names ||= {}
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.quoted_table_names # :nodoc:
|
114
|
+
@quoted_table_names ||= {}
|
115
|
+
end
|
116
|
+
|
101
117
|
def initialize(connection, logger = nil, config = {}) # :nodoc:
|
102
118
|
super()
|
103
119
|
|
@@ -106,11 +122,10 @@ module ActiveRecord
|
|
106
122
|
@instrumenter = ActiveSupport::Notifications.instrumenter
|
107
123
|
@logger = logger
|
108
124
|
@config = config
|
109
|
-
@pool =
|
125
|
+
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
110
126
|
@idle_since = Concurrent.monotonic_time
|
111
|
-
@schema_cache = SchemaCache.new self
|
112
|
-
@quoted_column_names, @quoted_table_names = {}, {}
|
113
127
|
@visitor = arel_visitor
|
128
|
+
@statements = build_statement_pool
|
114
129
|
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
115
130
|
|
116
131
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
@@ -119,6 +134,22 @@ module ActiveRecord
|
|
119
134
|
else
|
120
135
|
@prepared_statements = false
|
121
136
|
end
|
137
|
+
|
138
|
+
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
|
139
|
+
config.fetch(:advisory_locks, true)
|
140
|
+
)
|
141
|
+
end
|
142
|
+
|
143
|
+
def replica?
|
144
|
+
@config[:replica] || false
|
145
|
+
end
|
146
|
+
|
147
|
+
# Determines whether writes are currently being prevents.
|
148
|
+
#
|
149
|
+
# Returns true if the connection is a replica, or if +prevent_writes+
|
150
|
+
# is set to true.
|
151
|
+
def preventing_writes?
|
152
|
+
replica? || ActiveRecord::Base.connection_handler.prevent_writes
|
122
153
|
end
|
123
154
|
|
124
155
|
def migrations_paths # :nodoc:
|
@@ -126,19 +157,41 @@ module ActiveRecord
|
|
126
157
|
end
|
127
158
|
|
128
159
|
def migration_context # :nodoc:
|
129
|
-
MigrationContext.new(migrations_paths)
|
160
|
+
MigrationContext.new(migrations_paths, schema_migration)
|
161
|
+
end
|
162
|
+
|
163
|
+
def schema_migration # :nodoc:
|
164
|
+
@schema_migration ||= begin
|
165
|
+
conn = self
|
166
|
+
spec_name = conn.pool.spec.name
|
167
|
+
name = "#{spec_name}::SchemaMigration"
|
168
|
+
|
169
|
+
Class.new(ActiveRecord::SchemaMigration) do
|
170
|
+
define_singleton_method(:name) { name }
|
171
|
+
define_singleton_method(:to_s) { name }
|
172
|
+
|
173
|
+
self.connection_specification_name = spec_name
|
174
|
+
end
|
175
|
+
end
|
130
176
|
end
|
131
177
|
|
132
178
|
class Version
|
133
179
|
include Comparable
|
134
180
|
|
135
|
-
|
181
|
+
attr_reader :full_version_string
|
182
|
+
|
183
|
+
def initialize(version_string, full_version_string = nil)
|
136
184
|
@version = version_string.split(".").map(&:to_i)
|
185
|
+
@full_version_string = full_version_string
|
137
186
|
end
|
138
187
|
|
139
188
|
def <=>(version_string)
|
140
189
|
@version <=> version_string.split(".").map(&:to_i)
|
141
190
|
end
|
191
|
+
|
192
|
+
def to_s
|
193
|
+
@version.join(".")
|
194
|
+
end
|
142
195
|
end
|
143
196
|
|
144
197
|
def valid_type?(type) # :nodoc:
|
@@ -148,7 +201,7 @@ module ActiveRecord
|
|
148
201
|
# this method must only be called while holding connection pool's mutex
|
149
202
|
def lease
|
150
203
|
if in_use?
|
151
|
-
msg = "Cannot lease connection, "
|
204
|
+
msg = +"Cannot lease connection, "
|
152
205
|
if @owner == Thread.current
|
153
206
|
msg << "it is already leased by the current thread."
|
154
207
|
else
|
@@ -161,9 +214,13 @@ module ActiveRecord
|
|
161
214
|
@owner = Thread.current
|
162
215
|
end
|
163
216
|
|
217
|
+
def schema_cache
|
218
|
+
@pool.get_schema_cache(self)
|
219
|
+
end
|
220
|
+
|
164
221
|
def schema_cache=(cache)
|
165
222
|
cache.connection = self
|
166
|
-
@
|
223
|
+
@pool.set_schema_cache(cache)
|
167
224
|
end
|
168
225
|
|
169
226
|
# this method must only be called while holding connection pool's mutex
|
@@ -214,6 +271,11 @@ module ActiveRecord
|
|
214
271
|
self.class::ADAPTER_NAME
|
215
272
|
end
|
216
273
|
|
274
|
+
# Does the database for this adapter exist?
|
275
|
+
def self.database_exists?(config)
|
276
|
+
raise NotImplementedError
|
277
|
+
end
|
278
|
+
|
217
279
|
# Does this adapter support DDL rollbacks in transactions? That is, would
|
218
280
|
# CREATE TABLE or ALTER TABLE get rolled back by a transaction?
|
219
281
|
def supports_ddl_transactions?
|
@@ -292,12 +354,18 @@ module ActiveRecord
|
|
292
354
|
def supports_foreign_keys_in_create?
|
293
355
|
supports_foreign_keys?
|
294
356
|
end
|
357
|
+
deprecate :supports_foreign_keys_in_create?
|
295
358
|
|
296
359
|
# Does this adapter support views?
|
297
360
|
def supports_views?
|
298
361
|
false
|
299
362
|
end
|
300
363
|
|
364
|
+
# Does this adapter support materialized views?
|
365
|
+
def supports_materialized_views?
|
366
|
+
false
|
367
|
+
end
|
368
|
+
|
301
369
|
# Does this adapter support datetime with precision?
|
302
370
|
def supports_datetime_with_precision?
|
303
371
|
false
|
@@ -322,6 +390,7 @@ module ActiveRecord
|
|
322
390
|
def supports_multi_insert?
|
323
391
|
true
|
324
392
|
end
|
393
|
+
deprecate :supports_multi_insert?
|
325
394
|
|
326
395
|
# Does this adapter support virtual columns?
|
327
396
|
def supports_virtual_columns?
|
@@ -333,6 +402,31 @@ module ActiveRecord
|
|
333
402
|
false
|
334
403
|
end
|
335
404
|
|
405
|
+
# Does this adapter support optimizer hints?
|
406
|
+
def supports_optimizer_hints?
|
407
|
+
false
|
408
|
+
end
|
409
|
+
|
410
|
+
def supports_lazy_transactions?
|
411
|
+
false
|
412
|
+
end
|
413
|
+
|
414
|
+
def supports_insert_returning?
|
415
|
+
false
|
416
|
+
end
|
417
|
+
|
418
|
+
def supports_insert_on_duplicate_skip?
|
419
|
+
false
|
420
|
+
end
|
421
|
+
|
422
|
+
def supports_insert_on_duplicate_update?
|
423
|
+
false
|
424
|
+
end
|
425
|
+
|
426
|
+
def supports_insert_conflict_target?
|
427
|
+
false
|
428
|
+
end
|
429
|
+
|
336
430
|
# This is meant to be implemented by the adapters that support extensions
|
337
431
|
def disable_extension(name)
|
338
432
|
end
|
@@ -341,6 +435,10 @@ module ActiveRecord
|
|
341
435
|
def enable_extension(name)
|
342
436
|
end
|
343
437
|
|
438
|
+
def advisory_locks_enabled? # :nodoc:
|
439
|
+
supports_advisory_locks? && @advisory_locks_enabled
|
440
|
+
end
|
441
|
+
|
344
442
|
# This is meant to be implemented by the adapters that support advisory
|
345
443
|
# locks
|
346
444
|
#
|
@@ -406,6 +504,9 @@ module ActiveRecord
|
|
406
504
|
#
|
407
505
|
# Prevent @connection's finalizer from touching the socket, or
|
408
506
|
# otherwise communicating with its server, when it is collected.
|
507
|
+
if schema_cache.connection == self
|
508
|
+
schema_cache.connection = nil
|
509
|
+
end
|
409
510
|
end
|
410
511
|
|
411
512
|
# Reset the state of this connection, directing the DBMS to clear
|
@@ -418,11 +519,9 @@ module ActiveRecord
|
|
418
519
|
# this should be overridden by concrete adapters
|
419
520
|
end
|
420
521
|
|
421
|
-
|
422
|
-
# Clear any caching the database adapter may be doing, for example
|
423
|
-
# clearing the prepared statement cache. This is database specific.
|
522
|
+
# Clear any caching the database adapter may be doing.
|
424
523
|
def clear_cache!
|
425
|
-
|
524
|
+
@lock.synchronize { @statements.clear } if @statements
|
426
525
|
end
|
427
526
|
|
428
527
|
# Returns true if its required to reload the connection between requests for development mode.
|
@@ -444,18 +543,25 @@ module ActiveRecord
|
|
444
543
|
# This is useful for when you need to call a proprietary method such as
|
445
544
|
# PostgreSQL's lo_* methods.
|
446
545
|
def raw_connection
|
546
|
+
disable_lazy_transactions!
|
447
547
|
@connection
|
448
548
|
end
|
449
549
|
|
450
|
-
def
|
451
|
-
|
550
|
+
def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
|
551
|
+
attribute.eq(value)
|
452
552
|
end
|
453
553
|
|
454
|
-
def
|
554
|
+
def case_sensitive_comparison(attribute, value) # :nodoc:
|
555
|
+
attribute.eq(value)
|
556
|
+
end
|
557
|
+
|
558
|
+
def case_insensitive_comparison(attribute, value) # :nodoc:
|
559
|
+
column = column_for_attribute(attribute)
|
560
|
+
|
455
561
|
if can_perform_case_insensitive_comparison_for?(column)
|
456
|
-
|
562
|
+
attribute.lower.eq(attribute.relation.lower(value))
|
457
563
|
else
|
458
|
-
|
564
|
+
attribute.eq(value)
|
459
565
|
end
|
460
566
|
end
|
461
567
|
|
@@ -470,18 +576,38 @@ module ActiveRecord
|
|
470
576
|
end
|
471
577
|
|
472
578
|
def column_name_for_operation(operation, node) # :nodoc:
|
473
|
-
|
474
|
-
end
|
475
|
-
|
476
|
-
def column_name_from_arel_node(node) # :nodoc:
|
477
|
-
visitor.accept(node, Arel::Collectors::SQLString.new).value
|
579
|
+
visitor.compile(node)
|
478
580
|
end
|
479
581
|
|
480
582
|
def default_index_type?(index) # :nodoc:
|
481
583
|
index.using.nil?
|
482
584
|
end
|
483
585
|
|
586
|
+
# Called by ActiveRecord::InsertAll,
|
587
|
+
# Passed an instance of ActiveRecord::InsertAll::Builder,
|
588
|
+
# This method implements standard bulk inserts for all databases, but
|
589
|
+
# should be overridden by adapters to implement common features with
|
590
|
+
# non-standard syntax like handling duplicates or returning values.
|
591
|
+
def build_insert_sql(insert) # :nodoc:
|
592
|
+
if insert.skip_duplicates? || insert.update_duplicates?
|
593
|
+
raise NotImplementedError, "#{self.class} should define `build_insert_sql` to implement adapter-specific logic for handling duplicates during INSERT"
|
594
|
+
end
|
595
|
+
|
596
|
+
"INSERT #{insert.into} #{insert.values_list}"
|
597
|
+
end
|
598
|
+
|
599
|
+
def get_database_version # :nodoc:
|
600
|
+
end
|
601
|
+
|
602
|
+
def database_version # :nodoc:
|
603
|
+
schema_cache.database_version
|
604
|
+
end
|
605
|
+
|
606
|
+
def check_version # :nodoc:
|
607
|
+
end
|
608
|
+
|
484
609
|
private
|
610
|
+
|
485
611
|
def type_map
|
486
612
|
@type_map ||= Type::TypeMap.new.tap do |mapping|
|
487
613
|
initialize_type_map(mapping)
|
@@ -555,14 +681,12 @@ module ActiveRecord
|
|
555
681
|
$1.to_i if sql_type =~ /\((.*)\)/
|
556
682
|
end
|
557
683
|
|
558
|
-
def translate_exception_class(e, sql)
|
559
|
-
|
560
|
-
message = "#{e.class.name}: #{e.message}: #{sql}"
|
561
|
-
rescue Encoding::CompatibilityError
|
562
|
-
message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
|
563
|
-
end
|
684
|
+
def translate_exception_class(e, sql, binds)
|
685
|
+
message = "#{e.class.name}: #{e.message}"
|
564
686
|
|
565
|
-
exception = translate_exception(
|
687
|
+
exception = translate_exception(
|
688
|
+
e, message: message, sql: sql, binds: binds
|
689
|
+
)
|
566
690
|
exception.set_backtrace e.backtrace
|
567
691
|
exception
|
568
692
|
end
|
@@ -575,24 +699,23 @@ module ActiveRecord
|
|
575
699
|
binds: binds,
|
576
700
|
type_casted_binds: type_casted_binds,
|
577
701
|
statement_name: statement_name,
|
578
|
-
connection_id: object_id
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
end
|
583
|
-
rescue => e
|
584
|
-
raise translate_exception_class(e, sql)
|
702
|
+
connection_id: object_id,
|
703
|
+
connection: self) do
|
704
|
+
@lock.synchronize do
|
705
|
+
yield
|
585
706
|
end
|
707
|
+
rescue => e
|
708
|
+
raise translate_exception_class(e, sql, binds)
|
586
709
|
end
|
587
710
|
end
|
588
711
|
|
589
|
-
def translate_exception(exception, message)
|
712
|
+
def translate_exception(exception, message:, sql:, binds:)
|
590
713
|
# override in derived class
|
591
714
|
case exception
|
592
715
|
when RuntimeError
|
593
716
|
exception
|
594
717
|
else
|
595
|
-
ActiveRecord::StatementInvalid.new(message)
|
718
|
+
ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
|
596
719
|
end
|
597
720
|
end
|
598
721
|
|
@@ -606,6 +729,11 @@ module ActiveRecord
|
|
606
729
|
raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
|
607
730
|
end
|
608
731
|
|
732
|
+
def column_for_attribute(attribute)
|
733
|
+
table_name = attribute.relation.name
|
734
|
+
schema_cache.columns_hash(table_name)[attribute.name.to_s]
|
735
|
+
end
|
736
|
+
|
609
737
|
def collector
|
610
738
|
if prepared_statements
|
611
739
|
Arel::Collectors::Composite.new(
|
@@ -623,6 +751,9 @@ module ActiveRecord
|
|
623
751
|
def arel_visitor
|
624
752
|
Arel::Visitors::ToSql.new(self)
|
625
753
|
end
|
754
|
+
|
755
|
+
def build_statement_pool
|
756
|
+
end
|
626
757
|
end
|
627
758
|
end
|
628
759
|
end
|
@@ -11,8 +11,6 @@ require "active_record/connection_adapters/mysql/schema_dumper"
|
|
11
11
|
require "active_record/connection_adapters/mysql/schema_statements"
|
12
12
|
require "active_record/connection_adapters/mysql/type_metadata"
|
13
13
|
|
14
|
-
require "active_support/core_ext/string/strip"
|
15
|
-
|
16
14
|
module ActiveRecord
|
17
15
|
module ConnectionAdapters
|
18
16
|
class AbstractMysqlAdapter < AbstractAdapter
|
@@ -31,7 +29,7 @@ module ActiveRecord
|
|
31
29
|
NATIVE_DATABASE_TYPES = {
|
32
30
|
primary_key: "bigint auto_increment PRIMARY KEY",
|
33
31
|
string: { name: "varchar", limit: 255 },
|
34
|
-
text: { name: "text"
|
32
|
+
text: { name: "text" },
|
35
33
|
integer: { name: "int", limit: 4 },
|
36
34
|
float: { name: "float", limit: 24 },
|
37
35
|
decimal: { name: "decimal" },
|
@@ -39,41 +37,44 @@ module ActiveRecord
|
|
39
37
|
timestamp: { name: "timestamp" },
|
40
38
|
time: { name: "time" },
|
41
39
|
date: { name: "date" },
|
42
|
-
binary: { name: "blob"
|
40
|
+
binary: { name: "blob" },
|
41
|
+
blob: { name: "blob" },
|
43
42
|
boolean: { name: "tinyint", limit: 1 },
|
44
43
|
json: { name: "json" },
|
45
44
|
}
|
46
45
|
|
47
46
|
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
48
|
-
private
|
49
|
-
|
50
|
-
|
47
|
+
private
|
48
|
+
|
49
|
+
def dealloc(stmt)
|
50
|
+
stmt.close
|
51
|
+
end
|
51
52
|
end
|
52
53
|
|
53
54
|
def initialize(connection, logger, connection_options, config)
|
54
55
|
super(connection, logger, config)
|
55
|
-
|
56
|
-
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
57
|
-
|
58
|
-
if version < "5.1.10"
|
59
|
-
raise "Your version of MySQL (#{version_string}) is too old. Active Record supports MySQL >= 5.1.10."
|
60
|
-
end
|
61
56
|
end
|
62
57
|
|
63
|
-
def
|
64
|
-
|
58
|
+
def get_database_version #:nodoc:
|
59
|
+
full_version_string = get_full_version
|
60
|
+
version_string = version_string(full_version_string)
|
61
|
+
Version.new(version_string, full_version_string)
|
65
62
|
end
|
66
63
|
|
67
64
|
def mariadb? # :nodoc:
|
68
65
|
/mariadb/i.match?(full_version)
|
69
66
|
end
|
70
67
|
|
71
|
-
def supports_bulk_alter?
|
68
|
+
def supports_bulk_alter?
|
72
69
|
true
|
73
70
|
end
|
74
71
|
|
75
72
|
def supports_index_sort_order?
|
76
|
-
!mariadb? &&
|
73
|
+
!mariadb? && database_version >= "8.0.1"
|
74
|
+
end
|
75
|
+
|
76
|
+
def supports_expression_index?
|
77
|
+
!mariadb? && database_version >= "8.0.13"
|
77
78
|
end
|
78
79
|
|
79
80
|
def supports_transaction_isolation?
|
@@ -97,25 +98,30 @@ module ActiveRecord
|
|
97
98
|
end
|
98
99
|
|
99
100
|
def supports_datetime_with_precision?
|
100
|
-
|
101
|
-
version >= "5.3.0"
|
102
|
-
else
|
103
|
-
version >= "5.6.4"
|
104
|
-
end
|
101
|
+
mariadb? || database_version >= "5.6.4"
|
105
102
|
end
|
106
103
|
|
107
104
|
def supports_virtual_columns?
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
105
|
+
mariadb? || database_version >= "5.7.5"
|
106
|
+
end
|
107
|
+
|
108
|
+
# See https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html for more details.
|
109
|
+
def supports_optimizer_hints?
|
110
|
+
!mariadb? && database_version >= "5.7.7"
|
113
111
|
end
|
114
112
|
|
115
113
|
def supports_advisory_locks?
|
116
114
|
true
|
117
115
|
end
|
118
116
|
|
117
|
+
def supports_insert_on_duplicate_skip?
|
118
|
+
true
|
119
|
+
end
|
120
|
+
|
121
|
+
def supports_insert_on_duplicate_update?
|
122
|
+
true
|
123
|
+
end
|
124
|
+
|
119
125
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
120
126
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
121
127
|
end
|
@@ -129,7 +135,7 @@ module ActiveRecord
|
|
129
135
|
end
|
130
136
|
|
131
137
|
def index_algorithms
|
132
|
-
{ default: "ALGORITHM = DEFAULT"
|
138
|
+
{ default: +"ALGORITHM = DEFAULT", copy: +"ALGORITHM = COPY", inplace: +"ALGORITHM = INPLACE" }
|
133
139
|
end
|
134
140
|
|
135
141
|
# HELPER METHODS ===========================================
|
@@ -161,10 +167,9 @@ module ActiveRecord
|
|
161
167
|
|
162
168
|
# CONNECTION MANAGEMENT ====================================
|
163
169
|
|
164
|
-
|
165
|
-
def clear_cache!
|
170
|
+
def clear_cache! # :nodoc:
|
166
171
|
reload_type_map
|
167
|
-
|
172
|
+
super
|
168
173
|
end
|
169
174
|
|
170
175
|
#--
|
@@ -173,15 +178,17 @@ module ActiveRecord
|
|
173
178
|
|
174
179
|
def explain(arel, binds = [])
|
175
180
|
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
176
|
-
start =
|
181
|
+
start = Concurrent.monotonic_time
|
177
182
|
result = exec_query(sql, "EXPLAIN", binds)
|
178
|
-
elapsed =
|
183
|
+
elapsed = Concurrent.monotonic_time - start
|
179
184
|
|
180
185
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
181
186
|
end
|
182
187
|
|
183
188
|
# Executes the SQL statement in the context of this connection.
|
184
189
|
def execute(sql, name = nil)
|
190
|
+
materialize_transactions
|
191
|
+
|
185
192
|
log(sql, name) do
|
186
193
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
187
194
|
@connection.query(sql)
|
@@ -213,19 +220,7 @@ module ActiveRecord
|
|
213
220
|
execute "ROLLBACK"
|
214
221
|
end
|
215
222
|
|
216
|
-
|
217
|
-
# query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
|
218
|
-
# these, we must use a subquery.
|
219
|
-
def join_to_update(update, select, key) # :nodoc:
|
220
|
-
if select.limit || select.offset || select.orders.any?
|
221
|
-
super
|
222
|
-
else
|
223
|
-
update.table select.source
|
224
|
-
update.wheres = select.constraints
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def empty_insert_statement_value
|
223
|
+
def empty_insert_statement_value(primary_key = nil)
|
229
224
|
"VALUES ()"
|
230
225
|
end
|
231
226
|
|
@@ -241,7 +236,7 @@ module ActiveRecord
|
|
241
236
|
end
|
242
237
|
|
243
238
|
# Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
|
244
|
-
# Charset defaults to
|
239
|
+
# Charset defaults to utf8mb4.
|
245
240
|
#
|
246
241
|
# Example:
|
247
242
|
# create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
|
@@ -250,8 +245,12 @@ module ActiveRecord
|
|
250
245
|
def create_database(name, options = {})
|
251
246
|
if options[:collation]
|
252
247
|
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT COLLATE #{quote_table_name(options[:collation])}"
|
248
|
+
elsif options[:charset]
|
249
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset])}"
|
250
|
+
elsif row_format_dynamic_by_default?
|
251
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET `utf8mb4`"
|
253
252
|
else
|
254
|
-
|
253
|
+
raise "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
|
255
254
|
end
|
256
255
|
end
|
257
256
|
|
@@ -277,14 +276,10 @@ module ActiveRecord
|
|
277
276
|
show_variable "collation_database"
|
278
277
|
end
|
279
278
|
|
280
|
-
def truncate(table_name, name = nil)
|
281
|
-
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
282
|
-
end
|
283
|
-
|
284
279
|
def table_comment(table_name) # :nodoc:
|
285
280
|
scope = quoted_scope(table_name)
|
286
281
|
|
287
|
-
query_value(
|
282
|
+
query_value(<<~SQL, "SCHEMA").presence
|
288
283
|
SELECT table_comment
|
289
284
|
FROM information_schema.tables
|
290
285
|
WHERE table_schema = #{scope[:schema]}
|
@@ -292,22 +287,8 @@ module ActiveRecord
|
|
292
287
|
SQL
|
293
288
|
end
|
294
289
|
|
295
|
-
def
|
296
|
-
|
297
|
-
table, arguments = args.shift, args
|
298
|
-
method = :"#{command}_for_alter"
|
299
|
-
|
300
|
-
if respond_to?(method, true)
|
301
|
-
send(method, table, *arguments)
|
302
|
-
else
|
303
|
-
raise "Unknown method called : #{method}(#{arguments.inspect})"
|
304
|
-
end
|
305
|
-
end.join(", ")
|
306
|
-
|
307
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
|
308
|
-
end
|
309
|
-
|
310
|
-
def change_table_comment(table_name, comment) #:nodoc:
|
290
|
+
def change_table_comment(table_name, comment_or_changes) # :nodoc:
|
291
|
+
comment = extract_new_comment_value(comment_or_changes)
|
311
292
|
comment = "" if comment.nil?
|
312
293
|
execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
|
313
294
|
end
|
@@ -363,7 +344,8 @@ module ActiveRecord
|
|
363
344
|
change_column table_name, column_name, nil, null: null
|
364
345
|
end
|
365
346
|
|
366
|
-
def change_column_comment(table_name, column_name,
|
347
|
+
def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
|
348
|
+
comment = extract_new_comment_value(comment_or_changes)
|
367
349
|
change_column table_name, column_name, nil, comment: comment
|
368
350
|
end
|
369
351
|
|
@@ -378,7 +360,7 @@ module ActiveRecord
|
|
378
360
|
|
379
361
|
def add_index(table_name, column_name, options = {}) #:nodoc:
|
380
362
|
index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
|
381
|
-
sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
|
363
|
+
sql = +"CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
|
382
364
|
execute add_sql_comment!(sql, comment)
|
383
365
|
end
|
384
366
|
|
@@ -392,7 +374,7 @@ module ActiveRecord
|
|
392
374
|
|
393
375
|
scope = quoted_scope(table_name)
|
394
376
|
|
395
|
-
fk_info = exec_query(
|
377
|
+
fk_info = exec_query(<<~SQL, "SCHEMA")
|
396
378
|
SELECT fk.referenced_table_name AS 'to_table',
|
397
379
|
fk.referenced_column_name AS 'primary_key',
|
398
380
|
fk.column_name AS 'column',
|
@@ -444,30 +426,6 @@ module ActiveRecord
|
|
444
426
|
table_options
|
445
427
|
end
|
446
428
|
|
447
|
-
# Maps logical Rails types to MySQL-specific data types.
|
448
|
-
def type_to_sql(type, limit: nil, precision: nil, scale: nil, unsigned: nil, **) # :nodoc:
|
449
|
-
sql = \
|
450
|
-
case type.to_s
|
451
|
-
when "integer"
|
452
|
-
integer_to_sql(limit)
|
453
|
-
when "text"
|
454
|
-
text_to_sql(limit)
|
455
|
-
when "blob"
|
456
|
-
binary_to_sql(limit)
|
457
|
-
when "binary"
|
458
|
-
if (0..0xfff) === limit
|
459
|
-
"varbinary(#{limit})"
|
460
|
-
else
|
461
|
-
binary_to_sql(limit)
|
462
|
-
end
|
463
|
-
else
|
464
|
-
super
|
465
|
-
end
|
466
|
-
|
467
|
-
sql = "#{sql} unsigned" if unsigned && type != :primary_key
|
468
|
-
sql
|
469
|
-
end
|
470
|
-
|
471
429
|
# SHOW VARIABLES LIKE 'name'
|
472
430
|
def show_variable(name)
|
473
431
|
query_value("SELECT @@#{name}", "SCHEMA")
|
@@ -480,7 +438,7 @@ module ActiveRecord
|
|
480
438
|
|
481
439
|
scope = quoted_scope(table_name)
|
482
440
|
|
483
|
-
query_values(
|
441
|
+
query_values(<<~SQL, "SCHEMA")
|
484
442
|
SELECT column_name
|
485
443
|
FROM information_schema.key_column_usage
|
486
444
|
WHERE constraint_name = 'PRIMARY'
|
@@ -490,9 +448,26 @@ module ActiveRecord
|
|
490
448
|
SQL
|
491
449
|
end
|
492
450
|
|
493
|
-
def
|
451
|
+
def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
|
452
|
+
column = column_for_attribute(attribute)
|
453
|
+
|
454
|
+
if column.collation && !column.case_sensitive? && !value.nil?
|
455
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
456
|
+
Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1.
|
457
|
+
To continue case sensitive comparison on the :#{attribute.name} attribute in #{klass} model,
|
458
|
+
pass `case_sensitive: true` option explicitly to the uniqueness validator.
|
459
|
+
MSG
|
460
|
+
attribute.eq(Arel::Nodes::Bin.new(value))
|
461
|
+
else
|
462
|
+
super
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def case_sensitive_comparison(attribute, value) # :nodoc:
|
467
|
+
column = column_for_attribute(attribute)
|
468
|
+
|
494
469
|
if column.collation && !column.case_sensitive?
|
495
|
-
|
470
|
+
attribute.eq(Arel::Nodes::Bin.new(value))
|
496
471
|
else
|
497
472
|
super
|
498
473
|
end
|
@@ -526,39 +501,27 @@ module ActiveRecord
|
|
526
501
|
index.using == :btree || super
|
527
502
|
end
|
528
503
|
|
529
|
-
def
|
530
|
-
|
531
|
-
super { discard_remaining_results }
|
532
|
-
end
|
533
|
-
end
|
504
|
+
def build_insert_sql(insert) # :nodoc:
|
505
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
534
506
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
total_sql_chunks << sql
|
542
|
-
else
|
543
|
-
previous_packet << sql
|
544
|
-
end
|
545
|
-
end
|
507
|
+
if insert.skip_duplicates?
|
508
|
+
no_op_column = quote_column_name(insert.keys.first)
|
509
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
510
|
+
elsif insert.update_duplicates?
|
511
|
+
sql << " ON DUPLICATE KEY UPDATE "
|
512
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
546
513
|
end
|
547
514
|
|
548
|
-
|
549
|
-
|
550
|
-
raise ActiveRecordError, "Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
|
551
|
-
elsif previous_packet.nil?
|
552
|
-
false
|
553
|
-
else
|
554
|
-
(current_packet.bytesize + previous_packet.bytesize) > max_allowed_packet
|
555
|
-
end
|
556
|
-
end
|
515
|
+
sql
|
516
|
+
end
|
557
517
|
|
558
|
-
|
559
|
-
|
560
|
-
|
518
|
+
def check_version # :nodoc:
|
519
|
+
if database_version < "5.5.8"
|
520
|
+
raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
|
561
521
|
end
|
522
|
+
end
|
523
|
+
|
524
|
+
private
|
562
525
|
|
563
526
|
def initialize_type_map(m = type_map)
|
564
527
|
super
|
@@ -587,13 +550,13 @@ module ActiveRecord
|
|
587
550
|
m.alias_type %r(bit)i, "binary"
|
588
551
|
|
589
552
|
m.register_type(%r(enum)i) do |sql_type|
|
590
|
-
limit = sql_type[/^enum\((.+)\)/i, 1]
|
553
|
+
limit = sql_type[/^enum\s*\((.+)\)/i, 1]
|
591
554
|
.split(",").map { |enum| enum.strip.length - 2 }.max
|
592
555
|
MysqlString.new(limit: limit)
|
593
556
|
end
|
594
557
|
|
595
558
|
m.register_type(%r(^set)i) do |sql_type|
|
596
|
-
limit = sql_type[/^set\((.+)\)/i, 1]
|
559
|
+
limit = sql_type[/^set\s*\((.+)\)/i, 1]
|
597
560
|
.split(",").map { |set| set.strip.length - 1 }.sum - 1
|
598
561
|
MysqlString.new(limit: limit)
|
599
562
|
end
|
@@ -620,7 +583,10 @@ module ActiveRecord
|
|
620
583
|
# See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
|
621
584
|
ER_DUP_ENTRY = 1062
|
622
585
|
ER_NOT_NULL_VIOLATION = 1048
|
586
|
+
ER_NO_REFERENCED_ROW = 1216
|
587
|
+
ER_ROW_IS_REFERENCED = 1217
|
623
588
|
ER_DO_NOT_HAVE_DEFAULT = 1364
|
589
|
+
ER_ROW_IS_REFERENCED_2 = 1451
|
624
590
|
ER_NO_REFERENCED_ROW_2 = 1452
|
625
591
|
ER_DATA_TOO_LONG = 1406
|
626
592
|
ER_OUT_OF_RANGE = 1264
|
@@ -630,35 +596,36 @@ module ActiveRecord
|
|
630
596
|
ER_LOCK_WAIT_TIMEOUT = 1205
|
631
597
|
ER_QUERY_INTERRUPTED = 1317
|
632
598
|
ER_QUERY_TIMEOUT = 3024
|
599
|
+
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
633
600
|
|
634
|
-
def translate_exception(exception, message)
|
601
|
+
def translate_exception(exception, message:, sql:, binds:)
|
635
602
|
case error_number(exception)
|
636
603
|
when ER_DUP_ENTRY
|
637
|
-
RecordNotUnique.new(message)
|
638
|
-
when ER_NO_REFERENCED_ROW_2
|
639
|
-
InvalidForeignKey.new(message)
|
640
|
-
when ER_CANNOT_ADD_FOREIGN
|
641
|
-
mismatched_foreign_key(message)
|
604
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
605
|
+
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
606
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
607
|
+
when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
|
608
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
642
609
|
when ER_CANNOT_CREATE_TABLE
|
643
610
|
if message.include?("errno: 150")
|
644
|
-
mismatched_foreign_key(message)
|
611
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
645
612
|
else
|
646
613
|
super
|
647
614
|
end
|
648
615
|
when ER_DATA_TOO_LONG
|
649
|
-
ValueTooLong.new(message)
|
616
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
650
617
|
when ER_OUT_OF_RANGE
|
651
|
-
RangeError.new(message)
|
618
|
+
RangeError.new(message, sql: sql, binds: binds)
|
652
619
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
653
|
-
NotNullViolation.new(message)
|
620
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
654
621
|
when ER_LOCK_DEADLOCK
|
655
|
-
Deadlocked.new(message)
|
622
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
656
623
|
when ER_LOCK_WAIT_TIMEOUT
|
657
|
-
LockWaitTimeout.new(message)
|
624
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
658
625
|
when ER_QUERY_TIMEOUT
|
659
|
-
StatementTimeout.new(message)
|
626
|
+
StatementTimeout.new(message, sql: sql, binds: binds)
|
660
627
|
when ER_QUERY_INTERRUPTED
|
661
|
-
QueryCanceled.new(message)
|
628
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
662
629
|
else
|
663
630
|
super
|
664
631
|
end
|
@@ -711,6 +678,12 @@ module ActiveRecord
|
|
711
678
|
end
|
712
679
|
|
713
680
|
def add_timestamps_for_alter(table_name, options = {})
|
681
|
+
options[:null] = false if options[:null].nil?
|
682
|
+
|
683
|
+
if !options.key?(:precision) && supports_datetime_with_precision?
|
684
|
+
options[:precision] = 6
|
685
|
+
end
|
686
|
+
|
714
687
|
[add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
|
715
688
|
end
|
716
689
|
|
@@ -718,22 +691,8 @@ module ActiveRecord
|
|
718
691
|
[remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
|
719
692
|
end
|
720
693
|
|
721
|
-
# MySQL is too stupid to create a temporary table for use subquery, so we have
|
722
|
-
# to give it some prompting in the form of a subsubquery. Ugh!
|
723
|
-
def subquery_for(key, select)
|
724
|
-
subselect = select.clone
|
725
|
-
subselect.projections = [key]
|
726
|
-
|
727
|
-
# Materialize subquery by adding distinct
|
728
|
-
# to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
|
729
|
-
subselect.distinct unless select.limit || select.offset || select.orders.any?
|
730
|
-
|
731
|
-
key_name = quote_column_name(key.name)
|
732
|
-
Arel::SelectManager.new(subselect.as("__active_record_temp")).project(Arel.sql(key_name))
|
733
|
-
end
|
734
|
-
|
735
694
|
def supports_rename_index?
|
736
|
-
mariadb? ? false :
|
695
|
+
mariadb? ? false : database_version >= "5.7.6"
|
737
696
|
end
|
738
697
|
|
739
698
|
def configure_connection
|
@@ -770,7 +729,7 @@ module ActiveRecord
|
|
770
729
|
# https://dev.mysql.com/doc/refman/5.7/en/set-names.html
|
771
730
|
# (trailing comma because variable_assignments will always have content)
|
772
731
|
if @config[:encoding]
|
773
|
-
encoding = "NAMES #{@config[:encoding]}"
|
732
|
+
encoding = +"NAMES #{@config[:encoding]}"
|
774
733
|
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
775
734
|
encoding << ", "
|
776
735
|
end
|
@@ -803,15 +762,21 @@ module ActiveRecord
|
|
803
762
|
Arel::Visitors::MySQL.new(self)
|
804
763
|
end
|
805
764
|
|
806
|
-
def
|
765
|
+
def build_statement_pool
|
766
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
767
|
+
end
|
768
|
+
|
769
|
+
def mismatched_foreign_key(message, sql:, binds:)
|
807
770
|
match = %r/
|
808
771
|
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
809
772
|
FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
|
810
773
|
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
811
|
-
/xmi.match(
|
774
|
+
/xmi.match(sql)
|
812
775
|
|
813
776
|
options = {
|
814
777
|
message: message,
|
778
|
+
sql: sql,
|
779
|
+
binds: binds,
|
815
780
|
}
|
816
781
|
|
817
782
|
if match
|
@@ -825,39 +790,8 @@ module ActiveRecord
|
|
825
790
|
MismatchedForeignKey.new(options)
|
826
791
|
end
|
827
792
|
|
828
|
-
def
|
829
|
-
|
830
|
-
when 1; "tinyint"
|
831
|
-
when 2; "smallint"
|
832
|
-
when 3; "mediumint"
|
833
|
-
when nil, 4; "int"
|
834
|
-
when 5..8; "bigint"
|
835
|
-
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a decimal with scale 0 instead.")
|
836
|
-
end
|
837
|
-
end
|
838
|
-
|
839
|
-
def text_to_sql(limit) # :nodoc:
|
840
|
-
case limit
|
841
|
-
when 0..0xff; "tinytext"
|
842
|
-
when nil, 0x100..0xffff; "text"
|
843
|
-
when 0x10000..0xffffff; "mediumtext"
|
844
|
-
when 0x1000000..0xffffffff; "longtext"
|
845
|
-
else raise(ActiveRecordError, "No text type has byte length #{limit}")
|
846
|
-
end
|
847
|
-
end
|
848
|
-
|
849
|
-
def binary_to_sql(limit) # :nodoc:
|
850
|
-
case limit
|
851
|
-
when 0..0xff; "tinyblob"
|
852
|
-
when nil, 0x100..0xffff; "blob"
|
853
|
-
when 0x10000..0xffffff; "mediumblob"
|
854
|
-
when 0x1000000..0xffffffff; "longblob"
|
855
|
-
else raise(ActiveRecordError, "No binary type has byte length #{limit}")
|
856
|
-
end
|
857
|
-
end
|
858
|
-
|
859
|
-
def version_string
|
860
|
-
full_version.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
793
|
+
def version_string(full_version_string)
|
794
|
+
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
861
795
|
end
|
862
796
|
|
863
797
|
class MysqlString < Type::String # :nodoc:
|