Class | ActiveRecord::ConnectionAdapters::SQLServerAdapter |
In: |
vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb
|
Parent: | AbstractAdapter |
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 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:
ADO specific options:
ODBC specific options:
ADO code tested on Windows 2000 and higher systems, running ruby 1.8.2 (2004-07-29) [i386-mswin32], and SQL Server 2000 SP3.
ODBC code tested on a Fedora Core 4 system, running FreeTDS 0.63, unixODBC 2.2.11, Ruby ODBC 0.996, Ruby DBI 0.0.23 and Ruby 1.8.2. [Linux strongmad 2.6.11-1.1369_FC4 1 Thu Jun 2 22:55:56 EDT 2005 i686 i686 i386 GNU/Linux]
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 189 189: def initialize(connection, logger, connection_options=nil) 190: super(connection, logger) 191: @connection_options = connection_options 192: end
Returns true if the connection is active.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 234 234: def active? 235: @connection.execute("SELECT 1").finish 236: true 237: rescue DBI::DatabaseError, DBI::InterfaceError 238: false 239: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 211 211: def adapter_name 212: 'SQLServer' 213: end
Adds a new column to the named table. See TableDefinition#column for details of the options you can use.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 457 457: def add_column(table_name, column_name, type, options = {}) 458: add_column_sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" 459: add_column_options!(add_column_sql, options) 460: # TODO: Add support to mimic date columns, using constraints to mark them as such in the database 461: # add_column_sql << " CONSTRAINT ck__#{table_name}__#{column_name}__date_only CHECK ( CONVERT(CHAR(12), #{quote_column_name(column_name)}, 14)='00:00:00:000' )" if type == :date 462: execute(add_column_sql) 463: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 373 373: def add_limit_offset!(sql, options) 374: if options[:limit] and options[:offset] 375: total_rows = @connection.select_all("SELECT count(*) as TotalRows from (#{sql.gsub(/\bSELECT(\s+DISTINCT)?\b/i, "SELECT#{$1} TOP 1000000000")}) tally")[0][:TotalRows].to_i 376: if (options[:limit] + options[:offset]) >= total_rows 377: options[:limit] = (total_rows - options[:offset] >= 0) ? (total_rows - options[:offset]) : 0 378: end 379: sql.sub!(/^\s*SELECT(\s+DISTINCT)?/i, "SELECT * FROM (SELECT TOP #{options[:limit]} * FROM (SELECT#{$1} TOP #{options[:limit] + options[:offset]} ") 380: sql << ") AS tmp1" 381: if options[:order] 382: options[:order] = options[:order].split(',').map do |field| 383: parts = field.split(" ") 384: tc = parts[0] 385: if sql =~ /\.\[/ and tc =~ /\./ # if column quoting used in query 386: tc.gsub!(/\./, '\\.\\[') 387: tc << '\\]' 388: end 389: if sql =~ /#{tc} AS (t\d_r\d\d?)/ 390: parts[0] = $1 391: elsif parts[0] =~ /\w+\.(\w+)/ 392: parts[0] = $1 393: end 394: parts.join(' ') 395: end.join(', ') 396: sql << " ORDER BY #{change_order_direction(options[:order])}) AS tmp2 ORDER BY #{options[:order]}" 397: else 398: sql << " ) AS tmp2" 399: end 400: elsif sql !~ /^\s*SELECT (@@|COUNT\()/i 401: sql.sub!(/^\s*SELECT(\s+DISTINCT)?/i) do 402: "SELECT#{$1} TOP #{options[:limit]}" 403: end unless options[:limit].nil? 404: end 405: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 335 335: def begin_db_transaction 336: @connection["AutoCommit"] = false 337: rescue Exception => e 338: @connection["AutoCommit"] = true 339: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 266 266: def columns(table_name, name = nil) 267: return [] if table_name.blank? 268: table_name = table_name.to_s if table_name.is_a?(Symbol) 269: table_name = table_name.split('.')[-1] unless table_name.nil? 270: sql = %Q{ 271: SELECT 272: cols.COLUMN_NAME as ColName, 273: cols.COLUMN_DEFAULT as DefaultValue, 274: cols.NUMERIC_SCALE as numeric_scale, 275: cols.NUMERIC_PRECISION as numeric_precision, 276: cols.DATA_TYPE as ColType, 277: cols.IS_NULLABLE As IsNullable, 278: COL_LENGTH(cols.TABLE_NAME, cols.COLUMN_NAME) as Length, 279: COLUMNPROPERTY(OBJECT_ID(cols.TABLE_NAME), cols.COLUMN_NAME, 'IsIdentity') as IsIdentity, 280: cols.NUMERIC_SCALE as Scale 281: FROM INFORMATION_SCHEMA.COLUMNS cols 282: WHERE cols.TABLE_NAME = '#{table_name}' 283: } 284: # Comment out if you want to have the Columns select statment logged. 285: # Personally, I think it adds unnecessary bloat to the log. 286: # If you do comment it out, make sure to un-comment the "result" line that follows 287: result = log(sql, name) { @connection.select_all(sql) } 288: #result = @connection.select_all(sql) 289: columns = [] 290: result.each do |field| 291: default = field[:DefaultValue].to_s.gsub!(/[()\']/,"") =~ /null/ ? nil : field[:DefaultValue] 292: if field[:ColType] =~ /numeric|decimal/i 293: type = "#{field[:ColType]}(#{field[:numeric_precision]},#{field[:numeric_scale]})" 294: else 295: type = "#{field[:ColType]}(#{field[:Length]})" 296: end 297: is_identity = field[:IsIdentity] == 1 298: is_nullable = field[:IsNullable] == 'YES' 299: columns << SQLServerColumn.new(field[:ColName], default, type, is_identity, is_nullable) 300: end 301: columns 302: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 341 341: def commit_db_transaction 342: @connection.commit 343: ensure 344: @connection["AutoCommit"] = true 345: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 416 416: def create_database(name) 417: execute "CREATE DATABASE #{name}" 418: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 420 420: def current_database 421: @connection.select_one("select DB_NAME()")[0] 422: end
Disconnects from the database
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 252 252: def disconnect! 253: @connection.disconnect rescue nil 254: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 412 412: def drop_database(name) 413: execute "DROP DATABASE #{name}" 414: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 317 317: def execute(sql, name = nil) 318: if sql =~ /^\s*INSERT/i && (table_name = query_requires_identity_insert?(sql)) 319: log(sql, name) do 320: with_identity_insert_enabled(table_name) do 321: @connection.execute(sql) do |handle| 322: yield(handle) if block_given? 323: end 324: end 325: end 326: else 327: log(sql, name) do 328: @connection.execute(sql) do |handle| 329: yield(handle) if block_given? 330: end 331: end 332: end 333: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 434 434: def indexes(table_name, name = nil) 435: ActiveRecord::Base.connection.instance_variable_get("@connection")["AutoCommit"] = false 436: indexes = [] 437: execute("EXEC sp_helpindex #{table_name}", name) do |sth| 438: sth.each do |index| 439: unique = index[1] =~ /unique/ 440: primary = index[1] =~ /primary key/ 441: if !primary 442: indexes << IndexDefinition.new(table_name, index[0], unique, index[2].split(", ")) 443: end 444: end 445: end 446: indexes 447: ensure 448: ActiveRecord::Base.connection.instance_variable_get("@connection")["AutoCommit"] = true 449: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 304 304: def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) 305: execute(sql, name) 306: id_value || select_one("SELECT @@IDENTITY AS Ident")["Ident"] 307: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 194 194: def native_database_types 195: { 196: :primary_key => "int NOT NULL IDENTITY(1, 1) PRIMARY KEY", 197: :string => { :name => "varchar", :limit => 255 }, 198: :text => { :name => "text" }, 199: :integer => { :name => "int" }, 200: :float => { :name => "float", :limit => 8 }, 201: :decimal => { :name => "decimal" }, 202: :datetime => { :name => "datetime" }, 203: :timestamp => { :name => "datetime" }, 204: :time => { :name => "datetime" }, 205: :date => { :name => "datetime" }, 206: :binary => { :name => "image"}, 207: :boolean => { :name => "bit"} 208: } 209: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 353 353: def quote(value, column = nil) 354: return value.quoted_id if value.respond_to?(:quoted_id) 355: 356: case value 357: when TrueClass then '1' 358: when FalseClass then '0' 359: when Time, DateTime then "'#{value.strftime("%Y%m%d %H:%M:%S")}'" 360: when Date then "'#{value.strftime("%Y%m%d")}'" 361: else super 362: end 363: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 369 369: def quote_column_name(name) 370: "[#{name}]" 371: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 365 365: def quote_string(string) 366: string.gsub(/\'/, "''") 367: end
Reconnects to the database, returns false if no connection could be made.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 242 242: def reconnect! 243: disconnect! 244: @connection = DBI.connect(*@connection_options) 245: rescue DBI::DatabaseError => e 246: @logger.warn "#{adapter_name} reconnection failed: #{e.message}" if @logger 247: false 248: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 407 407: def recreate_database(name) 408: drop_database(name) 409: create_database(name) 410: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 494 494: def remove_check_constraints(table_name, column_name) 495: # TODO remove all constraints in single method 496: constraints = select "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE where TABLE_NAME = '#{table_name}' and COLUMN_NAME = '#{column_name}'" 497: constraints.each do |constraint| 498: execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["CONSTRAINT_NAME"]}" 499: end 500: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 480 480: def remove_column(table_name, column_name) 481: remove_check_constraints(table_name, column_name) 482: remove_default_constraint(table_name, column_name) 483: execute "ALTER TABLE [#{table_name}] DROP COLUMN [#{column_name}]" 484: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 486 486: def remove_default_constraint(table_name, column_name) 487: constraints = select "select def.name from sysobjects def, syscolumns col, sysobjects tab where col.cdefault = def.id and col.name = '#{column_name}' and tab.name = '#{table_name}' and col.id = tab.id" 488: 489: constraints.each do |constraint| 490: execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}" 491: end 492: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 502 502: def remove_index(table_name, options = {}) 503: execute "DROP INDEX #{table_name}.#{quote_column_name(index_name(table_name, options))}" 504: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 465 465: def rename_column(table, column, new_column_name) 466: execute "EXEC sp_rename '#{table}.#{column}', '#{new_column_name}'" 467: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 451 451: def rename_table(name, new_name) 452: execute "EXEC sp_rename '#{name}', '#{new_name}'" 453: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 347 347: def rollback_db_transaction 348: @connection.rollback 349: ensure 350: @connection["AutoCommit"] = true 351: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 256 256: def select_all(sql, name = nil) 257: select(sql, name) 258: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 260 260: def select_one(sql, name = nil) 261: add_limit!(sql, :limit => 1) 262: result = select(sql, name) 263: result.nil? ? nil : result.first 264: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 424 424: def tables(name = nil) 425: execute("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'", name) do |sth| 426: sth.inject([]) do |tables, field| 427: table_name = field[0] 428: tables << table_name unless table_name == 'dtproperties' 429: tables 430: end 431: end 432: end