class ActiveRecord::ConnectionAdapters::AbstractAdapter

Active Record Abstract Adapter

Active Record supports multiple database systems. AbstractAdapter and related classes form the abstraction layer which makes this possible. An AbstractAdapter represents a connection to a database, and provides an abstract interface for database-specific functionality such as establishing a connection, escaping values, building the right SQL fragments for :offset and :limit options, etc.

All the concrete database adapters follow the interface laid down in this class. ActiveRecord::Base.lease_connection returns an AbstractAdapter object, which you can use.

Most of the methods in the adapter are useful during migrations. Most notably, the instance methods provided by SchemaStatements are very useful.

Constants

ADAPTER_NAME
COMMENT_REGEX
EXTENDED_TYPE_MAPS
SIMPLE_INT
TYPE_MAP

Attributes

in_use?[R]
lock[R]
logger[R]
owner[R]
pool[R]
visitor[R]

Public Class Methods

database_exists?(config) click to toggle source

Does the database for this adapter exist?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 360
def self.database_exists?(config)
  new(config).database_exists?
end
dbconsole(config, options = {}) click to toggle source

Opens a database console session.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 121
def self.dbconsole(config, options = {})
  raise NotImplementedError
end
find_cmd_and_exec(commands, *args) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 92
def self.find_cmd_and_exec(commands, *args) # :doc:
  commands = Array(commands)

  dirs_on_path = ENV["PATH"].to_s.split(File::PATH_SEPARATOR)
  unless (ext = RbConfig::CONFIG["EXEEXT"]).empty?
    commands = commands.map { |cmd| "#{cmd}#{ext}" }
  end

  full_path_command = nil
  found = commands.detect do |cmd|
    dirs_on_path.detect do |path|
      full_path_command = File.join(path, cmd)
      begin
        stat = File.stat(full_path_command)
      rescue SystemCallError
      else
        stat.file? && stat.executable?
      end
    end
  end

  if found
    exec full_path_command, *args
  else
    abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
  end
end
type_cast_config_to_boolean(config) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 65
def self.type_cast_config_to_boolean(config)
  if config == "false"
    false
  else
    config
  end
end
type_cast_config_to_integer(config) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 55
def self.type_cast_config_to_integer(config)
  if config.is_a?(Integer)
    config
  elsif SIMPLE_INT.match?(config)
    config.to_i
  else
    config
  end
end
validate_default_timezone(config) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 73
def self.validate_default_timezone(config)
  case config
  when nil
  when "utc", "local"
    config.to_sym
  else
    raise ArgumentError, "default_timezone must be either 'utc' or 'local'"
  end
end

Private Class Methods

extract_limit(sql_type) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 936
def extract_limit(sql_type)
  $1.to_i if sql_type =~ /\((.*)\)/
end
extract_precision(sql_type) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 932
def extract_precision(sql_type)
  $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
end
extract_scale(sql_type) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 925
def extract_scale(sql_type)
  case sql_type
  when /\((\d+)\)/ then 0
  when /\((\d+)(,(\d+))\)/ then $3.to_i
  end
end
initialize_type_map(m) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 885
def initialize_type_map(m)
  register_class_with_limit m, %r(boolean)i,       Type::Boolean
  register_class_with_limit m, %r(char)i,          Type::String
  register_class_with_limit m, %r(binary)i,        Type::Binary
  register_class_with_limit m, %r(text)i,          Type::Text
  register_class_with_precision m, %r(date)i,      Type::Date
  register_class_with_precision m, %r(time)i,      Type::Time
  register_class_with_precision m, %r(datetime)i,  Type::DateTime
  register_class_with_limit m, %r(float)i,         Type::Float
  register_class_with_limit m, %r(int)i,           Type::Integer

  m.alias_type %r(blob)i,      "binary"
  m.alias_type %r(clob)i,      "text"
  m.alias_type %r(timestamp)i, "datetime"
  m.alias_type %r(numeric)i,   "decimal"
  m.alias_type %r(number)i,    "decimal"
  m.alias_type %r(double)i,    "float"

  m.register_type %r(^json)i, Type::Json.new

  m.register_type(%r(decimal)i) do |sql_type|
    scale = extract_scale(sql_type)
    precision = extract_precision(sql_type)

    if scale == 0
      # FIXME: Remove this class as well
      Type::DecimalWithoutScale.new(precision: precision)
    else
      Type::Decimal.new(precision: precision, scale: scale)
    end
  end
