activerecord 6.1.6 → 7.0.4
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 +1314 -975
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +19 -21
- data/lib/active_record/associations/collection_proxy.rb +10 -5
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +8 -5
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/preloader/association.rb +186 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +49 -13
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +124 -95
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +57 -19
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +14 -15
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +8 -23
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +10 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +38 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -24
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +105 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -24
- data/lib/active_record/connection_adapters/mysql/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +37 -19
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +208 -107
- data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +96 -32
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +49 -55
- data/lib/active_record/core.rb +124 -134
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +15 -32
- data/lib/active_record/delegated_type.rb +53 -12
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +67 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +206 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +50 -43
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +20 -23
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/locking/pessimistic.rb +10 -4
- data/lib/active_record/log_subscriber.rb +23 -7
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +18 -6
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +7 -7
- data/lib/active_record/migration/compatibility.rb +84 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +114 -83
- data/lib/active_record/model_schema.rb +58 -59
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +228 -60
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +16 -6
- data/lib/active_record/railtie.rb +136 -22
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +78 -136
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +73 -50
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +6 -6
- data/lib/active_record/relation/calculations.rb +43 -38
- data/lib/active_record/relation/delegation.rb +7 -7
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +276 -67
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +189 -88
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +17 -12
- data/lib/active_record/schema.rb +38 -23
- data/lib/active_record/schema_dumper.rb +25 -19
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +60 -13
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +3 -3
- data/lib/active_record/store.rb +7 -2
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +127 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +16 -9
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +217 -27
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +55 -11
@@ -31,6 +31,7 @@ module ActiveRecord
|
|
31
31
|
string: { name: "varchar", limit: 255 },
|
32
32
|
text: { name: "text" },
|
33
33
|
integer: { name: "int", limit: 4 },
|
34
|
+
bigint: { name: "bigint" },
|
34
35
|
float: { name: "float", limit: 24 },
|
35
36
|
decimal: { name: "decimal" },
|
36
37
|
datetime: { name: "datetime" },
|
@@ -54,7 +55,7 @@ module ActiveRecord
|
|
54
55
|
super(connection, logger, config)
|
55
56
|
end
|
56
57
|
|
57
|
-
def get_database_version
|
58
|
+
def get_database_version # :nodoc:
|
58
59
|
full_version_string = get_full_version
|
59
60
|
version_string = version_string(full_version_string)
|
60
61
|
Version.new(version_string, full_version_string)
|
@@ -137,6 +138,11 @@ module ActiveRecord
|
|
137
138
|
true
|
138
139
|
end
|
139
140
|
|
141
|
+
def field_ordered_value(column, values) # :nodoc:
|
142
|
+
field = Arel::Nodes::NamedFunction.new("FIELD", [column, values.reverse.map { |value| Arel::Nodes.build_quoted(value) }])
|
143
|
+
Arel::Nodes::Descending.new(field)
|
144
|
+
end
|
145
|
+
|
140
146
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
141
147
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
142
148
|
end
|
@@ -174,7 +180,7 @@ module ActiveRecord
|
|
174
180
|
|
175
181
|
# REFERENTIAL INTEGRITY ====================================
|
176
182
|
|
177
|
-
def disable_referential_integrity
|
183
|
+
def disable_referential_integrity # :nodoc:
|
178
184
|
old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
|
179
185
|
|
180
186
|
begin
|
@@ -185,54 +191,40 @@ module ActiveRecord
|
|
185
191
|
end
|
186
192
|
end
|
187
193
|
|
188
|
-
# CONNECTION MANAGEMENT ====================================
|
189
|
-
|
190
|
-
def clear_cache! # :nodoc:
|
191
|
-
reload_type_map
|
192
|
-
super
|
193
|
-
end
|
194
|
-
|
195
194
|
#--
|
196
195
|
# DATABASE STATEMENTS ======================================
|
197
196
|
#++
|
198
197
|
|
199
198
|
# Executes the SQL statement in the context of this connection.
|
200
|
-
def execute(sql, name = nil)
|
201
|
-
|
202
|
-
mark_transaction_written_if_write(sql)
|
203
|
-
|
204
|
-
log(sql, name) do
|
205
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
206
|
-
@connection.query(sql)
|
207
|
-
end
|
208
|
-
end
|
199
|
+
def execute(sql, name = nil, async: false)
|
200
|
+
raw_execute(sql, name, async: async)
|
209
201
|
end
|
210
202
|
|
211
203
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
212
204
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
213
205
|
# needs to be explicitly freed or not.
|
214
|
-
def execute_and_free(sql, name = nil) # :nodoc:
|
215
|
-
yield execute(sql, name)
|
206
|
+
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
207
|
+
yield execute(sql, name, async: async)
|
216
208
|
end
|
217
209
|
|
218
|
-
def begin_db_transaction
|
210
|
+
def begin_db_transaction # :nodoc:
|
219
211
|
execute("BEGIN", "TRANSACTION")
|
220
212
|
end
|
221
213
|
|
222
|
-
def begin_isolated_db_transaction(isolation)
|
214
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
223
215
|
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
|
224
216
|
begin_db_transaction
|
225
217
|
end
|
226
218
|
|
227
|
-
def commit_db_transaction
|
219
|
+
def commit_db_transaction # :nodoc:
|
228
220
|
execute("COMMIT", "TRANSACTION")
|
229
221
|
end
|
230
222
|
|
231
|
-
def exec_rollback_db_transaction
|
223
|
+
def exec_rollback_db_transaction # :nodoc:
|
232
224
|
execute("ROLLBACK", "TRANSACTION")
|
233
225
|
end
|
234
226
|
|
235
|
-
def empty_insert_statement_value(primary_key = nil)
|
227
|
+
def empty_insert_statement_value(primary_key = nil) # :nodoc:
|
236
228
|
"VALUES ()"
|
237
229
|
end
|
238
230
|
|
@@ -270,7 +262,7 @@ module ActiveRecord
|
|
270
262
|
#
|
271
263
|
# Example:
|
272
264
|
# drop_database('sebastian_development')
|
273
|
-
def drop_database(name)
|
265
|
+
def drop_database(name) # :nodoc:
|
274
266
|
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
275
267
|
end
|
276
268
|
|
@@ -346,12 +338,12 @@ module ActiveRecord
|
|
346
338
|
end
|
347
339
|
end
|
348
340
|
|
349
|
-
def change_column_default(table_name, column_name, default_or_changes)
|
341
|
+
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
350
342
|
default = extract_new_default_value(default_or_changes)
|
351
343
|
change_column table_name, column_name, nil, default: default
|
352
344
|
end
|
353
345
|
|
354
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
346
|
+
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
355
347
|
unless null || default.nil?
|
356
348
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
357
349
|
end
|
@@ -364,16 +356,16 @@ module ActiveRecord
|
|
364
356
|
change_column table_name, column_name, nil, comment: comment
|
365
357
|
end
|
366
358
|
|
367
|
-
def change_column(table_name, column_name, type, **options)
|
359
|
+
def change_column(table_name, column_name, type, **options) # :nodoc:
|
368
360
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
|
369
361
|
end
|
370
362
|
|
371
|
-
def rename_column(table_name, column_name, new_column_name)
|
363
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
372
364
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
373
365
|
rename_column_indexes(table_name, column_name, new_column_name)
|
374
366
|
end
|
375
367
|
|
376
|
-
def add_index(table_name, column_name, **options)
|
368
|
+
def add_index(table_name, column_name, **options) # :nodoc:
|
377
369
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
378
370
|
|
379
371
|
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
@@ -427,7 +419,7 @@ module ActiveRecord
|
|
427
419
|
if supports_check_constraints?
|
428
420
|
scope = quoted_scope(table_name)
|
429
421
|
|
430
|
-
|
422
|
+
sql = <<~SQL
|
431
423
|
SELECT cc.constraint_name AS 'name',
|
432
424
|
cc.check_clause AS 'expression'
|
433
425
|
FROM information_schema.check_constraints cc
|
@@ -437,6 +429,9 @@ module ActiveRecord
|
|
437
429
|
AND tc.table_name = #{scope[:name]}
|
438
430
|
AND cc.constraint_schema = #{scope[:schema]}
|
439
431
|
SQL
|
432
|
+
sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
|
433
|
+
|
434
|
+
chk_info = exec_query(sql, "SCHEMA")
|
440
435
|
|
441
436
|
chk_info.map do |row|
|
442
437
|
options = {
|
@@ -548,8 +543,12 @@ module ActiveRecord
|
|
548
543
|
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
549
544
|
elsif insert.update_duplicates?
|
550
545
|
sql << " ON DUPLICATE KEY UPDATE "
|
551
|
-
|
552
|
-
|
546
|
+
if insert.raw_update_sql?
|
547
|
+
sql << insert.raw_update_sql
|
548
|
+
else
|
549
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
550
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
551
|
+
end
|
553
552
|
end
|
554
553
|
|
555
554
|
sql
|
@@ -561,55 +560,77 @@ module ActiveRecord
|
|
561
560
|
end
|
562
561
|
end
|
563
562
|
|
564
|
-
|
565
|
-
|
566
|
-
|
563
|
+
class << self
|
564
|
+
private
|
565
|
+
def initialize_type_map(m)
|
566
|
+
super
|
567
|
+
|
568
|
+
m.register_type(%r(char)i) do |sql_type|
|
569
|
+
limit = extract_limit(sql_type)
|
570
|
+
Type.lookup(:string, adapter: :mysql2, limit: limit)
|
571
|
+
end
|
567
572
|
|
568
|
-
|
569
|
-
limit
|
570
|
-
Type.
|
573
|
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
574
|
+
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
575
|
+
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
576
|
+
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
|
577
|
+
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
|
578
|
+
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
|
579
|
+
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
|
580
|
+
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
|
581
|
+
m.register_type %r(^float)i, Type::Float.new(limit: 24)
|
582
|
+
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
583
|
+
|
584
|
+
register_integer_type m, %r(^bigint)i, limit: 8
|
585
|
+
register_integer_type m, %r(^int)i, limit: 4
|
586
|
+
register_integer_type m, %r(^mediumint)i, limit: 3
|
587
|
+
register_integer_type m, %r(^smallint)i, limit: 2
|
588
|
+
register_integer_type m, %r(^tinyint)i, limit: 1
|
589
|
+
|
590
|
+
m.alias_type %r(year)i, "integer"
|
591
|
+
m.alias_type %r(bit)i, "binary"
|
592
|
+
|
593
|
+
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
594
|
+
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
571
595
|
end
|
572
596
|
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
583
|
-
|
584
|
-
register_integer_type m, %r(^bigint)i, limit: 8
|
585
|
-
register_integer_type m, %r(^int)i, limit: 4
|
586
|
-
register_integer_type m, %r(^mediumint)i, limit: 3
|
587
|
-
register_integer_type m, %r(^smallint)i, limit: 2
|
588
|
-
register_integer_type m, %r(^tinyint)i, limit: 1
|
589
|
-
|
590
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
591
|
-
m.alias_type %r(year)i, "integer"
|
592
|
-
m.alias_type %r(bit)i, "binary"
|
593
|
-
|
594
|
-
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
595
|
-
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
596
|
-
end
|
597
|
+
def register_integer_type(mapping, key, **options)
|
598
|
+
mapping.register_type(key) do |sql_type|
|
599
|
+
if /\bunsigned\b/.match?(sql_type)
|
600
|
+
Type::UnsignedInteger.new(**options)
|
601
|
+
else
|
602
|
+
Type::Integer.new(**options)
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
597
606
|
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
Type::UnsignedInteger.new(**options)
|
607
|
+
def extract_precision(sql_type)
|
608
|
+
if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
|
609
|
+
super || 0
|
602
610
|
else
|
603
|
-
|
611
|
+
super
|
604
612
|
end
|
605
613
|
end
|
614
|
+
end
|
615
|
+
|
616
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
617
|
+
TYPE_MAP_WITH_BOOLEAN = Type::TypeMap.new(TYPE_MAP).tap do |m|
|
618
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
619
|
+
end
|
620
|
+
|
621
|
+
private
|
622
|
+
def type_map
|
623
|
+
emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
|
606
624
|
end
|
607
625
|
|
608
|
-
def
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
626
|
+
def raw_execute(sql, name, async: false)
|
627
|
+
materialize_transactions
|
628
|
+
mark_transaction_written_if_write(sql)
|
629
|
+
|
630
|
+
log(sql, name, async: async) do
|
631
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
632
|
+
@connection.query(sql)
|
633
|
+
end
|
613
634
|
end
|
614
635
|
end
|
615
636
|
|
@@ -690,6 +711,14 @@ module ActiveRecord
|
|
690
711
|
options[:comment] = column.comment
|
691
712
|
end
|
692
713
|
|
714
|
+
unless options.key?(:collation)
|
715
|
+
options[:collation] = column.collation
|
716
|
+
end
|
717
|
+
|
718
|
+
unless options.key?(:auto_increment)
|
719
|
+
options[:auto_increment] = column.auto_increment?
|
720
|
+
end
|
721
|
+
|
693
722
|
td = create_table_definition(table_name)
|
694
723
|
cd = td.new_column_definition(column.name, type, **options)
|
695
724
|
schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
|
@@ -780,14 +809,13 @@ module ActiveRecord
|
|
780
809
|
end
|
781
810
|
|
782
811
|
# Gather up all of the SET variables...
|
783
|
-
variable_assignments = variables.
|
812
|
+
variable_assignments = variables.filter_map do |k, v|
|
784
813
|
if defaults.include?(v)
|
785
814
|
"@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
|
786
815
|
elsif !v.nil?
|
787
816
|
"@@SESSION.#{k} = #{quote(v)}"
|
788
817
|
end
|
789
|
-
|
790
|
-
end.compact.join(", ")
|
818
|
+
end.join(", ")
|
791
819
|
|
792
820
|
# ...and send them all in one query
|
793
821
|
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
@@ -839,10 +867,6 @@ module ActiveRecord
|
|
839
867
|
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
840
868
|
end
|
841
869
|
|
842
|
-
# Alias MysqlString to work Mashal.load(File.read("legacy_record.dump")).
|
843
|
-
# TODO: Remove the constant alias once Rails 6.1 has released.
|
844
|
-
MysqlString = Type::String # :nodoc:
|
845
|
-
|
846
870
|
ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
|
847
871
|
Type::ImmutableString.new(true: "1", false: "0", **args)
|
848
872
|
end
|
@@ -32,29 +32,24 @@ module ActiveRecord
|
|
32
32
|
|
33
33
|
def explain(arel, binds = [])
|
34
34
|
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
35
|
-
start =
|
35
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
36
36
|
result = exec_query(sql, "EXPLAIN", binds)
|
37
|
-
elapsed =
|
37
|
+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
38
38
|
|
39
39
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
40
40
|
end
|
41
41
|
|
42
42
|
# Executes the SQL statement in the context of this connection.
|
43
|
-
def execute(sql, name = nil)
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
49
|
-
# made since we established the connection
|
50
|
-
@connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
|
43
|
+
def execute(sql, name = nil, async: false)
|
44
|
+
sql = transform_query(sql)
|
45
|
+
check_if_write_query(sql)
|
51
46
|
|
52
|
-
|
47
|
+
raw_execute(sql, name, async: async)
|
53
48
|
end
|
54
49
|
|
55
|
-
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
50
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
|
56
51
|
if without_prepared_statement?(binds)
|
57
|
-
execute_and_free(sql, name) do |result|
|
52
|
+
execute_and_free(sql, name, async: async) do |result|
|
58
53
|
if result
|
59
54
|
build_result(columns: result.fields, rows: result.to_a)
|
60
55
|
else
|
@@ -62,7 +57,7 @@ module ActiveRecord
|
|
62
57
|
end
|
63
58
|
end
|
64
59
|
else
|
65
|
-
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare) do |_, result|
|
60
|
+
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async) do |_, result|
|
66
61
|
if result
|
67
62
|
build_result(columns: result.fields, rows: result.to_a)
|
68
63
|
else
|
@@ -72,7 +67,7 @@ module ActiveRecord
|
|
72
67
|
end
|
73
68
|
end
|
74
69
|
|
75
|
-
def exec_delete(sql, name = nil, binds = [])
|
70
|
+
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
76
71
|
if without_prepared_statement?(binds)
|
77
72
|
@lock.synchronize do
|
78
73
|
execute_and_free(sql, name) { @connection.affected_rows }
|
@@ -83,12 +78,30 @@ module ActiveRecord
|
|
83
78
|
end
|
84
79
|
alias :exec_update :exec_delete
|
85
80
|
|
81
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_current-timestamp
|
82
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-syntax.html
|
83
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)").freeze # :nodoc:
|
84
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
85
|
+
|
86
|
+
def high_precision_current_timestamp
|
87
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
88
|
+
end
|
89
|
+
|
86
90
|
private
|
91
|
+
def raw_execute(sql, name, async: false)
|
92
|
+
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
93
|
+
# made since we established the connection
|
94
|
+
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
95
|
+
|
96
|
+
super
|
97
|
+
end
|
98
|
+
|
87
99
|
def execute_batch(statements, name = nil)
|
100
|
+
statements = statements.map { |sql| transform_query(sql) }
|
88
101
|
combine_multi_statements(statements).each do |statement|
|
89
|
-
|
102
|
+
raw_execute(statement, name)
|
103
|
+
@connection.abandon_results!
|
90
104
|
end
|
91
|
-
@connection.abandon_results!
|
92
105
|
end
|
93
106
|
|
94
107
|
def default_insert_value(column)
|
@@ -150,21 +163,20 @@ module ActiveRecord
|
|
150
163
|
@max_allowed_packet ||= show_variable("max_allowed_packet")
|
151
164
|
end
|
152
165
|
|
153
|
-
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
|
154
|
-
|
155
|
-
|
156
|
-
end
|
166
|
+
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false)
|
167
|
+
sql = transform_query(sql)
|
168
|
+
check_if_write_query(sql)
|
157
169
|
|
158
170
|
materialize_transactions
|
159
171
|
mark_transaction_written_if_write(sql)
|
160
172
|
|
161
|
-
# make sure we carry over any changes to ActiveRecord
|
173
|
+
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
162
174
|
# made since we established the connection
|
163
|
-
@connection.query_options[:database_timezone] = ActiveRecord
|
175
|
+
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
164
176
|
|
165
177
|
type_casted_binds = type_casted_binds(binds)
|
166
178
|
|
167
|
-
log(sql, name, binds, type_casted_binds) do
|
179
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
168
180
|
if cache_stmt
|
169
181
|
stmt = @statements[sql] ||= @connection.prepare(sql)
|
170
182
|
else
|
@@ -6,6 +6,23 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters
|
7
7
|
module MySQL
|
8
8
|
module Quoting # :nodoc:
|
9
|
+
def quote_bound_value(value)
|
10
|
+
case value
|
11
|
+
when Rational
|
12
|
+
quote(value.to_f.to_s)
|
13
|
+
when Numeric, ActiveSupport::Duration
|
14
|
+
quote(value.to_s)
|
15
|
+
when BigDecimal
|
16
|
+
quote(value.to_s("F"))
|
17
|
+
when true
|
18
|
+
"'1'"
|
19
|
+
when false
|
20
|
+
"'0'"
|
21
|
+
else
|
22
|
+
quote(value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
9
26
|
def quote_column_name(name)
|
10
27
|
self.class.quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
|
11
28
|
end
|
@@ -34,6 +51,26 @@ module ActiveRecord
|
|
34
51
|
"x'#{value.hex}'"
|
35
52
|
end
|
36
53
|
|
54
|
+
# Override +type_cast+ we pass to mysql2 Date and Time objects instead
|
55
|
+
# of Strings since mysql2 is able to handle those classes more efficiently.
|
56
|
+
def type_cast(value) # :nodoc:
|
57
|
+
case value
|
58
|
+
when ActiveSupport::TimeWithZone
|
59
|
+
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
60
|
+
# we need to transform it to Time objects but we don't want to
|
61
|
+
# transform Time objects to themselves.
|
62
|
+
if ActiveRecord.default_timezone == :utc
|
63
|
+
value.getutc
|
64
|
+
else
|
65
|
+
value.getlocal
|
66
|
+
end
|
67
|
+
when Date, Time
|
68
|
+
value
|
69
|
+
else
|
70
|
+
super
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
37
74
|
def column_name_matcher
|
38
75
|
COLUMN_NAME
|
39
76
|
end
|
@@ -69,27 +106,6 @@ module ActiveRecord
|
|
69
106
|
/ix
|
70
107
|
|
71
108
|
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
72
|
-
|
73
|
-
private
|
74
|
-
# Override +_type_cast+ we pass to mysql2 Date and Time objects instead
|
75
|
-
# of Strings since mysql2 is able to handle those classes more efficiently.
|
76
|
-
def _type_cast(value)
|
77
|
-
case value
|
78
|
-
when ActiveSupport::TimeWithZone
|
79
|
-
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
80
|
-
# we need to transform it to Time objects but we don't want to
|
81
|
-
# transform Time objects to themselves.
|
82
|
-
if ActiveRecord::Base.default_timezone == :utc
|
83
|
-
value.getutc
|
84
|
-
else
|
85
|
-
value.getlocal
|
86
|
-
end
|
87
|
-
when Date, Time
|
88
|
-
value
|
89
|
-
else
|
90
|
-
super
|
91
|
-
end
|
92
|
-
end
|
93
109
|
end
|
94
110
|
end
|
95
111
|
end
|
@@ -53,7 +53,13 @@ module ActiveRecord
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def schema_precision(column)
|
56
|
-
|
56
|
+
if /\Atime(?:stamp)?\b/.match?(column.sql_type) && column.precision == 0
|
57
|
+
nil
|
58
|
+
elsif column.type == :datetime
|
59
|
+
column.precision == 0 ? "nil" : super
|
60
|
+
else
|
61
|
+
super
|
62
|
+
end
|
57
63
|
end
|
58
64
|
|
59
65
|
def schema_collation(column)
|
@@ -158,18 +158,37 @@ module ActiveRecord
|
|
158
158
|
MySQL::TableDefinition.new(self, name, **options)
|
159
159
|
end
|
160
160
|
|
161
|
+
def default_type(table_name, field_name)
|
162
|
+
match = create_table_info(table_name)&.match(/`#{field_name}` (.+) DEFAULT ('|\d+|[A-z]+)/)
|
163
|
+
default_pre = match[2] if match
|
164
|
+
|
165
|
+
if default_pre == "'"
|
166
|
+
:string
|
167
|
+
elsif default_pre&.match?(/^\d+$/)
|
168
|
+
:integer
|
169
|
+
elsif default_pre&.match?(/^[A-z]+$/)
|
170
|
+
:function
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
161
174
|
def new_column_from_field(table_name, field)
|
175
|
+
field_name = field.fetch(:Field)
|
162
176
|
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
163
177
|
default, default_function = field[:Default], nil
|
164
178
|
|
165
179
|
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
180
|
+
default = "#{default} ON UPDATE #{default}" if /on update CURRENT_TIMESTAMP/i.match?(field[:Extra])
|
166
181
|
default, default_function = nil, default
|
167
182
|
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
168
183
|
default = +"(#{default})" unless default.start_with?("(")
|
169
184
|
default, default_function = nil, default
|
170
|
-
elsif type_metadata.type == :text && default
|
185
|
+
elsif type_metadata.type == :text && default&.start_with?("'")
|
171
186
|
# strip and unescape quotes
|
172
187
|
default = default[1...-1].gsub("\\'", "'")
|
188
|
+
elsif default&.match?(/\A\d/)
|
189
|
+
# Its a number so we can skip the query to check if it is a function
|
190
|
+
elsif default && default_type(table_name, field_name) == :function
|
191
|
+
default, default_function = nil, default
|
173
192
|
end
|
174
193
|
|
175
194
|
MySQL::Column.new(
|
@@ -30,7 +30,11 @@ module ActiveRecord
|
|
30
30
|
|
31
31
|
module ConnectionAdapters
|
32
32
|
class Mysql2Adapter < AbstractMysqlAdapter
|
33
|
-
ER_BAD_DB_ERROR
|
33
|
+
ER_BAD_DB_ERROR = 1049
|
34
|
+
ER_ACCESS_DENIED_ERROR = 1045
|
35
|
+
ER_CONN_HOST_ERROR = 2003
|
36
|
+
ER_UNKNOWN_HOST_ERROR = 2005
|
37
|
+
|
34
38
|
ADAPTER_NAME = "Mysql2"
|
35
39
|
|
36
40
|
include MySQL::DatabaseStatements
|
@@ -40,7 +44,11 @@ module ActiveRecord
|
|
40
44
|
Mysql2::Client.new(config)
|
41
45
|
rescue Mysql2::Error => error
|
42
46
|
if error.error_number == ConnectionAdapters::Mysql2Adapter::ER_BAD_DB_ERROR
|
43
|
-
raise ActiveRecord::NoDatabaseError
|
47
|
+
raise ActiveRecord::NoDatabaseError.db_error(config[:database])
|
48
|
+
elsif error.error_number == ConnectionAdapters::Mysql2Adapter::ER_ACCESS_DENIED_ERROR
|
49
|
+
raise ActiveRecord::DatabaseConnectionError.username_error(config[:username])
|
50
|
+
elsif [ConnectionAdapters::Mysql2Adapter::ER_CONN_HOST_ERROR, ConnectionAdapters::Mysql2Adapter::ER_UNKNOWN_HOST_ERROR].include?(error.error_number)
|
51
|
+
raise ActiveRecord::DatabaseConnectionError.hostname_error(config[:host])
|
44
52
|
else
|
45
53
|
raise ActiveRecord::ConnectionNotEstablished, error.message
|
46
54
|
end
|
@@ -81,11 +89,9 @@ module ActiveRecord
|
|
81
89
|
|
82
90
|
# HELPER METHODS ===========================================
|
83
91
|
|
84
|
-
def each_hash(result) # :nodoc:
|
92
|
+
def each_hash(result, &block) # :nodoc:
|
85
93
|
if block_given?
|
86
|
-
result.each(as: :hash, symbolize_keys: true)
|
87
|
-
yield row
|
88
|
-
end
|
94
|
+
result.each(as: :hash, symbolize_keys: true, &block)
|
89
95
|
else
|
90
96
|
to_enum(:each_hash, result)
|
91
97
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
class PoolConfig # :nodoc:
|
6
6
|
include Mutex_m
|
7
7
|
|
8
|
-
attr_reader :db_config, :
|
8
|
+
attr_reader :db_config, :connection_class, :role, :shard
|
9
9
|
attr_accessor :schema_cache
|
10
10
|
|
11
11
|
INSTANCES = ObjectSpace::WeakMap.new
|
@@ -17,21 +17,21 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def initialize(
|
20
|
+
def initialize(connection_class, db_config, role, shard)
|
21
21
|
super()
|
22
|
-
@
|
22
|
+
@connection_class = connection_class
|
23
23
|
@db_config = db_config
|
24
|
+
@role = role
|
25
|
+
@shard = shard
|
24
26
|
@pool = nil
|
25
27
|
INSTANCES[self] = self
|
26
28
|
end
|
27
29
|
|
28
30
|
def connection_specification_name
|
29
|
-
if
|
30
|
-
connection_klass
|
31
|
-
elsif connection_klass.primary_class?
|
31
|
+
if connection_class.primary_class?
|
32
32
|
"ActiveRecord::Base"
|
33
33
|
else
|
34
|
-
|
34
|
+
connection_class.name
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|