activerecord 6.1.7 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +520 -1385
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +2 -12
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +60 -21
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +37 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +41 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +4 -4
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +46 -36
- data/lib/active_record/associations/collection_proxy.rb +44 -16
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +29 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +212 -53
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -16
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +15 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +404 -509
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +2 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +47 -27
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +14 -11
- data/lib/active_record/attribute_methods/serialization.rb +174 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -9
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +164 -52
- data/lib/active_record/attributes.rb +51 -49
- data/lib/active_record/autosave_association.rb +74 -57
- data/lib/active_record/base.rb +27 -5
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +327 -612
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +377 -142
- data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
- data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +345 -166
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
- data/lib/active_record/connection_adapters/pool_config.rb +26 -16
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- 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/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +401 -77
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +518 -251
- data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +130 -6
- data/lib/active_record/connection_handling.rb +132 -146
- data/lib/active_record/core.rb +276 -251
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -3
- data/lib/active_record/database_configurations/database_config.rb +34 -10
- data/lib/active_record/database_configurations/hash_config.rb +107 -31
- data/lib/active_record/database_configurations/url_config.rb +38 -13
- data/lib/active_record/database_configurations.rb +96 -60
- data/lib/active_record/delegated_type.rb +90 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +3 -3
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -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 +170 -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 +157 -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 +53 -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_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +163 -63
- data/lib/active_record/errors.rb +210 -27
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +179 -112
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +85 -31
- data/lib/active_record/insert_all.rb +148 -32
- data/lib/active_record/integration.rb +14 -10
- data/lib/active_record/internal_metadata.rb +123 -23
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +43 -27
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +41 -29
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +113 -16
- data/lib/active_record/migration/compatibility.rb +235 -46
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +374 -177
- data/lib/active_record/model_schema.rb +143 -159
- data/lib/active_record/nested_attributes.rb +48 -21
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +282 -283
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +19 -25
- data/lib/active_record/query_logs.rb +189 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +44 -9
- data/lib/active_record/railtie.rb +234 -71
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +189 -256
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +325 -103
- data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +300 -111
- data/lib/active_record/relation/delegation.rb +33 -22
- data/lib/active_record/relation/finder_methods.rb +123 -52
- data/lib/active_record/relation/merger.rb +26 -19
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +29 -22
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +842 -150
- data/lib/active_record/relation/record_fetch_warning.rb +10 -9
- data/lib/active_record/relation/spawn_methods.rb +7 -6
- data/lib/active_record/relation/where_clause.rb +15 -36
- data/lib/active_record/relation.rb +736 -145
- data/lib/active_record/result.rb +67 -54
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +84 -34
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +90 -31
- data/lib/active_record/schema_migration.rb +74 -23
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +30 -9
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +277 -149
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +173 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +118 -41
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -7
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -7
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +64 -15
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +444 -32
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +7 -2
- data/lib/arel/predications.rb +14 -4
- data/lib/arel/select_manager.rb +11 -5
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +20 -5
- data/lib/arel/visitors/dot.rb +81 -90
- data/lib/arel/visitors/mysql.rb +23 -5
- data/lib/arel/visitors/postgresql.rb +1 -22
- data/lib/arel/visitors/to_sql.rb +170 -36
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +23 -4
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- 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 +100 -14
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -63,6 +63,15 @@ module ActiveRecord
|
|
63
63
|
coder["comment"] = @comment
|
64
64
|
end
|
65
65
|
|
66
|
+
# whether the column is auto-populated by the database using a sequence
|
67
|
+
def auto_incremented_by_db?
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
71
|
+
def auto_populated?
|
72
|
+
auto_incremented_by_db? || default_function
|
73
|
+
end
|
74
|
+
|
66
75
|
def ==(other)
|
67
76
|
other.is_a?(Column) &&
|
68
77
|
name == other.name &&
|
@@ -87,6 +96,10 @@ module ActiveRecord
|
|
87
96
|
comment.hash
|
88
97
|
end
|
89
98
|
|
99
|
+
def virtual?
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
90
103
|
private
|
91
104
|
def deduplicated
|
92
105
|
@name = -name
|
@@ -4,122 +4,62 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module MySQL
|
6
6
|
module DatabaseStatements
|
7
|
-
|
8
|
-
|
9
|
-
result = if ExplainRegistry.collect? && prepared_statements
|
10
|
-
unprepared_statement { super }
|
11
|
-
else
|
12
|
-
super
|
13
|
-
end
|
14
|
-
@connection.abandon_results!
|
15
|
-
result
|
16
|
-
end
|
17
|
-
|
18
|
-
def query(sql, name = nil) # :nodoc:
|
19
|
-
execute(sql, name).to_a
|
20
|
-
end
|
21
|
-
|
22
|
-
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
23
|
-
:desc, :describe, :set, :show, :use
|
7
|
+
READ_QUERY = AbstractAdapter.build_read_query_regexp(
|
8
|
+
:desc, :describe, :set, :show, :use, :kill
|
24
9
|
) # :nodoc:
|
25
10
|
private_constant :READ_QUERY
|
26
11
|
|
12
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_current-timestamp
|
13
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-syntax.html
|
14
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)", retryable: true).freeze # :nodoc:
|
15
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
16
|
+
|
27
17
|
def write_query?(sql) # :nodoc:
|
28
18
|
!READ_QUERY.match?(sql)
|
29
19
|
rescue ArgumentError # Invalid encoding
|
30
20
|
!READ_QUERY.match?(sql.b)
|
31
21
|
end
|
32
22
|
|
33
|
-
def
|
34
|
-
|
35
|
-
start = Concurrent.monotonic_time
|
36
|
-
result = exec_query(sql, "EXPLAIN", binds)
|
37
|
-
elapsed = Concurrent.monotonic_time - start
|
38
|
-
|
39
|
-
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
23
|
+
def high_precision_current_timestamp
|
24
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
40
25
|
end
|
41
26
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
27
|
+
def explain(arel, binds = [], options = [])
|
28
|
+
sql = build_explain_clause(options) + " " + to_sql(arel, binds)
|
29
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
30
|
+
result = internal_exec_query(sql, "EXPLAIN", binds)
|
31
|
+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
51
32
|
|
52
|
-
|
33
|
+
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
53
34
|
end
|
54
35
|
|
55
|
-
def
|
56
|
-
if
|
57
|
-
execute_and_free(sql, name) do |result|
|
58
|
-
if result
|
59
|
-
build_result(columns: result.fields, rows: result.to_a)
|
60
|
-
else
|
61
|
-
build_result(columns: [], rows: [])
|
62
|
-
end
|
63
|
-
end
|
64
|
-
else
|
65
|
-
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare) do |_, result|
|
66
|
-
if result
|
67
|
-
build_result(columns: result.fields, rows: result.to_a)
|
68
|
-
else
|
69
|
-
build_result(columns: [], rows: [])
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
36
|
+
def build_explain_clause(options = [])
|
37
|
+
return "EXPLAIN" if options.empty?
|
74
38
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
39
|
+
explain_clause = "EXPLAIN #{options.join(" ").upcase}"
|
40
|
+
|
41
|
+
if analyze_without_explain? && explain_clause.include?("ANALYZE")
|
42
|
+
explain_clause.sub("EXPLAIN ", "")
|
80
43
|
else
|
81
|
-
|
44
|
+
explain_clause
|
82
45
|
end
|
83
46
|
end
|
84
|
-
alias :exec_update :exec_delete
|
85
47
|
|
86
48
|
private
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
@connection.abandon_results!
|
49
|
+
# https://mariadb.com/kb/en/analyze-statement/
|
50
|
+
def analyze_without_explain?
|
51
|
+
mariadb? && database_version >= "10.1.0"
|
92
52
|
end
|
93
53
|
|
94
54
|
def default_insert_value(column)
|
95
55
|
super unless column.auto_increment?
|
96
56
|
end
|
97
57
|
|
98
|
-
def
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
def multi_statements_enabled?
|
103
|
-
flags = @config[:flags]
|
104
|
-
|
105
|
-
if flags.is_a?(Array)
|
106
|
-
flags.include?("MULTI_STATEMENTS")
|
58
|
+
def returning_column_values(result)
|
59
|
+
if supports_insert_returning?
|
60
|
+
result.rows.first
|
107
61
|
else
|
108
|
-
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def with_multi_statements
|
113
|
-
multi_statements_was = multi_statements_enabled?
|
114
|
-
|
115
|
-
unless multi_statements_was
|
116
|
-
@connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
117
|
-
end
|
118
|
-
|
119
|
-
yield
|
120
|
-
ensure
|
121
|
-
unless multi_statements_was
|
122
|
-
@connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
62
|
+
super
|
123
63
|
end
|
124
64
|
end
|
125
65
|
|
@@ -149,47 +89,6 @@ module ActiveRecord
|
|
149
89
|
def max_allowed_packet
|
150
90
|
@max_allowed_packet ||= show_variable("max_allowed_packet")
|
151
91
|
end
|
152
|
-
|
153
|
-
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
|
154
|
-
if preventing_writes? && write_query?(sql)
|
155
|
-
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
156
|
-
end
|
157
|
-
|
158
|
-
materialize_transactions
|
159
|
-
mark_transaction_written_if_write(sql)
|
160
|
-
|
161
|
-
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
162
|
-
# made since we established the connection
|
163
|
-
@connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
|
164
|
-
|
165
|
-
type_casted_binds = type_casted_binds(binds)
|
166
|
-
|
167
|
-
log(sql, name, binds, type_casted_binds) do
|
168
|
-
if cache_stmt
|
169
|
-
stmt = @statements[sql] ||= @connection.prepare(sql)
|
170
|
-
else
|
171
|
-
stmt = @connection.prepare(sql)
|
172
|
-
end
|
173
|
-
|
174
|
-
begin
|
175
|
-
result = ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
176
|
-
stmt.execute(*type_casted_binds)
|
177
|
-
end
|
178
|
-
rescue Mysql2::Error => e
|
179
|
-
if cache_stmt
|
180
|
-
@statements.delete(sql)
|
181
|
-
else
|
182
|
-
stmt.close
|
183
|
-
end
|
184
|
-
raise e
|
185
|
-
end
|
186
|
-
|
187
|
-
ret = yield stmt, result
|
188
|
-
result.free if result
|
189
|
-
stmt.close unless cache_stmt
|
190
|
-
ret
|
191
|
-
end
|
192
|
-
end
|
193
92
|
end
|
194
93
|
end
|
195
94
|
end
|
@@ -6,12 +6,67 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters
|
7
7
|
module MySQL
|
8
8
|
module Quoting # :nodoc:
|
9
|
-
|
10
|
-
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
12
|
+
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
13
|
+
|
14
|
+
module ClassMethods # :nodoc:
|
15
|
+
def column_name_matcher
|
16
|
+
/
|
17
|
+
\A
|
18
|
+
(
|
19
|
+
(?:
|
20
|
+
# `table_name`.`column_name` | function(one or no argument)
|
21
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
22
|
+
)
|
23
|
+
(?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
|
24
|
+
)
|
25
|
+
(?:\s*,\s*\g<1>)*
|
26
|
+
\z
|
27
|
+
/ix
|
28
|
+
end
|
29
|
+
|
30
|
+
def column_name_with_order_matcher
|
31
|
+
/
|
32
|
+
\A
|
33
|
+
(
|
34
|
+
(?:
|
35
|
+
# `table_name`.`column_name` | function(one or no argument)
|
36
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
37
|
+
)
|
38
|
+
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
39
|
+
(?:\s+ASC|\s+DESC)?
|
40
|
+
)
|
41
|
+
(?:\s*,\s*\g<1>)*
|
42
|
+
\z
|
43
|
+
/ix
|
44
|
+
end
|
45
|
+
|
46
|
+
def quote_column_name(name)
|
47
|
+
QUOTED_COLUMN_NAMES[name] ||= "`#{name.to_s.gsub('`', '``')}`".freeze
|
48
|
+
end
|
49
|
+
|
50
|
+
def quote_table_name(name)
|
51
|
+
QUOTED_TABLE_NAMES[name] ||= "`#{name.to_s.gsub('`', '``').gsub(".", "`.`")}`".freeze
|
52
|
+
end
|
11
53
|
end
|
12
54
|
|
13
|
-
def
|
14
|
-
|
55
|
+
def cast_bound_value(value)
|
56
|
+
case value
|
57
|
+
when Rational
|
58
|
+
value.to_f.to_s
|
59
|
+
when Numeric
|
60
|
+
value.to_s
|
61
|
+
when BigDecimal
|
62
|
+
value.to_s("F")
|
63
|
+
when true
|
64
|
+
"1"
|
65
|
+
when false
|
66
|
+
"0"
|
67
|
+
else
|
68
|
+
value
|
69
|
+
end
|
15
70
|
end
|
16
71
|
|
17
72
|
def unquoted_true
|
@@ -34,62 +89,33 @@ module ActiveRecord
|
|
34
89
|
"x'#{value.hex}'"
|
35
90
|
end
|
36
91
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
92
|
+
def unquote_identifier(identifier)
|
93
|
+
if identifier && identifier.start_with?("`")
|
94
|
+
identifier[1..-2]
|
95
|
+
else
|
96
|
+
identifier
|
97
|
+
end
|
43
98
|
end
|
44
99
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
\z
|
56
|
-
/ix
|
57
|
-
|
58
|
-
COLUMN_NAME_WITH_ORDER = /
|
59
|
-
\A
|
60
|
-
(
|
61
|
-
(?:
|
62
|
-
# `table_name`.`column_name` | function(one or no argument)
|
63
|
-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
|
64
|
-
)
|
65
|
-
(?:\s+ASC|\s+DESC)?
|
66
|
-
)
|
67
|
-
(?:\s*,\s*\g<1>)*
|
68
|
-
\z
|
69
|
-
/ix
|
70
|
-
|
71
|
-
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
|
100
|
+
# Override +type_cast+ we pass to mysql2 Date and Time objects instead
|
101
|
+
# of Strings since MySQL adapters are able to handle those classes more efficiently.
|
102
|
+
def type_cast(value) # :nodoc:
|
103
|
+
case value
|
104
|
+
when ActiveSupport::TimeWithZone
|
105
|
+
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
106
|
+
# we need to transform it to Time objects but we don't want to
|
107
|
+
# transform Time objects to themselves.
|
108
|
+
if default_timezone == :utc
|
109
|
+
value.getutc
|
89
110
|
else
|
90
|
-
|
111
|
+
value.getlocal
|
91
112
|
end
|
113
|
+
when Date, Time
|
114
|
+
value
|
115
|
+
else
|
116
|
+
super
|
92
117
|
end
|
118
|
+
end
|
93
119
|
end
|
94
120
|
end
|
95
121
|
end
|
@@ -24,6 +24,15 @@ module ActiveRecord
|
|
24
24
|
add_column_position!(change_column_sql, column_options(o.column))
|
25
25
|
end
|
26
26
|
|
27
|
+
def visit_ChangeColumnDefaultDefinition(o)
|
28
|
+
sql = +"ALTER COLUMN #{quote_column_name(o.column.name)} "
|
29
|
+
if o.default.nil? && !o.column.null
|
30
|
+
sql << "DROP DEFAULT"
|
31
|
+
else
|
32
|
+
sql << "SET DEFAULT #{quote_default_expression(o.default, o.column)}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
27
36
|
def visit_CreateIndexDefinition(o)
|
28
37
|
sql = visit_IndexDefinition(o.index, true)
|
29
38
|
sql << " #{o.algorithm}" if o.algorithm
|
@@ -57,6 +57,7 @@ module ActiveRecord
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
# = Active Record MySQL Adapter \Table Definition
|
60
61
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
61
62
|
include ColumnMethods
|
62
63
|
|
@@ -85,16 +86,24 @@ module ActiveRecord
|
|
85
86
|
end
|
86
87
|
|
87
88
|
private
|
89
|
+
def valid_column_definition_options
|
90
|
+
super + [:auto_increment, :charset, :as, :size, :unsigned, :first, :after, :type, :stored]
|
91
|
+
end
|
92
|
+
|
88
93
|
def aliased_types(name, fallback)
|
89
94
|
fallback
|
90
95
|
end
|
91
96
|
|
92
97
|
def integer_like_primary_key_type(type, options)
|
93
|
-
options[:auto_increment]
|
98
|
+
unless options[:auto_increment] == false
|
99
|
+
options[:auto_increment] = true
|
100
|
+
end
|
101
|
+
|
94
102
|
type
|
95
103
|
end
|
96
104
|
end
|
97
105
|
|
106
|
+
# = Active Record MySQL Adapter \Table
|
98
107
|
class Table < ActiveRecord::ConnectionAdapters::Table
|
99
108
|
include ColumnMethods
|
100
109
|
end
|
@@ -53,14 +53,20 @@ 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)
|
60
66
|
if column.collation
|
61
67
|
@table_collation_cache ||= {}
|
62
68
|
@table_collation_cache[table_name] ||=
|
63
|
-
@connection.
|
69
|
+
@connection.internal_exec_query("SHOW TABLE STATUS LIKE #{@connection.quote(table_name)}", "SCHEMA").first["Collation"]
|
64
70
|
column.collation.inspect if column.collation != @table_collation_cache[table_name]
|
65
71
|
end
|
66
72
|
end
|
@@ -36,7 +36,7 @@ module ActiveRecord
|
|
36
36
|
end
|
37
37
|
|
38
38
|
if row[:Expression]
|
39
|
-
expression = row[:Expression]
|
39
|
+
expression = row[:Expression].gsub("\\'", "'")
|
40
40
|
expression = +"(#{expression})" unless expression.start_with?("(")
|
41
41
|
indexes.last[-2] << expression
|
42
42
|
indexes.last[-1][:expressions] ||= {}
|
@@ -57,9 +57,9 @@ module ActiveRecord
|
|
57
57
|
orders = options.delete(:orders)
|
58
58
|
lengths = options.delete(:lengths)
|
59
59
|
|
60
|
-
columns = index[-1].
|
60
|
+
columns = index[-1].to_h { |name|
|
61
61
|
[ name.to_sym, expressions[name] || +quote_column_name(name) ]
|
62
|
-
}
|
62
|
+
}
|
63
63
|
|
64
64
|
index[-1] = add_options_for_index_columns(
|
65
65
|
columns, order: orders, length: lengths
|
@@ -68,6 +68,12 @@ module ActiveRecord
|
|
68
68
|
|
69
69
|
IndexDefinition.new(*index, **options)
|
70
70
|
end
|
71
|
+
rescue StatementInvalid => e
|
72
|
+
if e.message.match?(/Table '.+' doesn't exist/)
|
73
|
+
[]
|
74
|
+
else
|
75
|
+
raise
|
76
|
+
end
|
71
77
|
end
|
72
78
|
|
73
79
|
def remove_column(table_name, column_name, type = nil, **options)
|
@@ -125,6 +131,10 @@ module ActiveRecord
|
|
125
131
|
256 # https://dev.mysql.com/doc/refman/en/identifiers.html
|
126
132
|
end
|
127
133
|
|
134
|
+
def schema_creation # :nodoc:
|
135
|
+
MySQL::SchemaCreation.new(self)
|
136
|
+
end
|
137
|
+
|
128
138
|
private
|
129
139
|
CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"]
|
130
140
|
|
@@ -150,26 +160,46 @@ module ActiveRecord
|
|
150
160
|
@default_row_format
|
151
161
|
end
|
152
162
|
|
153
|
-
def
|
154
|
-
|
163
|
+
def valid_primary_key_options
|
164
|
+
super + [:unsigned]
|
155
165
|
end
|
156
166
|
|
157
167
|
def create_table_definition(name, **options)
|
158
168
|
MySQL::TableDefinition.new(self, name, **options)
|
159
169
|
end
|
160
170
|
|
161
|
-
def
|
171
|
+
def default_type(table_name, field_name)
|
172
|
+
match = create_table_info(table_name)&.match(/`#{field_name}` (.+) DEFAULT ('|\d+|[A-z]+)/)
|
173
|
+
default_pre = match[2] if match
|
174
|
+
|
175
|
+
if default_pre == "'"
|
176
|
+
:string
|
177
|
+
elsif default_pre&.match?(/^\d+$/)
|
178
|
+
:integer
|
179
|
+
elsif default_pre&.match?(/^[A-z]+$/)
|
180
|
+
:function
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def new_column_from_field(table_name, field, _definitions)
|
185
|
+
field_name = field.fetch(:Field)
|
162
186
|
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
163
187
|
default, default_function = field[:Default], nil
|
164
188
|
|
165
189
|
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
190
|
+
default = "#{default} ON UPDATE #{default}" if /on update CURRENT_TIMESTAMP/i.match?(field[:Extra])
|
166
191
|
default, default_function = nil, default
|
167
192
|
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
168
193
|
default = +"(#{default})" unless default.start_with?("(")
|
194
|
+
default = default.gsub("\\'", "'")
|
169
195
|
default, default_function = nil, default
|
170
|
-
elsif type_metadata.type == :text && default
|
196
|
+
elsif type_metadata.type == :text && default&.start_with?("'")
|
171
197
|
# strip and unescape quotes
|
172
198
|
default = default[1...-1].gsub("\\'", "'")
|
199
|
+
elsif default&.match?(/\A\d/)
|
200
|
+
# Its a number so we can skip the query to check if it is a function
|
201
|
+
elsif default && default_type(table_name, field_name) == :function
|
202
|
+
default, default_function = nil, default
|
173
203
|
end
|
174
204
|
|
175
205
|
MySQL::Column.new(
|
@@ -206,14 +236,15 @@ module ActiveRecord
|
|
206
236
|
def data_source_sql(name = nil, type: nil)
|
207
237
|
scope = quoted_scope(name, type: type)
|
208
238
|
|
209
|
-
sql = +"SELECT table_name FROM
|
210
|
-
sql << " WHERE table_schema = #{scope[:schema]}
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
sql << " WHERE #{conditions.join(" AND ")}"
|
239
|
+
sql = +"SELECT table_name FROM information_schema.tables"
|
240
|
+
sql << " WHERE table_schema = #{scope[:schema]}"
|
241
|
+
|
242
|
+
if scope[:name]
|
243
|
+
sql << " AND table_name = #{scope[:name]}"
|
244
|
+
sql << " AND table_name IN (SELECT table_name FROM information_schema.tables WHERE table_schema = #{scope[:schema]})"
|
216
245
|
end
|
246
|
+
|
247
|
+
sql << " AND table_type = #{scope[:type]}" if scope[:type]
|
217
248
|
sql
|
218
249
|
end
|
219
250
|
|