end
register_class_with_limit(mapping, key, klass) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 918
def register_class_with_limit(mapping, key, klass)
  mapping.register_type(key) do |*args|
    limit = extract_limit(args.last)
    klass.new(limit: limit)
  end
end

Public Instance Methods

active?() click to toggle source

Checks whether the connection to the database is still active. This includes checking whether the database is actually capable of responding, i.e. whether the connection isn’t stale.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 658
def active?
end
adapter_name() click to toggle source

Returns the human-readable name of the adapter. Use mixed case - one can always use downcase if needed.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 355
def adapter_name
  self.class::ADAPTER_NAME
end
check_all_foreign_keys_valid!() click to toggle source

Override to check all foreign key constraints in a database. The adapter should raise a ActiveRecord::StatementInvalid if foreign key constraints are not met.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 643
def check_all_foreign_keys_valid!
end
clear_cache!(new_connection: false) click to toggle source

Clear any caching the database adapter may be doing.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 739
def clear_cache!(new_connection: false)
  if @statements
    @lock.synchronize do
      if new_connection
        @statements.reset
      else
        @statements.clear
      end
    end
  end
end
close() click to toggle source

Check the connection back in to the connection pool

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 829
def close
  pool.checkin self
end
connect!() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 777
def connect!
  verify!
  self
end
connected?() click to toggle source

Checks whether the connection to the database was established. This doesn’t include checking whether the database is actually capable of responding, i.e. whether the connection is stale.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 651
def connected?
  !@raw_connection.nil?
end
connection_retries() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 216
def connection_retries
  (@config[:connection_retries] || 1).to_i
end
database_exists?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 364
def database_exists?
  connect!
  true
rescue ActiveRecord::NoDatabaseError
  false
end
default_timezone() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 228
def default_timezone
  @default_timezone || ActiveRecord.default_timezone
end
disable_extension(name, **) click to toggle source

This is meant to be implemented by the adapters that support extensions

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 570
def disable_extension(name, **)
end
disable_referential_integrity() { || ... } click to toggle source

Override to turn off referential integrity while executing &block.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 636
def disable_referential_integrity
  yield
end
discard!() click to toggle source

Immediately forget this connection ever existed. Unlike disconnect!, this will not communicate with the server.

After calling this method, the behavior of all other methods becomes undefined. This is called internally just before a forked process gets rid of a connection that belonged to its parent.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 714
def discard!
  # This should be overridden by concrete adapters.
end
disconnect!() click to toggle source

Disconnects from the database if already connected. Otherwise, this method does nothing.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 700
def disconnect!
  @lock.synchronize do
    clear_cache!(new_connection: true)
    reset_transaction
    @raw_connection_dirty = false
  end
end
enable_extension(name, **) click to toggle source

This is meant to be implemented by the adapters that support extensions

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 574
def enable_extension(name, **)
end
expire() click to toggle source

this method must only be called while holding connection pool’s mutex

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 312
def expire
  if in_use?
    if @owner != ActiveSupport::IsolatedExecutionState.context
      raise ActiveRecordError, "Cannot expire connection, " \
        "it is owned by a different thread: #{@owner}. " \
        "Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
    end

    @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    @owner = nil
  else
    raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
  end
end
extensions() click to toggle source

A list of extensions, to be filled in by adapters that support them.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 624
def extensions
  []
end
index_algorithms() click to toggle source

A list of index algorithms, to be filled by adapters that support them.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 629
def index_algorithms
  {}
end
lease() click to toggle source

this method must only be called while holding connection pool’s mutex

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 276
def lease
  if in_use?
    msg = +"Cannot lease connection, "
    if @owner == ActiveSupport::IsolatedExecutionState.context
      msg << "it is already leased by the current thread."
    else
      msg << "it is already in use by a different thread: #{@owner}. " \
             "Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
    end
    raise ActiveRecordError, msg
  end

  @owner = ActiveSupport::IsolatedExecutionState.context
end
pool=(value) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 47
def pool=(value)
  return if value.eql?(@pool)
  @schema_cache = nil
  @pool = value
end
prefetch_primary_key?(table_name = nil) click to toggle source

Should primary key values be selected from their corresponding sequence before the insert statement? If true, next_sequence_value is called before each insert to set the record’s primary key.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 404
def prefetch_primary_key?(table_name = nil)
  false
