Skip to content

Commit

Permalink
Fix test failures for AR 6.1 and AR 7.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lorint committed Jan 13, 2023
1 parent 9cc4a25 commit be7812e
Showing 1 changed file with 72 additions and 10 deletions.
82 changes: 72 additions & 10 deletions lib/trilogy_adapter/backwards_ar_compatibility.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,49 @@ class ConnectionFailed < QueryAborted
end
end

# For ActiveRecord <= 6.1
unless const_defined?("DatabaseConnectionError")
class DatabaseConnectionError < ConnectionNotEstablished
def initialize(message = nil)
super(message || "Database connection error")
end

class << self
def hostname_error(hostname)
DatabaseConnectionError.new(<<~MSG)
There is an issue connecting with your hostname: #{hostname}.\n
Please check your database configuration and ensure there is a valid connection to your database.
MSG
end

def username_error(username)
DatabaseConnectionError.new(<<~MSG)
There is an issue connecting to your database with your username/password, username: #{username}.\n
Please check your database configuration to ensure the username/password are valid.
MSG
end
end
end
end

# For ActiveRecord <= 6.1
unless NoDatabaseError.respond_to?(:db_error)
NoDatabaseError.class_exec do
def self.db_error(db_name)
NoDatabaseError.new(<<~MSG)
We could not find your database: #{db_name}. Available database configurations can be found in config/database.yml file.
To resolve this error:
- Did you create the database for this app, or delete it? You may need to create your database.
- Has the database name changed? Check your database.yml config has the correct database name.
To create your database, run:\n\n bin/rails db:create
MSG
end
end
end

require "active_record/connection_adapters/abstract_mysql_adapter"
module ConnectionAdapters
unless AbstractAdapter.private_instance_methods.include?(:with_raw_connection)
Expand All @@ -36,16 +79,14 @@ def initialize(version_string, full_version_string = nil)
# For ActiveRecord <= 7.0
def with_raw_connection(allow_retry: false, uses_transaction: true)
@lock.synchronize do
@raw_connection = nil unless instance_variable_defined?(:@raw_connection)
verify! unless @verified # || (@raw_connection.server_status & 1).positive?
@raw_connection = @connection || nil unless instance_variable_defined?(:@raw_connection)
verify! unless @verified # || (@raw_connection&.closed? == false && (@raw_connection.server_status & 1).positive?)
materialize_transactions if uses_transaction
begin
yield @raw_connection
rescue StandardError => exception
@verified = false unless exception.is_a?(Deadlocked) || exception.is_a?(LockWaitTimeout)
# raise translate_exception_class(exception, nil, nil)
# raise translate_exception(exception, message: exception.message, sql: nil, binds: nil)
raise exception
raise
end
end
end
Expand Down Expand Up @@ -97,27 +138,48 @@ def reconnect!
end
alias :reset! :reconnect!

def exec_rollback_db_transaction
# 16384 tests the bit flag for SERVER_SESSION_STATE_CHANGED, which gets set when the
# last statement executed has caused a change in the server's state.
if active? || (@raw_connection.server_status & 16384).positive?
super
else
@verified = false
end
end

# For ActiveRecord <= 6.1
if AbstractMysqlAdapter.instance_method(:execute).parameters.length < 3
# Adds an #execute specific to the TrilogyAdapter that allows
# (but disregards) +async+ and other keyword parameters.
alias raw_execute execute
def execute(sql, name = nil, **kwargs)
@raw_connection = nil unless instance_variable_defined?(:@raw_connection)
# 16384 tests the bit flag for SERVER_SESSION_STATE_CHANGED, which gets set when the
# last statement executed has caused a change in the server's state.
# Was: (!@verified && !active?)
reconnect if @raw_connection.nil? || (!@verified && (@raw_connection&.server_status & 16384).zero?)
reconnect if @raw_connection.nil? || (!@verified && (@raw_connection.server_status & 16384).zero?)
if default_timezone == :local
@raw_connection.query_flags |= ::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
else
@raw_connection.query_flags &= ~::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
end
raw_execute(sql, name)
rescue => original_exception
@verified = false unless original_exception.is_a?(Deadlocked) || original_exception.is_a?(LockWaitTimeout)
rescue => exception
return if exception.is_a?(Deadlocked)

@verified = false unless exception.is_a?(LockWaitTimeout)
raise
end
else # For ActiveRecord 7.0
def execute(sql, name = nil, **kwargs)
sql = transform_query(sql)
check_if_write_query(sql)
begin
super
rescue => exception
@verified = true if exception.is_a?(ActiveRecord::StatementInvalid) && (@raw_connection.server_status & 16384).positive?
raise
end
end
end

private
Expand Down

0 comments on commit be7812e

Please sign in to comment.