activerecord 6.1.7 → 7.1.5
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 +2030 -1020
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +51 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- 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 +6 -2
- data/lib/active_record/associations/collection_association.rb +39 -35
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- 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 +3 -2
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/preloader/association.rb +210 -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 +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +446 -306
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +27 -12
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +161 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +65 -31
- data/lib/active_record/base.rb +25 -2
- 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 +367 -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 +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- 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 +367 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
- 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 +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- 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 +39 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- 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 +89 -52
- 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/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.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- 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 +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
- 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 +258 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +108 -137
- data/lib/active_record/core.rb +242 -233
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +88 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +66 -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 +1 -1
- 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 +155 -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 +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_serializer.rb +92 -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 +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +172 -15
- data/lib/active_record/explain.rb +23 -3
- 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 +147 -86
- data/lib/active_record/future_result.rb +174 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +37 -22
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +59 -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 +112 -14
- data/lib/active_record/migration/compatibility.rb +233 -46
- data/lib/active_record/migration/default_strategy.rb +23 -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 +361 -173
- data/lib/active_record/model_schema.rb +125 -101
- data/lib/active_record/nested_attributes.rb +50 -20
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +409 -88
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +220 -44
- data/lib/active_record/railties/controller_runtime.rb +15 -10
- data/lib/active_record/railties/databases.rake +188 -252
- 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 +248 -81
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +246 -90
- data/lib/active_record/relation/delegation.rb +28 -14
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- 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 +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +670 -129
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +287 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +32 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- 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 +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +251 -140
- 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 +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +117 -96
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- 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 -5
- 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/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- 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 +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- 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/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/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -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/node.rb +111 -2
- 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 +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +5 -13
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +141 -20
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- 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.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 +96 -16
- 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,125 +4,57 @@ 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)").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 last_inserted_id(result)
|
99
|
-
@connection.last_id
|
100
|
-
end
|
101
|
-
|
102
|
-
def multi_statements_enabled?
|
103
|
-
flags = @config[:flags]
|
104
|
-
|
105
|
-
if flags.is_a?(Array)
|
106
|
-
flags.include?("MULTI_STATEMENTS")
|
107
|
-
else
|
108
|
-
flags.anybits?(Mysql2::Client::MULTI_STATEMENTS)
|
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)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
58
|
def combine_multi_statements(total_sql)
|
127
59
|
total_sql.each_with_object([]) do |sql, total_sql_chunks|
|
128
60
|
previous_packet = total_sql_chunks.last
|
@@ -149,47 +81,6 @@ module ActiveRecord
|
|
149
81
|
def max_allowed_packet
|
150
82
|
@max_allowed_packet ||= show_variable("max_allowed_packet")
|
151
83
|
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
84
|
end
|
194
85
|
end
|
195
86
|
end
|
@@ -6,12 +6,35 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters
|
7
7
|
module MySQL
|
8
8
|
module Quoting # :nodoc:
|
9
|
+
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
10
|
+
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
11
|
+
|
12
|
+
def cast_bound_value(value)
|
13
|
+
case value
|
14
|
+
when Rational
|
15
|
+
value.to_f.to_s
|
16
|
+
when Numeric
|
17
|
+
value.to_s
|
18
|
+
when BigDecimal
|
19
|
+
value.to_s("F")
|
20
|
+
when true
|
21
|
+
"1"
|
22
|
+
when false
|
23
|
+
"0"
|
24
|
+
when ActiveSupport::Duration
|
25
|
+
warn_quote_duration_deprecated
|
26
|
+
value.to_s
|
27
|
+
else
|
28
|
+
value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
9
32
|
def quote_column_name(name)
|
10
|
-
|
33
|
+
QUOTED_COLUMN_NAMES[name] ||= "`#{super.gsub('`', '``')}`"
|
11
34
|
end
|
12
35
|
|
13
36
|
def quote_table_name(name)
|
14
|
-
|
37
|
+
QUOTED_TABLE_NAMES[name] ||= super.gsub(".", "`.`").freeze
|
15
38
|
end
|
16
39
|
|
17
40
|
def unquoted_true
|
@@ -34,6 +57,34 @@ module ActiveRecord
|
|
34
57
|
"x'#{value.hex}'"
|
35
58
|
end
|
36
59
|
|
60
|
+
def unquote_identifier(identifier)
|
61
|
+
if identifier && identifier.start_with?("`")
|
62
|
+
identifier[1..-2]
|
63
|
+
else
|
64
|
+
identifier
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Override +type_cast+ we pass to mysql2 Date and Time objects instead
|
69
|
+
# of Strings since MySQL adapters are able to handle those classes more efficiently.
|
70
|
+
def type_cast(value) # :nodoc:
|
71
|
+
case value
|
72
|
+
when ActiveSupport::TimeWithZone
|
73
|
+
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
74
|
+
# we need to transform it to Time objects but we don't want to
|
75
|
+
# transform Time objects to themselves.
|
76
|
+
if default_timezone == :utc
|
77
|
+
value.getutc
|
78
|
+
else
|
79
|
+
value.getlocal
|
80
|
+
end
|
81
|
+
when Date, Time
|
82
|
+
value
|
83
|
+
else
|
84
|
+
super
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
37
88
|
def column_name_matcher
|
38
89
|
COLUMN_NAME
|
39
90
|
end
|
@@ -47,7 +98,7 @@ module ActiveRecord
|
|
47
98
|
(
|
48
99
|
(?:
|
49
100
|
# `table_name`.`column_name` | function(one or no argument)
|
50
|
-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)
|
101
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
51
102
|
)
|
52
103
|
(?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
|
53
104
|
)
|
@@ -60,8 +111,9 @@ module ActiveRecord
|
|
60
111
|
(
|
61
112
|
(?:
|
62
113
|
# `table_name`.`column_name` | function(one or no argument)
|
63
|
-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)
|
114
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
64
115
|
)
|
116
|
+
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
65
117
|
(?:\s+ASC|\s+DESC)?
|
66
118
|
)
|
67
119
|
(?:\s*,\s*\g<1>)*
|
@@ -69,27 +121,6 @@ module ActiveRecord
|
|
69
121
|
/ix
|
70
122
|
|
71
123
|
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
124
|
end
|
94
125
|
end
|
95
126
|
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
|
@@ -125,6 +125,10 @@ module ActiveRecord
|
|
125
125
|
256 # https://dev.mysql.com/doc/refman/en/identifiers.html
|
126
126
|
end
|
127
127
|
|
128
|
+
def schema_creation # :nodoc:
|
129
|
+
MySQL::SchemaCreation.new(self)
|
130
|
+
end
|
131
|
+
|
128
132
|
private
|
129
133
|
CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"]
|
130
134
|
|
@@ -150,26 +154,46 @@ module ActiveRecord
|
|
150
154
|
@default_row_format
|
151
155
|
end
|
152
156
|
|
153
|
-
def
|
154
|
-
|
157
|
+
def valid_primary_key_options
|
158
|
+
super + [:unsigned, :auto_increment]
|
155
159
|
end
|
156
160
|
|
157
161
|
def create_table_definition(name, **options)
|
158
162
|
MySQL::TableDefinition.new(self, name, **options)
|
159
163
|
end
|
160
164
|
|
161
|
-
def
|
165
|
+
def default_type(table_name, field_name)
|
166
|
+
match = create_table_info(table_name)&.match(/`#{field_name}` (.+) DEFAULT ('|\d+|[A-z]+)/)
|
167
|
+
default_pre = match[2] if match
|
168
|
+
|
169
|
+
if default_pre == "'"
|
170
|
+
:string
|
171
|
+
elsif default_pre&.match?(/^\d+$/)
|
172
|
+
:integer
|
173
|
+
elsif default_pre&.match?(/^[A-z]+$/)
|
174
|
+
:function
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def new_column_from_field(table_name, field, _definitions)
|
179
|
+
field_name = field.fetch(:Field)
|
162
180
|
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
163
181
|
default, default_function = field[:Default], nil
|
164
182
|
|
165
183
|
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
184
|
+
default = "#{default} ON UPDATE #{default}" if /on update CURRENT_TIMESTAMP/i.match?(field[:Extra])
|
166
185
|
default, default_function = nil, default
|
167
186
|
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
168
187
|
default = +"(#{default})" unless default.start_with?("(")
|
188
|
+
default = default.gsub("\\'", "'")
|
169
189
|
default, default_function = nil, default
|
170
|
-
elsif type_metadata.type == :text && default
|
190
|
+
elsif type_metadata.type == :text && default&.start_with?("'")
|
171
191
|
# strip and unescape quotes
|
172
192
|
default = default[1...-1].gsub("\\'", "'")
|
193
|
+
elsif default&.match?(/\A\d/)
|
194
|
+
# Its a number so we can skip the query to check if it is a function
|
195
|
+
elsif default && default_type(table_name, field_name) == :function
|
196
|
+
default, default_function = nil, default
|
173
197
|
end
|
174
198
|
|
175
199
|
MySQL::Column.new(
|
@@ -206,14 +230,15 @@ module ActiveRecord
|
|
206
230
|
def data_source_sql(name = nil, type: nil)
|
207
231
|
scope = quoted_scope(name, type: type)
|
208
232
|
|
209
|
-
sql = +"SELECT table_name FROM
|
210
|
-
sql << " WHERE table_schema = #{scope[:schema]}
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
sql << " WHERE #{conditions.join(" AND ")}"
|
233
|
+
sql = +"SELECT table_name FROM information_schema.tables"
|
234
|
+
sql << " WHERE table_schema = #{scope[:schema]}"
|
235
|
+
|
236
|
+
if scope[:name]
|
237
|
+
sql << " AND table_name = #{scope[:name]}"
|
238
|
+
sql << " AND table_name IN (SELECT table_name FROM information_schema.tables WHERE table_schema = #{scope[:schema]})"
|
216
239
|
end
|
240
|
+
|
241
|
+
sql << " AND table_type = #{scope[:type]}" if scope[:type]
|
217
242
|
sql
|
218
243
|
end
|
219
244
|
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module Mysql2
|
6
|
+
module DatabaseStatements
|
7
|
+
# Returns an ActiveRecord::Result instance.
|
8
|
+
def select_all(*, **) # :nodoc:
|
9
|
+
result = nil
|
10
|
+
with_raw_connection do |conn|
|
11
|
+
result = if ExplainRegistry.collect? && prepared_statements
|
12
|
+
unprepared_statement { super }
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
conn.abandon_results!
|
17
|
+
end
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
|
22
|
+
if without_prepared_statement?(binds)
|
23
|
+
execute_and_free(sql, name, async: async) do |result|
|
24
|
+
if result
|
25
|
+
build_result(columns: result.fields, rows: result.to_a)
|
26
|
+
else
|
27
|
+
build_result(columns: [], rows: [])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else
|
31
|
+
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async) do |_, result|
|
32
|
+
if result
|
33
|
+
build_result(columns: result.fields, rows: result.to_a)
|
34
|
+
else
|
35
|
+
build_result(columns: [], rows: [])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
42
|
+
if without_prepared_statement?(binds)
|
43
|
+
with_raw_connection do |conn|
|
44
|
+
@affected_rows_before_warnings = nil
|
45
|
+
execute_and_free(sql, name) { @affected_rows_before_warnings || conn.affected_rows }
|
46
|
+
end
|
47
|
+
else
|
48
|
+
exec_stmt_and_free(sql, name, binds) { |stmt| stmt.affected_rows }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
alias :exec_update :exec_delete
|
52
|
+
|
53
|
+
private
|
54
|
+
def sync_timezone_changes(raw_connection)
|
55
|
+
raw_connection.query_options[:database_timezone] = default_timezone
|
56
|
+
end
|
57
|
+
|
58
|
+
def execute_batch(statements, name = nil)
|
59
|
+
statements = statements.map { |sql| transform_query(sql) }
|
60
|
+
combine_multi_statements(statements).each do |statement|
|
61
|
+
with_raw_connection do |conn|
|
62
|
+
raw_execute(statement, name)
|
63
|
+
conn.abandon_results!
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def last_inserted_id(result)
|
69
|
+
@raw_connection&.last_id
|
70
|
+
end
|
71
|
+
|
72
|
+
def multi_statements_enabled?
|
73
|
+
flags = @config[:flags]
|
74
|
+
|
75
|
+
if flags.is_a?(Array)
|
76
|
+
flags.include?("MULTI_STATEMENTS")
|
77
|
+
else
|
78
|
+
flags.anybits?(::Mysql2::Client::MULTI_STATEMENTS)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def with_multi_statements
|
83
|
+
if multi_statements_enabled?
|
84
|
+
return yield
|
85
|
+
end
|
86
|
+
|
87
|
+
with_raw_connection do |conn|
|
88
|
+
conn.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
89
|
+
|
90
|
+
yield
|
91
|
+
ensure
|
92
|
+
conn.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
97
|
+
log(sql, name, async: async) do
|
98
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
99
|
+
sync_timezone_changes(conn)
|
100
|
+
result = conn.query(sql)
|
101
|
+
verified!
|
102
|
+
handle_warnings(sql)
|
103
|
+
result
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false)
|
109
|
+
sql = transform_query(sql)
|
110
|
+
check_if_write_query(sql)
|
111
|
+
|
112
|
+
mark_transaction_written_if_write(sql)
|
113
|
+
|
114
|
+
type_casted_binds = type_casted_binds(binds)
|
115
|
+
|
116
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
117
|
+
with_raw_connection do |conn|
|
118
|
+
sync_timezone_changes(conn)
|
119
|
+
|
120
|
+
if cache_stmt
|
121
|
+
stmt = @statements[sql] ||= conn.prepare(sql)
|
122
|
+
else
|
123
|
+
stmt = conn.prepare(sql)
|
124
|
+
end
|
125
|
+
|
126
|
+
begin
|
127
|
+
result = ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
128
|
+
stmt.execute(*type_casted_binds)
|
129
|
+
end
|
130
|
+
verified!
|
131
|
+
result
|
132
|
+
rescue ::Mysql2::Error => e
|
133
|
+
if cache_stmt
|
134
|
+
@statements.delete(sql)
|
135
|
+
else
|
136
|
+
stmt.close
|
137
|
+
end
|
138
|
+
raise e
|
139
|
+
end
|
140
|
+
|
141
|
+
ret = yield stmt, result
|
142
|
+
result.free if result
|
143
|
+
stmt.close unless cache_stmt
|
144
|
+
ret
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|