end
prepared_statements()
prepared_statements?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 243
def prepared_statements?
  @prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
end
Also aliased as: prepared_statements
preventing_writes?() click to toggle source

Determines whether writes are currently being prevented.

Returns true if the connection is a replica or returns the value of current_preventing_writes.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 236
def preventing_writes?
  return true if replica?
  return false if connection_class.nil?

  connection_class.current_preventing_writes
end
raw_connection() click to toggle source

Provides access to the underlying database driver for this adapter. For example, this method returns a Mysql2::Client object in case of Mysql2Adapter, and a PG::Connection object in case of PostgreSQLAdapter.

This is useful for when you need to call a proprietary method such as PostgreSQL’s lo_* methods.

Active Record cannot track if the database is getting modified using this client. If that is the case, generally you’ll want to invalidate the query cache using ActiveRecord::Base.clear_query_cache.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 797
def raw_connection
  with_raw_connection do |conn|
    disable_lazy_transactions!
    @raw_connection_dirty = true
    conn
  end
end
reconnect!(restore_transactions: false) click to toggle source

Disconnects from the database if already connected, and establishes a new connection with the database. Implementors should define private reconnect instead.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 664
def reconnect!(restore_transactions: false)
  retries_available = connection_retries
  deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline

  @lock.synchronize do
    reconnect

    enable_lazy_transactions!
    @raw_connection_dirty = false
    @verified = true

    reset_transaction(restore: restore_transactions) do
      clear_cache!(new_connection: true)
      configure_connection
    end
  rescue => original_exception
    translated_exception = translate_exception_class(original_exception, nil, nil)
    retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)

    if !retry_deadline_exceeded && retries_available > 0
      retries_available -= 1

      if retryable_connection_error?(translated_exception)
        backoff(connection_retries - retries_available)
        retry
      end
    end

    @verified = false

    raise translated_exception
  end
end
replica?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 212
def replica?
  @config[:replica] || false
end
requires_reloading?() click to toggle source

Returns true if its required to reload the connection between requests for development mode.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 752
def requires_reloading?
  false
end
reset!() click to toggle source

Reset the state of this connection, directing the DBMS to clear transactions and other connection-related server-side state. Usually a database-dependent operation.

If a database driver or protocol does not support such a feature, implementors may alias this to reconnect!. Otherwise, implementors should call super immediately after resetting the connection (and while still holding @lock).

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 726
def reset!
  clear_cache!(new_connection: true)
  reset_transaction
  configure_connection
end
retry_deadline() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 220
def retry_deadline
  if @config[:retry_deadline]
    @config[:retry_deadline].to_f
  else
    nil
  end
end
role() click to toggle source

The role (e.g. :writing) for the current connection. In a non-multi role application, :writing is returned.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 297
def role
  @pool.role
end
savepoint_errors_invalidate_transactions?() click to toggle source

Do TransactionRollbackErrors on savepoints affect the parent transaction?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 388
def savepoint_errors_invalidate_transactions?
  false
end
schema_cache() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 307
def schema_cache
  @pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self))
end
schema_version() click to toggle source

Returns the version identifier of the schema currently available in the database. This is generally equal to the number of the highest- numbered migration that has been executed, or 0 if no schema information is present / the database is empty.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 864
def schema_version
  pool.migration_context.current_version
end
shard() click to toggle source

The shard (e.g. :default) for the current connection. In a non-sharded application, :default is returned.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 303
def shard
  @pool.shard
end
supports_advisory_locks?() click to toggle source

Does this adapter support application-enforced advisory locking?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 397
def supports_advisory_locks?
  false
end
supports_bulk_alter?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 377
def supports_bulk_alter?
  false
end
supports_check_constraints?() click to toggle source

Does this adapter support creating check constraints?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 469
def supports_check_constraints?
  false
end
supports_comments?() click to toggle source

Does this adapter support metadata comments on database objects (tables, columns, indexes)?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 504
def supports_comments?
  false
end
supports_comments_in_create?() click to toggle source

Can comments for tables, columns, and indexes be specified in create/alter table statements?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 509
def supports_comments_in_create?
  false
end
supports_common_table_expressions?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 528
def supports_common_table_expressions?
  false
end
supports_concurrent_connections?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 552
def supports_concurrent_connections?
  true
