Class: ActiveRecord::ConnectionAdapters::SQLServerAdapter

Inherits:
AbstractAdapter
  • Object
show all
Defined in:
lib/active_record/connection_adapters/sqlserver_adapter.rb

Overview

In ADO mode, this adapter will ONLY work on Windows systems, since it relies on Win32OLE, which, to my knowledge, is only available on Windows.

This mode also relies on the ADO support in the DBI module. If you are using the one-click installer of Ruby, then you already have DBI installed, but the ADO module is NOT installed. You will need to get the latest source distribution of Ruby-DBI from ruby-dbi.sourceforge.net/ unzip it, and copy the file from src/lib/dbd_ado/ADO.rb to X:/Ruby/lib/ruby/site_ruby/1.8/DBD/ADO/ADO.rb

You will more than likely need to create the ADO directory. Once you’ve installed that file, you are ready to go.

In ODBC mode, the adapter requires the ODBC support in the DBI module which requires the Ruby ODBC module. Ruby ODBC 0.996 was used in development and testing, and it is available at www.ch-werner.de/rubyodbc/

Options:

  • :mode – ADO or ODBC. Defaults to ADO.

  • :username – Defaults to sa.

  • :password – Defaults to empty string.

  • :windows_auth – Defaults to “User ID=#username;Password=#password”

ADO specific options:

  • :host – Defaults to localhost.

  • :database – The name of the database. No default, must be provided.

  • :windows_auth – Use windows authentication instead of username/password.

ODBC specific options:

  • :dsn – Defaults to nothing.

Constant Summary collapse

ADAPTER_NAME =
'SQLServer'.freeze
VERSION =
'2.2.18'.freeze
DATABASE_VERSION_REGEXP =
/Microsoft SQL Server\s+(\d{4})/
SUPPORTED_VERSIONS =
[2000,2005,2008].freeze
LIMITABLE_TYPES =
['string','integer','float','char','nchar','varchar','nvarchar'].freeze
LOST_CONNECTION_EXCEPTIONS =
[DBI::DatabaseError, DBI::InterfaceError]
LOST_CONNECTION_MESSAGES =
[
'Communication link failure',
'Read from the server failed',
'Write to the server failed',
'Database connection was already closed']
VALID_ISOLATION_LEVELS =
["READ COMMITTED", "READ UNCOMMITTED", "REPEATABLE READ", "SERIALIZABLE", "SNAPSHOT"]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger, connection_options) ⇒ SQLServerAdapter

Returns a new instance of SQLServerAdapter.



209
210
211
212
213
214
215
216
217
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 209

def initialize(logger, connection_options)
  @connection_options = connection_options
  connect
  super(raw_connection, logger)
  initialize_sqlserver_caches
  unless SUPPORTED_VERSIONS.include?(database_year)
    raise NotImplementedError, "Currently, only #{SUPPORTED_VERSIONS.to_sentence} are supported."
  end
end

Class Method Details

.type_limitable?(type) ⇒ Boolean

Returns:

  • (Boolean)


203
204
205
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 203

def type_limitable?(type)
  LIMITABLE_TYPES.include?(type.to_s)
end

Instance Method Details

#active?Boolean

CONNECTION MANAGEMENT ====================================#

Returns:

  • (Boolean)


351
352
353
354
355
356
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 351

def active?
  raw_connection.execute("SELECT 1").finish
  true
rescue *LOST_CONNECTION_EXCEPTIONS
  false
end

#adapter_nameObject

ABSTRACT ADAPTER =========================================#



221
222
223
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 221

def adapter_name
  ADAPTER_NAME
end

#add_column(table_name, column_name, type, options = {}) ⇒ Object



638
639
640
641
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 638

def add_column(table_name, column_name, type, options = {})
  super
  remove_sqlserver_columns_cache_for(table_name)
end

#add_limit_offset!(sql, options) ⇒ Object



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 447

