activerecord 7.1.5.2 → 8.1.2.1
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 +567 -2443
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +3 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +31 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +18 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +36 -5
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +268 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +8 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +250 -315
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +25 -61
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +20 -27
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +96 -68
- data/lib/active_record/autosave_association.rb +93 -58
- data/lib/active_record/base.rb +5 -7
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
- data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +136 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +44 -41
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
- data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +43 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +66 -0
- data/lib/active_record/connection_handling.rb +88 -46
- data/lib/active_record/core.rb +142 -58
- data/lib/active_record/counter_cache.rb +52 -18
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +28 -5
- data/lib/active_record/database_configurations/hash_config.rb +103 -41
- data/lib/active_record/database_configurations/url_config.rb +30 -1
- data/lib/active_record/database_configurations.rb +8 -4
- data/lib/active_record/delegated_type.rb +43 -19
- data/lib/active_record/dynamic_matchers.rb +56 -71
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +12 -12
- data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
- data/lib/active_record/encryption/encryptor.rb +58 -22
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +57 -36
- data/lib/active_record/errors.rb +76 -26
- data/lib/active_record/explain.rb +14 -25
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +39 -35
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +5 -3
- data/lib/active_record/insert_all.rb +28 -20
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +15 -7
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -34
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +46 -14
- data/lib/active_record/migration/compatibility.rb +40 -25
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +119 -103
- data/lib/active_record/model_schema.rb +66 -78
- data/lib/active_record/nested_attributes.rb +17 -9
- data/lib/active_record/persistence.rb +161 -454
- data/lib/active_record/query_cache.rb +33 -15
- data/lib/active_record/query_logs.rb +106 -39
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +28 -16
- data/lib/active_record/railtie.rb +61 -74
- data/lib/active_record/railties/controller_runtime.rb +19 -5
- data/lib/active_record/railties/databases.rake +64 -78
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +147 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +153 -73
- data/lib/active_record/relation/calculations.rb +146 -96
- data/lib/active_record/relation/delegation.rb +30 -23
- data/lib/active_record/relation/finder_methods.rb +64 -34
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +19 -11
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +25 -10
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +351 -124
- data/lib/active_record/relation/spawn_methods.rb +9 -25
- data/lib/active_record/relation/where_clause.rb +17 -30
- data/lib/active_record/relation.rb +590 -124
- data/lib/active_record/result.rb +131 -59
- data/lib/active_record/runtime_registry.rb +44 -21
- data/lib/active_record/sanitization.rb +33 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +66 -31
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +68 -20
- data/lib/active_record/statement_cache.rb +29 -25
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +7 -33
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +118 -90
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +17 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +123 -89
- data/lib/active_record/testing/query_assertions.rb +127 -0
- data/lib/active_record/timestamp.rb +6 -4
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +129 -0
- data/lib/active_record/transactions.rb +97 -18
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +15 -2
- data/lib/active_record/type/serialized.rb +12 -7
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +5 -4
- data/lib/active_record/validations/associated.rb +10 -4
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +203 -59
- data/lib/arel/alias_predication.rb +3 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +6 -5
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -4
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +14 -5
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -3
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +56 -12
- data/lib/arel/visitors/sqlite.rb +80 -8
- data/lib/arel/visitors/to_sql.rb +34 -37
- data/lib/arel.rb +10 -4
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +23 -14
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -167
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
|
@@ -4,93 +4,64 @@ module ActiveRecord
|
|
|
4
4
|
module ConnectionAdapters
|
|
5
5
|
module Trilogy
|
|
6
6
|
module DatabaseStatements
|
|
7
|
-
def select_all(*, **) # :nodoc:
|
|
8
|
-
result = super
|
|
9
|
-
with_raw_connection do |conn|
|
|
10
|
-
conn.next_result while conn.more_results_exist?
|
|
11
|
-
end
|
|
12
|
-
result
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
|
|
16
|
-
sql = transform_query(sql)
|
|
17
|
-
check_if_write_query(sql)
|
|
18
|
-
mark_transaction_written_if_write(sql)
|
|
19
|
-
|
|
20
|
-
result = raw_execute(sql, name, async: async)
|
|
21
|
-
ActiveRecord::Result.new(result.fields, result.to_a)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
7
|
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil, returning: nil) # :nodoc:
|
|
25
|
-
sql =
|
|
26
|
-
|
|
27
|
-
mark_transaction_written_if_write(sql)
|
|
28
|
-
|
|
29
|
-
raw_execute(to_sql(sql, binds), name)
|
|
8
|
+
sql, _binds = sql_for_insert(sql, pk, binds, returning)
|
|
9
|
+
internal_execute(sql, name)
|
|
30
10
|
end
|
|
31
11
|
|
|
32
|
-
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
|
33
|
-
sql = transform_query(sql)
|
|
34
|
-
check_if_write_query(sql)
|
|
35
|
-
mark_transaction_written_if_write(sql)
|
|
36
|
-
|
|
37
|
-
result = raw_execute(to_sql(sql, binds), name)
|
|
38
|
-
result.affected_rows
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
alias :exec_update :exec_delete # :nodoc:
|
|
42
|
-
|
|
43
12
|
private
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
result = conn.query(sql)
|
|
49
|
-
verified!
|
|
50
|
-
handle_warnings(sql)
|
|
51
|
-
result
|
|
52
|
-
end
|
|
13
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
|
|
14
|
+
reset_multi_statement = if batch && !@config[:multi_statement]
|
|
15
|
+
raw_connection.set_server_option(::Trilogy::SET_SERVER_MULTI_STATEMENTS_ON)
|
|
16
|
+
true
|
|
53
17
|
end
|
|
54
|
-
end
|
|
55
18
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def sync_timezone_changes(conn)
|
|
61
|
-
# Sync any changes since connection last established.
|
|
19
|
+
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
20
|
+
# made since we established the connection
|
|
62
21
|
if default_timezone == :local
|
|
63
|
-
|
|
22
|
+
raw_connection.query_flags |= ::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
|
|
64
23
|
else
|
|
65
|
-
|
|
24
|
+
raw_connection.query_flags &= ~::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
result = raw_connection.query(sql)
|
|
28
|
+
while raw_connection.more_results_exist?
|
|
29
|
+
raw_connection.next_result
|
|
30
|
+
end
|
|
31
|
+
verified!
|
|
32
|
+
|
|
33
|
+
notification_payload[:affected_rows] = result.affected_rows
|
|
34
|
+
notification_payload[:row_count] = result.count
|
|
35
|
+
result
|
|
36
|
+
ensure
|
|
37
|
+
if reset_multi_statement && active?
|
|
38
|
+
raw_connection.set_server_option(::Trilogy::SET_SERVER_MULTI_STATEMENTS_OFF)
|
|
66
39
|
end
|
|
67
40
|
end
|
|
68
41
|
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
conn.next_result while conn.more_results_exist?
|
|
75
|
-
end
|
|
42
|
+
def cast_result(result)
|
|
43
|
+
if result.fields.empty?
|
|
44
|
+
ActiveRecord::Result.empty(affected_rows: result.affected_rows)
|
|
45
|
+
else
|
|
46
|
+
ActiveRecord::Result.new(result.fields, result.rows, affected_rows: result.affected_rows)
|
|
76
47
|
end
|
|
77
48
|
end
|
|
78
49
|
|
|
79
|
-
def
|
|
80
|
-
|
|
50
|
+
def affected_rows(result)
|
|
51
|
+
result.affected_rows
|
|
81
52
|
end
|
|
82
53
|
|
|
83
|
-
def
|
|
84
|
-
if
|
|
85
|
-
|
|
54
|
+
def last_inserted_id(result)
|
|
55
|
+
if supports_insert_returning?
|
|
56
|
+
super
|
|
57
|
+
else
|
|
58
|
+
result.last_insert_id
|
|
86
59
|
end
|
|
60
|
+
end
|
|
87
61
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
yield
|
|
92
|
-
ensure
|
|
93
|
-
conn.set_server_option(::Trilogy::SET_SERVER_MULTI_STATEMENTS_OFF)
|
|
62
|
+
def execute_batch(statements, name = nil, **kwargs)
|
|
63
|
+
combine_multi_statements(statements).each do |statement|
|
|
64
|
+
raw_execute(statement, name, batch: true, **kwargs)
|
|
94
65
|
end
|
|
95
66
|
end
|
|
96
67
|
end
|
|
@@ -2,44 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
require "active_record/connection_adapters/abstract_mysql_adapter"
|
|
4
4
|
|
|
5
|
-
gem "trilogy", "~> 2.
|
|
5
|
+
gem "trilogy", "~> 2.7"
|
|
6
6
|
require "trilogy"
|
|
7
7
|
|
|
8
8
|
require "active_record/connection_adapters/trilogy/database_statements"
|
|
9
9
|
|
|
10
10
|
module ActiveRecord
|
|
11
|
-
module ConnectionHandling # :nodoc:
|
|
12
|
-
def trilogy_adapter_class
|
|
13
|
-
ConnectionAdapters::TrilogyAdapter
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Establishes a connection to the database that's used by all Active Record objects.
|
|
17
|
-
def trilogy_connection(config)
|
|
18
|
-
configuration = config.dup
|
|
19
|
-
|
|
20
|
-
# Set FOUND_ROWS capability on the connection so UPDATE queries returns number of rows
|
|
21
|
-
# matched rather than number of rows updated.
|
|
22
|
-
configuration[:found_rows] = true
|
|
23
|
-
|
|
24
|
-
options = [
|
|
25
|
-
configuration[:host],
|
|
26
|
-
configuration[:port],
|
|
27
|
-
configuration[:database],
|
|
28
|
-
configuration[:username],
|
|
29
|
-
configuration[:password],
|
|
30
|
-
configuration[:socket],
|
|
31
|
-
0
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
trilogy_adapter_class.new nil, logger, options, configuration
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
11
|
module ConnectionAdapters
|
|
38
12
|
class TrilogyAdapter < AbstractMysqlAdapter
|
|
39
13
|
ER_BAD_DB_ERROR = 1049
|
|
40
14
|
ER_DBACCESS_DENIED_ERROR = 1044
|
|
41
15
|
ER_ACCESS_DENIED_ERROR = 1045
|
|
42
|
-
ER_SERVER_SHUTDOWN = 1053
|
|
43
16
|
|
|
44
17
|
ADAPTER_NAME = "Trilogy"
|
|
45
18
|
|
|
@@ -99,16 +72,22 @@ module ActiveRecord
|
|
|
99
72
|
end
|
|
100
73
|
end
|
|
101
74
|
|
|
102
|
-
def initialize(
|
|
103
|
-
|
|
75
|
+
def initialize(config, *)
|
|
76
|
+
config = config.dup
|
|
104
77
|
|
|
105
|
-
if
|
|
78
|
+
# Trilogy ignores `socket` if `host is set. We want the opposite to allow
|
|
79
|
+
# configuring UNIX domain sockets via `DATABASE_URL`.
|
|
80
|
+
config.delete(:host) if config[:socket]
|
|
81
|
+
|
|
82
|
+
# Set FOUND_ROWS capability on the connection so UPDATE queries returns number of rows
|
|
83
|
+
# matched rather than number of rows updated.
|
|
84
|
+
config[:found_rows] = true
|
|
85
|
+
|
|
86
|
+
if config[:prepared_statements]
|
|
106
87
|
raise ArgumentError, "Trilogy currently doesn't support prepared statements. Remove `prepared_statements: true` from your database configuration."
|
|
107
88
|
end
|
|
108
89
|
|
|
109
|
-
|
|
110
|
-
# configuring UNIX domain sockets via `DATABASE_URL`.
|
|
111
|
-
@config.delete(:host) if @config[:socket]
|
|
90
|
+
super
|
|
112
91
|
end
|
|
113
92
|
|
|
114
93
|
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
|
@@ -137,14 +116,12 @@ module ActiveRecord
|
|
|
137
116
|
true
|
|
138
117
|
end
|
|
139
118
|
|
|
140
|
-
def
|
|
141
|
-
|
|
142
|
-
conn.escape(string)
|
|
143
|
-
end
|
|
119
|
+
def connected?
|
|
120
|
+
!(@raw_connection.nil? || @raw_connection.closed?)
|
|
144
121
|
end
|
|
145
122
|
|
|
146
123
|
def active?
|
|
147
|
-
|
|
124
|
+
connected? && @lock.synchronize { @raw_connection&.ping; verified! } || false
|
|
148
125
|
rescue ::Trilogy::Error
|
|
149
126
|
false
|
|
150
127
|
end
|
|
@@ -172,23 +149,6 @@ module ActiveRecord
|
|
|
172
149
|
TYPE_MAP.lookup(type).is_a?(Type::String) || TYPE_MAP.lookup(type).is_a?(Type::Text)
|
|
173
150
|
end
|
|
174
151
|
|
|
175
|
-
def each_hash(result)
|
|
176
|
-
return to_enum(:each_hash, result) unless block_given?
|
|
177
|
-
|
|
178
|
-
keys = result.fields.map(&:to_sym)
|
|
179
|
-
result.rows.each do |row|
|
|
180
|
-
hash = {}
|
|
181
|
-
idx = 0
|
|
182
|
-
row.each do |value|
|
|
183
|
-
hash[keys[idx]] = value
|
|
184
|
-
idx += 1
|
|
185
|
-
end
|
|
186
|
-
yield hash
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
nil
|
|
190
|
-
end
|
|
191
|
-
|
|
192
152
|
def error_number(exception)
|
|
193
153
|
exception.error_code if exception.respond_to?(:error_code)
|
|
194
154
|
end
|
|
@@ -206,7 +166,7 @@ module ActiveRecord
|
|
|
206
166
|
end
|
|
207
167
|
|
|
208
168
|
def full_version
|
|
209
|
-
|
|
169
|
+
database_version.full_version_string
|
|
210
170
|
end
|
|
211
171
|
|
|
212
172
|
def get_full_version
|
|
@@ -219,18 +179,12 @@ module ActiveRecord
|
|
|
219
179
|
if exception.is_a?(::Trilogy::TimeoutError) && !exception.error_code
|
|
220
180
|
return ActiveRecord::AdapterTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
221
181
|
end
|
|
222
|
-
error_code = exception.error_code if exception.respond_to?(:error_code)
|
|
223
|
-
|
|
224
|
-
case error_code
|
|
225
|
-
when ER_SERVER_SHUTDOWN
|
|
226
|
-
return ConnectionFailed.new(message, connection_pool: @pool)
|
|
227
|
-
end
|
|
228
182
|
|
|
229
183
|
case exception
|
|
230
|
-
when
|
|
184
|
+
when ::Trilogy::ConnectionClosed, ::Trilogy::EOFError, ::Trilogy::SSLError
|
|
231
185
|
return ConnectionFailed.new(message, connection_pool: @pool)
|
|
232
186
|
when ::Trilogy::Error
|
|
233
|
-
if
|
|
187
|
+
if exception.is_a?(SystemCallError) || exception.message.include?("TRILOGY_INVALID_SEQUENCE_ID")
|
|
234
188
|
return ConnectionFailed.new(message, connection_pool: @pool)
|
|
235
189
|
end
|
|
236
190
|
end
|
|
@@ -1,9 +1,74 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/core_ext/string/filters"
|
|
4
|
+
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
module ConnectionAdapters
|
|
5
7
|
extend ActiveSupport::Autoload
|
|
6
8
|
|
|
9
|
+
@adapters = {}
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
# Registers a custom database adapter.
|
|
13
|
+
#
|
|
14
|
+
# Can also be used to define aliases.
|
|
15
|
+
#
|
|
16
|
+
# == Example
|
|
17
|
+
#
|
|
18
|
+
# ActiveRecord::ConnectionAdapters.register("megadb", "MegaDB::ActiveRecordAdapter", "mega_db/active_record_adapter")
|
|
19
|
+
#
|
|
20
|
+
# ActiveRecord::ConnectionAdapters.register("mysql", "ActiveRecord::ConnectionAdapters::TrilogyAdapter", "active_record/connection_adapters/trilogy_adapter")
|
|
21
|
+
#
|
|
22
|
+
def register(name, class_name, path = class_name.underscore)
|
|
23
|
+
@adapters[name.to_s] = [class_name, path]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def resolve(adapter_name) # :nodoc:
|
|
27
|
+
# Require the adapter itself and give useful feedback about
|
|
28
|
+
# 1. Missing adapter gems.
|
|
29
|
+
# 2. Incorrectly registered adapters.
|
|
30
|
+
# 3. Adapter gems' missing dependencies.
|
|
31
|
+
class_name, path_to_adapter = @adapters[adapter_name.to_s]
|
|
32
|
+
|
|
33
|
+
unless class_name
|
|
34
|
+
raise AdapterNotFound, <<~MSG.squish
|
|
35
|
+
Database configuration specifies nonexistent '#{adapter_name}' adapter.
|
|
36
|
+
Available adapters are: #{@adapters.keys.sort.join(", ")}.
|
|
37
|
+
Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary
|
|
38
|
+
adapter gem to your Gemfile if it's not in the list of available adapters.
|
|
39
|
+
MSG
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
unless Object.const_defined?(class_name)
|
|
43
|
+
begin
|
|
44
|
+
require path_to_adapter
|
|
45
|
+
rescue LoadError => error
|
|
46
|
+
# We couldn't require the adapter itself.
|
|
47
|
+
if error.path == path_to_adapter
|
|
48
|
+
# We can assume here that a non-builtin adapter was specified and the path
|
|
49
|
+
# registered by the adapter gem is incorrect.
|
|
50
|
+
raise LoadError, "Error loading the '#{adapter_name}' Active Record adapter. Ensure that the path registered by the adapter gem is correct. #{error.message}", error.backtrace
|
|
51
|
+
else
|
|
52
|
+
# Bubbled up from the adapter require. Prefix the exception message
|
|
53
|
+
# with some guidance about how to address it and reraise.
|
|
54
|
+
raise LoadError, "Error loading the '#{adapter_name}' Active Record adapter. Missing a gem it depends on? #{error.message}", error.backtrace
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
begin
|
|
60
|
+
Object.const_get(class_name)
|
|
61
|
+
rescue NameError => error
|
|
62
|
+
raise AdapterNotFound, "Could not load the #{class_name} Active Record adapter (#{error.message})."
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
register "sqlite3", "ActiveRecord::ConnectionAdapters::SQLite3Adapter", "active_record/connection_adapters/sqlite3_adapter"
|
|
68
|
+
register "mysql2", "ActiveRecord::ConnectionAdapters::Mysql2Adapter", "active_record/connection_adapters/mysql2_adapter"
|
|
69
|
+
register "trilogy", "ActiveRecord::ConnectionAdapters::TrilogyAdapter", "active_record/connection_adapters/trilogy_adapter"
|
|
70
|
+
register "postgresql", "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter", "active_record/connection_adapters/postgresql_adapter"
|
|
71
|
+
|
|
7
72
|
eager_autoload do
|
|
8
73
|
autoload :AbstractAdapter
|
|
9
74
|
end
|
|
@@ -19,6 +84,7 @@ module ActiveRecord
|
|
|
19
84
|
autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
|
|
20
85
|
autoload :IndexDefinition
|
|
21
86
|
autoload :ColumnDefinition
|
|
87
|
+
autoload :ColumnMethods
|
|
22
88
|
autoload :ChangeColumnDefinition
|
|
23
89
|
autoload :ChangeColumnDefaultDefinition
|
|
24
90
|
autoload :ForeignKeyDefinition
|
|
@@ -87,6 +87,8 @@ module ActiveRecord
|
|
|
87
87
|
|
|
88
88
|
connections = []
|
|
89
89
|
|
|
90
|
+
@shard_keys = shards.keys
|
|
91
|
+
|
|
90
92
|
if shards.empty?
|
|
91
93
|
shards[:default] = database
|
|
92
94
|
end
|
|
@@ -98,7 +100,8 @@ module ActiveRecord
|
|
|
98
100
|
db_config = resolve_config_for_connection(database_key)
|
|
99
101
|
|
|
100
102
|
self.connection_class = true
|
|
101
|
-
|
|
103
|
+
shard = shard.to_sym unless shard.is_a? Integer
|
|
104
|
+
connections << connection_handler.establish_connection(db_config, owner_name: self, role: role, shard: shard)
|
|
102
105
|
end
|
|
103
106
|
end
|
|
104
107
|
|
|
@@ -170,9 +173,23 @@ module ActiveRecord
|
|
|
170
173
|
prevent_writes = true if role == ActiveRecord.reading_role
|
|
171
174
|
|
|
172
175
|
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
+
begin
|
|
177
|
+
yield
|
|
178
|
+
ensure
|
|
179
|
+
connected_to_stack.pop
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Passes the block to +connected_to+ for every +shard+ the
|
|
184
|
+
# model is configured to connect to (if any), and returns the
|
|
185
|
+
# results in an array.
|
|
186
|
+
#
|
|
187
|
+
# Optionally, +role+ and/or +prevent_writes+ can be passed which
|
|
188
|
+
# will be forwarded to each +connected_to+ call.
|
|
189
|
+
def connected_to_all_shards(role: nil, prevent_writes: false, &blk)
|
|
190
|
+
shard_keys.map do |shard|
|
|
191
|
+
connected_to(shard: shard, role: role, prevent_writes: prevent_writes, &blk)
|
|
192
|
+
end
|
|
176
193
|
end
|
|
177
194
|
|
|
178
195
|
# Use a specified connection.
|
|
@@ -243,22 +260,64 @@ module ActiveRecord
|
|
|
243
260
|
# Clears the query cache for all connections associated with the current thread.
|
|
244
261
|
def clear_query_caches_for_current_thread
|
|
245
262
|
connection_handler.each_connection_pool do |pool|
|
|
246
|
-
pool.
|
|
263
|
+
pool.clear_query_cache
|
|
247
264
|
end
|
|
248
265
|
end
|
|
249
266
|
|
|
250
267
|
# Returns the connection currently associated with the class. This can
|
|
251
268
|
# also be used to "borrow" the connection to do database work unrelated
|
|
252
269
|
# to any of the specific Active Records.
|
|
270
|
+
# The connection will remain leased for the entire duration of the request
|
|
271
|
+
# or job, or until +#release_connection+ is called.
|
|
272
|
+
def lease_connection
|
|
273
|
+
connection_pool.lease_connection
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Soft deprecated. Use +#with_connection+ or +#lease_connection+ instead.
|
|
253
277
|
def connection
|
|
254
|
-
|
|
278
|
+
pool = connection_pool
|
|
279
|
+
if pool.permanent_lease?
|
|
280
|
+
case ActiveRecord.permanent_connection_checkout
|
|
281
|
+
when :deprecated
|
|
282
|
+
ActiveRecord.deprecator.warn <<~MESSAGE
|
|
283
|
+
Called deprecated `ActiveRecord::Base.connection` method.
|
|
284
|
+
|
|
285
|
+
Either use `with_connection` or `lease_connection`.
|
|
286
|
+
MESSAGE
|
|
287
|
+
when :disallowed
|
|
288
|
+
raise ActiveRecordError, <<~MESSAGE
|
|
289
|
+
Called deprecated `ActiveRecord::Base.connection` method.
|
|
290
|
+
|
|
291
|
+
Either use `with_connection` or `lease_connection`.
|
|
292
|
+
MESSAGE
|
|
293
|
+
end
|
|
294
|
+
pool.lease_connection
|
|
295
|
+
else
|
|
296
|
+
pool.active_connection
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Return the currently leased connection into the pool
|
|
301
|
+
def release_connection
|
|
302
|
+
connection_pool.release_connection
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Checkouts a connection from the pool, yield it and then check it back in.
|
|
306
|
+
# If a connection was already leased via #lease_connection or a parent call to
|
|
307
|
+
# #with_connection, that same connection is yielded.
|
|
308
|
+
# If #lease_connection is called inside the block, the connection won't be checked
|
|
309
|
+
# back in.
|
|
310
|
+
# If #connection is called inside the block, the connection won't be checked back in
|
|
311
|
+
# unless the +prevent_permanent_checkout+ argument is set to +true+.
|
|
312
|
+
def with_connection(prevent_permanent_checkout: false, &block)
|
|
313
|
+
connection_pool.with_connection(prevent_permanent_checkout: prevent_permanent_checkout, &block)
|
|
255
314
|
end
|
|
256
315
|
|
|
257
316
|
attr_writer :connection_specification_name
|
|
258
317
|
|
|
259
318
|
# Returns the connection specification name from the current class or its parent.
|
|
260
319
|
def connection_specification_name
|
|
261
|
-
if
|
|
320
|
+
if @connection_specification_name.nil?
|
|
262
321
|
return self == Base ? Base.name : superclass.connection_specification_name
|
|
263
322
|
end
|
|
264
323
|
@connection_specification_name
|
|
@@ -279,8 +338,12 @@ module ActiveRecord
|
|
|
279
338
|
connection_pool.db_config
|
|
280
339
|
end
|
|
281
340
|
|
|
341
|
+
def adapter_class # :nodoc:
|
|
342
|
+
connection_pool.db_config.adapter_class
|
|
343
|
+
end
|
|
344
|
+
|
|
282
345
|
def connection_pool
|
|
283
|
-
connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard
|
|
346
|
+
connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard, strict: true)
|
|
284
347
|
end
|
|
285
348
|
|
|
286
349
|
def retrieve_connection
|
|
@@ -292,16 +355,9 @@ module ActiveRecord
|
|
|
292
355
|
connection_handler.connected?(connection_specification_name, role: current_role, shard: current_shard)
|
|
293
356
|
end
|
|
294
357
|
|
|
295
|
-
def remove_connection
|
|
296
|
-
if
|
|
297
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
|
298
|
-
The name argument for `#remove_connection` is deprecated without replacement
|
|
299
|
-
and will be removed in Rails 7.2. `#remove_connection` should always be called
|
|
300
|
-
on the connection class directly, which makes the name argument obsolete.
|
|
301
|
-
MSG
|
|
302
|
-
end
|
|
358
|
+
def remove_connection
|
|
359
|
+
name = @connection_specification_name if defined?(@connection_specification_name)
|
|
303
360
|
|
|
304
|
-
name ||= @connection_specification_name if defined?(@connection_specification_name)
|
|
305
361
|
# if removing a connection that has a pool, we reset the
|
|
306
362
|
# connection_specification_name so it will use the parent
|
|
307
363
|
# pool.
|
|
@@ -312,39 +368,23 @@ module ActiveRecord
|
|
|
312
368
|
connection_handler.remove_connection_pool(name, role: current_role, shard: current_shard)
|
|
313
369
|
end
|
|
314
370
|
|
|
315
|
-
def
|
|
316
|
-
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
def clear_active_connections!(role = nil)
|
|
320
|
-
deprecation_for_delegation(__method__)
|
|
321
|
-
connection_handler.clear_active_connections!(role)
|
|
371
|
+
def schema_cache # :nodoc:
|
|
372
|
+
connection_pool.schema_cache
|
|
322
373
|
end
|
|
323
374
|
|
|
324
|
-
def
|
|
325
|
-
|
|
326
|
-
connection_handler.clear_reloadable_connections!(role)
|
|
375
|
+
def clear_cache! # :nodoc:
|
|
376
|
+
connection_pool.schema_cache.clear!
|
|
327
377
|
end
|
|
328
378
|
|
|
329
|
-
def
|
|
330
|
-
|
|
331
|
-
connection_handler.clear_all_connections!(role)
|
|
379
|
+
def shard_keys
|
|
380
|
+
connection_class_for_self.instance_variable_get(:@shard_keys) || []
|
|
332
381
|
end
|
|
333
382
|
|
|
334
|
-
def
|
|
335
|
-
|
|
336
|
-
connection_handler.flush_idle_connections!(role)
|
|
383
|
+
def sharded?
|
|
384
|
+
shard_keys.any?
|
|
337
385
|
end
|
|
338
386
|
|
|
339
387
|
private
|
|
340
|
-
def deprecation_for_delegation(method)
|
|
341
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
|
342
|
-
Calling `ActiveRecord::Base.#{method} is deprecated. Please
|
|
343
|
-
call the method directly on the connection handler; for
|
|
344
|
-
example: `ActiveRecord::Base.connection_handler.#{method}`.
|
|
345
|
-
MSG
|
|
346
|
-
end
|
|
347
|
-
|
|
348
388
|
def resolve_config_for_connection(config_or_env)
|
|
349
389
|
raise "Anonymous class is not allowed." unless name
|
|
350
390
|
|
|
@@ -358,11 +398,13 @@ module ActiveRecord
|
|
|
358
398
|
prevent_writes = true if role == ActiveRecord.reading_role
|
|
359
399
|
|
|
360
400
|
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
401
|
+
begin
|
|
402
|
+
return_value = yield
|
|
403
|
+
return_value.load if return_value.is_a? ActiveRecord::Relation
|
|
404
|
+
return_value
|
|
405
|
+
ensure
|
|
406
|
+
self.connected_to_stack.pop
|
|
407
|
+
end
|
|
366
408
|
end
|
|
367
409
|
|
|
368
410
|
def append_to_connected_to_stack(entry)
|