class ActiveRecord::ConnectionAdapters::SQLServerAdapter

Constants

ADAPTER_NAME
DEFAULT_TIME_PRECISION

Default precision for 'time' (See docs.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql)

USING_JDBC_DRIVER

Attributes

spid[R]

Public Class Methods

new(connection, logger = nil, config = {}) click to toggle source
Calls superclass method
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 72
def initialize(connection, logger = nil, config = {})
  super(connection, logger, config)
  # Our Responsibility
  @connection_options = config
  connect
  initialize_dateformatter
  use_database
end

Public Instance Methods

active?() click to toggle source

Abstract Adapter (Connection Management) ================== #

# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 173
def active?
  return false unless @connection
  raw_connection_do 'SELECT 1'
  true
rescue *connection_errors
  false
end
arel_visitor() click to toggle source

Abstract Adapter ========================================== #

# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 83
def arel_visitor
  Arel::Visitors::SQLServer.new self
end
clear_cache!() click to toggle source
Calls superclass method
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 198
def clear_cache!
  @view_information = nil
  super
end
combine_bind_parameters(from_clause: [], join_clause: [], where_clause: [], having_clause: [], limit: nil, offset: nil) click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 264
def combine_bind_parameters(from_clause: [], join_clause: [], where_clause: [], having_clause: [], limit: nil, offset: nil)
  result = from_clause + join_clause + where_clause + having_clause
  result << offset if offset
  result << limit if limit
  result
end
database_prefix() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 244
def database_prefix
  @connection_options[:database_prefix]
end
database_prefix_identifier(name) click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 248
def database_prefix_identifier(name)
  if database_prefix_remote_server?
    SQLServer::Utils.extract_identifiers("#{database_prefix}#{name}")
  else
    SQLServer::Utils.extract_identifiers(name)
  end
end
database_prefix_remote_server?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 238
def database_prefix_remote_server?
  return false if database_prefix.blank?
  name = SQLServer::Utils.extract_identifiers(database_prefix)
  name.fully_qualified? && name.object.blank?
end
disable_referential_integrity() { || ... } click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 163
def disable_referential_integrity
  tables = tables_with_referential_integrity
  tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} NOCHECK CONSTRAINT ALL" }
  yield
ensure
  tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} CHECK CONSTRAINT ALL" }
end
disconnect!() click to toggle source
Calls superclass method
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 187
def disconnect!
  super
  case @connection_options[:mode]
  when :dblib
    @connection.close rescue nil
  end
  @connection = nil unless USING_JDBC_DRIVER
  @spid = nil
  @collation = nil
end
inspect() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 260
def inspect
  "#<#{self.class} version: #{version}, mode: #{@connection_options[:mode]}, azure: #{sqlserver_azure?.inspect}>"
end
pk_and_sequence_for(table_name) click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 223
def pk_and_sequence_for(table_name)
  pk = primary_key(table_name)
  pk ? [pk, nil] : nil
end
reconnect!() click to toggle source
Calls superclass method
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 181
def reconnect!
  super
  disconnect! unless USING_JDBC_DRIVER # Don't need to disconnect in JDBC
  connect
end
reset!() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 203
def reset!
  reset_transaction
  do_execute 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION'
end
schema_creation() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 91
def schema_creation
  SQLServer::SchemaCreation.new self
end
sqlserver?() click to toggle source

SQLServer Specific (DB Reflection) ======================== #

# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 230
def sqlserver?
  true
end
sqlserver_azure?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 234
def sqlserver_azure?
  !!(sqlserver_version =~ /Azure/i)
end
supports_advisory_locks?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 103
def supports_advisory_locks?
  false
end
supports_bulk_alter?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 99
def supports_bulk_alter?
  false
end
supports_comments?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 147
def supports_comments?
  false
end
supports_comments_in_create?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 151
def supports_comments_in_create?
  false
end
supports_datetime_with_precision?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 139
def supports_datetime_with_precision?
  true
end
supports_ddl_transactions?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 95
def supports_ddl_transactions?
  true
end
supports_explain?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 119
def supports_explain?
  true
end
supports_expression_index?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 115
def supports_expression_index?
  false
end
supports_foreign_keys?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 131
def supports_foreign_keys?
  true
end
supports_in_memory_oltp?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 159
def supports_in_memory_oltp?
  @version_year >= 2014
end
supports_index_sort_order?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 107
def supports_index_sort_order?
  true
end
supports_indexes_in_create?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 127
def supports_indexes_in_create?
  false
end
supports_json?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 143
def supports_json?
  @version_year >= 2016
end
supports_partial_index?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 111
def supports_partial_index?
  true
end
supports_savepoints?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 155
def supports_savepoints?
  true
end
supports_transaction_isolation?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 123
def supports_transaction_isolation?
  true
end
supports_views?() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 135
def supports_views?
  true