def add_limit_offset!(sql, options)
  # Validate and/or convert integers for :limit and :offets options.
  if options[:offset]
    raise ArgumentError, "offset should have a limit" unless options[:limit]
    unless options[:offset].kind_of?(Integer)
      if options[:offset] =~ /^\d+$/
        options[:offset] = options[:offset].to_i
      else
        raise ArgumentError, "offset should be an integer"
      end
    end
  end
  if options[:limit] && !(options[:limit].kind_of?(Integer))
    if options[:limit] =~ /^\d+$/
      options[:limit] = options[:limit].to_i
    else
      raise ArgumentError, "limit should be an integer"
    end
  end
  # The business of adding limit/offset
  if options[:limit] and options[:offset]
    tally_sql = "SELECT count(*) as TotalRows from (#{sql.sub(/\bSELECT(\s+DISTINCT)?\b/i, "SELECT#{$1} TOP 1000000000")}) tally"
    add_lock! tally_sql, options
    total_rows = select_value(tally_sql).to_i
    if (options[:limit] + options[:offset]) >= total_rows
      options[:limit] = (total_rows - options[:offset] >= 0) ? (total_rows - options[:offset]) : 0
    end
    # Make sure we do not need a special limit/offset for association limiting. http://gist.github.com/25118
    add_limit_offset_for_association_limiting!(sql,options) and return if sql_for_association_limiting?(sql)
    # Wrap the SQL query in a bunch of outer SQL queries that emulate proper LIMIT,OFFSET support.
    sql.sub!(/^\s*SELECT(\s+DISTINCT)?/i, "SELECT * FROM (SELECT TOP #{options[:limit]} * FROM (SELECT#{$1} TOP #{options[:limit] + options[:offset]}")
    sql << ") AS tmp1"
    if options[:order]
      order = options[:order].split(',').map do |field|
        order_by_column, order_direction = field.split(" ")
        order_by_column = quote_column_name(order_by_column)
        # Investigate the SQL query to figure out if the order_by_column has been renamed.
        if sql =~ /#{Regexp.escape(order_by_column)} AS (t\d_r\d\d?)/
          # Fx "[foo].[bar] AS t4_r2" was found in the SQL. Use the column alias (ie 't4_r2') for the subsequent orderings
          order_by_column = $1
        elsif order_by_column =~ /\w+\.\[?(\w+)\]?/
          order_by_column = $1
        else
          # It doesn't appear that the column name has been renamed as part of the query. Use just the column
          # name rather than the full identifier for the outer queries.
          order_by_column = order_by_column.split('.').last
        end
        # Put the column name and eventual direction back together
        [order_by_column, order_direction].join(' ').strip
      end.join(', ')
      sql << " ORDER BY #{change_order_direction(order)}) AS tmp2 ORDER BY #{order}"
    else
      sql << ") AS tmp2"
    end
  elsif options[:limit] && sql !~ /^\s*SELECT (@@|COUNT\()/i
    if md = sql.match(/^(\s*SELECT)(\s+DISTINCT)?(.*)/im)
      sql.replace "#{md[1]}#{md[2]} TOP #{options[:limit]}#{md[3]}"
    else
      # Account for building SQL fragments without SELECT yet. See #update_all and #limited_update_conditions.
      sql.replace "TOP #{options[:limit]} #{sql}"
    end
  end
end

#add_lock!(sql, options) ⇒ Object



511
512
513
514
515
516
517
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 511

def add_lock!(sql, options)
  # http://blog.sqlauthority.com/2007/04/27/sql-server-2005-locking-hints-and-examples/
  return unless options[:lock]
  lock_type = options[:lock] == true ? 'WITH(HOLDLOCK, ROWLOCK)' : options[:lock]
  sql.gsub! %r|LEFT OUTER JOIN\s+(.*?)\s+ON|im, "LEFT OUTER JOIN \\1 #{lock_type} ON"
  sql.gsub! %r{FROM\s([\w\[\]\.]+)}im, "FROM \\1 #{lock_type}"
end

#add_order_by_for_association_limiting!(sql, options) ⇒ Object



697
698
699
700
701
702
703
704
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 697

def add_order_by_for_association_limiting!(sql, options)
  # Disertation http://gist.github.com/24073
  # Information http://weblogs.sqlteam.com/jeffs/archive/2007/12/13/select-distinct-order-by-error.aspx
  return sql if options[:order].blank?
  columns = sql.match(/SELECT\s+DISTINCT(.*)FROM/)[1].strip
  sql.sub!(/SELECT\s+DISTINCT/,'SELECT')
  sql << "GROUP BY #{columns} ORDER BY #{order_to_min_set(options[:order])}"
end

#auto_connectObject



269
270
271
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 269

def auto_connect
  @@auto_connect.is_a?(FalseClass) ? false : true
end

#begin_db_transactionObject



424
425
426
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 424

def begin_db_transaction
  do_execute "BEGIN TRANSACTION"
end

#case_sensitive_equality_operatorObject



523
524
525
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 523

def case_sensitive_equality_operator
  "COLLATE Latin1_General_CS_AS ="
end

#change_column(table_name, column_name, type, options = {}) ⇒ Object



653
654
655
656
657
658
659
660
661
662
663
664
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 653

def change_column(table_name, column_name, type, options = {})
  sql_commands = []
  change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
  change_column_sql << " NOT NULL" if options[:null] == false
  sql_commands << change_column_sql
  if options_include_default?(options)
    remove_default_constraint(table_name, column_name)
    sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_name(table_name,column_name)} DEFAULT #{quote(options[:default])} FOR #{quote_column_name(column_name)}"
  end
  sql_commands.each { |c| do_execute(c) }
  remove_sqlserver_columns_cache_for(table_name)
