Skip to content

Commit b9e8e31

Browse files
committed
Clean up DBI removal and start an abstraction for different low level connection methods. Currently only ODBC but may include others like ADO.NET.
1 parent 5e9dc66 commit b9e8e31

File tree

4 files changed

+66
-44
lines changed

4 files changed

+66
-44
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
MASTER
33

4+
* Remove DBI dependency and go straight ODBC for speed improvement [Erik Bryn]
5+
46
* Leave order by alone when same column crosses two tables [Ransom Briggs]
57

68

activerecord-sqlserver-adapter.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Gem::Specification.new do |s|
22
s.name = "activerecord-sqlserver-adapter"
3-
s.version = "2.3.2.mmi"
3+
s.version = "2.3.2"
44
s.date = "2009-09-10"
55
s.summary = "SQL Server 2000, 2005 and 2008 Adapter For Rails."
66
s.email = "ken@metaskills.net"

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
require 'active_record'
12
require 'active_record/connection_adapters/abstract_adapter'
2-
require_library_or_gem 'odbc' unless defined?(ODBC)
3-
require File.dirname(__FILE__)+'/sqlserver_adapter/core_ext/odbc'
43
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/active_record'
54
require 'base64'
65

@@ -9,12 +8,22 @@ module ActiveRecord
98
class Base
109

1110
def self.sqlserver_connection(config) #:nodoc:
12-
config.symbolize_keys!
13-
username = config[:username] ? config[:username].to_s : 'sa'
14-
password = config[:password] ? config[:password].to_s : ''
15-
raise ArgumentError, "Missing DSN. Argument ':dsn' must be set in order for this adapter to work." unless config.has_key?(:dsn)
16-
dsn = config[:dsn]
17-
ConnectionAdapters::SQLServerAdapter.new(logger, [dsn, username, password])
11+
config = config.dup.symbolize_keys!
12+
config.reverse_merge! :mode => :odbc, :host => 'localhost', :username => 'sa', :password => ''
13+
mode = config[:mode].to_s.downcase.underscore.to_sym
14+
case mode
15+
when :odbc
16+
require_library_or_gem 'odbc' unless defined?(ODBC)
17+
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/odbc'
18+
raise ArgumentError, 'Missing :dsn configuration.' unless config.has_key?(:dsn)
19+
config = config.slice :dsn, :username, :password
20+
when :ado
21+
raise NotImplementedError, 'Please use version 2.3.1 of the adapter for ADO connections. Future versions may support ADO.NET.'
22+
raise ArgumentError, 'Missing :database configuration.' unless config.has_key?(:database)
23+
else
24+
raise ArgumentError, "Unknown connection mode in #{config.inspect}."
25+
end
26+
ConnectionAdapters::SQLServerAdapter.new(logger,config.merge(:mode=>mode))
1827
end
1928

2029
protected
@@ -138,28 +147,30 @@ def simplified_datetime
138147

139148
end #SQLServerColumn
140149

141-
# In ODBC mode, the adapter requires the ODBC support in the DBI module which requires
142-
# the Ruby ODBC module. Ruby ODBC 0.996 was used in development and testing,
143-
# and it is available at http://www.ch-werner.de/rubyodbc/
150+
# In ODBC mode, the adapter requires Ruby ODBC and requires that you specify
151+
# a :dsn option. Ruby ODBC is available at http://www.ch-werner.de/rubyodbc/
144152
#
145153
# Options:
146154
#
147155
# * <tt>:username</tt> -- Defaults to sa.
148-
# * <tt>:password</tt> -- Defaults to empty string.
149-
# * <tt>:dsn</tt> -- Defaults to nothing.
156+
# * <tt>:password</tt> -- Defaults to blank string.
157+
# * <tt>:dsn</tt> -- An ODBC DSN. (required)
150158
#
151159
class SQLServerAdapter < AbstractAdapter
152160

153-
ADAPTER_NAME = 'SQLServer'.freeze
154-
VERSION = '2.4-mmi'.freeze
155-
DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
156-
SUPPORTED_VERSIONS = [2000,2005,2008].freeze
157-
LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].freeze
158-
159-
LOST_CONNECTION_EXCEPTIONS = [ODBC::Error] #[DBI::DatabaseError, DBI::InterfaceError]
160-
LOST_CONNECTION_MESSAGES = [
161-
'Invalid handle'
162-
]
161+
ADAPTER_NAME = 'SQLServer'.freeze
162+
VERSION = '2.3.2'.freeze
163+
DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+(\d{4})/
164+
SUPPORTED_VERSIONS = [2000,2005,2008].freeze
165+
LIMITABLE_TYPES = ['string','integer','float','char','nchar','varchar','nvarchar'].freeze
166+
LOST_CONNECTION_EXCEPTIONS = {
167+
:odbc => ['ODBC::Error'],
168+
:ado => []
169+
}
170+
LOST_CONNECTION_MESSAGES = {
171+
:odbc => [/link failure/, /server failed/, /connection was already closed/, /invalid handle/i],
172+
:ado => []
173+
}
163174

