Skip to content

Commit d892a78

Browse files
aidanharanAidan Haran
authored and
Lavika
committed
Refactored to use new_client connection pattern (rails-sqlserver#917)
Co-authored-by: Aidan Haran <aharan@fusioneer.com>
1 parent 5323a99 commit d892a78

File tree

3 files changed

+115
-90
lines changed

3 files changed

+115
-90
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
#### Changed
2525

26-
- ...
26+
- [#917](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/917) Refactored to use new_client connection pattern
2727

2828
#### Added
2929

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 103 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,95 @@ class SQLServerAdapter < AbstractAdapter
6060
self.use_output_inserted = true
6161
self.exclude_output_inserted_table_names = Concurrent::Map.new { false }
6262

63-
def initialize(connection, logger = nil, config = {})
63+
class << self
64+
def new_client(config)
65+
case config[:mode]
66+
when :dblib
67+
require "tiny_tds"
68+
dblib_connect(config)
69+
when :odbc
70+
odbc_connect(config)
71+
else
72+
raise ArgumentError, "Unknown connection mode in #{config.inspect}."
73+
end
74+
end
75+
76+
def dblib_connect(config)
77+
TinyTds::Client.new(
78+
dataserver: config[:dataserver],
79+
host: config[:host],
80+
port: config[:port],
81+
username: config[:username],
82+
password: config[:password],
83+
database: config[:database],
84+
tds_version: config[:tds_version] || "7.3",
85+
appname: config_appname(config),
86+
login_timeout: config_login_timeout(config),
87+
timeout: config_timeout(config),
88+
encoding: config_encoding(config),
89+
azure: config[:azure],
90+
contained: config[:contained]
91+
).tap do |client|
92+
if config[:azure]
93+
client.execute("SET ANSI_NULLS ON").do
94+
client.execute("SET ANSI_NULL_DFLT_ON ON").do
95+
client.execute("SET ANSI_PADDING ON").do
96+
client.execute("SET ANSI_WARNINGS ON").do
97+
else
98+
client.execute("SET ANSI_DEFAULTS ON").do
99+
end
100+
client.execute("SET QUOTED_IDENTIFIER ON").do
101+
client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
102+
client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
103+
client.execute("SET TEXTSIZE 2147483647").do
104+
client.execute("SET CONCAT_NULL_YIELDS_NULL ON").do
105+
end
106+
rescue TinyTds::Error => e
107+
raise ActiveRecord::NoDatabaseError if e.message.match(/database .* does not exist/i)
108+
raise e
109+
end
110+
111+
112+
def odbc_connect(config)
113+
if config[:dsn].include?(';')
114+
driver = ODBC::Driver.new.tap do |d|
115+
d.name = config[:dsn_name] || 'Driver1'
116+
d.attrs = config[:dsn].split(';').map { |atr| atr.split('=') }.reject { |kv| kv.size != 2 }.reduce({}) { |a, e| k, v = e ; a[k] = v ; a }
117+
end
118+
ODBC::Database.new.drvconnect(driver)
119+
else
120+
ODBC.connect config[:dsn], config[:username], config[:password]
121+
end.tap do |c|
122+
begin
123+
c.use_time = true
124+
c.use_utc = ActiveRecord.default_timezone == :utc
125+
rescue Exception
126+
warn 'Ruby ODBC v0.99992 or higher is required.'
127+
end
128+
end
129+
end
130+
131+
def config_appname(config)
132+
config[:appname] || configure_application_name || Rails.application.class.name.split("::").first rescue nil
133+
end
134+
135+
def config_login_timeout(config)
136+
config[:login_timeout].present? ? config[:login_timeout].to_i : nil
137+
end
138+
139+
def config_timeout(config)
140+
config[:timeout].present? ? config[:timeout].to_i / 1000 : nil
141+
end
142+
143+
def config_encoding(config)
144+
config[:encoding].present? ? config[:encoding] : nil
145+
end
146+
end
147+
148+
def initialize(connection, logger, _connection_options, config)
64149
super(connection, logger, config)
65-
# Our Responsibility
66150
@connection_options = config
67-
connect
68-
initialize_dateformatter
69-
use_database
151+
configure_connection
70152
end
71153

72154
# === Abstract Adapter ========================================== #
@@ -229,6 +311,14 @@ def reset!
229311
do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
230312
end
231313

314+
def configure_connection
315+
@spid = _raw_select("SELECT @@SPID", fetch: :rows).first.first
316+
@version_year = version_year
317+
318+
initialize_dateformatter
319+
use_database
320+
end
321+
232322
# === Abstract Adapter (Misc Support) =========================== #
233323

234324
def tables_with_referential_integrity
@@ -411,100 +501,19 @@ def translate_exception(e, message:, sql:, binds:)
411501

412502
# === SQLServer Specific (Connection Management) ================ #
413503

414-
def connect
415-
config = @connection_options
416-
@connection = case config[:mode]
417-
when :dblib
418-
dblib_connect(config)
419-
when :odbc
420-
odbc_connect(config)
421-
end
422-
@spid = _raw_select("SELECT @@SPID", fetch: :rows).first.first
423-
@version_year = version_year
424-
configure_connection
425-
end
426-
427504
def connection_errors
428505
@connection_errors ||= [].tap do |errors|
429506
errors << TinyTds::Error if defined?(TinyTds::Error)
430507
errors << ODBC::Error if defined?(ODBC::Error)
431508
end
432509
end
433510

434-
def dblib_connect(config)
435-
TinyTds::Client.new(
436-
dataserver: config[:dataserver],
437-
host: config[:host],
438-
port: config[:port],
439-
username: config[:username],
440-
password: config[:password],
441-
database: config[:database],
442-
tds_version: config[:tds_version] || "7.3",
443-
appname: config_appname(config),
444-
login_timeout: config_login_timeout(config),
445-
timeout: config_timeout(config),
446-
encoding: config_encoding(config),
447-
azure: config[:azure],
448-
contained: config[:contained]
449-
).tap do |client|
450-
if config[:azure]
451-
client.execute("SET ANSI_NULLS ON").do
452-
client.execute("SET ANSI_NULL_DFLT_ON ON").do
453-
client.execute("SET ANSI_PADDING ON").do
454-
client.execute("SET ANSI_WARNINGS ON").do
455-
else
456-
client.execute("SET ANSI_DEFAULTS ON").do
457-
end
458-
client.execute("SET QUOTED_IDENTIFIER ON").do
459-
client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
460-
client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
461-
client.execute("SET TEXTSIZE 2147483647").do
462-
client.execute("SET CONCAT_NULL_YIELDS_NULL ON").do
463-
end
464-
end
465-
466-
def odbc_connect(config)
467-
if config[:dsn].include?(';')
468-
driver = ODBC::Driver.new.tap do |d|
469-
d.name = config[:dsn_name] || 'Driver1'
470-
d.attrs = config[:dsn].split(';').map { |atr| atr.split('=') }.reject { |kv| kv.size != 2 }.reduce({}) { |a, e| k, v = e ; a[k] = v ; a }
471-
end
472-
ODBC::Database.new.drvconnect(driver)
473-
else
474-
ODBC.connect config[:dsn], config[:username], config[:password]
475-
end.tap do |c|
476-
begin
477-
c.use_time = true
478-
c.use_utc = ActiveRecord::Base.default_timezone == :utc
479-
rescue Exception
480-
warn 'Ruby ODBC v0.99992 or higher is required.'
481-
end
482-
end
483-
end
484-
485-
def config_appname(config)
486-
config[:appname] || configure_application_name || Rails.application.class.name.split("::").first rescue nil
487-
end
488-
489-
def config_login_timeout(config)
490-
config[:login_timeout].present? ? config[:login_timeout].to_i : nil
491-
end
492-
493-
def config_timeout(config)
494-
config[:timeout].present? ? config[:timeout].to_i / 1000 : nil
495-
end
496-
497-
def config_encoding(config)
498-
config[:encoding].present? ? config[:encoding] : nil
499-
end
500-
501-
def configure_connection; end
502-
503511
def configure_application_name; end
504512

505513
def initialize_dateformatter
506514
@database_dateformat = user_options_dateformat
507515
a, b, c = @database_dateformat.each_char.to_a
516+
508517
[a, b, c].each { |f| f.upcase! if f == "y" }
509518
dateformat = "%#{a}-%#{b}-%#{c}"
510519
::Date::DATE_FORMATS[:_sqlserver_dateformat] = dateformat
@@ -527,6 +536,13 @@ def version_year
527536
def sqlserver_version
528537
@sqlserver_version ||= _raw_select("SELECT @@version", fetch: :rows).first.first.to_s
529538
end
539+
540+
private
541+
542+
def connect
543+
@connection = self.class.new_client(@connection_options)
544+
configure_connection
545+
end
530546
end
531547
end
532548
end

lib/active_record/sqlserver_base.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
module ActiveRecord
44
module ConnectionHandling
5+
def sqlserver_adapter_class
6+
ConnectionAdapters::SQLServerAdapter
7+
end
8+
59
def sqlserver_connection(config) #:nodoc:
610
config = config.symbolize_keys
711
config.reverse_merge! mode: :dblib
@@ -16,7 +20,12 @@ def sqlserver_connection(config) #:nodoc:
1620
else
1721
raise ArgumentError, "Unknown connection mode in #{config.inspect}."
1822
end
19-
ConnectionAdapters::SQLServerAdapter.new(nil, nil, config.merge(mode: mode))
23+
sqlserver_adapter_class.new(
24+
sqlserver_adapter_class.new_client(config),
25+
logger,
26+
nil,
27+
config
28+
)
2029
rescue ODBC::Error => e
2130
if e.message.match(/database .* does not exist/i)
2231
raise ActiveRecord::NoDatabaseError
@@ -25,4 +34,4 @@ def sqlserver_connection(config) #:nodoc:
2534
end
2635
end
2736
end
28-
end
37+
end

0 commit comments

Comments
 (0)