end

#change_column_default(table_name, column_name, default) ⇒ Object



666
667
668
669
670
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 666

def change_column_default(table_name, column_name, default)
  remove_default_constraint(table_name, column_name)
  do_execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_name(table_name, column_name)} DEFAULT #{quote(default)} FOR #{quote_column_name(column_name)}"
  remove_sqlserver_columns_cache_for(table_name)
end

#change_column_null(table_name, column_name, null, default = nil) ⇒ Object



706
707
708
709
710
711
712
713
714
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 706

def change_column_null(table_name, column_name, null, default = nil)
  column = column_for(table_name,column_name)
  unless null || default.nil?
    do_execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
  end
  sql = "ALTER TABLE #{table_name} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql column.type, column.limit, column.precision, column.scale}"
  sql << " NOT NULL" unless null
  do_execute sql
end

#columns(table_name, name = nil) ⇒ Object



615
616
617
618
619
620
621
622
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 615

def columns(table_name, name = nil)
  return [] if table_name.blank?
  cache_key = unqualify_table_name(table_name)
  @sqlserver_columns_cache[cache_key] ||= column_definitions(table_name).collect do |ci|
    sqlserver_options = ci.except(:name,:default_value,:type,:null)
    SQLServerColumn.new ci[:name], ci[:default_value], ci[:type], ci[:null], sqlserver_options
  end
end

#commit_db_transactionObject



428
429
430
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 428

def commit_db_transaction
  do_execute "COMMIT TRANSACTION"
end

#create_database(name) ⇒ Object



753
754
755
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 753

def create_database(name)
  do_execute "CREATE DATABASE #{name}"
end

#create_savepointObject



436
437
438
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 436

def create_savepoint
  do_execute "SAVE TRANSACTION #{current_savepoint_name}"
end

#create_table(table_name, options = {}) ⇒ Object



624
625
626
627
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 624

def create_table(table_name, options = {})
  super
  remove_sqlserver_columns_cache_for(table_name)
end

#current_databaseObject



757
758
759
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 757

def current_database
  select_value 'SELECT DB_NAME()'
end

#database_versionObject



237
238
239
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 237

def database_version
  @database_version ||= info_schema_query { select_value('SELECT @@version') }
end

#database_yearObject



241
242
243
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 241

def database_year
  DATABASE_VERSION_REGEXP.match(database_version)[1].to_i
end

#disable_referential_integrity(&block) ⇒ Object

REFERENTIAL INTEGRITY ====================================#



342
343
344
345
346
347
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 342

def disable_referential_integrity(&block)
  do_execute "EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'"
  yield
ensure
  do_execute "EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'"
end

#disconnect!Object



364
365
366
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 364

def disconnect!
  raw_connection.disconnect rescue nil
end

#drop_database(name) ⇒ Object



734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 734

def drop_database(name)
  retry_count = 0
  max_retries = 1
  begin
    do_execute "DROP DATABASE #{name}"
  rescue ActiveRecord::StatementInvalid => err
    # Remove existing connections and rollback any transactions if we received the message
    #  'Cannot drop the database 'test' because it is currently in use'
    if err.message =~ /because it is currently in use/
      raise if retry_count >= max_retries
      retry_count += 1
      remove_database_connections_and_rollback(name)
      retry
    else
      raise
    end
  end
end

#drop_table(table_name, options = {}) ⇒ Object



633
634
635
636
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 633

def drop_table(table_name, options = {})
  super
  remove_sqlserver_columns_cache_for(table_name)
end

#empty_insert_statement(table_name) ⇒ Object



519
520
521
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 519

