activerecord 5.2.4.5 → 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 -739
- data/MIT-LICENSE +3 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +16 -12
- 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.rb +15 -20
- 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/preloader.rb +32 -29
- data/lib/active_record/associations/preloader/association.rb +1 -2
- 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 +34 -56
- 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/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/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 +76 -43
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +184 -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 +74 -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.rb +38 -37
- data/lib/active_record/migration/command_recorder.rb +35 -5
- data/lib/active_record/migration/compatibility.rb +34 -16
- 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 -42
- 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.rb +150 -69
- 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.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 +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/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.rb +9 -8
- data/lib/active_record/scoping/default.rb +10 -3
- data/lib/active_record/scoping/named.rb +10 -14
- 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.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- 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/arel.rb +44 -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 +67 -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/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 +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/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/model/model_generator.rb +1 -0
- metadata +104 -26
@@ -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:
|
@@ -57,9 +57,7 @@ module ActiveRecord
|
|
57
57
|
|
58
58
|
private
|
59
59
|
|
60
|
-
|
61
|
-
@uri
|
62
|
-
end
|
60
|
+
attr_reader :uri
|
63
61
|
|
64
62
|
def uri_parser
|
65
63
|
@uri_parser ||= URI::Parser.new
|
@@ -116,8 +114,7 @@ module ActiveRecord
|
|
116
114
|
class Resolver # :nodoc:
|
117
115
|
attr_reader :configurations
|
118
116
|
|
119
|
-
# Accepts a
|
120
|
-
# environments such as "production". Keys must be strings.
|
117
|
+
# Accepts a list of db config objects.
|
121
118
|
def initialize(configurations)
|
122
119
|
@configurations = configurations
|
123
120
|
end
|
@@ -138,34 +135,14 @@ module ActiveRecord
|
|
138
135
|
# Resolver.new(configurations).resolve(:production)
|
139
136
|
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
|
140
137
|
#
|
141
|
-
def resolve(
|
142
|
-
if
|
143
|
-
resolve_connection
|
144
|
-
elsif env = ActiveRecord::ConnectionHandling::RAILS_ENV.call
|
145
|
-
resolve_symbol_connection env.to_sym
|
138
|
+
def resolve(config_or_env, pool_name = nil)
|
139
|
+
if config_or_env
|
140
|
+
resolve_connection config_or_env, pool_name
|
146
141
|
else
|
147
142
|
raise AdapterNotSpecified
|
148
143
|
end
|
149
144
|
end
|
150
145
|
|
151
|
-
# Expands each key in @configurations hash into fully resolved hash
|
152
|
-
def resolve_all
|
153
|
-
config = configurations.dup
|
154
|
-
|
155
|
-
if env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
156
|
-
env_config = config[env] if config[env].is_a?(Hash) && !(config[env].key?("adapter") || config[env].key?("url"))
|
157
|
-
end
|
158
|
-
|
159
|
-
config.reject! { |k, v| v.is_a?(Hash) && !(v.key?("adapter") || v.key?("url")) }
|
160
|
-
config.merge! env_config if env_config
|
161
|
-
|
162
|
-
config.each do |key, value|
|
163
|
-
config[key] = resolve(value) if value
|
164
|
-
end
|
165
|
-
|
166
|
-
config
|
167
|
-
end
|
168
|
-
|
169
146
|
# Returns an instance of ConnectionSpecification for a given adapter.
|
170
147
|
# Accepts a hash one layer deep that contains all connection information.
|
171
148
|
#
|
@@ -179,7 +156,9 @@ module ActiveRecord
|
|
179
156
|
# # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" }
|
180
157
|
#
|
181
158
|
def spec(config)
|
182
|
-
|
159
|
+
pool_name = config if config.is_a?(Symbol)
|
160
|
+
|
161
|
+
spec = resolve(config, pool_name).symbolize_keys
|
183
162
|
|
184
163
|
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
|
185
164
|
|
@@ -214,7 +193,6 @@ module ActiveRecord
|
|
214
193
|
end
|
215
194
|
|
216
195
|
private
|
217
|
-
|
218
196
|
# Returns fully resolved connection, accepts hash, string or symbol.
|
219
197
|
# Always returns a hash.
|
220
198
|
#
|
@@ -235,32 +213,64 @@ module ActiveRecord
|
|
235
213
|
# Resolver.new({}).resolve_connection("postgresql://localhost/foo")
|
236
214
|
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
|
237
215
|
#
|
238
|
-
def resolve_connection(
|
239
|
-
case
|
216
|
+
def resolve_connection(config_or_env, pool_name = nil)
|
217
|
+
case config_or_env
|
240
218
|
when Symbol
|
241
|
-
resolve_symbol_connection
|
219
|
+
resolve_symbol_connection config_or_env, pool_name
|
242
220
|
when String
|
243
|
-
resolve_url_connection
|
221
|
+
resolve_url_connection config_or_env
|
244
222
|
when Hash
|
245
|
-
resolve_hash_connection
|
223
|
+
resolve_hash_connection config_or_env
|
224
|
+
else
|
225
|
+
resolve_connection config_or_env
|
246
226
|
end
|
247
227
|
end
|
248
228
|
|
249
|
-
# Takes the environment such as +:production+ or +:development
|
229
|
+
# Takes the environment such as +:production+ or +:development+ and a
|
230
|
+
# pool name the corresponds to the name given by the connection pool
|
231
|
+
# to the connection. That pool name is merged into the hash with the
|
232
|
+
# name key.
|
233
|
+
#
|
250
234
|
# This requires that the @configurations was initialized with a key that
|
251
235
|
# matches.
|
252
236
|
#
|
253
|
-
#
|
254
|
-
#
|
237
|
+
# configurations = #<ActiveRecord::DatabaseConfigurations:0x00007fd9fdace3e0
|
238
|
+
# @configurations=[
|
239
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd9fdace250
|
240
|
+
# @env_name="production", @spec_name="primary", @config={"database"=>"my_db"}>
|
241
|
+
# ]>
|
255
242
|
#
|
256
|
-
|
257
|
-
|
258
|
-
|
243
|
+
# Resolver.new(configurations).resolve_symbol_connection(:production, "primary")
|
244
|
+
# # => { "database" => "my_db" }
|
245
|
+
def resolve_symbol_connection(env_name, pool_name)
|
246
|
+
db_config = configurations.find_db_config(env_name)
|
247
|
+
|
248
|
+
if db_config
|
249
|
+
resolve_connection(db_config.config).merge("name" => pool_name.to_s)
|
259
250
|
else
|
260
|
-
raise
|
251
|
+
raise AdapterNotSpecified, <<~MSG
|
252
|
+
The `#{env_name}` database is not configured for the `#{ActiveRecord::ConnectionHandling::DEFAULT_ENV.call}` environment.
|
253
|
+
|
254
|
+
Available databases configurations are:
|
255
|
+
|
256
|
+
#{build_configuration_sentence}
|
257
|
+
MSG
|
261
258
|
end
|
262
259
|
end
|
263
260
|
|
261
|
+
def build_configuration_sentence # :nodoc:
|
262
|
+
configs = configurations.configs_for(include_replicas: true)
|
263
|
+
|
264
|
+
configs.group_by(&:env_name).map do |env, config|
|
265
|
+
namespaces = config.map(&:spec_name)
|
266
|
+
if namespaces.size > 1
|
267
|
+
"#{env}: #{namespaces.join(", ")}"
|
268
|
+
else
|
269
|
+
env
|
270
|
+
end
|
271
|
+
end.join("\n")
|
272
|
+
end
|
273
|
+
|
264
274
|
# Accepts a hash. Expands the "url" key that contains a
|
265
275
|
# URL database connection to a full connection
|
266
276
|
# hash and merges with the rest of the hash.
|