end
supports_datetime_with_precision?() click to toggle source

Does this adapter support datetime with precision?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 494
def supports_datetime_with_precision?
  false
end
supports_ddl_transactions?() click to toggle source

Does this adapter support DDL rollbacks in transactions? That is, would CREATE TABLE or ALTER TABLE get rolled back by a transaction?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 373
def supports_ddl_transactions?
  false
end
supports_deferrable_constraints?() click to toggle source

Does this adapter support creating deferrable constraints?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 464
def supports_deferrable_constraints?
  false
end
supports_exclusion_constraints?() click to toggle source

Does this adapter support creating exclusion constraints?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 474
def supports_exclusion_constraints?
  false
end
supports_explain?() click to toggle source

Does this adapter support explain?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 433
def supports_explain?
  false
end
supports_expression_index?() click to toggle source

Does this adapter support expression indices?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 428
def supports_expression_index?
  false
end
supports_extensions?() click to toggle source

Does this adapter support database extensions?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 443
def supports_extensions?
  false
end
supports_foreign_keys?() click to toggle source

Does this adapter support creating foreign key constraints?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 454
def supports_foreign_keys?
  false
end
supports_foreign_tables?() click to toggle source

Does this adapter support foreign/external tables?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 519
def supports_foreign_tables?
  false
end
supports_index_include?() click to toggle source

Does this adapter support including non-key columns?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 423
def supports_index_include?
  false
end
supports_index_sort_order?() click to toggle source

Does this adapter support index sort order?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 413
def supports_index_sort_order?
  false
end
supports_indexes_in_create?() click to toggle source

Does this adapter support creating indexes in the same statement as creating the table?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 449
def supports_indexes_in_create?
  false
end
supports_insert_conflict_target?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 548
def supports_insert_conflict_target?
  false
end
supports_insert_on_duplicate_skip?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 540
def supports_insert_on_duplicate_skip?
  false
end
supports_insert_on_duplicate_update?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 544
def supports_insert_on_duplicate_update?
  false
end
supports_insert_returning?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 536
def supports_insert_returning?
  false
end
supports_json?() click to toggle source

Does this adapter support JSON data type?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 499
def supports_json?
  false
end
supports_lazy_transactions?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 532
def supports_lazy_transactions?
  false
end
supports_materialized_views?() click to toggle source

Does this adapter support materialized views?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 489
def supports_materialized_views?
  false
end
supports_nulls_not_distinct?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 556
def supports_nulls_not_distinct?
  false
end
supports_optimizer_hints?() click to toggle source

Does this adapter support optimizer hints?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 524
def supports_optimizer_hints?
  false
end
supports_partial_index?() click to toggle source

Does this adapter support partial indices?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 418
def supports_partial_index?
  false
end
supports_partitioned_indexes?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 408
def supports_partitioned_indexes?
  false
end
supports_restart_db_transaction?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 392
def supports_restart_db_transaction?
  false
end
supports_savepoints?() click to toggle source

Does this adapter support savepoints?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 382
def supports_savepoints?
  false
end
supports_transaction_isolation?() click to toggle source

Does this adapter support setting the isolation level for a transaction?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 438
def supports_transaction_isolation?
  false
end
supports_unique_constraints?() click to toggle source

Does this adapter support creating unique constraints?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 479
def supports_unique_constraints?
  false
end
supports_validate_constraints?() click to toggle source

Does this adapter support creating invalid constraints?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 459
def supports_validate_constraints?
  false
end
supports_views?() click to toggle source

Does this adapter support views?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 484
def supports_views?
  false
end
supports_virtual_columns?() click to toggle source

Does this adapter support virtual columns?

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 514
def supports_virtual_columns?
  false
end
throw_away!() click to toggle source

Removes the connection from the pool and disconnect it.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 733
def throw_away!
  pool.remove self
  disconnect!
end
unprepared_statement() { || ... } click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 346
def unprepared_statement
  cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
  yield
ensure
  cache&.delete(object_id)
end
verify!() click to toggle source

Checks whether the connection to the database is still active (i.e. not stale). This is done under the hood by calling active?. If the connection is no longer active, then this method will reconnect to the database.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 759
def verify!
  unless active?
    @lock.synchronize do
      if @unconfigured_connection
        @raw_connection = @unconfigured_connection
        @unconfigured_connection = nil
        configure_connection
        @verified = true
        return
      end

      reconnect!(restore_transactions: true)
    end
  end

  @verified = true