def empty_insert_statement(table_name)
  "INSERT INTO #{quote_table_name(table_name)} DEFAULT VALUES"
end

#execute(sql, name = nil, &block) ⇒ Object



403
404
405
406
407
408
409
410
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 403

def execute(sql, name = nil, &block)
  if table_name = query_requires_identity_insert?(sql)
    handle = with_identity_insert_enabled(table_name) { raw_execute(sql,name,&block) }
  else
    handle = raw_execute(sql,name,&block)
  end
  finish_statement_handle(handle)
end

#execute_procedure(proc_name, *variables) ⇒ Object



412
413
414
415
416
417
418
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 412

def execute_procedure(proc_name, *variables)
  vars = variables.map{ |v| quote(v) }.join(', ')
  sql = "EXEC #{proc_name} #{vars}".strip
  select(sql,'Execute Procedure',true).inject([]) do |results,row|
    results << row.with_indifferent_access
  end
end

#finish_statement_handle(handle) ⇒ Object



368
369
370
371
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 368

def finish_statement_handle(handle)
  handle.finish if handle && handle.respond_to?(:finish) && !handle.finished?
  handle
end

#indexes(table_name, name = nil) ⇒ Object



597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 597

def indexes(table_name, name = nil)
  unquoted_table_name = unqualify_table_name(table_name)
  select("EXEC sp_helpindex #{quote_table_name(unquoted_table_name)}",name).inject([]) do |indexes,index|
    if index['index_description'] =~ /primary key/
      indexes
    else
      name    = index['index_name']
      unique  = index['index_description'] =~ /unique/
      columns = index['index_keys'].split(',').map do |column|
        column.strip!
        column.gsub! '(-)', '' if column.ends_with?('(-)')
        column
      end
      indexes << IndexDefinition.new(table_name, name, unique, columns)
    end
  end
end

#inspectObject



265
266
267
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 265

def inspect
  "#<#{self.class} version: #{version}, year: #{database_year}, connection_options: #{@connection_options.inspect}>"
end

#limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) ⇒ Object



527
528
529
530
531
532
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 527

def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
  match_data = where_sql.match(/(.*)WHERE/)
  limit = match_data[1]
  where_sql.sub!(limit,'')
  "WHERE #{quoted_primary_key} IN (SELECT #{limit} #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
end

#native_binary_database_typeObject



286
287
288
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 286

def native_binary_database_type
  @@native_binary_database_type || ((sqlserver_2005? || sqlserver_2008?) ? 'varbinary(max)' : 'image')
end

#native_database_typesObject

SCHEMA STATEMENTS ========================================#



536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 536

def native_database_types
  {
    :primary_key  => "int NOT NULL IDENTITY(1, 1) PRIMARY KEY",
    :string       => { :name => native_string_database_type, :limit => 255  },
    :text         => { :name => native_text_database_type },
    :integer      => { :name => "int", :limit => 4 },
    :float        => { :name => "float", :limit => 8 },
    :decimal      => { :name => "decimal" },
    :datetime     => { :name => "datetime" },
    :timestamp    => { :name => "datetime" },
    :time         => { :name => "datetime" },
    :date         => { :name => "datetime" },
    :binary       => { :name => native_binary_database_type },
    :boolean      => { :name => "bit"},
    # These are custom types that may move somewhere else for good schema_dumper.rb hacking to output them.
    :char         => { :name => 'char' },
    :varchar_max  => { :name => 'varchar(max)' },
    :nchar        => { :name => "nchar" },
    :nvarchar     => { :name => "nvarchar", :limit => 255 },
    :nvarchar_max => { :name => "nvarchar(max)" },
    :ntext        => { :name => "ntext" }
  }
end

#native_string_database_typeObject



273
274
275
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 273

def native_string_database_type
  @@native_string_database_type || (enable_default_unicode_types ? 'nvarchar' : 'varchar') 
end

#native_text_database_typeObject



277
278
279
280
281
282
283
284
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 277

def native_text_database_type
  @@native_text_database_type || 
  if sqlserver_2005? || sqlserver_2008?
    enable_default_unicode_types ? 'nvarchar(max)' : 'varchar(max)'
  else
    enable_default_unicode_types ? 'ntext' : 'text'
  end
end

#outside_transaction?Boolean

Returns:

  • (Boolean)


420
421
422
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 420

def outside_transaction?
  info_schema_query { select_value("SELECT @@TRANCOUNT") == 0 }
