activerecord 7.0.8 → 7.1.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 +1401 -1513
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +15 -9
- data/lib/active_record/associations/collection_proxy.rb +15 -10
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +295 -199
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +105 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +55 -9
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- 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 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +128 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -122
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +502 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +207 -108
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -143
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +18 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +71 -40
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +347 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +337 -176
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +45 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +209 -79
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +71 -94
- data/lib/active_record/core.rb +134 -146
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +8 -3
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +36 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -26
- data/lib/active_record/errors.rb +108 -15
- data/lib/active_record/explain.rb +23 -3
- 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 +29 -8
- data/lib/active_record/fixtures.rb +119 -71
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +118 -30
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- 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 +4 -0
- data/lib/active_record/middleware/database_selector.rb +5 -7
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +100 -4
- data/lib/active_record/migration/compatibility.rb +131 -5
- 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.rb +213 -109
- data/lib/active_record/model_schema.rb +60 -40
- data/lib/active_record/nested_attributes.rb +23 -3
- data/lib/active_record/normalization.rb +159 -0
- data/lib/active_record/persistence.rb +184 -34
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +108 -46
- data/lib/active_record/railties/controller_runtime.rb +10 -5
- data/lib/active_record/railties/databases.rake +139 -145
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +162 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +152 -63
- data/lib/active_record/relation/delegation.rb +22 -8
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +351 -62
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +76 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +46 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +10 -1
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +26 -14
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +36 -10
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- 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 +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.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/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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
- metadata +46 -11
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module Trilogy
|
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
|
+
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil, returning: nil) # :nodoc:
|
25
|
+
sql = transform_query(sql)
|
26
|
+
check_if_write_query(sql)
|
27
|
+
mark_transaction_written_if_write(sql)
|
28
|
+
|
29
|
+
raw_execute(to_sql(sql, binds), name)
|
30
|
+
end
|
31
|
+
|
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
|
+
private
|
44
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
45
|
+
log(sql, name, async: async) do
|
46
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
47
|
+
sync_timezone_changes(conn)
|
48
|
+
result = conn.query(sql)
|
49
|
+
handle_warnings(sql)
|
50
|
+
result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def last_inserted_id(result)
|
56
|
+
result.last_insert_id
|
57
|
+
end
|
58
|
+
|
59
|
+
def sync_timezone_changes(conn)
|
60
|
+
# Sync any changes since connection last established.
|
61
|
+
if default_timezone == :local
|
62
|
+
conn.query_flags |= ::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
|
63
|
+
else
|
64
|
+
conn.query_flags &= ~::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def execute_batch(statements, name = nil)
|
69
|
+
statements = statements.map { |sql| transform_query(sql) }
|
70
|
+
combine_multi_statements(statements).each do |statement|
|
71
|
+
with_raw_connection do |conn|
|
72
|
+
raw_execute(statement, name)
|
73
|
+
conn.next_result while conn.more_results_exist?
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def multi_statements_enabled?
|
79
|
+
!!@config[:multi_statement]
|
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(::Trilogy::SET_SERVER_MULTI_STATEMENTS_ON)
|
89
|
+
|
90
|
+
yield
|
91
|
+
ensure
|
92
|
+
conn.set_server_option(::Trilogy::SET_SERVER_MULTI_STATEMENTS_OFF)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/connection_adapters/abstract_mysql_adapter"
|
4
|
+
|
5
|
+
gem "trilogy", "~> 2.4"
|
6
|
+
require "trilogy"
|
7
|
+
|
8
|
+
require "active_record/connection_adapters/trilogy/database_statements"
|
9
|
+
|
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
|
+
module ConnectionAdapters
|
38
|
+
class TrilogyAdapter < AbstractMysqlAdapter
|
39
|
+
ER_BAD_DB_ERROR = 1049
|
40
|
+
ER_DBACCESS_DENIED_ERROR = 1044
|
41
|
+
ER_ACCESS_DENIED_ERROR = 1045
|
42
|
+
ER_SERVER_SHUTDOWN = 1053
|
43
|
+
|
44
|
+
ADAPTER_NAME = "Trilogy"
|
45
|
+
|
46
|
+
include Trilogy::DatabaseStatements
|
47
|
+
|
48
|
+
SSL_MODES = {
|
49
|
+
SSL_MODE_DISABLED: ::Trilogy::SSL_DISABLED,
|
50
|
+
SSL_MODE_PREFERRED: ::Trilogy::SSL_PREFERRED_NOVERIFY,
|
51
|
+
SSL_MODE_REQUIRED: ::Trilogy::SSL_REQUIRED_NOVERIFY,
|
52
|
+
SSL_MODE_VERIFY_CA: ::Trilogy::SSL_VERIFY_CA,
|
53
|
+
SSL_MODE_VERIFY_IDENTITY: ::Trilogy::SSL_VERIFY_IDENTITY
|
54
|
+
}.freeze
|
55
|
+
|
56
|
+
class << self
|
57
|
+
def new_client(config)
|
58
|
+
config[:ssl_mode] = parse_ssl_mode(config[:ssl_mode]) if config[:ssl_mode]
|
59
|
+
::Trilogy.new(config)
|
60
|
+
rescue ::Trilogy::ConnectionError, ::Trilogy::ProtocolError => error
|
61
|
+
raise translate_connect_error(config, error)
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_ssl_mode(mode)
|
65
|
+
return mode if mode.is_a? Integer
|
66
|
+
|
67
|
+
m = mode.to_s.upcase
|
68
|
+
m = "SSL_MODE_#{m}" unless m.start_with? "SSL_MODE_"
|
69
|
+
|
70
|
+
SSL_MODES.fetch(m.to_sym, mode)
|
71
|
+
end
|
72
|
+
|
73
|
+
def translate_connect_error(config, error)
|
74
|
+
case error.error_code
|
75
|
+
when ER_DBACCESS_DENIED_ERROR, ER_BAD_DB_ERROR
|
76
|
+
ActiveRecord::NoDatabaseError.db_error(config[:database])
|
77
|
+
when ER_ACCESS_DENIED_ERROR
|
78
|
+
ActiveRecord::DatabaseConnectionError.username_error(config[:username])
|
79
|
+
else
|
80
|
+
if error.message.include?("TRILOGY_DNS_ERROR")
|
81
|
+
ActiveRecord::DatabaseConnectionError.hostname_error(config[:host])
|
82
|
+
else
|
83
|
+
ActiveRecord::ConnectionNotEstablished.new(error.message)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
def initialize_type_map(m)
|
90
|
+
super
|
91
|
+
|
92
|
+
m.register_type(%r(char)i) do |sql_type|
|
93
|
+
limit = extract_limit(sql_type)
|
94
|
+
Type.lookup(:string, adapter: :trilogy, limit: limit)
|
95
|
+
end
|
96
|
+
|
97
|
+
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :trilogy)
|
98
|
+
m.register_type %r(^set)i, Type.lookup(:string, adapter: :trilogy)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
103
|
+
|
104
|
+
def supports_json?
|
105
|
+
!mariadb? && database_version >= "5.7.8"
|
106
|
+
end
|
107
|
+
|
108
|
+
def supports_comments?
|
109
|
+
true
|
110
|
+
end
|
111
|
+
|
112
|
+
def supports_comments_in_create?
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
116
|
+
def supports_savepoints?
|
117
|
+
true
|
118
|
+
end
|
119
|
+
|
120
|
+
def savepoint_errors_invalidate_transactions?
|
121
|
+
true
|
122
|
+
end
|
123
|
+
|
124
|
+
def supports_lazy_transactions?
|
125
|
+
true
|
126
|
+
end
|
127
|
+
|
128
|
+
def quote_string(string)
|
129
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
130
|
+
conn.escape(string)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def active?
|
135
|
+
connection&.ping || false
|
136
|
+
rescue ::Trilogy::Error
|
137
|
+
false
|
138
|
+
end
|
139
|
+
|
140
|
+
alias reset! reconnect!
|
141
|
+
|
142
|
+
def disconnect!
|
143
|
+
super
|
144
|
+
unless connection.nil?
|
145
|
+
connection.close
|
146
|
+
self.connection = nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def discard!
|
151
|
+
super
|
152
|
+
unless connection.nil?
|
153
|
+
connection.discard!
|
154
|
+
self.connection = nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
def text_type?(type)
|
160
|
+
TYPE_MAP.lookup(type).is_a?(Type::String) || TYPE_MAP.lookup(type).is_a?(Type::Text)
|
161
|
+
end
|
162
|
+
|
163
|
+
def each_hash(result)
|
164
|
+
return to_enum(:each_hash, result) unless block_given?
|
165
|
+
|
166
|
+
keys = result.fields.map(&:to_sym)
|
167
|
+
result.rows.each do |row|
|
168
|
+
hash = {}
|
169
|
+
idx = 0
|
170
|
+
row.each do |value|
|
171
|
+
hash[keys[idx]] = value
|
172
|
+
idx += 1
|
173
|
+
end
|
174
|
+
yield hash
|
175
|
+
end
|
176
|
+
|
177
|
+
nil
|
178
|
+
end
|
179
|
+
|
180
|
+
def error_number(exception)
|
181
|
+
exception.error_code if exception.respond_to?(:error_code)
|
182
|
+
end
|
183
|
+
|
184
|
+
def connection
|
185
|
+
@raw_connection
|
186
|
+
end
|
187
|
+
|
188
|
+
def connection=(conn)
|
189
|
+
@raw_connection = conn
|
190
|
+
end
|
191
|
+
|
192
|
+
def connect
|
193
|
+
self.connection = self.class.new_client(@config)
|
194
|
+
rescue ConnectionNotEstablished => ex
|
195
|
+
raise ex.set_pool(@pool)
|
196
|
+
end
|
197
|
+
|
198
|
+
def reconnect
|
199
|
+
connection&.close
|
200
|
+
self.connection = nil
|
201
|
+
connect
|
202
|
+
end
|
203
|
+
|
204
|
+
def full_version
|
205
|
+
schema_cache.database_version.full_version_string
|
206
|
+
end
|
207
|
+
|
208
|
+
def get_full_version
|
209
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
|
210
|
+
conn.server_info[:version]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def translate_exception(exception, message:, sql:, binds:)
|
215
|
+
if exception.is_a?(::Trilogy::TimeoutError) && !exception.error_code
|
216
|
+
return ActiveRecord::AdapterTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
217
|
+
end
|
218
|
+
error_code = exception.error_code if exception.respond_to?(:error_code)
|
219
|
+
|
220
|
+
case error_code
|
221
|
+
when ER_SERVER_SHUTDOWN
|
222
|
+
return ConnectionFailed.new(message, connection_pool: @pool)
|
223
|
+
end
|
224
|
+
|
225
|
+
case exception
|
226
|
+
when Errno::EPIPE, SocketError, IOError
|
227
|
+
return ConnectionFailed.new(message, connection_pool: @pool)
|
228
|
+
when ::Trilogy::Error
|
229
|
+
if /Connection reset by peer|TRILOGY_CLOSED_CONNECTION|TRILOGY_INVALID_SEQUENCE_ID|TRILOGY_UNEXPECTED_PACKET/.match?(exception.message)
|
230
|
+
return ConnectionFailed.new(message, connection_pool: @pool)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
super
|
235
|
+
end
|
236
|
+
|
237
|
+
def default_prepared_statements
|
238
|
+
false
|
239
|
+
end
|
240
|
+
|
241
|
+
ActiveRecord::Type.register(:immutable_string, adapter: :trilogy) do |_, **args|
|
242
|
+
Type::ImmutableString.new(true: "1", false: "0", **args)
|
243
|
+
end
|
244
|
+
|
245
|
+
ActiveRecord::Type.register(:string, adapter: :trilogy) do |_, **args|
|
246
|
+
Type::String.new(true: "1", false: "0", **args)
|
247
|
+
end
|
248
|
+
|
249
|
+
ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :trilogy)
|
250
|
+
end
|
251
|
+
|
252
|
+
ActiveSupport.run_load_hooks(:active_record_trilogyadapter, TrilogyAdapter)
|
253
|
+
end
|
254
|
+
end
|
@@ -11,14 +11,16 @@ module ActiveRecord
|
|
11
11
|
autoload :Column
|
12
12
|
autoload :PoolConfig
|
13
13
|
autoload :PoolManager
|
14
|
-
autoload :LegacyPoolManager
|
15
14
|
autoload :SchemaCache
|
15
|
+
autoload :BoundSchemaReflection, "active_record/connection_adapters/schema_cache"
|
16
|
+
autoload :SchemaReflection, "active_record/connection_adapters/schema_cache"
|
16
17
|
autoload :Deduplicable
|
17
18
|
|
18
19
|
autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
|
19
20
|
autoload :IndexDefinition
|
20
21
|
autoload :ColumnDefinition
|
21
22
|
autoload :ChangeColumnDefinition
|
23
|
+
autoload :ChangeColumnDefaultDefinition
|
22
24
|
autoload :ForeignKeyDefinition
|
23
25
|
autoload :CheckConstraintDefinition
|
24
26
|
autoload :TableDefinition
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
+
# = Active Record Connection Handling
|
4
5
|
module ConnectionHandling
|
5
6
|
RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
|
6
7
|
DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
|
@@ -38,7 +39,7 @@ module ActiveRecord
|
|
38
39
|
# )
|
39
40
|
#
|
40
41
|
# In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
|
41
|
-
# is set (Rails automatically loads the contents of config/database.yml into it),
|
42
|
+
# is set (\Rails automatically loads the contents of config/database.yml into it),
|
42
43
|
# a symbol can also be given as argument, representing a key in the
|
43
44
|
# configuration hash:
|
44
45
|
#
|
@@ -48,16 +49,15 @@ module ActiveRecord
|
|
48
49
|
# may be returned on an error.
|
49
50
|
def establish_connection(config_or_env = nil)
|
50
51
|
config_or_env ||= DEFAULT_ENV.call.to_sym
|
51
|
-
db_config
|
52
|
-
connection_handler.establish_connection(db_config, owner_name:
|
52
|
+
db_config = resolve_config_for_connection(config_or_env)
|
53
|
+
connection_handler.establish_connection(db_config, owner_name: self, role: current_role, shard: current_shard)
|
53
54
|
end
|
54
55
|
|
55
56
|
# Connects a model to the databases specified. The +database+ keyword
|
56
57
|
# takes a hash consisting of a +role+ and a +database_key+.
|
57
58
|
#
|
58
|
-
# This will
|
59
|
-
#
|
60
|
-
# establishes a connection to that config.
|
59
|
+
# This will look up the database config using the +database_key+ and
|
60
|
+
# establish a connection to that config.
|
61
61
|
#
|
62
62
|
# class AnimalsModel < ApplicationRecord
|
63
63
|
# self.abstract_class = true
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
# end
|
67
67
|
#
|
68
68
|
# +connects_to+ also supports horizontal sharding. The horizontal sharding API
|
69
|
-
#
|
69
|
+
# supports read replicas as well. You can connect a model to a list of shards like this:
|
70
70
|
#
|
71
71
|
# class AnimalsModel < ApplicationRecord
|
72
72
|
# self.abstract_class = true
|
@@ -87,21 +87,18 @@ module ActiveRecord
|
|
87
87
|
|
88
88
|
connections = []
|
89
89
|
|
90
|
-
|
91
|
-
|
92
|
-
handler = lookup_connection_handler(role.to_sym)
|
93
|
-
|
94
|
-
self.connection_class = true
|
95
|
-
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
90
|
+
if shards.empty?
|
91
|
+
shards[:default] = database
|
96
92
|
end
|
97
93
|
|
94
|
+
self.default_shard = shards.keys.first
|
95
|
+
|
98
96
|
shards.each do |shard, database_keys|
|
99
97
|
database_keys.each do |role, database_key|
|
100
|
-
db_config
|
101
|
-
handler = lookup_connection_handler(role.to_sym)
|
98
|
+
db_config = resolve_config_for_connection(database_key)
|
102
99
|
|
103
100
|
self.connection_class = true
|
104
|
-
connections <<
|
101
|
+
connections << connection_handler.establish_connection(db_config, owner_name: self, role: role, shard: shard.to_sym)
|
105
102
|
end
|
106
103
|
end
|
107
104
|
|
@@ -135,18 +132,12 @@ module ActiveRecord
|
|
135
132
|
# Dog.first # finds first Dog record stored on the shard one replica
|
136
133
|
# end
|
137
134
|
def connected_to(role: nil, shard: nil, prevent_writes: false, &blk)
|
138
|
-
if
|
139
|
-
|
140
|
-
|
141
|
-
end
|
142
|
-
else
|
143
|
-
if self != Base && !abstract_class
|
144
|
-
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
|
145
|
-
end
|
135
|
+
if self != Base && !abstract_class
|
136
|
+
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
|
137
|
+
end
|
146
138
|
|
147
|
-
|
148
|
-
|
149
|
-
end
|
139
|
+
if !connection_class? && !primary_class?
|
140
|
+
raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
|
150
141
|
end
|
151
142
|
|
152
143
|
unless role || shard
|
@@ -172,10 +163,6 @@ module ActiveRecord
|
|
172
163
|
def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
|
173
164
|
classes = classes.flatten
|
174
165
|
|
175
|
-
if ActiveRecord.legacy_connection_handling
|
176
|
-
raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
|
177
|
-
end
|
178
|
-
|
179
166
|
if self != Base || classes.include?(Base)
|
180
167
|
raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
|
181
168
|
end
|
@@ -196,10 +183,6 @@ module ActiveRecord
|
|
196
183
|
# It is not recommended to use this method in a request since it
|
197
184
|
# does not yield to a block like +connected_to+.
|
198
185
|
def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
|
199
|
-
if ActiveRecord.legacy_connection_handling
|
200
|
-
raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
|
201
|
-
end
|
202
|
-
|
203
186
|
prevent_writes = true if role == ActiveRecord.reading_role
|
204
187
|
|
205
188
|
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
@@ -236,40 +219,31 @@ module ActiveRecord
|
|
236
219
|
# See +READ_QUERY+ for the queries that are blocked by this
|
237
220
|
# method.
|
238
221
|
def while_preventing_writes(enabled = true, &block)
|
239
|
-
|
240
|
-
connection_handler.while_preventing_writes(enabled, &block)
|
241
|
-
else
|
242
|
-
connected_to(role: current_role, prevent_writes: enabled, &block)
|
243
|
-
end
|
222
|
+
connected_to(role: current_role, prevent_writes: enabled, &block)
|
244
223
|
end
|
245
224
|
|
246
|
-
# Returns true if role is the current connected role
|
225
|
+
# Returns true if role is the current connected role and/or
|
226
|
+
# current connected shard. If no shard is passed, the default will be
|
227
|
+
# used.
|
247
228
|
#
|
248
229
|
# ActiveRecord::Base.connected_to(role: :writing) do
|
249
230
|
# ActiveRecord::Base.connected_to?(role: :writing) #=> true
|
250
231
|
# ActiveRecord::Base.connected_to?(role: :reading) #=> false
|
251
232
|
# end
|
233
|
+
#
|
234
|
+
# ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one) do
|
235
|
+
# ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one) #=> true
|
236
|
+
# ActiveRecord::Base.connected_to?(role: :reading, shard: :default) #=> false
|
237
|
+
# ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one) #=> true
|
238
|
+
# end
|
252
239
|
def connected_to?(role:, shard: ActiveRecord::Base.default_shard)
|
253
240
|
current_role == role.to_sym && current_shard == shard.to_sym
|
254
241
|
end
|
255
242
|
|
256
|
-
def lookup_connection_handler(handler_key) # :nodoc:
|
257
|
-
if ActiveRecord.legacy_connection_handling
|
258
|
-
handler_key ||= ActiveRecord.writing_role
|
259
|
-
connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
260
|
-
else
|
261
|
-
ActiveRecord::Base.connection_handler
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
243
|
# Clears the query cache for all connections associated with the current thread.
|
266
244
|
def clear_query_caches_for_current_thread
|
267
|
-
|
268
|
-
|
269
|
-
clear_on_handler(handler)
|
270
|
-
end
|
271
|
-
else
|
272
|
-
clear_on_handler(ActiveRecord::Base.connection_handler)
|
245
|
+
connection_handler.each_connection_pool do |pool|
|
246
|
+
pool.connection.clear_query_cache if pool.active_connection?
|
273
247
|
end
|
274
248
|
end
|
275
249
|
|
@@ -298,7 +272,7 @@ module ActiveRecord
|
|
298
272
|
#
|
299
273
|
# ActiveRecord::Base.connection_db_config
|
300
274
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
301
|
-
# @name="primary", @config={pool: 5, timeout: 5000, database: "
|
275
|
+
# @name="primary", @config={pool: 5, timeout: 5000, database: "storage/development.sqlite3", adapter: "sqlite3"}>
|
302
276
|
#
|
303
277
|
# Use only for reading.
|
304
278
|
def connection_db_config
|
@@ -319,6 +293,14 @@ module ActiveRecord
|
|
319
293
|
end
|
320
294
|
|
321
295
|
def remove_connection(name = nil)
|
296
|
+
if name
|
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
|
303
|
+
|
322
304
|
name ||= @connection_specification_name if defined?(@connection_specification_name)
|
323
305
|
# if removing a connection that has a pool, we reset the
|
324
306
|
# connection_specification_name so it will use the parent
|
@@ -334,47 +316,51 @@ module ActiveRecord
|
|
334
316
|
connection.schema_cache.clear!
|
335
317
|
end
|
336
318
|
|
337
|
-
|
338
|
-
|
319
|
+
def clear_active_connections!(role = nil)
|
320
|
+
deprecation_for_delegation(__method__)
|
321
|
+
connection_handler.clear_active_connections!(role)
|
322
|
+
end
|
323
|
+
|
324
|
+
def clear_reloadable_connections!(role = nil)
|
325
|
+
deprecation_for_delegation(__method__)
|
326
|
+
connection_handler.clear_reloadable_connections!(role)
|
327
|
+
end
|
328
|
+
|
329
|
+
def clear_all_connections!(role = nil)
|
330
|
+
deprecation_for_delegation(__method__)
|
331
|
+
connection_handler.clear_all_connections!(role)
|
332
|
+
end
|
333
|
+
|
334
|
+
def flush_idle_connections!(role = nil)
|
335
|
+
deprecation_for_delegation(__method__)
|
336
|
+
connection_handler.flush_idle_connections!(role)
|
337
|
+
end
|
339
338
|
|
340
339
|
private
|
341
|
-
def
|
342
|
-
|
343
|
-
|
344
|
-
|
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
|
345
346
|
end
|
346
347
|
|
347
348
|
def resolve_config_for_connection(config_or_env)
|
348
349
|
raise "Anonymous class is not allowed." unless name
|
349
350
|
|
350
|
-
|
351
|
-
self.connection_specification_name =
|
351
|
+
connection_name = primary_class? ? Base.name : name
|
352
|
+
self.connection_specification_name = connection_name
|
352
353
|
|
353
|
-
|
354
|
-
[db_config, self]
|
355
|
-
end
|
356
|
-
|
357
|
-
def with_handler(handler_key, &blk)
|
358
|
-
handler = lookup_connection_handler(handler_key)
|
359
|
-
swap_connection_handler(handler, &blk)
|
354
|
+
Base.configurations.resolve(config_or_env)
|
360
355
|
end
|
361
356
|
|
362
357
|
def with_role_and_shard(role, shard, prevent_writes)
|
363
358
|
prevent_writes = true if role == ActiveRecord.reading_role
|
364
359
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
yield
|
370
|
-
end
|
371
|
-
end
|
372
|
-
else
|
373
|
-
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
374
|
-
return_value = yield
|
375
|
-
return_value.load if return_value.is_a? ActiveRecord::Relation
|
376
|
-
return_value
|
377
|
-
end
|
360
|
+
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
|
361
|
+
return_value = yield
|
362
|
+
return_value.load if return_value.is_a? ActiveRecord::Relation
|
363
|
+
return_value
|
378
364
|
ensure
|
379
365
|
self.connected_to_stack.pop
|
380
366
|
end
|
@@ -386,14 +372,5 @@ module ActiveRecord
|
|
386
372
|
|
387
373
|
connected_to_stack << entry
|
388
374
|
end
|
389
|
-
|
390
|
-
def swap_connection_handler(handler, &blk) # :nodoc:
|
391
|
-
old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
|
392
|
-
return_value = yield
|
393
|
-
return_value.load if return_value.is_a? ActiveRecord::Relation
|
394
|
-
return_value
|
395
|
-
ensure
|
396
|
-
ActiveRecord::Base.connection_handler = old_handler
|
397
|
-
end
|
398
375
|
end
|
399
376
|
end
|