end
tables_with_referential_integrity() click to toggle source

Abstract Adapter (Misc Support) =========================== #

# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 210
      def tables_with_referential_integrity
        schemas_and_tables = select_rows <<-SQL.strip_heredoc
          SELECT DISTINCT s.name AS schema_name, o.name AS table_name
          FROM sys.foreign_keys i
          INNER JOIN sys.objects o ON i.parent_object_id = o.OBJECT_ID
          INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
        SQL
        schemas_and_tables.map do |schema_table|
          schema, table = schema_table
          "#{SQLServer::Utils.quoted_raw(schema)}.#{SQLServer::Utils.quoted_raw(table)}"
        end
      end
valid_type?(type) click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 87
def valid_type?(type)
  !native_database_types[type].nil?
end
version() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 256
def version
  self.class::VERSION
end

Protected Instance Methods

config_appname(config) click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 422
def config_appname(config)
  config[:appname] || configure_application_name || Rails.application.class.name.split('::').first rescue nil
end
config_encoding(config) click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 434
def config_encoding(config)
  config[:encoding].present? ? config[:encoding] : nil
end
config_login_timeout(config) click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 426
def config_login_timeout(config)
  config[:login_timeout].present? ? config[:login_timeout].to_i : nil
end
config_timeout(config) click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 430
def config_timeout(config)
  config[:timeout].present? ? config[:timeout].to_i / 1000 : nil
end
configure_application_name() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 440
def configure_application_name ; end
configure_connection() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 438
def configure_connection ; end
connect() click to toggle source

SQLServer Specific (Connection Management) ================ #

# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 373
def connect
  config = @connection_options
  @connection = case config[:mode]
                when :dblib
                  dblib_connect(config)
                end
  @spid = _raw_select('SELECT @@SPID', fetch: :rows).first.first
  @version_year = version_year
  configure_connection
end
connection_errors() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 384
def connection_errors
  @connection_errors ||= [].tap do |errors|
    errors << TinyTds::Error if defined?(TinyTds::Error)
  end
end
dblib_connect(config) click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 390
def dblib_connect(config)
  TinyTds::Client.new(
    dataserver: config[:dataserver],
    host: config[:host],
    port: config[:port],
    username: config[:username],
    password: config[:password],
    database: config[:database],
    tds_version: config[:tds_version] || '7.3',
    appname: config_appname(config),
    login_timeout: config_login_timeout(config),
    timeout: config_timeout(config),
    encoding:  config_encoding(config),
    azure: config[:azure],
    contained: config[:contained]
  ).tap do |client|
    if config[:azure]
      client.execute('SET ANSI_NULLS ON').do
      client.execute('SET ANSI_NULL_DFLT_ON ON').do
      client.execute('SET ANSI_PADDING ON').do
      client.execute('SET ANSI_WARNINGS ON').do
    else
      client.execute('SET ANSI_DEFAULTS ON').do
    end
    client.execute('SET QUOTED_IDENTIFIER ON').do
    client.execute('SET CURSOR_CLOSE_ON_COMMIT OFF').do
    client.execute('SET IMPLICIT_TRANSACTIONS OFF').do
    client.execute('SET TEXTSIZE 2147483647').do
    client.execute('SET CONCAT_NULL_YIELDS_NULL ON').do
  end
end
initialize_dateformatter() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 442
def initialize_dateformatter
  @database_dateformat = user_options_dateformat
  a, b, c = @database_dateformat.each_char.to_a
  [a, b, c].each { |f| f.upcase! if f == 'y' }
  dateformat = "%#{a}-%#{b}-%#{c}"
  ::Date::DATE_FORMATS[:_sqlserver_dateformat]     = dateformat
  ::Time::DATE_FORMATS[:_sqlserver_dateformat]     = dateformat
  ::Time::DATE_FORMATS[:_sqlserver_time]           = '%H:%M:%S'
  ::Time::DATE_FORMATS[:_sqlserver_datetime]       = "#{dateformat} %H:%M:%S"
  ::Time::DATE_FORMATS[:_sqlserver_datetimeoffset] = lambda { |time|
    time.strftime "#{dateformat} %H:%M:%S.%9N #{time.formatted_offset}"
  }
end
initialize_type_map(m = type_map) click to toggle source

Abstract Adapter (Misc Support) =========================== #

# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 276
def initialize_type_map(m = type_map)
  m.register_type              %r{.*},            SQLServer::Type::UnicodeString.new
  # Exact Numerics
  register_class_with_limit m, 'bigint(8)',         SQLServer::Type::BigInteger
  m.alias_type                 'bigint',            'bigint(8)'
  register_class_with_limit m, 'int(4)',            SQLServer::Type::Integer
  m.alias_type                 'integer',           'int(4)'
  m.alias_type                 'int',               'int(4)'
  register_class_with_limit m, 'smallint(2)',       SQLServer::Type::SmallInteger
  m.alias_type                 'smallint',          'smallint(2)'
  register_class_with_limit m, 'tinyint(1)',        SQLServer::Type::TinyInteger
  m.alias_type                 'tinyint',           'tinyint(1)'
  m.register_type              'bit',               SQLServer::Type::Boolean.new
  m.register_type              %r{\Adecimal}i do |sql_type|
    scale = extract_scale(sql_type)
    precision = extract_precision(sql_type)
    SQLServer::Type::Decimal.new precision: precision, scale: scale
  end
  m.alias_type                 %r{\Anumeric}i,      'decimal'
  m.register_type              'money',             SQLServer::Type::Money.new
  m.register_type              'smallmoney',        SQLServer::Type::SmallMoney.new
  # Approximate Numerics
  m.register_type              'float',             SQLServer::Type::Float.new
  m.register_type              'real',              SQLServer::Type::Real.new
  # Date and Time
  m.register_type              'date',              SQLServer::Type::Date.new
  m.register_type              %r{\Adatetime} do |sql_type|
    precision = extract_precision(sql_type)
    if precision
      SQLServer::Type::DateTime2.new precision: precision
    else
      SQLServer::Type::DateTime.new
    end
  end
  m.register_type              %r{\Adatetimeoffset}i do |sql_type|
    precision = extract_precision(sql_type)
    SQLServer::Type::DateTimeOffset.new precision: precision
  end
  m.register_type              'smalldatetime',     SQLServer::Type::SmallDateTime.new
  m.register_type              %r{\Atime}i do |sql_type|
    precision = extract_precision(sql_type) || DEFAULT_TIME_PRECISION
    SQLServer::Type::Time.new precision: precision
  end
  # Character Strings
  register_class_with_limit m, %r{\Achar}i,         SQLServer::Type::Char
  register_class_with_limit m, %r{\Avarchar}i,      SQLServer::Type::Varchar
  m.register_type              'varchar(max)',      SQLServer::Type::VarcharMax.new
  m.register_type              'text',              SQLServer::Type::Text.new
  # Unicode Character Strings
  register_class_with_limit m, %r{\Anchar}i,        SQLServer::Type::UnicodeChar
  register_class_with_limit m, %r{\Anvarchar}i,     SQLServer::Type::UnicodeVarchar
  m.alias_type                 'string',            'nvarchar(4000)'
  m.register_type              'nvarchar(max)',     SQLServer::Type::UnicodeVarcharMax.new
  m.register_type              'nvarchar(max)',     SQLServer::Type::UnicodeVarcharMax.new
  m.register_type              'ntext',             SQLServer::Type::UnicodeText.new
  # Binary Strings
  register_class_with_limit m, %r{\Abinary}i,       SQLServer::Type::Binary
  register_class_with_limit m, %r{\Avarbinary}i,    SQLServer::Type::Varbinary
  m.register_type              'varbinary(max)',    SQLServer::Type::VarbinaryMax.new
  # Other Data Types
  m.register_type              'uniqueidentifier',  SQLServer::Type::Uuid.new
  m.register_type              'timestamp',         SQLServer::Type::Timestamp.new
end
sqlserver_version() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 463
def sqlserver_version
  @sqlserver_version ||= _raw_select('SELECT @@version', fetch: :rows).first.first.to_s
end
translate_exception(e, message) click to toggle source
Calls superclass method
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 340
def translate_exception(e, message)
  case message
  when /(cannot insert duplicate key .* with unique index) | (violation of unique key constraint)/i
    RecordNotUnique.new(message)
  when /conflicted with the foreign key constraint/i
    InvalidForeignKey.new(message)
  when /has been chosen as the deadlock victim/i
    DeadlockVictim.new(message)
  when /database .* does not exist/i
    NoDatabaseError.new(message)
  when /data would be truncated/
    ValueTooLong.new(message)
  when /Column '(.*)' is not the same data type as referencing column '(.*)' in foreign key/
    pk_id, fk_id = SQLServer::Utils.extract_identifiers($1), SQLServer::Utils.extract_identifiers($2)
    MismatchedForeignKey.new(
      self,
      message: message,
      table: fk_id.schema,
      foreign_key: fk_id.object,
      target_table: pk_id.schema,
      primary_key: pk_id.object
    )
  when /Cannot insert the value NULL into column.*does not allow nulls/
    NotNullViolation.new(message)
  when /Arithmetic overflow error/
    RangeError.new(message)
  else
    super
  end
end
version_year() click to toggle source
# File lib/active_record/connection_adapters/sqlserver_adapter.rb, line 456
def version_year
  return 2016 if sqlserver_version =~ /vNext/
  /SQL Server (\d+)/.match(sqlserver_version).to_a.last.to_s.to_i
rescue StandardError => e
  2016
end