164175
cattr_accessor :native_text_database_type, :native_binary_database_type, :native_string_database_type,
165176
:log_info_schema_queries, :enable_default_unicode_types, :auto_connect
@@ -172,8 +183,8 @@ def type_limitable?(type)
172183

173184
end
174185

175-
def initialize(logger, connection_options)
176-
@connection_options = connection_options
186+
def initialize(logger,config)
187+
@connection_options = config
177188
connect
178189
super(raw_connection, logger)
179190
initialize_sqlserver_caches
@@ -317,7 +328,7 @@ def disable_referential_integrity(&block)
317328
def active?
318329
raw_connection.run("SELECT 1").drop
319330
true
320-
rescue *LOST_CONNECTION_EXCEPTIONS
331+
rescue *lost_connection_exceptions
321332
false
322333
end
323334

@@ -737,22 +748,35 @@ def remove_database_connections_and_rollback(name)
737748
# CONNECTION MANAGEMENT ====================================#
738749

739750
def connect
740-
dsn, username, password = @connection_options
741-
@connection = ODBC.connect(dsn, username, password)
742-
configure_connection
751+
config = @connection_options
752+
@connection = case connection_mode
753+
when :odbc
754+
ODBC.connect config[:dsn], config[:username], config[:password]
755+
when :ado
756+
757+
end
743758
rescue
744759
raise unless @auto_connecting
745760
end
746761

747-
def configure_connection
748-
# raw_connection['AutoCommit'] = true
762+
def connection_mode
763+
@connection_options[:mode]
764+
end
765+
766+
def lost_connection_exceptions
767+
exceptions = LOST_CONNECTION_EXCEPTIONS[connection_mode]
768+
@lost_connection_exceptions ||= exceptions ? exceptions.map(&:constantize) : []
769+
end
770+
771+
def lost_connection_messages
772+
LOST_CONNECTION_MESSAGES[connection_mode]
749773
end
750774

751775
def with_auto_reconnect
752776
begin
753777
yield
754-
rescue *LOST_CONNECTION_EXCEPTIONS => e
755-
if LOST_CONNECTION_MESSAGES.any? { |lcm| e.message =~ Regexp.new(lcm,Regexp::IGNORECASE) }
778+
rescue *lost_connection_exceptions => e
779+
if lost_connection_messages.any? { |lcm| e.message =~ lcm }
756780
retry if auto_reconnected?
757781
end
758782
raise
@@ -831,7 +855,6 @@ def raw_select(sql, name = nil)
831855
results = handle_as_array(handle)
832856
rows = results.inject([]) do |rows,row|
833857
row.each_with_index do |value, i|
834-
# DEPRECATED in DBI 0.4.0 and above. Remove when 0.2.2 and lower is no longer supported.
835858
if value.is_a? ODBC::TimeStamp
836859
row[i] = value.to_sqlserver_string
837860
end

lib/active_record/connection_adapters/sqlserver_adapter/core_ext/odbc.rb

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module ActiveRecord
33
module ConnectionAdapters
44
module SQLServerCoreExtensions
55
module ODBC
6+
67
module TimeStamp
78
def to_sqlserver_string
89
date, time, nanoseconds = to_s.split(' ')
@@ -28,17 +29,13 @@ def run_block(*args)
2829
sth.drop
2930
end
3031
end
32+
3133
end
3234
end
3335
end
3436
end
3537

36-
if defined?(ODBC::TimeStamp)
37-
ODBC::TimeStamp.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ODBC::TimeStamp
38-
end
39-
if defined?(ODBC::Statement)
40-
ODBC::Statement.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ODBC::Statement
41-
end
42-
if defined?(ODBC::Database)
43-
ODBC::Database.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ODBC::Database
44-
end
38+
ODBC::TimeStamp.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ODBC::TimeStamp if defined?(ODBC::TimeStamp)
39+
ODBC::Statement.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ODBC::Statement if defined?(ODBC::Statement)
40+
ODBC::Database.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ODBC::Database if defined?(ODBC::Database)
41+

0 commit comments

Comments
 (0)