asa-2000 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +501 -0
- data/MIT-LICENSE +20 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +49 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/database_statements.rb +97 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +38 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +445 -0
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +36 -0
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +104 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +85 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +364 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +28 -0
- data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +516 -0
- data/lib/activerecord-sqlserver-adapter.rb +1 -0
- data/lib/arel/visitors/sqlserver.rb +386 -0
- metadata +81 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
class Utils
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def unqualify_table_name(table_name)
|
9
|
+
table_name.to_s.split('.').last.tr('[]','')
|
10
|
+
end
|
11
|
+
|
12
|
+
def unqualify_table_schema(table_name)
|
13
|
+
table_name.to_s.split('.')[-2].gsub(/[\[\]]/,'') rescue nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def unqualify_db_name(table_name)
|
17
|
+
table_names = table_name.to_s.split('.')
|
18
|
+
table_names.length == 3 ? table_names.first.tr('[]','') : nil
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
@@ -0,0 +1,516 @@
|
|
1
|
+
require 'arel/visitors/sqlserver'
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
4
|
+
require 'active_record/connection_adapters/sqlserver/core_ext/active_record'
|
5
|
+
require 'active_record/connection_adapters/sqlserver/core_ext/database_statements'
|
6
|
+
require 'active_record/connection_adapters/sqlserver/database_limits'
|
7
|
+
require 'active_record/connection_adapters/sqlserver/database_statements'
|
8
|
+
require 'active_record/connection_adapters/sqlserver/errors'
|
9
|
+
require 'active_record/connection_adapters/sqlserver/schema_cache'
|
10
|
+
require 'active_record/connection_adapters/sqlserver/schema_statements'
|
11
|
+
require 'active_record/connection_adapters/sqlserver/quoting'
|
12
|
+
require 'active_record/connection_adapters/sqlserver/utils'
|
13
|
+
require 'active_record/connection_adapters/sqlserver/version'
|
14
|
+
require 'active_support/core_ext/string'
|
15
|
+
require 'base64'
|
16
|
+
|
17
|
+
module ActiveRecord
|
18
|
+
|
19
|
+
class Base
|
20
|
+
|
21
|
+
def self.sqlserver_connection(config) #:nodoc:
|
22
|
+
config = config.symbolize_keys
|
23
|
+
config.reverse_merge! :mode => :dblib, :host => 'localhost', :username => 'sa', :password => ''
|
24
|
+
mode = config[:mode].to_s.downcase.underscore.to_sym
|
25
|
+
case mode
|
26
|
+
when :dblib
|
27
|
+
require 'tiny_tds'
|
28
|
+
warn("TinyTds v0.4.3 or higher required. Using #{TinyTds::VERSION}") unless TinyTds::Client.instance_methods.map(&:to_s).include?("active?")
|
29
|
+
when :odbc
|
30
|
+
raise ArgumentError, 'Missing :dsn configuration.' unless config.has_key?(:dsn)
|
31
|
+
require 'odbc'
|
32
|
+
require 'active_record/connection_adapters/sqlserver/core_ext/odbc'
|
33
|
+
else
|
34
|
+
raise ArgumentError, "Unknown connection mode in #{config.inspect}."
|
35
|
+
end
|
36
|
+
ConnectionAdapters::SQLServerAdapter.new(nil, logger, nil, config.merge(:mode=>mode))
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def self.did_retry_sqlserver_connection(connection,count)
|
42
|
+
logger.info "CONNECTION RETRY: #{connection.class.name} retry ##{count}."
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.did_lose_sqlserver_connection(connection)
|
46
|
+
logger.info "CONNECTION LOST: #{connection.class.name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
module ConnectionAdapters
|
52
|
+
|
53
|
+
class SQLServerColumn < Column
|
54
|
+
|
55
|
+
def initialize(name, default, sql_type = nil, null = true, sqlserver_options = {})
|
56
|
+
@sqlserver_options = sqlserver_options.symbolize_keys
|
57
|
+
super(name, default, sql_type, null)
|
58
|
+
@primary = @sqlserver_options[:is_identity] || @sqlserver_options[:is_primary]
|
59
|
+
end
|
60
|
+
|
61
|
+
class << self
|
62
|
+
|
63
|
+
def string_to_binary(value)
|
64
|
+
"0x#{value.unpack("H*")[0]}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def binary_to_string(value)
|
68
|
+
value =~ /[^[:xdigit:]]/ ? value : [value].pack('H*')
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
def is_identity?
|
74
|
+
@sqlserver_options[:is_identity]
|
75
|
+
end
|
76
|
+
|
77
|
+
def is_primary?
|
78
|
+
@sqlserver_options[:is_primary]
|
79
|
+
end
|
80
|
+
|
81
|
+
def is_utf8?
|
82
|
+
!!(@sql_type =~ /nvarchar|ntext|nchar/i)
|
83
|
+
end
|
84
|
+
|
85
|
+
def is_integer?
|
86
|
+
!!(@sql_type =~ /int/i)
|
87
|
+
end
|
88
|
+
|
89
|
+
def is_real?
|
90
|
+
!!(@sql_type =~ /real/i)
|
91
|
+
end
|
92
|
+
|
93
|
+
def sql_type_for_statement
|
94
|
+
if is_integer? || is_real?
|
95
|
+
sql_type.sub(/\(\d+\)/,'')
|
96
|
+
else
|
97
|
+
sql_type
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def default_function
|
102
|
+
@sqlserver_options[:default_function]
|
103
|
+
end
|
104
|
+
|
105
|
+
def table_name
|
106
|
+
@sqlserver_options[:table_name]
|
107
|
+
end
|
108
|
+
|
109
|
+
def table_klass
|
110
|
+
@table_klass ||= begin
|
111
|
+
table_name.classify.constantize
|
112
|
+
rescue StandardError, NameError, LoadError
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
(@table_klass && @table_klass < ActiveRecord::Base) ? @table_klass : nil
|
116
|
+
end
|
117
|
+
|
118
|
+
def database_year
|
119
|
+
@sqlserver_options[:database_year]
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def extract_limit(sql_type)
|
126
|
+
case sql_type
|
127
|
+
when /^smallint/i
|
128
|
+
2
|
129
|
+
when /^int/i
|
130
|
+
4
|
131
|
+
when /^bigint/i
|
132
|
+
8
|
133
|
+
when /\(max\)/, /decimal/, /numeric/
|
134
|
+
nil
|
135
|
+
else
|
136
|
+
super
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def simplified_type(field_type)
|
141
|
+
case field_type
|
142
|
+
when /real/i then :float
|
143
|
+
when /money/i then :decimal
|
144
|
+
when /image/i then :binary
|
145
|
+
when /bit/i then :boolean
|
146
|
+
when /uniqueidentifier/i then :string
|
147
|
+
when /datetime/i then simplified_datetime
|
148
|
+
when /varchar\(max\)/ then :text
|
149
|
+
when /timestamp/ then :binary
|
150
|
+
else super
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def simplified_datetime
|
155
|
+
if database_year >= 2008
|
156
|
+
:datetime
|
157
|
+
elsif table_klass && table_klass.coerced_sqlserver_date_columns.include?(name)
|
158
|
+
:date
|
159
|
+
elsif table_klass && table_klass.coerced_sqlserver_time_columns.include?(name)
|
160
|
+
:time
|
161
|
+
else
|
162
|
+
:datetime
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end #class SQLServerColumn
|
167
|
+
|
168
|
+
class SQLServerAdapter < AbstractAdapter
|
169
|
+
|
170
|
+
include Sqlserver::Quoting
|
171
|
+
include Sqlserver::DatabaseStatements
|
172
|
+
include Sqlserver::SchemaStatements
|
173
|
+
include Sqlserver::DatabaseLimits
|
174
|
+
include Sqlserver::Errors
|
175
|
+
include Sqlserver::Version
|
176
|
+
|
177
|
+
ADAPTER_NAME = 'SQLServer'.freeze
|
178
|
+
DATABASE_VERSION_REGEXP = /Microsoft SQL Server\s+"?(\d{4}|\w+)"?/
|
179
|
+
SUPPORTED_VERSIONS = [2005,2008,2010,2011].freeze
|
180
|
+
|
181
|
+
attr_reader :database_version, :database_year, :spid, :product_level, :product_version, :edition
|
182
|
+
|
183
|
+
cattr_accessor :native_text_database_type, :native_binary_database_type, :native_string_database_type,
|
184
|
+
:log_info_schema_queries, :enable_default_unicode_types, :auto_connect, :retry_deadlock_victim,
|
185
|
+
:cs_equality_operator, :lowercase_schema_reflection, :auto_connect_duration
|
186
|
+
|
187
|
+
self.enable_default_unicode_types = true
|
188
|
+
|
189
|
+
|
190
|
+
def initialize(connection, logger, pool, config)
|
191
|
+
super(connection, logger, pool)
|
192
|
+
# AbstractAdapter Responsibility
|
193
|
+
@schema_cache = Sqlserver::SchemaCache.new self
|
194
|
+
@visitor = Arel::Visitors::SQLServer.new self
|
195
|
+
# Our Responsibility
|
196
|
+
@connection_options = config
|
197
|
+
connect
|
198
|
+
@database_version = info_schema_query { select_value('SELECT @@version') }
|
199
|
+
@database_year = begin
|
200
|
+
if @database_version =~ /Microsoft SQL Azure/i
|
201
|
+
@sqlserver_azure = true
|
202
|
+
@database_version.match(/\s(\d{4})\s/)[1].to_i
|
203
|
+
else
|
204
|
+
year = DATABASE_VERSION_REGEXP.match(@database_version)[1]
|
205
|
+
year == "Denali" ? 2011 : year.to_i
|
206
|
+
end
|
207
|
+
rescue
|
208
|
+
0
|
209
|
+
end
|
210
|
+
@product_level = info_schema_query { select_value("SELECT CAST(SERVERPROPERTY('productlevel') AS VARCHAR(128))") }
|
211
|
+
@product_version = info_schema_query { select_value("SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(128))") }
|
212
|
+
@edition = info_schema_query { select_value("SELECT CAST(SERVERPROPERTY('edition') AS VARCHAR(128))") }
|
213
|
+
initialize_dateformatter
|
214
|
+
use_database
|
215
|
+
unless SUPPORTED_VERSIONS.include?(@database_year)
|
216
|
+
#raise NotImplementedError, "Currently, only #{SUPPORTED_VERSIONS.to_sentence} are supported. We got back #{@database_version}."
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# === Abstract Adapter ========================================== #
|
221
|
+
|
222
|
+
def adapter_name
|
223
|
+
ADAPTER_NAME
|
224
|
+
end
|
225
|
+
|
226
|
+
def supports_migrations?
|
227
|
+
true
|
228
|
+
end
|
229
|
+
|
230
|
+
def supports_primary_key?
|
231
|
+
true
|
232
|
+
end
|
233
|
+
|
234
|
+
def supports_count_distinct?
|
235
|
+
true
|
236
|
+
end
|
237
|
+
|
238
|
+
def supports_ddl_transactions?
|
239
|
+
true
|
240
|
+
end
|
241
|
+
|
242
|
+
def supports_savepoints?
|
243
|
+
true
|
244
|
+
end
|
245
|
+
|
246
|
+
def disable_referential_integrity
|
247
|
+
do_execute "EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'"
|
248
|
+
yield
|
249
|
+
ensure
|
250
|
+
do_execute "EXEC sp_MSforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL'"
|
251
|
+
end
|
252
|
+
|
253
|
+
# === Abstract Adapter (Connection Management) ================== #
|
254
|
+
|
255
|
+
def active?
|
256
|
+
case @connection_options[:mode]
|
257
|
+
when :dblib
|
258
|
+
return @connection.active?
|
259
|
+
end
|
260
|
+
raw_connection_do("SELECT 1")
|
261
|
+
true
|
262
|
+
rescue *lost_connection_exceptions
|
263
|
+
false
|
264
|
+
end
|
265
|
+
|
266
|
+
def reconnect!
|
267
|
+
disconnect!
|
268
|
+
connect
|
269
|
+
active?
|
270
|
+
end
|
271
|
+
|
272
|
+
def disconnect!
|
273
|
+
@spid = nil
|
274
|
+
case @connection_options[:mode]
|
275
|
+
when :dblib
|
276
|
+
@connection.close rescue nil
|
277
|
+
when :odbc
|
278
|
+
@connection.disconnect rescue nil
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def reset!
|
283
|
+
remove_database_connections_and_rollback { }
|
284
|
+
end
|
285
|
+
|
286
|
+
# === Abstract Adapter (Misc Support) =========================== #
|
287
|
+
|
288
|
+
def pk_and_sequence_for(table_name)
|
289
|
+
idcol = identity_column(table_name)
|
290
|
+
idcol ? [idcol.name,nil] : nil
|
291
|
+
end
|
292
|
+
|
293
|
+
def primary_key(table_name)
|
294
|
+
identity_column(table_name).try(:name) || schema_cache.columns[table_name].detect(&:is_primary?).try(:name)
|
295
|
+
end
|
296
|
+
|
297
|
+
# === SQLServer Specific (DB Reflection) ======================== #
|
298
|
+
|
299
|
+
def sqlserver?
|
300
|
+
true
|
301
|
+
end
|
302
|
+
|
303
|
+
def sqlserver_2005?
|
304
|
+
@database_year == 2005
|
305
|
+
end
|
306
|
+
|
307
|
+
def sqlserver_2008?
|
308
|
+
@database_year == 2008
|
309
|
+
end
|
310
|
+
|
311
|
+
def sqlserver_2011?
|
312
|
+
@database_year == 2011
|
313
|
+
end
|
314
|
+
|
315
|
+
def sqlserver_azure?
|
316
|
+
@sqlserver_azure
|
317
|
+
end
|
318
|
+
|
319
|
+
def version
|
320
|
+
self.class::VERSION
|
321
|
+
end
|
322
|
+
|
323
|
+
def inspect
|
324
|
+
"#<#{self.class} version: #{version}, year: #{@database_year}, product_level: #{@product_level.inspect}, product_version: #{@product_version.inspect}, edition: #{@edition.inspect}, connection_options: #{@connection_options.inspect}>"
|
325
|
+
end
|
326
|
+
|
327
|
+
def auto_connect
|
328
|
+
@@auto_connect.is_a?(FalseClass) ? false : true
|
329
|
+
end
|
330
|
+
|
331
|
+
def auto_connect_duration
|
332
|
+
@@auto_connect_duration ||= 10
|
333
|
+
end
|
334
|
+
|
335
|
+
def retry_deadlock_victim
|
336
|
+
@@retry_deadlock_victim.is_a?(FalseClass) ? false : true
|
337
|
+
end
|
338
|
+
alias :retry_deadlock_victim? :retry_deadlock_victim
|
339
|
+
|
340
|
+
def native_string_database_type
|
341
|
+
@@native_string_database_type || (enable_default_unicode_types ? 'nvarchar' : 'varchar')
|
342
|
+
end
|
343
|
+
|
344
|
+
def native_text_database_type
|
345
|
+
@@native_text_database_type || enable_default_unicode_types ? 'nvarchar(max)' : 'varchar(max)'
|
346
|
+
end
|
347
|
+
|
348
|
+
def native_time_database_type
|
349
|
+
sqlserver_2005? ? 'datetime' : 'time'
|
350
|
+
end
|
351
|
+
|
352
|
+
def native_date_database_type
|
353
|
+
sqlserver_2005? ? 'datetime' : 'date'
|
354
|
+
end
|
355
|
+
|
356
|
+
def native_binary_database_type
|
357
|
+
@@native_binary_database_type || 'varbinary(max)'
|
358
|
+
end
|
359
|
+
|
360
|
+
def cs_equality_operator
|
361
|
+
@@cs_equality_operator || 'COLLATE Latin1_General_CS_AS_WS'
|
362
|
+
end
|
363
|
+
|
364
|
+
protected
|
365
|
+
|
366
|
+
# === Abstract Adapter (Misc Support) =========================== #
|
367
|
+
|
368
|
+
def translate_exception(e, message)
|
369
|
+
case message
|
370
|
+
when /cannot insert duplicate key .* with unique index/i
|
371
|
+
RecordNotUnique.new(message,e)
|
372
|
+
when /conflicted with the foreign key constraint/i
|
373
|
+
InvalidForeignKey.new(message,e)
|
374
|
+
when /has been chosen as the deadlock victim/i
|
375
|
+
DeadlockVictim.new(message,e)
|
376
|
+
when *lost_connection_messages
|
377
|
+
LostConnection.new(message,e)
|
378
|
+
else
|
379
|
+
super
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
# === SQLServer Specific (Connection Management) ================ #
|
384
|
+
|
385
|
+
def connect
|
386
|
+
config = @connection_options
|
387
|
+
@connection = case config[:mode]
|
388
|
+
when :dblib
|
389
|
+
appname = config[:appname] || configure_application_name || Rails.application.class.name.split('::').first rescue nil
|
390
|
+
login_timeout = config[:login_timeout].present? ? config[:login_timeout].to_i : nil
|
391
|
+
timeout = config[:timeout].present? ? config[:timeout].to_i/1000 : nil
|
392
|
+
encoding = config[:encoding].present? ? config[:encoding] : nil
|
393
|
+
TinyTds::Client.new({
|
394
|
+
:dataserver => config[:dataserver],
|
395
|
+
:host => config[:host],
|
396
|
+
:port => config[:port],
|
397
|
+
:username => config[:username],
|
398
|
+
:password => config[:password],
|
399
|
+
:database => config[:database],
|
400
|
+
:appname => appname,
|
401
|
+
:login_timeout => login_timeout,
|
402
|
+
:timeout => timeout,
|
403
|
+
:encoding => encoding,
|
404
|
+
:azure => config[:azure]
|
405
|
+
}).tap do |client|
|
406
|
+
if config[:azure]
|
407
|
+
client.execute("SET ANSI_NULLS ON").do
|
408
|
+
client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
|
409
|
+
client.execute("SET ANSI_NULL_DFLT_ON ON").do
|
410
|
+
client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
|
411
|
+
client.execute("SET ANSI_PADDING ON").do
|
412
|
+
client.execute("SET QUOTED_IDENTIFIER ON")
|
413
|
+
client.execute("SET ANSI_WARNINGS ON").do
|
414
|
+
else
|
415
|
+
client.execute("SET ANSI_DEFAULTS ON").do
|
416
|
+
client.execute("SET CURSOR_CLOSE_ON_COMMIT OFF").do
|
417
|
+
client.execute("SET IMPLICIT_TRANSACTIONS OFF").do
|
418
|
+
end
|
419
|
+
end
|
420
|
+
when :odbc
|
421
|
+
if config[:dsn].include?(';')
|
422
|
+
driver = ODBC::Driver.new.tap do |d|
|
423
|
+
d.name = config[:dsn_name] || 'Driver1'
|
424
|
+
d.attrs = config[:dsn].split(';').map{ |atr| atr.split('=') }.reject{ |kv| kv.size != 2 }.inject({}){ |h,kv| k,v = kv ; h[k] = v ; h }
|
425
|
+
end
|
426
|
+
ODBC::Database.new.drvconnect(driver)
|
427
|
+
else
|
428
|
+
ODBC.connect config[:dsn], config[:username], config[:password]
|
429
|
+
end.tap do |c|
|
430
|
+
begin
|
431
|
+
c.use_time = true
|
432
|
+
c.use_utc = ActiveRecord::Base.default_timezone == :utc
|
433
|
+
rescue Exception => e
|
434
|
+
warn "Ruby ODBC v0.99992 or higher is required."
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
@spid = _raw_select("SELECT @@SPID", :fetch => :rows).first.first
|
439
|
+
configure_connection
|
440
|
+
rescue
|
441
|
+
raise unless @auto_connecting
|
442
|
+
end
|
443
|
+
|
444
|
+
# Override this method so every connection can be configured to your needs.
|
445
|
+
# For example:
|
446
|
+
# raw_connection_do "SET TEXTSIZE #{64.megabytes}"
|
447
|
+
# raw_connection_do "SET CONCAT_NULL_YIELDS_NULL ON"
|
448
|
+
def configure_connection
|
449
|
+
end
|
450
|
+
|
451
|
+
# Override this method so every connection can have a unique name. Max 30 characters. Used by TinyTDS only.
|
452
|
+
# For example:
|
453
|
+
# "myapp_#{$$}_#{Thread.current.object_id}".to(29)
|
454
|
+
def configure_application_name
|
455
|
+
end
|
456
|
+
|
457
|
+
def initialize_dateformatter
|
458
|
+
@database_dateformat = user_options_dateformat
|
459
|
+
a, b, c = @database_dateformat.each_char.to_a
|
460
|
+
[a,b,c].each { |f| f.upcase! if f == 'y' }
|
461
|
+
dateformat = "%#{a}-%#{b}-%#{c}"
|
462
|
+
::Date::DATE_FORMATS[:_sqlserver_dateformat] = dateformat
|
463
|
+
::Time::DATE_FORMATS[:_sqlserver_dateformat] = dateformat
|
464
|
+
end
|
465
|
+
|
466
|
+
def remove_database_connections_and_rollback(database=nil)
|
467
|
+
database ||= current_database
|
468
|
+
do_execute "ALTER DATABASE #{quote_table_name(database)} SET SINGLE_USER WITH ROLLBACK IMMEDIATE"
|
469
|
+
begin
|
470
|
+
yield
|
471
|
+
ensure
|
472
|
+
do_execute "ALTER DATABASE #{quote_table_name(database)} SET MULTI_USER"
|
473
|
+
end if block_given?
|
474
|
+
end
|
475
|
+
|
476
|
+
def with_sqlserver_error_handling
|
477
|
+
begin
|
478
|
+
yield
|
479
|
+
rescue Exception => e
|
480
|
+
case translate_exception(e,e.message)
|
481
|
+
when LostConnection; retry if auto_reconnected?
|
482
|
+
when DeadlockVictim; retry if retry_deadlock_victim? && open_transactions == 0
|
483
|
+
end
|
484
|
+
raise
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
def disable_auto_reconnect
|
489
|
+
old_auto_connect, self.class.auto_connect = self.class.auto_connect, false
|
490
|
+
yield
|
491
|
+
ensure
|
492
|
+
self.class.auto_connect = old_auto_connect
|
493
|
+
end
|
494
|
+
|
495
|
+
def auto_reconnected?
|
496
|
+
return false unless auto_connect
|
497
|
+
@auto_connecting = true
|
498
|
+
count = 0
|
499
|
+
while count <= (auto_connect_duration / 2)
|
500
|
+
sleep 2** count
|
501
|
+
ActiveRecord::Base.did_retry_sqlserver_connection(self,count)
|
502
|
+
return true if reconnect!
|
503
|
+
count += 1
|
504
|
+
end
|
505
|
+
ActiveRecord::Base.did_lose_sqlserver_connection(self)
|
506
|
+
false
|
507
|
+
ensure
|
508
|
+
@auto_connecting = false
|
509
|
+
end
|
510
|
+
|
511
|
+
end #class SQLServerAdapter < AbstractAdapter
|
512
|
+
|
513
|
+
end #module ConnectionAdapters
|
514
|
+
|
515
|
+
end #module ActiveRecord
|
516
|
+
|