end

Private Instance Methods

any_raw_connection() click to toggle source

Returns a raw connection for internal use with methods that are known to both be thread-safe and not rely upon actual server communication. This is useful for e.g. string escaping methods.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1083
def any_raw_connection
  @raw_connection || valid_raw_connection
end
arel_visitor() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1180
def arel_visitor
  Arel::Visitors::ToSql.new(self)
end
backoff(counter) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1072
def backoff(counter)
  sleep 0.1 * counter
end
build_result(columns:, rows:, column_types: nil) click to toggle source

Builds the result object.

This is an internal hook to make possible connection adapters to build custom result objects with connection-specific data.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1191
def build_result(columns:, rows:, column_types: nil)
  ActiveRecord::Result.new(columns, rows, column_types)
end
build_statement_pool() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1184
def build_statement_pool
end
can_perform_case_insensitive_comparison_for?(column) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 823
def can_perform_case_insensitive_comparison_for?(column)
  true
end
collector() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1166
def collector
  if prepared_statements
    Arel::Collectors::Composite.new(
      Arel::Collectors::SQLString.new,
      Arel::Collectors::Bind.new,
    )
  else
    Arel::Collectors::SubstituteBinds.new(
      self,
      Arel::Collectors::SQLString.new,
    )
  end
end
column_for(table_name, column_name) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1155
def column_for(table_name, column_name)
  column_name = column_name.to_s
  columns(table_name).detect { |c| c.name == column_name } ||
    raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
end
column_for_attribute(attribute) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1161
def column_for_attribute(attribute)
  table_name = attribute.relation.name
  schema_cache.columns_hash(table_name)[attribute.name.to_s]
end
configure_connection() click to toggle source

Perform any necessary initialization upon the newly-established @raw_connection – this is the place to modify the adapter’s connection settings, run queries to configure any application-global “session” variables, etc.

Implementations may assume this method will only be called while holding @lock (or from initialize).

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1202
def configure_connection
  check_version
end
default_prepared_statements() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1206
def default_prepared_statements
  true
end
extended_type_map_key() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1100
def extended_type_map_key
  if @default_timezone
    { default_timezone: @default_timezone }
  end
end
invalidate_transaction(exception) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1058
def invalidate_transaction(exception)
  return unless exception.is_a?(TransactionRollbackError)
  return unless savepoint_errors_invalidate_transactions?

  current_transaction.invalidate!
end
log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, &block) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1128
def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, &block) # :doc:
  @instrumenter.instrument(
    "sql.active_record",
    sql:               sql,
    name:              name,
    binds:             binds,
    type_casted_binds: type_casted_binds,
    async:             async,
    connection:        self,
    transaction:       current_transaction.user_transaction.presence,
    row_count:         0,
    &block
  )
rescue ActiveRecord::StatementInvalid => ex
  raise ex.set_query(sql, binds)
end
reconnect() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1076
def reconnect
  raise NotImplementedError
end
reconnect_can_restore_state?() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 945
def reconnect_can_restore_state?
  transaction_manager.restorable? && !@raw_connection_dirty
