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]
- active?
- adapter_name
- add_limit_offset!
- begin_db_transaction
- columns
- commit_db_transaction
- create_database
- delete
- drop_database
- execute
- indexes
- insert
- native_database_types
- new
- quote
- quote_column_name
- quote_string
- quoted_false
- quoted_true
- reconnect!
- recreate_database
- remove_column
- remove_column
- remove_default_constraint
- remove_index
- rename_column
- rename_table
- rollback_db_transaction
- select_all
- select_one
- tables
- update
[ show source ]
# 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
Returns true if the connection is active.
[ show source ]
# 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
[ show source ]
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 199
199: def adapter_name
200: 'SQLServer'
201: end
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
Alias for update
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 348
348: def quote_column_name(name)
349: "[#{name}]"
350: end
[ show source ]
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 336
336: def quote_string(string)
337: string.gsub(/\'/, "''")
338: end
[ show source ]
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 344
344: def quoted_false
345: "0"
346: end
[ show source ]
# File vendor/rails/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb, line 340
340: def quoted_true
341: "1"
342: end
Reconnects to the database, returns false if no connection could be made.
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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
[ show source ]
# 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