end

#pk_and_sequence_for(table_name) ⇒ Object



716
717
718
719
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 716

def pk_and_sequence_for(table_name)
  idcol = identity_column(table_name)
  idcol ? [idcol.name,nil] : nil
end

#quote(value, column = nil) ⇒ Object

QUOTING ==================================================#



292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 292

def quote(value, column = nil)
  case value
  when String, ActiveSupport::Multibyte::Chars
    if column && column.type == :binary
      column.class.string_to_binary(value)
    elsif column && column.respond_to?(:is_utf8?) && column.is_utf8?
      quoted_utf8_value(value)
    else
      super
    end
  else
    super
  end
end

#quote_column_name(column_name) ⇒ Object



311
312
313
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 311

def quote_column_name(column_name)
  column_name.to_s.split('.').map{ |name| "[#{name}]" }.join('.')
end

#quote_string(string) ⇒ Object



307
308
309
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 307

def quote_string(string)
  string.to_s.gsub(/\'/, "''")
end

#quote_table_name(table_name) ⇒ Object



315
316
317
318
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 315

def quote_table_name(table_name)
  return table_name if table_name =~ /^\[.*\]$/
  quote_column_name(table_name)
end

#quoted_date(value) ⇒ Object



328
329
330
331
332
333
334
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 328

def quoted_date(value)
  if value.acts_like?(:time) && value.respond_to?(:usec)
    "#{super}.#{sprintf("%03d",value.usec/1000)}"
  else
    super
  end
end

#quoted_falseObject



324
325
326
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 324

def quoted_false
  '0'
end

#quoted_trueObject



320
321
322
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 320

def quoted_true
  '1'
end

#quoted_utf8_value(value) ⇒ Object



336
337
338
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 336

def quoted_utf8_value(value)
  "N'#{quote_string(value)}'"
end

#reconnect!Object



358
359
360
361
362
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 358

def reconnect!
  disconnect!
  connect
  active?
end

#recreate_database(name) ⇒ Object

RAKE UTILITY METHODS =====================================#



723
724
725
726
727
728
729
730
731
732
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 723

def recreate_database(name)
  existing_database = current_database.to_s
  if name.to_s == existing_database
    do_execute 'USE master' 
  end
  drop_database(name)
  create_database(name)
ensure
  do_execute "USE #{existing_database}" if name.to_s == existing_database 
end

#release_savepointObject



440
441
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 440

def release_savepoint
end

#remove_column(table_name, *column_names) ⇒ Object



643
644
645
646
647
648
649
650
651
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 643

def remove_column(table_name, *column_names)
  column_names.flatten.each do |column_name|
    remove_check_constraints(table_name, column_name)
    remove_default_constraint(table_name, column_name)
    remove_indexes(table_name, column_name)
    do_execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
  end
  remove_sqlserver_columns_cache_for(table_name)
end

#remove_database_connections_and_rollback(name) ⇒ Object



761
762
763
764
765
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 761

def remove_database_connections_and_rollback(name)
  # This should disconnect all other users and rollback any transactions for SQL 2000 and 2005
  # http://sqlserver2000.databases.aspfaq.com/how-do-i-drop-a-sql-server-database.html
  do_execute "ALTER DATABASE #{name} SET SINGLE_USER WITH ROLLBACK IMMEDIATE"
end

#remove_index(table_name, options = {}) ⇒ Object



678
679
680
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 678

def remove_index(table_name, options = {})
  do_execute "DROP INDEX #{table_name}.#{quote_column_name(index_name(table_name, options))}"
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object



672
673
674
675
676
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 672

def rename_column(table_name, column_name, new_column_name)
  column_for(table_name,column_name)
  do_execute "EXEC sp_rename '#{table_name}.#{column_name}', '#{new_column_name}', 'COLUMN'"
  remove_sqlserver_columns_cache_for(table_name)
end

#rename_table(table_name, new_name) ⇒ Object



629
630
631
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 629

def rename_table(table_name, new_name)
  do_execute "EXEC sp_rename '#{table_name}', '#{new_name}'"
end

#rollback_db_transactionObject



432
433
434
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 432

def rollback_db_transaction
  do_execute "ROLLBACK TRANSACTION" rescue nil
end

#rollback_to_savepointObject



443
444
445
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 443

def rollback_to_savepoint
  do_execute "ROLLBACK TRANSACTION #{current_savepoint_name}"
end

#run_with_isolation_level(isolation_level) ⇒ Object

Raises:

  • (ArgumentError)


388
389
390
391
392
393
394
395
396
397
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 388

def run_with_isolation_level(isolation_level)
  raise ArgumentError, "Invalid isolation level, #{isolation_level}. Supported levels include #{VALID_ISOLATION_LEVELS.to_sentence}." if !VALID_ISOLATION_LEVELS.include?(isolation_level.upcase)
  initial_isolation_level = user_options[:isolation_level] || "READ COMMITTED"
  do_execute "SET TRANSACTION ISOLATION LEVEL #{isolation_level}"
  begin
    yield 
  ensure
    do_execute "SET TRANSACTION ISOLATION LEVEL #{initial_isolation_level}"
  end if block_given?
end

#select_rows(sql, name = nil) ⇒ Object



399
400
401
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 399

def select_rows(sql, name = nil)
  raw_select(sql,name).last
end

#sqlserver?Boolean

Returns:

  • (Boolean)


245
246
247
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 245

def sqlserver?
  true
end

#sqlserver_2000?Boolean

Returns:

  • (Boolean)


249
250
251
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 249

def sqlserver_2000?
  database_year == 2000
end

#sqlserver_2005?Boolean

Returns:

  • (Boolean)


253
254
255
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 253

def sqlserver_2005?
  database_year == 2005
end

#sqlserver_2008?Boolean

Returns:

  • (Boolean)


257
258
259
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 257

def sqlserver_2008?
  database_year == 2008
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)