end
retryable_connection_error?(exception) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1053
def retryable_connection_error?(exception)
  (exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
    exception.is_a?(ConnectionFailed)
end
retryable_query_error?(exception) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1065
def retryable_query_error?(exception)
  # We definitely can't retry if we were inside an invalidated transaction.
  return false if current_transaction.invalidated?

  exception.is_a?(Deadlocked) || exception.is_a?(LockWaitTimeout)
end
translate_exception(exception, message:, sql:, binds:) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1145
def translate_exception(exception, message:, sql:, binds:)
  # override in derived class
  case exception
  when RuntimeError, ActiveRecord::ActiveRecordError
    exception
  else
    ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
  end
end
translate_exception_class(native_error, sql, binds) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1116
def translate_exception_class(native_error, sql, binds)
  return native_error if native_error.is_a?(ActiveRecordError)

  message = "#{native_error.class.name}: #{native_error.message}"

  active_record_error = translate_exception(
    native_error, message: message, sql: sql, binds: binds
  )
  active_record_error.set_backtrace(native_error.backtrace)
  active_record_error
end
type_map() click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1106
def type_map
  if key = extended_type_map_key
    self.class::EXTENDED_TYPE_MAPS.compute_if_absent(key) do
      self.class.extended_type_map(**key)
    end
  else
    self.class::TYPE_MAP
  end
end
valid_raw_connection() click to toggle source

Similar to any_raw_connection, but ensures it is validated and connected. Any method called on this result still needs to be independently thread-safe, so it probably shouldn’t talk to the server… but some drivers fail if they know the connection has gone away.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1092
def valid_raw_connection
  (@verified && @raw_connection) ||
    # `allow_retry: false`, to force verification: the block won't
    # raise, so a retry wouldn't help us get the valid connection we
    # need.
    with_raw_connection(allow_retry: false, materialize_transactions: false) { |conn| conn }
end
verified!() click to toggle source

Mark the connection as verified. Call this inside a ‘with_raw_connection` block only when the block is guaranteed to exercise the raw connection.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1049
def verified!
  @verified = true
end
warning_ignored?(warning) click to toggle source
# File lib/active_record/connection_adapters/abstract_adapter.rb, line 1210
def warning_ignored?(warning)
  ActiveRecord.db_warnings_ignore.any? do |warning_matcher|
    warning.message.match?(warning_matcher) || warning.code.to_s.match?(warning_matcher)
  end
end
with_raw_connection(allow_retry: false, materialize_transactions: true) { |raw_connection| ... } click to toggle source

Lock the monitor, ensure we’re properly connected and transactions are materialized, and then yield the underlying raw connection object.

If allow_retry is true, a connection-related exception will cause an automatic reconnect and re-run of the block, up to the connection’s configured connection_retries setting and the configured retry_deadline limit. (Note that when allow_retry is true, it’s possible to return without having marked the connection as verified. If the block is guaranteed to exercise the connection, consider calling ‘verified!` to avoid needless verification queries in subsequent calls.)

If materialize_transactions is false, the block will be run without ensuring virtual transactions have been materialized in the DB server’s state. The active transaction will also remain clean (if it is not already dirty), meaning it’s able to be restored by reconnecting and opening an equivalent-depth set of new transactions. This should only be used by transaction control methods, and internal transaction-agnostic queries.

It’s not the primary use case, so not something to optimize for, but note that this method does need to be re-entrant: materialize_transactions will re-enter if it has work to do, and the yield block can also do so under some circumstances.

In the latter case, we really ought to guarantee the inner call will not reconnect (which would interfere with the still-yielded connection in the outer block), but we currently provide no special enforcement there.

# File lib/active_record/connection_adapters/abstract_adapter.rb, line 982
def with_raw_connection(allow_retry: false, materialize_transactions: true)
  @lock.synchronize do
    connect! if @raw_connection.nil? && reconnect_can_restore_state?

    self.materialize_transactions if materialize_transactions

    retries_available = allow_retry ? connection_retries : 0
    deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
    reconnectable = reconnect_can_restore_state?

    if @verified
      # Cool, we're confident the connection's ready to use. (Note this might have
      # become true during the above #materialize_transactions.)
    elsif reconnectable
      if allow_retry
        # Not sure about the connection yet, but if anything goes wrong we can
        # just reconnect and re-run our query
      else
        # We can reconnect if needed, but we don't trust the upcoming query to be
        # safely re-runnable: let's verify the connection to be sure
        verify!
      end
    else
      # We don't know whether the connection is okay, but it also doesn't matter:
      # we wouldn't be able to reconnect anyway. We're just going to run our query
      # and hope for the best.
    end

    begin
      yield @raw_connection
    rescue => original_exception
      translated_exception = translate_exception_class(original_exception, nil, nil)
      invalidate_transaction(translated_exception)
      retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)

      if !retry_deadline_exceeded && retries_available > 0
        retries_available -= 1

        if retryable_query_error?(translated_exception)
          backoff(connection_retries - retries_available)
          retry
        elsif reconnectable && retryable_connection_error?(translated_exception)
          reconnect!(restore_transactions: true)
          # Only allowed to reconnect once, because reconnect! has its own retry
          # loop
          reconnectable = false
          retry
        end
      end

      unless retryable_query_error?(translated_exception)
        # Barring a known-retryable error inside the query (regardless of
        # whether we were in a _position_ to retry it), we should infer that
        # there's likely a real problem with the connection.
        @verified = false
      end

      raise translated_exception
    ensure
      dirty_current_transaction if materialize_transactions
    end
  end
end