Class: ActiveRecord::ConnectionAdapters::SQLServerAdapter
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 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:
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
Instance Method Summary
collapse
-
#active? ⇒ Boolean
Returns true if the connection is active.
-
#adapter_name ⇒ Object
-
#add_limit_offset!(sql, options) ⇒ Object
-
#begin_db_transaction ⇒ Object
-
#change_column(table_name, column_name, type, options = {}) ⇒ Object
-
#columns(table_name, name = nil) ⇒ Object
-
#commit_db_transaction ⇒ Object
-
#create_database(name) ⇒ Object
-
#current_database ⇒ Object
-
#disconnect! ⇒ Object
Disconnects from the database.
-
#drop_database(name) ⇒ Object
-
#execute(sql, name = nil) ⇒ Object
-
#indexes(table_name, name = nil) ⇒ Object
-
#initialize(connection, logger, connection_options = nil) ⇒ SQLServerAdapter
constructor
A new instance of SQLServerAdapter.
-
#insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) ⇒ Object
-
#native_database_types ⇒ Object
-
#quote(value, column = nil) ⇒ Object
-
#quote_column_name(name) ⇒ Object
-
#quote_string(string) ⇒ Object
-
#quoted_false ⇒ Object
-
#quoted_true ⇒ Object
-
#reconnect! ⇒ Object
Reconnects to the database, returns false if no connection could be made.
-
#recreate_database(name) ⇒ Object
-
#remove_column(table_name, column_name) ⇒ Object
-
#remove_default_constraint(table_name, column_name) ⇒ Object
-
#remove_index(table_name, options = {}) ⇒ Object
-
#rename_column(table, column, new_column_name) ⇒ Object
-
#rename_table(name, new_name) ⇒ Object
-
#rollback_db_transaction ⇒ Object
-
#select_all(sql, name = nil) ⇒ Object
-
#select_one(sql, name = nil) ⇒ Object
-
#supports_migrations? ⇒ Boolean
-
#tables(name = nil) ⇒ Object
-
#type_to_sql(type, limit = nil) ⇒ Object
-
#update(sql, name = nil) ⇒ Object
(also: #delete)
#prefetch_primary_key?, #raw_connection, #reset_runtime, #supports_count_distinct?, #verify!
Methods included from Quoting
#quoted_date
#add_limit!, #default_sequence_name, #reset_sequence!, #select_value, #select_values, #transaction
#add_column, #add_column_options!, #add_index, #change_column_default, #create_table, #drop_table, #dump_schema_information, #index_name, #initialize_schema_information, #structure_dump, #table_alias_for, #table_alias_length
Constructor Details
#initialize(connection, logger, connection_options = nil) ⇒ SQLServerAdapter
Returns a new instance of SQLServerAdapter.
178
179
180
181
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 178
def initialize(connection, logger, connection_options=nil)
super(connection, logger)
@connection_options = connection_options
end
|
Instance Method Details
#active? ⇒ Boolean
Returns true if the connection is active.
210
211
212
213
214
215
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 210
def active?
@connection.execute("SELECT 1") { }
true
rescue DBI::DatabaseError, DBI::InterfaceError
false
end
|
#adapter_name ⇒ Object
199
200
201
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 199
def adapter_name
'SQLServer'
end
|
#add_limit_offset!(sql, options) ⇒ Object
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 364
def add_limit_offset!(sql, options)
if options[:limit] and options[:offset]
total_rows = @connection.select_all("SELECT count(*) as TotalRows from (#{sql.gsub(/\bSELECT\b/i, "SELECT TOP 1000000000")}) tally")[0][:TotalRows].to_i
if (options[:limit] + options[:offset]) >= total_rows
options[:limit] = (total_rows - options[:offset] >= 0) ? (total_rows - options[:offset]) : 0
end
sql.sub!(/^\s*SELECT/i, "SELECT * FROM (SELECT TOP #{options[:limit]} * FROM (SELECT TOP #{options[:limit] + options[:offset]} ")
sql << ") AS tmp1"
if options[:order]
options[:order] = options[:order].split(',').map do |field|
parts = field.split(" ")
tc = parts[0]
if sql =~ /\.\[/ and tc =~ /\./ tc.gsub!(/\./, '\\.\\[')
tc << '\\]'
end
if sql =~ /#{tc} AS (t\d_r\d\d?)/
parts[0] = $1
end
parts.join(' ')
end.join(', ')
sql << " ORDER BY #{change_order_direction(options[:order])}) AS tmp2 ORDER BY #{options[:order]}"
else
sql << " ) AS tmp2"
end
elsif sql !~ /^\s*SELECT (@@|COUNT\()/i
sql.sub!(/^\s*SELECT([\s]*distinct)?/i) do
"SELECT#{$1} TOP #{options[:limit]}"
end unless options[:limit].nil?
end
end
|
#begin_db_transaction ⇒ Object
312
313
314
315
316
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 312
def begin_db_transaction
@connection["AutoCommit"] = false
rescue Exception => e
@connection["AutoCommit"] = true
end
|
#change_column(table_name, column_name, type, options = {}) ⇒ Object
445
446
447
448
449
450
451
452
453
454
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 445
def change_column(table_name, column_name, type, options = {}) sql_commands = ["ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"]
if options[:default]
remove_default_constraint(table_name, column_name)
sql_commands << "ALTER TABLE #{table_name} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{options[:default]} FOR #{column_name}"
end
sql_commands.each {|c|
execute(c)
}
end
|
#columns(table_name, name = nil) ⇒ Object
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 242
def columns(table_name, name = nil)
return [] if table_name.blank?
table_name = table_name.to_s if table_name.is_a?(Symbol)
table_name = table_name.split('.')[-1] unless table_name.nil?
sql = "SELECT COLUMN_NAME as ColName, COLUMN_DEFAULT as DefaultValue, DATA_TYPE as ColType, IS_NULLABLE As IsNullable, 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}'"
result = log(sql, name) { @connection.select_all(sql) }
columns = []
result.each do |field|
default = field[:DefaultValue].to_s.gsub!(/[()\']/,"") =~ /null/ ? nil : field[:DefaultValue]
type = "#{field[:ColType]}(#{field[:Length]})"
is_identity = field[:IsIdentity] == 1
is_nullable = field[:IsNullable] == 'YES'
columns << ColumnWithIdentity.new(field[:ColName], default, type, is_identity, is_nullable, field[:Scale])
end
columns
end
|
#commit_db_transaction ⇒ Object
318
319
320
321
322
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 318
def commit_db_transaction
@connection.commit
ensure
@connection["AutoCommit"] = true
end
|
#create_database(name) ⇒ Object
405
406
407
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 405
def create_database(name)
execute "CREATE DATABASE #{name}"
end
|
#current_database ⇒ Object
409
410
411
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 409
def current_database
@connection.select_one("select DB_NAME()")[0]
end
|
#disconnect! ⇒ Object
Disconnects from the database
228
229
230
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 228
def disconnect!
@connection.disconnect rescue nil
end
|
#drop_database(name) ⇒ Object
401
402
403
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 401
def drop_database(name)
execute "DROP DATABASE #{name}"
end
|
#execute(sql, name = nil) ⇒ Object
294
295
296
297
298
299
300
301
302
303
304
305
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 294
def execute(sql, name = nil)
if sql =~ /^\s*INSERT/i
insert(sql, name)
elsif sql =~ /^\s*UPDATE|^\s*DELETE/i
log(sql, name) do
@connection.execute(sql)
retVal = select_one("SELECT @@ROWCOUNT AS AffectedRows")["AffectedRows"]
end
else
log(sql, name) { @connection.execute(sql) }
end
end
|
#indexes(table_name, name = nil) ⇒ Object
421
422
423
424
425
426
427
428
429
430
431
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 421
def indexes(table_name, name = nil)
indexes = []
execute("EXEC sp_helpindex #{table_name}", name).each do |index|
unique = index[1] =~ /unique/
primary = index[1] =~ /primary key/
if !primary
indexes << IndexDefinition.new(table_name, index[0], unique, index[2].split(", "))
end
end
indexes
end
|
#insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) ⇒ Object
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 263
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
begin
table_name = get_table_name(sql)
col = get_identity_column(table_name)
ii_enabled = false
if col != nil
if query_contains_identity_column(sql, col)
begin
execute enable_identity_insert(table_name, true)
ii_enabled = true
rescue Exception => e
raise ActiveRecordError, "IDENTITY_INSERT could not be turned ON"
end
end
end
log(sql, name) do
@connection.execute(sql)
id_value || select_one("SELECT @@IDENTITY AS Ident")["Ident"]
end
ensure
if ii_enabled
begin
execute enable_identity_insert(table_name, false)
rescue Exception => e
raise ActiveRecordError, "IDENTITY_INSERT could not be turned OFF"
end
end
end
end
|
#native_database_types ⇒ Object
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 183
def native_database_types
{
:primary_key => "int NOT NULL IDENTITY(1, 1) PRIMARY KEY",
:string => { :name => "varchar", :limit => 255 },
:text => { :name => "text" },
:integer => { :name => "int" },
:float => { :name => "float", :limit => 8 },
:datetime => { :name => "datetime" },
:timestamp => { :name => "datetime" },
:time => { :name => "datetime" },
:date => { :name => "datetime" },
:binary => { :name => "image"},
:boolean => { :name => "bit"}
}
end
|
#quote(value, column = nil) ⇒ Object
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 330
def quote(value, column = nil)
case value
when String
if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
"'#{quote_string(column.class.string_to_binary(value))}'"
else
"'#{quote_string(value)}'"
end
when NilClass then "NULL"
when TrueClass then '1'
when FalseClass then '0'
when Float, Fixnum, Bignum then value.to_s
when Date then "'#{value.to_s}'"
when Time, DateTime then "'#{value.strftime("%Y-%m-%d %H:%M:%S")}'"
else "'#{quote_string(value.to_yaml)}'"
end
end
|
#quote_column_name(name) ⇒ Object
360
361
362
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 360
def quote_column_name(name)
"[#{name}]"
end
|
#quote_string(string) ⇒ Object
348
349
350
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 348
def quote_string(string)
string.gsub(/\'/, "''")
end
|
#quoted_false ⇒ Object
356
357
358
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 356
def quoted_false
"0"
end
|
#quoted_true ⇒ Object
352
353
354
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 352
def quoted_true
"1"
end
|
#reconnect! ⇒ Object
Reconnects to the database, returns false if no connection could be made.
218
219
220
221
222
223
224
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 218
def reconnect!
disconnect!
@connection = DBI.connect(*@connection_options)
rescue DBI::DatabaseError => e
@logger.warn "#{adapter_name} reconnection failed: #{e.message}" if @logger
false
end
|
#recreate_database(name) ⇒ Object
396
397
398
399
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 396
def recreate_database(name)
drop_database(name)
create_database(name)
end
|
#remove_column(table_name, column_name) ⇒ Object
437
438
439
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 437
def remove_column(table_name, column_name)
execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
end
|
#remove_default_constraint(table_name, column_name) ⇒ Object
461
462
463
464
465
466
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 461
def remove_default_constraint(table_name, column_name)
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"
defaults.each {|constraint|
execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}"
}
end
|
#remove_index(table_name, options = {}) ⇒ Object
468
469
470
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 468
def remove_index(table_name, options = {})
execute "DROP INDEX #{table_name}.#{index_name(table_name, options)}"
end
|
#rename_column(table, column, new_column_name) ⇒ Object
441
442
443
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 441
def rename_column(table, column, new_column_name)
execute "EXEC sp_rename '#{table}.#{column}', '#{new_column_name}'"
end
|
#rename_table(name, new_name) ⇒ Object
433
434
435
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 433
def rename_table(name, new_name)
execute "EXEC sp_rename '#{name}', '#{new_name}'"
end
|
#rollback_db_transaction ⇒ Object
324
325
326
327
328
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 324
def rollback_db_transaction
@connection.rollback
ensure
@connection["AutoCommit"] = true
end
|
#select_all(sql, name = nil) ⇒ Object
232
233
234
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 232
def select_all(sql, name = nil)
select(sql, name)
end
|
#select_one(sql, name = nil) ⇒ Object
236
237
238
239
240
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 236
def select_one(sql, name = nil)
add_limit!(sql, :limit => 1)
result = select(sql, name)
result.nil? ? nil : result.first
end
|
#supports_migrations? ⇒ Boolean
203
204
205
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 203
def supports_migrations? true
end
|
#tables(name = nil) ⇒ Object
413
414
415
416
417
418
419
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 413
def tables(name = nil)
execute("SELECT table_name from information_schema.tables WHERE table_type = 'BASE TABLE'", name).inject([]) do |tables, field|
table_name = field[0]
tables << table_name unless table_name == 'dtproperties'
tables
end
end
|
#type_to_sql(type, limit = nil) ⇒ Object
472
473
474
475
476
477
478
479
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 472
def type_to_sql(type, limit = nil) native = native_database_types[type]
limit = limit || native[:limit]
column_type_sql = native[:name]
column_type_sql << "(#{limit})" if limit
column_type_sql
end
|
#update(sql, name = nil) ⇒ Object
Also known as:
delete
307
308
309
|
# File 'lib/active_record/connection_adapters/sqlserver_adapter.rb', line 307
def update(sql, name = nil)
execute(sql, name)
end
|