@@ -60,13 +60,95 @@ class SQLServerAdapter < AbstractAdapter
60
60
self . use_output_inserted = true
61
61
self . exclude_output_inserted_table_names = Concurrent ::Map . new { false }
62
62
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 )
64
149
super ( connection , logger , config )
65
- # Our Responsibility
66
150
@connection_options = config
67
- connect
68
- initialize_dateformatter
69
- use_database
151
+ configure_connection
70
152
end
71
153
72
154
# === Abstract Adapter ========================================== #
@@ -229,6 +311,14 @@ def reset!
229
311
do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
230
312
end
231
313
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
+
232
322
# === Abstract Adapter (Misc Support) =========================== #
233
323
234
324
def tables_with_referential_integrity
@@ -411,100 +501,19 @@ def translate_exception(e, message:, sql:, binds:)
411
501
412
502
# === SQLServer Specific (Connection Management) ================ #
413
503
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
-
427
504
def connection_errors
428
505
@connection_errors ||= [ ] . tap do |errors |
429
506
errors << TinyTds ::Error if defined? ( TinyTds ::Error )
430
507
errors << ODBC ::Error if defined? ( ODBC ::Error )
431
508
end
432
509
end
433
510
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
-
503
511
def configure_application_name ; end
504
512
505
513
def initialize_dateformatter
506
514
@database_dateformat = user_options_dateformat
507
515
a , b , c = @database_dateformat . each_char . to_a
516
+
508
517
[ a , b , c ] . each { |f | f . upcase! if f == "y" }
509
518
dateformat = "%#{ a } -%#{ b } -%#{ c } "
510
519
::Date ::DATE_FORMATS [ :_sqlserver_dateformat ] = dateformat
@@ -527,6 +536,13 @@ def version_year
527
536
def sqlserver_version
528
537
@sqlserver_version ||= _raw_select ( "SELECT @@version" , fetch : :rows ) . first . first . to_s
529
538
end
539
+
540
+ private
541
+
542
+ def connect
543
+ @connection = self . class . new_client ( @connection_options )
544
+ configure_connection
545
+ end
530
546
end
531
547
end
532
548
end
0 commit comments