activerecord 5.2.8.1 → 6.0.0.beta1
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 +299 -816
- data/MIT-LICENSE +3 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations/association.rb +35 -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/belongs_to.rb +14 -50
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/collection_association.rb +11 -25
- data/lib/active_record/associations/collection_proxy.rb +32 -6
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +25 -18
- 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 +11 -26
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +15 -20
- data/lib/active_record/associations/preloader/association.rb +1 -2
- data/lib/active_record/associations/preloader.rb +32 -29
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations.rb +16 -12
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods/dirty.rb +64 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -7
- data/lib/active_record/attribute_methods/read.rb +16 -48
- 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 +15 -16
- data/lib/active_record/attribute_methods.rb +34 -56
- data/lib/active_record/autosave_association.rb +7 -21
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +3 -17
- data/lib/active_record/coders/yaml_column.rb +1 -13
- data/lib/active_record/collection_cache_key.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
- data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
- data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -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/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
- data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
- data/lib/active_record/connection_handling.rb +132 -26
- data/lib/active_record/core.rb +75 -52
- 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 +74 -0
- data/lib/active_record/database_configurations.rb +184 -0
- data/lib/active_record/enum.rb +22 -7
- data/lib/active_record/errors.rb +24 -21
- 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 +12 -2
- data/lib/active_record/integration.rb +56 -16
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/migration/command_recorder.rb +35 -5
- data/lib/active_record/migration/compatibility.rb +34 -16
- data/lib/active_record/migration.rb +38 -37
- 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 +18 -7
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +19 -11
- data/lib/active_record/railtie.rb +71 -60
- 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 +94 -43
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +38 -28
- data/lib/active_record/relation/delegation.rb +4 -13
- data/lib/active_record/relation/finder_methods.rb +12 -25
- data/lib/active_record/relation/merger.rb +2 -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/predicate_builder.rb +4 -6
- data/lib/active_record/relation/query_attribute.rb +15 -12
- data/lib/active_record/relation/query_methods.rb +29 -52
- data/lib/active_record/relation/where_clause.rb +4 -0
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +150 -69
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +2 -39
- data/lib/active_record/schema.rb +1 -10
- data/lib/active_record/schema_dumper.rb +12 -6
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +10 -3
- data/lib/active_record/scoping/named.rb +10 -14
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +39 -8
- data/lib/active_record/table_metadata.rb +1 -4
- data/lib/active_record/tasks/database_tasks.rb +89 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
- 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 +4 -6
- data/lib/active_record/transactions.rb +3 -22
- 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 +1 -6
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +13 -25
- data/lib/active_record.rb +2 -1
- 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/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 +63 -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 +44 -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.rb +16 -0
- data/lib/arel/nodes/values_list.rb +24 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +67 -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 +199 -0
- data/lib/arel/visitors/dot.rb +292 -0
- data/lib/arel/visitors/ibm_db.rb +21 -0
- data/lib/arel/visitors/informix.rb +56 -0
- data/lib/arel/visitors/mssql.rb +143 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +67 -0
- data/lib/arel/visitors/postgresql.rb +116 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +913 -0
- data/lib/arel/visitors/visitor.rb +42 -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 +44 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- metadata +107 -29
@@ -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,19 @@ module ActiveRecord
|
|
76
77
|
|
77
78
|
SIMPLE_INT = /\A\d+\z/
|
78
79
|
|
79
|
-
|
80
|
-
|
80
|
+
attr_writer :visitor
|
81
|
+
deprecate :visitor=
|
82
|
+
|
83
|
+
attr_accessor :pool
|
84
|
+
attr_reader :schema_cache, :visitor, :owner, :logger, :lock, :prepared_statements, :prevent_writes
|
81
85
|
alias :in_use? :owner
|
82
86
|
|
87
|
+
set_callback :checkin, :after, :enable_lazy_transactions!
|
88
|
+
|
83
89
|
def self.type_cast_config_to_integer(config)
|
84
90
|
if config.is_a?(Integer)
|
85
91
|
config
|
86
|
-
elsif config
|
92
|
+
elsif SIMPLE_INT.match?(config)
|
87
93
|
config.to_i
|
88
94
|
else
|
89
95
|
config
|
@@ -98,6 +104,11 @@ module ActiveRecord
|
|
98
104
|
end
|
99
105
|
end
|
100
106
|
|
107
|
+
def self.build_read_query_regexp(*parts) # :nodoc:
|
108
|
+
parts = parts.map { |part| /\A\s*#{part}/i }
|
109
|
+
Regexp.union(*parts)
|
110
|
+
end
|
111
|
+
|
101
112
|
def initialize(connection, logger = nil, config = {}) # :nodoc:
|
102
113
|
super()
|
103
114
|
|
@@ -110,6 +121,7 @@ module ActiveRecord
|
|
110
121
|
@idle_since = Concurrent.monotonic_time
|
111
122
|
@schema_cache = SchemaCache.new self
|
112
123
|
@quoted_column_names, @quoted_table_names = {}, {}
|
124
|
+
@prevent_writes = false
|
113
125
|
@visitor = arel_visitor
|
114
126
|
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
115
127
|
|
@@ -119,6 +131,36 @@ module ActiveRecord
|
|
119
131
|
else
|
120
132
|
@prepared_statements = false
|
121
133
|
end
|
134
|
+
|
135
|
+
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
|
136
|
+
config.fetch(:advisory_locks, true)
|
137
|
+
)
|
138
|
+
|
139
|
+
check_version
|
140
|
+
end
|
141
|
+
|
142
|
+
def replica?
|
143
|
+
@config[:replica] || false
|
144
|
+
end
|
145
|
+
|
146
|
+
# Determines whether writes are currently being prevents.
|
147
|
+
#
|
148
|
+
# Returns true if the connection is a replica, or if +prevent_writes+
|
149
|
+
# is set to true.
|
150
|
+
def preventing_writes?
|
151
|
+
replica? || prevent_writes
|
152
|
+
end
|
153
|
+
|
154
|
+
# Prevent writing to the database regardless of role.
|
155
|
+
#
|
156
|
+
# In some cases you may want to prevent writes to the database
|
157
|
+
# even if you are on a database that can write. `while_preventing_writes`
|
158
|
+
# will prevent writes to the database for the duration of the block.
|
159
|
+
def while_preventing_writes
|
160
|
+
original, @prevent_writes = @prevent_writes, true
|
161
|
+
yield
|
162
|
+
ensure
|
163
|
+
@prevent_writes = original
|
122
164
|
end
|
123
165
|
|
124
166
|
def migrations_paths # :nodoc:
|
@@ -139,6 +181,10 @@ module ActiveRecord
|
|
139
181
|
def <=>(version_string)
|
140
182
|
@version <=> version_string.split(".").map(&:to_i)
|
141
183
|
end
|
184
|
+
|
185
|
+
def to_s
|
186
|
+
@version.join(".")
|
187
|
+
end
|
142
188
|
end
|
143
189
|
|
144
190
|
def valid_type?(type) # :nodoc:
|
@@ -148,7 +194,7 @@ module ActiveRecord
|
|
148
194
|
# this method must only be called while holding connection pool's mutex
|
149
195
|
def lease
|
150
196
|
if in_use?
|
151
|
-
msg = "Cannot lease connection, "
|
197
|
+
msg = +"Cannot lease connection, "
|
152
198
|
if @owner == Thread.current
|
153
199
|
msg << "it is already leased by the current thread."
|
154
200
|
else
|
@@ -298,6 +344,11 @@ module ActiveRecord
|
|
298
344
|
false
|
299
345
|
end
|
300
346
|
|
347
|
+
# Does this adapter support materialized views?
|
348
|
+
def supports_materialized_views?
|
349
|
+
false
|
350
|
+
end
|
351
|
+
|
301
352
|
# Does this adapter support datetime with precision?
|
302
353
|
def supports_datetime_with_precision?
|
303
354
|
false
|
@@ -322,6 +373,7 @@ module ActiveRecord
|
|
322
373
|
def supports_multi_insert?
|
323
374
|
true
|
324
375
|
end
|
376
|
+
deprecate :supports_multi_insert?
|
325
377
|
|
326
378
|
# Does this adapter support virtual columns?
|
327
379
|
def supports_virtual_columns?
|
@@ -333,6 +385,10 @@ module ActiveRecord
|
|
333
385
|
false
|
334
386
|
end
|
335
387
|
|
388
|
+
def supports_lazy_transactions?
|
389
|
+
false
|
390
|
+
end
|
391
|
+
|
336
392
|
# This is meant to be implemented by the adapters that support extensions
|
337
393
|
def disable_extension(name)
|
338
394
|
end
|
@@ -341,6 +397,10 @@ module ActiveRecord
|
|
341
397
|
def enable_extension(name)
|
342
398
|
end
|
343
399
|
|
400
|
+
def advisory_locks_enabled? # :nodoc:
|
401
|
+
supports_advisory_locks? && @advisory_locks_enabled
|
402
|
+
end
|
403
|
+
|
344
404
|
# This is meant to be implemented by the adapters that support advisory
|
345
405
|
# locks
|
346
406
|
#
|
@@ -444,18 +504,21 @@ module ActiveRecord
|
|
444
504
|
# This is useful for when you need to call a proprietary method such as
|
445
505
|
# PostgreSQL's lo_* methods.
|
446
506
|
def raw_connection
|
507
|
+
disable_lazy_transactions!
|
447
508
|
@connection
|
448
509
|
end
|
449
510
|
|
450
|
-
def case_sensitive_comparison(
|
451
|
-
|
511
|
+
def case_sensitive_comparison(attribute, value) # :nodoc:
|
512
|
+
attribute.eq(value)
|
452
513
|
end
|
453
514
|
|
454
|
-
def case_insensitive_comparison(
|
515
|
+
def case_insensitive_comparison(attribute, value) # :nodoc:
|
516
|
+
column = column_for_attribute(attribute)
|
517
|
+
|
455
518
|
if can_perform_case_insensitive_comparison_for?(column)
|
456
|
-
|
519
|
+
attribute.lower.eq(attribute.relation.lower(value))
|
457
520
|
else
|
458
|
-
|
521
|
+
attribute.eq(value)
|
459
522
|
end
|
460
523
|
end
|
461
524
|
|
@@ -470,11 +533,7 @@ module ActiveRecord
|
|
470
533
|
end
|
471
534
|
|
472
535
|
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
|
536
|
+
visitor.compile(node)
|
478
537
|
end
|
479
538
|
|
480
539
|
def default_index_type?(index) # :nodoc:
|
@@ -482,6 +541,9 @@ module ActiveRecord
|
|
482
541
|
end
|
483
542
|
|
484
543
|
private
|
544
|
+
def check_version
|
545
|
+
end
|
546
|
+
|
485
547
|
def type_map
|
486
548
|
@type_map ||= Type::TypeMap.new.tap do |mapping|
|
487
549
|
initialize_type_map(mapping)
|
@@ -555,14 +617,12 @@ module ActiveRecord
|
|
555
617
|
$1.to_i if sql_type =~ /\((.*)\)/
|
556
618
|
end
|
557
619
|
|
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
|
620
|
+
def translate_exception_class(e, sql, binds)
|
621
|
+
message = "#{e.class.name}: #{e.message}"
|
564
622
|
|
565
|
-
exception = translate_exception(
|
623
|
+
exception = translate_exception(
|
624
|
+
e, message: message, sql: sql, binds: binds
|
625
|
+
)
|
566
626
|
exception.set_backtrace e.backtrace
|
567
627
|
exception
|
568
628
|
end
|
@@ -575,24 +635,23 @@ module ActiveRecord
|
|
575
635
|
binds: binds,
|
576
636
|
type_casted_binds: type_casted_binds,
|
577
637
|
statement_name: statement_name,
|
578
|
-
connection_id: object_id
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
end
|
583
|
-
rescue => e
|
584
|
-
raise translate_exception_class(e, sql)
|
638
|
+
connection_id: object_id,
|
639
|
+
connection: self) do
|
640
|
+
@lock.synchronize do
|
641
|
+
yield
|
585
642
|
end
|
643
|
+
rescue => e
|
644
|
+
raise translate_exception_class(e, sql, binds)
|
586
645
|
end
|
587
646
|
end
|
588
647
|
|
589
|
-
def translate_exception(exception, message)
|
648
|
+
def translate_exception(exception, message:, sql:, binds:)
|
590
649
|
# override in derived class
|
591
650
|
case exception
|
592
651
|
when RuntimeError
|
593
652
|
exception
|
594
653
|
else
|
595
|
-
ActiveRecord::StatementInvalid.new(message)
|
654
|
+
ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
|
596
655
|
end
|
597
656
|
end
|
598
657
|
|
@@ -606,6 +665,11 @@ module ActiveRecord
|
|
606
665
|
raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
|
607
666
|
end
|
608
667
|
|
668
|
+
def column_for_attribute(attribute)
|
669
|
+
table_name = attribute.relation.name
|
670
|
+
schema_cache.columns_hash(table_name)[attribute.name.to_s]
|
671
|
+
end
|
672
|
+
|
609
673
|
def collector
|
610
674
|
if prepared_statements
|
611
675
|
Arel::Collectors::Composite.new(
|
@@ -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
|
@@ -45,19 +43,17 @@ module ActiveRecord
|
|
45
43
|
}
|
46
44
|
|
47
45
|
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
48
|
-
private
|
49
|
-
|
50
|
-
|
46
|
+
private
|
47
|
+
|
48
|
+
def dealloc(stmt)
|
49
|
+
stmt.close
|
50
|
+
end
|
51
51
|
end
|
52
52
|
|
53
53
|
def initialize(connection, logger, connection_options, config)
|
54
54
|
super(connection, logger, config)
|
55
55
|
|
56
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
57
|
end
|
62
58
|
|
63
59
|
def version #:nodoc:
|
@@ -76,6 +72,10 @@ module ActiveRecord
|
|
76
72
|
!mariadb? && version >= "8.0.1"
|
77
73
|
end
|
78
74
|
|
75
|
+
def supports_expression_index?
|
76
|
+
!mariadb? && version >= "8.0.13"
|
77
|
+
end
|
78
|
+
|
79
79
|
def supports_transaction_isolation?
|
80
80
|
true
|
81
81
|
end
|
@@ -97,19 +97,11 @@ module ActiveRecord
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def supports_datetime_with_precision?
|
100
|
-
|
101
|
-
version >= "5.3.0"
|
102
|
-
else
|
103
|
-
version >= "5.6.4"
|
104
|
-
end
|
100
|
+
mariadb? || version >= "5.6.4"
|
105
101
|
end
|
106
102
|
|
107
103
|
def supports_virtual_columns?
|
108
|
-
|
109
|
-
version >= "5.2.0"
|
110
|
-
else
|
111
|
-
version >= "5.7.5"
|
112
|
-
end
|
104
|
+
mariadb? || version >= "5.7.5"
|
113
105
|
end
|
114
106
|
|
115
107
|
def supports_advisory_locks?
|
@@ -129,7 +121,7 @@ module ActiveRecord
|
|
129
121
|
end
|
130
122
|
|
131
123
|
def index_algorithms
|
132
|
-
{ default: "ALGORITHM = DEFAULT"
|
124
|
+
{ default: +"ALGORITHM = DEFAULT", copy: +"ALGORITHM = COPY", inplace: +"ALGORITHM = INPLACE" }
|
133
125
|
end
|
134
126
|
|
135
127
|
# HELPER METHODS ===========================================
|
@@ -182,6 +174,8 @@ module ActiveRecord
|
|
182
174
|
|
183
175
|
# Executes the SQL statement in the context of this connection.
|
184
176
|
def execute(sql, name = nil)
|
177
|
+
materialize_transactions
|
178
|
+
|
185
179
|
log(sql, name) do
|
186
180
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
187
181
|
@connection.query(sql)
|
@@ -213,19 +207,7 @@ module ActiveRecord
|
|
213
207
|
execute "ROLLBACK"
|
214
208
|
end
|
215
209
|
|
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
|
210
|
+
def empty_insert_statement_value(primary_key = nil)
|
229
211
|
"VALUES ()"
|
230
212
|
end
|
231
213
|
|
@@ -241,7 +223,7 @@ module ActiveRecord
|
|
241
223
|
end
|
242
224
|
|
243
225
|
# Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
|
244
|
-
# Charset defaults to
|
226
|
+
# Charset defaults to utf8mb4.
|
245
227
|
#
|
246
228
|
# Example:
|
247
229
|
# create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
|
@@ -250,8 +232,12 @@ module ActiveRecord
|
|
250
232
|
def create_database(name, options = {})
|
251
233
|
if options[:collation]
|
252
234
|
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT COLLATE #{quote_table_name(options[:collation])}"
|
235
|
+
elsif options[:charset]
|
236
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset])}"
|
237
|
+
elsif row_format_dynamic_by_default?
|
238
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET `utf8mb4`"
|
253
239
|
else
|
254
|
-
|
240
|
+
raise "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
|
255
241
|
end
|
256
242
|
end
|
257
243
|
|
@@ -284,7 +270,7 @@ module ActiveRecord
|
|
284
270
|
def table_comment(table_name) # :nodoc:
|
285
271
|
scope = quoted_scope(table_name)
|
286
272
|
|
287
|
-
query_value(
|
273
|
+
query_value(<<~SQL, "SCHEMA").presence
|
288
274
|
SELECT table_comment
|
289
275
|
FROM information_schema.tables
|
290
276
|
WHERE table_schema = #{scope[:schema]}
|
@@ -378,7 +364,7 @@ module ActiveRecord
|
|
378
364
|
|
379
365
|
def add_index(table_name, column_name, options = {}) #:nodoc:
|
380
366
|
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}"
|
367
|
+
sql = +"CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
|
382
368
|
execute add_sql_comment!(sql, comment)
|
383
369
|
end
|
384
370
|
|
@@ -392,7 +378,7 @@ module ActiveRecord
|
|
392
378
|
|
393
379
|
scope = quoted_scope(table_name)
|
394
380
|
|
395
|
-
fk_info = exec_query(
|
381
|
+
fk_info = exec_query(<<~SQL, "SCHEMA")
|
396
382
|
SELECT fk.referenced_table_name AS 'to_table',
|
397
383
|
fk.referenced_column_name AS 'primary_key',
|
398
384
|
fk.column_name AS 'column',
|
@@ -480,7 +466,7 @@ module ActiveRecord
|
|
480
466
|
|
481
467
|
scope = quoted_scope(table_name)
|
482
468
|
|
483
|
-
query_values(
|
469
|
+
query_values(<<~SQL, "SCHEMA")
|
484
470
|
SELECT column_name
|
485
471
|
FROM information_schema.key_column_usage
|
486
472
|
WHERE constraint_name = 'PRIMARY'
|
@@ -490,9 +476,11 @@ module ActiveRecord
|
|
490
476
|
SQL
|
491
477
|
end
|
492
478
|
|
493
|
-
def case_sensitive_comparison(
|
479
|
+
def case_sensitive_comparison(attribute, value) # :nodoc:
|
480
|
+
column = column_for_attribute(attribute)
|
481
|
+
|
494
482
|
if column.collation && !column.case_sensitive?
|
495
|
-
|
483
|
+
attribute.eq(Arel::Nodes::Bin.new(value))
|
496
484
|
else
|
497
485
|
super
|
498
486
|
end
|
@@ -533,6 +521,12 @@ module ActiveRecord
|
|
533
521
|
end
|
534
522
|
|
535
523
|
private
|
524
|
+
def check_version
|
525
|
+
if version < "5.5.8"
|
526
|
+
raise "Your version of MySQL (#{version_string}) is too old. Active Record supports MySQL >= 5.5.8."
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
536
530
|
def combine_multi_statements(total_sql)
|
537
531
|
total_sql.each_with_object([]) do |sql, total_sql_chunks|
|
538
532
|
previous_packet = total_sql_chunks.last
|
@@ -587,13 +581,13 @@ module ActiveRecord
|
|
587
581
|
m.alias_type %r(bit)i, "binary"
|
588
582
|
|
589
583
|
m.register_type(%r(enum)i) do |sql_type|
|
590
|
-
limit = sql_type[/^enum\((.+)\)/i, 1]
|
584
|
+
limit = sql_type[/^enum\s*\((.+)\)/i, 1]
|
591
585
|
.split(",").map { |enum| enum.strip.length - 2 }.max
|
592
586
|
MysqlString.new(limit: limit)
|
593
587
|
end
|
594
588
|
|
595
589
|
m.register_type(%r(^set)i) do |sql_type|
|
596
|
-
limit = sql_type[/^set\((.+)\)/i, 1]
|
590
|
+
limit = sql_type[/^set\s*\((.+)\)/i, 1]
|
597
591
|
.split(",").map { |set| set.strip.length - 1 }.sum - 1
|
598
592
|
MysqlString.new(limit: limit)
|
599
593
|
end
|
@@ -620,7 +614,10 @@ module ActiveRecord
|
|
620
614
|
# See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
|
621
615
|
ER_DUP_ENTRY = 1062
|
622
616
|
ER_NOT_NULL_VIOLATION = 1048
|
617
|
+
ER_NO_REFERENCED_ROW = 1216
|
618
|
+
ER_ROW_IS_REFERENCED = 1217
|
623
619
|
ER_DO_NOT_HAVE_DEFAULT = 1364
|
620
|
+
ER_ROW_IS_REFERENCED_2 = 1451
|
624
621
|
ER_NO_REFERENCED_ROW_2 = 1452
|
625
622
|
ER_DATA_TOO_LONG = 1406
|
626
623
|
ER_OUT_OF_RANGE = 1264
|
@@ -631,34 +628,34 @@ module ActiveRecord
|
|
631
628
|
ER_QUERY_INTERRUPTED = 1317
|
632
629
|
ER_QUERY_TIMEOUT = 3024
|
633
630
|
|
634
|
-
def translate_exception(exception, message)
|
631
|
+
def translate_exception(exception, message:, sql:, binds:)
|
635
632
|
case error_number(exception)
|
636
633
|
when ER_DUP_ENTRY
|
637
|
-
RecordNotUnique.new(message)
|
638
|
-
when ER_NO_REFERENCED_ROW_2
|
639
|
-
InvalidForeignKey.new(message)
|
634
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
635
|
+
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
|
636
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
640
637
|
when ER_CANNOT_ADD_FOREIGN
|
641
|
-
mismatched_foreign_key(message)
|
638
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
642
639
|
when ER_CANNOT_CREATE_TABLE
|
643
640
|
if message.include?("errno: 150")
|
644
|
-
mismatched_foreign_key(message)
|
641
|
+
mismatched_foreign_key(message, sql: sql, binds: binds)
|
645
642
|
else
|
646
643
|
super
|
647
644
|
end
|
648
645
|
when ER_DATA_TOO_LONG
|
649
|
-
ValueTooLong.new(message)
|
646
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
650
647
|
when ER_OUT_OF_RANGE
|
651
|
-
RangeError.new(message)
|
648
|
+
RangeError.new(message, sql: sql, binds: binds)
|
652
649
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
653
|
-
NotNullViolation.new(message)
|
650
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
654
651
|
when ER_LOCK_DEADLOCK
|
655
|
-
Deadlocked.new(message)
|
652
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
656
653
|
when ER_LOCK_WAIT_TIMEOUT
|
657
|
-
LockWaitTimeout.new(message)
|
654
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
658
655
|
when ER_QUERY_TIMEOUT
|
659
|
-
StatementTimeout.new(message)
|
656
|
+
StatementTimeout.new(message, sql: sql, binds: binds)
|
660
657
|
when ER_QUERY_INTERRUPTED
|
661
|
-
QueryCanceled.new(message)
|
658
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
662
659
|
else
|
663
660
|
super
|
664
661
|
end
|
@@ -718,20 +715,6 @@ module ActiveRecord
|
|
718
715
|
[remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
|
719
716
|
end
|
720
717
|
|
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
718
|
def supports_rename_index?
|
736
719
|
mariadb? ? false : version >= "5.7.6"
|
737
720
|
end
|
@@ -770,7 +753,7 @@ module ActiveRecord
|
|
770
753
|
# https://dev.mysql.com/doc/refman/5.7/en/set-names.html
|
771
754
|
# (trailing comma because variable_assignments will always have content)
|
772
755
|
if @config[:encoding]
|
773
|
-
encoding = "NAMES #{@config[:encoding]}"
|
756
|
+
encoding = +"NAMES #{@config[:encoding]}"
|
774
757
|
encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
|
775
758
|
encoding << ", "
|
776
759
|
end
|
@@ -803,26 +786,18 @@ module ActiveRecord
|
|
803
786
|
Arel::Visitors::MySQL.new(self)
|
804
787
|
end
|
805
788
|
|
806
|
-
def mismatched_foreign_key(message)
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
811
|
-
/xmi.match(message)
|
812
|
-
|
813
|
-
options = {
|
789
|
+
def mismatched_foreign_key(message, sql:, binds:)
|
790
|
+
parts = sql.scan(/`(\w+)`[ $)]/).flatten
|
791
|
+
MismatchedForeignKey.new(
|
792
|
+
self,
|
814
793
|
message: message,
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
823
|
-
end
|
824
|
-
|
825
|
-
MismatchedForeignKey.new(options)
|
794
|
+
sql: sql,
|
795
|
+
binds: binds,
|
796
|
+
table: parts[0],
|
797
|
+
foreign_key: parts[1],
|
798
|
+
target_table: parts[2],
|
799
|
+
primary_key: parts[3],
|
800
|
+
)
|
826
801
|
end
|
827
802
|
|
828
803
|
def integer_to_sql(limit) # :nodoc:
|