229
230
231
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 229

def supports_ddl_transactions?
  true
end

#supports_migrations?Boolean

Returns:

  • (Boolean)


225
226
227
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 225

def supports_migrations?
  true
end

#supports_savepoints?Boolean

Returns:

  • (Boolean)


233
234
235
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 233

def supports_savepoints?
  true
end

#table_alias_lengthObject



560
561
562
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 560

def table_alias_length
  128
end

#table_exists?(table_name) ⇒ Boolean

Returns:

  • (Boolean)


593
594
595
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 593

def table_exists?(table_name)
  super || tables.include?(unqualify_table_name(table_name)) || views.include?(table_name.to_s)
end

#tables(name = nil) ⇒ Object



564
565
566
567
568
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 564

def tables(name = nil)
  info_schema_query do
    select_values "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'"
  end
end

#type_to_sql(type, limit = nil, precision = nil, scale = nil) ⇒ Object



682
683
684
685
686
687
688
689
690
691
692
693
694
695
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 682

def type_to_sql(type, limit = nil, precision = nil, scale = nil)
  limit = nil unless self.class.type_limitable?(type)
  case type.to_s
  when 'integer'
    case limit
      when 1..2       then  'smallint'
      when 3..4, nil  then  'integer'
      when 5..8       then  'bigint'
      else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
    end
  else
    super
  end
end

#user_optionsObject

DATABASE STATEMENTS ======================================#



375
376
377
378
379
380
381
382
383
384
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 375

def user_options
  info_schema_query do
    select_rows("dbcc useroptions").inject(HashWithIndifferentAccess.new) do |values,row| 
      set_option = row[0].gsub(/\s+/,'_')
      user_value = row[1]
      values[set_option] = user_value
      values
    end
  end
end

#versionObject



261
262
263
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 261

def version
  self.class::VERSION
end

#view_information(table_name) ⇒ Object



575
576
577
578
579
580
581
582
583
584
585
586
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 575

def view_information(table_name)
  table_name = unqualify_table_name(table_name)
  @sqlserver_view_information_cache[table_name] ||= begin
    view_info = info_schema_query { select_one("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '#{table_name}'") }
    if view_info
      if view_info['VIEW_DEFINITION'].blank? || view_info['VIEW_DEFINITION'].length == 4000
        view_info['VIEW_DEFINITION'] = info_schema_query { select_values("EXEC sp_helptext #{table_name}").join }
      end
    end
    view_info
  end
end

#view_table_name(table_name) ⇒ Object



588
589
590
591
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 588

def view_table_name(table_name)
  view_info = view_information(table_name)
  view_info ? get_table_name(view_info['VIEW_DEFINITION']) : table_name
end

#views(name = nil) ⇒ Object



570
571
572
573
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 570

def views(name = nil)
  @sqlserver_views_cache ||= 
    info_schema_query { select_values("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME NOT IN ('sysconstraints','syssegments')") }
end