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:

  • :mode — ADO or ODBC. Defaults to ADO.
  • :username — Defaults to sa.
  • :password — Defaults to empty string.

ADO specific options:

  • :host — Defaults to localhost.
  • :database — The name of the database. No default, must be provided.

ODBC specific options:

  • :dsn — Defaults to nothing.

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]

Methods
Public Class methods
new(connection, logger, connection_options=nil)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 178
178:       def initialize(connection, logger, connection_options=nil)
179:         super(connection, logger)
180:         @connection_options = connection_options
181:       end
Public Instance methods
active?()

Returns true if the connection is active.

     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 210
210:       def active?
211:         @connection.execute("SELECT 1") { }
212:         true
213:       rescue DBI::DatabaseError, DBI::InterfaceError
214:         false
215:       end
adapter_name()
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 199
199:       def adapter_name
200:         'SQLServer'
201:       end
add_limit_offset!(sql, options)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 352
352:       def add_limit_offset!(sql, options)
353:         if options[:limit] and options[:offset]
354:           total_rows = @connection.select_all("SELECT count(*) as TotalRows from (#{sql.gsub(/\bSELECT\b/i, "SELECT TOP 1000000000")}) tally")[0][:TotalRows].to_i
355:           if (options[:limit] + options[:offset]) >= total_rows
356:             options[:limit] = (total_rows - options[:offset] >= 0) ? (total_rows - options[:offset]) : 0
357:           end
358:           sql.sub!(/^\s*SELECT/i, "SELECT * FROM (SELECT TOP #{options[:limit]} * FROM (SELECT TOP #{options[:limit] + options[:offset]} ")
359:           sql << ") AS tmp1"
360:           if options[:order]
361:             options[:order] = options[:order].split(',').map do |field|
362:               parts = field.split(" ")
363:               tc = parts[0]
364:               if sql =~ /\.\[/ and tc =~ /\./ # if column quoting used in query
365:                 tc.gsub!(/\./, '\\.\\[')
366:                 tc << '\\]'
367:               end
368:               if sql =~ /#{tc} AS (t\d_r\d\d?)/
369:                   parts[0] = $1
370:               end
371:               parts.join(' ')
372:             end.join(', ')
373:             sql << " ORDER BY #{change_order_direction(options[:order])}) AS tmp2 ORDER BY #{options[:order]}"
374:           else
375:             sql << " ) AS tmp2"
376:           end
377:         elsif sql !~ /^\s*SELECT (@@|COUNT\()/i
378:           sql.sub!(/^\s*SELECT/i, "SELECT TOP #{options[:limit]}") unless options[:limit].nil?
379:         end
380:       end
begin_db_transaction()
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 300
300:       def begin_db_transaction
301:         @connection["AutoCommit"] = false
302:       rescue Exception => e
303:         @connection["AutoCommit"] = true
304:       end
columns(table_name, name = nil)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 236
236:       def columns(table_name, name = nil)
237:         return [] if table_name.blank?
238:         table_name = table_name.to_s if table_name.is_a?(Symbol)
239:         table_name = table_name.split('.')[-1] unless table_name.nil?
240:         sql = "SELECT COLUMN_NAME as ColName, COLUMN_DEFAULT as DefaultValue, DATA_TYPE as ColType, COL_LENGTH('#{table_name}', COLUMN_NAME) as Length, COLUMNPROPERTY(OBJECT_ID('#{table_name}'), COLUMN_NAME, 'IsIdentity') as IsIdentity, NUMERIC_SCALE as Scale FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '#{table_name}'"
241:         # Comment out if you want to have the Columns select statment logged.
242:         # Personnally, I think it adds unneccessary bloat to the log. 
243:         # If you do comment it out, make sure to un-comment the "result" line that follows
244:         result = log(sql, name) { @connection.select_all(sql) }
245:         #result = @connection.select_all(sql)
246:         columns = []
247:         result.each { |field| columns << ColumnWithIdentity.new(field[:ColName], field[:DefaultValue].to_s.gsub!(/[()\']/,"") =~ /null/ ? nil : field[:DefaultValue], "#{field[:ColType]}(#{field[:Length]})", field[:IsIdentity] == 1 ? true : false, field[:Scale]) }
248:         columns
249:       end
commit_db_transaction()
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 306
306:       def commit_db_transaction
307:         @connection.commit
308:       ensure
309:         @connection["AutoCommit"] = true
310:       end
create_database(name)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 391
391:       def create_database(name)
392:         execute "CREATE DATABASE #{name}"
393:       end
delete(sql, name = nil)

Alias for update

drop_database(name)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 387
387:       def drop_database(name)
388:         execute "DROP DATABASE #{name}"
389:       end
execute(sql, name = nil)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 282
282:       def execute(sql, name = nil)
283:         if sql =~ /^\s*INSERT/i
284:           insert(sql, name)
285:         elsif sql =~ /^\s*UPDATE|^\s*DELETE/i
286:           log(sql, name) do
287:             @connection.execute(sql)
288:             retVal = select_one("SELECT @@ROWCOUNT AS AffectedRows")["AffectedRows"]
289:           end
290:         else
291:           log(sql, name) { @connection.execute(sql) }
292:         end
293:       end
indexes(table_name, name = nil)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 403
403:       def indexes(table_name, name = nil)
404:         indexes = []
405:         execute("EXEC sp_helpindex #{table_name}", name).each do |index| 
406:           unique = index[1] =~ /unique/
407:           primary = index[1] =~ /primary key/
408:           if !primary
409:             indexes << IndexDefinition.new(table_name, index[0], unique, index[2].split(", "))
410:           end
411:         end
412:         indexes
413:       end
insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 251
251:       def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
252:         begin
253:           table_name = get_table_name(sql)
254:           col = get_identity_column(table_name)
255:           ii_enabled = false
256: 
257:           if col != nil
258:             if query_contains_identity_column(sql, col)
259:               begin
260:                 execute enable_identity_insert(table_name, true)
261:                 ii_enabled = true
262:               rescue Exception => e
263:                 raise ActiveRecordError, "IDENTITY_INSERT could not be turned ON"
264:               end
265:             end
266:           end
267:           log(sql, name) do
268:             @connection.execute(sql)
269:             id_value || select_one("SELECT @@IDENTITY AS Ident")["Ident"]
270:           end
271:         ensure
272:           if ii_enabled
273:             begin
274:               execute enable_identity_insert(table_name, false)
275:             rescue Exception => e
276:               raise ActiveRecordError, "IDENTITY_INSERT could not be turned OFF"
277:             end
278:           end
279:         end
280:       end
native_database_types()
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 183
183:       def native_database_types
184:         {
185:           :primary_key => "int NOT NULL IDENTITY(1, 1) PRIMARY KEY",
186:           :string      => { :name => "varchar", :limit => 255  },
187:           :text        => { :name => "text" },
188:           :integer     => { :name => "int" },
189:           :float       => { :name => "float", :limit => 8 },
190:           :datetime    => { :name => "datetime" },
191:           :timestamp   => { :name => "datetime" },
192:           :time        => { :name => "datetime" },
193:           :date        => { :name => "datetime" },
194:           :binary      => { :name => "image"},
195:           :boolean     => { :name => "bit"}
196:         }
197:       end
quote(value, column = nil)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 318
318:       def quote(value, column = nil)
319:         case value
320:           when String                
321:             if column && column.type == :binary
322:               "'#{quote_string(column.class.string_to_binary(value))}'"
323:             else
324:               "'#{quote_string(value)}'"
325:             end
326:           when NilClass              then "NULL"
327:           when TrueClass             then '1'
328:           when FalseClass            then '0'
329:           when Float, Fixnum, Bignum then value.to_s
330:           when Date                  then "'#{value.to_s}'" 
331:           when Time, DateTime        then "'#{value.strftime("%Y-%m-%d %H:%M:%S")}'"
332:           else                            "'#{quote_string(value.to_yaml)}'"
333:         end
334:       end
quote_column_name(name)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 348
348:       def quote_column_name(name)
349:         "[#{name}]"
350:       end
quote_string(string)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 336
336:       def quote_string(string)
337:         string.gsub(/\'/, "''")
338:       end
quoted_false()
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 344
344:       def quoted_false
345:         "0"
346:       end
quoted_true()
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 340
340:       def quoted_true
341:         "1"
342:       end
reconnect!()

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 218
218:       def reconnect!
219:         @connection.disconnect rescue nil
220:         @connection = DBI.connect(*@connection_options)
221:       rescue DBI::DatabaseError => e
222:         @logger.warn "#{adapter_name} reconnection failed: #{e.message}" if @logger
223:         false
224:       end
recreate_database(name)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 382
382:       def recreate_database(name)
383:         drop_database(name)
384:         create_database(name)
385:       end
remove_column(table_name, column_name)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 438
438:       def remove_column(table_name, column_name)
439:         remove_default_constraint(table_name, column_name)
440:         execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
441:       end
remove_column(table_name, column_name)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 419
419:       def remove_column(table_name, column_name)
420:         execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
421:       end
remove_default_constraint(table_name, column_name)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 443
443:       def remove_default_constraint(table_name, column_name)
444:         defaults = 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"
445:         defaults.each {|constraint|
446:           execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}"
447:         }
448:       end
remove_index(table_name, options = {})
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 450
450:       def remove_index(table_name, options = {})
451:         execute "DROP INDEX #{table_name}.#{index_name(table_name, options)}"
452:       end
rename_column(table, column, new_column_name)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 423
423:       def rename_column(table, column, new_column_name)
424:         execute "EXEC sp_rename '#{table}.#{column}', '#{new_column_name}'"
425:       end
rename_table(name, new_name)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 415
415:       def rename_table(name, new_name)
416:         execute "EXEC sp_rename '#{name}', '#{new_name}'"
417:       end
rollback_db_transaction()
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 312
312:       def rollback_db_transaction
313:         @connection.rollback
314:       ensure
315:         @connection["AutoCommit"] = true
316:       end
select_all(sql, name = nil)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 226
226:       def select_all(sql, name = nil)
227:         select(sql, name)
228:       end
select_one(sql, name = nil)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 230
230:       def select_one(sql, name = nil)
231:         add_limit!(sql, :limit => 1)
232:         result = select(sql, name)
233:         result.nil? ? nil : result.first
234:       end
tables(name = nil)
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 395
395:       def tables(name = nil)
396:         execute("SELECT table_name from information_schema.tables WHERE table_type = 'BASE TABLE'", name).inject([]) do |tables, field|
397:           table_name = field[0]
398:           tables << table_name unless table_name == 'dtproperties'
399:           tables
400:         end
401:       end
update(sql, name = nil)
This method is also aliased as delete
     # File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 295
295:       def update(sql, name = nil)
296:         execute(sql, name)
297:       end