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.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008-2011
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ require 'set'
2
+ require 'active_record/base'
3
+ require 'active_record/version'
4
+ require 'active_support/concern'
5
+ require 'active_support/core_ext/class/attribute'
6
+
7
+ module ActiveRecord
8
+ module ConnectionAdapters
9
+ module Sqlserver
10
+ module CoreExt
11
+ module ActiveRecord
12
+
13
+ extend ActiveSupport::Concern
14
+
15
+ included do
16
+ class_attribute :coerced_sqlserver_date_columns, :coerced_sqlserver_time_columns
17
+ self.coerced_sqlserver_date_columns = Set.new
18
+ self.coerced_sqlserver_time_columns = Set.new
19
+ end
20
+
21
+ module ClassMethods
22
+
23
+ def execute_procedure(proc_name, *variables)
24
+ if connection.respond_to?(:execute_procedure)
25
+ connection.execute_procedure(proc_name,*variables)
26
+ else
27
+ []
28
+ end
29
+ end
30
+
31
+ def coerce_sqlserver_date(*attributes)
32
+ self.coerced_sqlserver_date_columns += attributes.map(&:to_s)
33
+ end
34
+
35
+ def coerce_sqlserver_time(*attributes)
36
+ self.coerced_sqlserver_time_columns += attributes.map(&:to_s)
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+
48
+ ActiveRecord::Base.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::ActiveRecord
49
+
@@ -0,0 +1,97 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module Sqlserver
4
+ module CoreExt
5
+ module DatabaseStatements
6
+
7
+ # This is a copy of the current (3.1.3) ActiveRecord's transaction method. We should propose
8
+ # a patch to the default transaction method to make it more callback for adapters that want to
9
+ # do deadlock retry logic. Because this is a copy, we really need to keep an eye out on this when
10
+ # upgradding the adapter.
11
+ def transaction_with_retry_deadlock_victim(options = {})
12
+ options.assert_valid_keys :requires_new, :joinable
13
+
14
+ last_transaction_joinable = defined?(@transaction_joinable) ? @transaction_joinable : nil
15
+ if options.has_key?(:joinable)
16
+ @transaction_joinable = options[:joinable]
17
+ else
18
+ @transaction_joinable = true
19
+ end
20
+ requires_new = options[:requires_new] || !last_transaction_joinable
21
+
22
+ transaction_open = false
23
+ @_current_transaction_records ||= []
24
+
25
+ begin
26
+ if block_given?
27
+ if requires_new || open_transactions == 0
28
+ if open_transactions == 0
29
+ begin_db_transaction
30
+ elsif requires_new
31
+ create_savepoint
32
+ end
33
+ increment_open_transactions
34
+ transaction_open = true
35
+ @_current_transaction_records.push([])
36
+ end
37
+ yield
38
+ end
39
+ rescue Exception => database_transaction_rollback
40
+ if transaction_open && !outside_transaction?
41
+ transaction_open = false
42
+ decrement_open_transactions
43
+ # handle deadlock victim retries at the outermost transaction
44
+ if open_transactions == 0
45
+ if database_transaction_rollback.is_a?(::ActiveRecord::DeadlockVictim)
46
+ # SQL Server has already rolled back, so rollback activerecord's history
47
+ rollback_transaction_records(true)
48
+ retry
49
+ else
50
+ rollback_db_transaction
51
+ rollback_transaction_records(true)
52
+ end
53
+ else
54
+ rollback_to_savepoint
55
+ rollback_transaction_records(false)
56
+ end
57
+ end
58
+ raise unless database_transaction_rollback.is_a?(::ActiveRecord::Rollback)
59
+ end
60
+ ensure
61
+ @transaction_joinable = last_transaction_joinable
62
+
63
+ if outside_transaction?
64
+ @open_transactions = 0
65
+ elsif transaction_open
66
+ decrement_open_transactions
67
+ begin
68
+ if open_transactions == 0
69
+ commit_db_transaction
70
+ commit_transaction_records
71
+ else
72
+ release_savepoint
73
+ save_point_records = @_current_transaction_records.pop
74
+ unless save_point_records.blank?
75
+ @_current_transaction_records.push([]) if @_current_transaction_records.empty?
76
+ @_current_transaction_records.last.concat(save_point_records)
77
+ end
78
+ end
79
+ rescue Exception => database_transaction_rollback
80
+ if open_transactions == 0
81
+ rollback_db_transaction
82
+ rollback_transaction_records(true)
83
+ else
84
+ rollback_to_savepoint
85
+ rollback_transaction_records(false)
86
+ end
87
+ raise
88
+ end
89
+ end
90
+ end
91
+
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+
@@ -0,0 +1,38 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module Sqlserver
4
+ module CoreExt
5
+ module ODBC
6
+
7
+ module Statement
8
+
9
+ def finished?
10
+ begin
11
+ connected?
12
+ false
13
+ rescue ::ODBC::Error
14
+ true
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ module Database
21
+
22
+ def run_block(*args)
23
+ yield sth = run(*args)
24
+ sth.drop
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+
36
+ ODBC::Statement.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::ODBC::Statement
37
+ ODBC::Database.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::ODBC::Database
38
+
@@ -0,0 +1,49 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module Sqlserver
4
+ module DatabaseLimits
5
+
6
+ def table_alias_length
7
+ 128
8
+ end
9
+
10
+ def column_name_length
11
+ 128
12
+ end
13
+
14
+ def table_name_length
15
+ 128
16
+ end
17
+
18
+ def index_name_length
19
+ 128
20
+ end
21
+
22
+ def columns_per_table
23
+ 1024
24
+ end
25
+
26
+ def indexes_per_table
27
+ 999
28
+ end
29
+
30
+ def columns_per_multicolumn_index
31
+ 16
32
+ end
33
+
34
+ def in_clause_length
35
+ 65536
36
+ end
37
+
38
+ def sql_query_length
39
+ 65536 * 4096
40
+ end
41
+
42
+ def joins_per_query
43
+ 256
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,445 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module Sqlserver
4
+ module DatabaseStatements
5
+
6
+ include CoreExt::DatabaseStatements
7
+
8
+ def select_rows(sql, name = nil)
9
+ raw_select sql, name, [], :fetch => :rows
10
+ end
11
+
12
+ def execute(sql, name = nil)
13
+ if id_insert_table_name = query_requires_identity_insert?(sql)
14
+ with_identity_insert_enabled(id_insert_table_name) { do_execute(sql,name) }
15
+ else
16
+ do_execute(sql,name)
17
+ end
18
+ end
19
+
20
+ def exec_query(sql, name = 'SQL', binds = [], sqlserver_options = {})
21
+ if id_insert_table_name = sqlserver_options[:insert] ? query_requires_identity_insert?(sql) : nil
22
+ with_identity_insert_enabled(id_insert_table_name) { do_exec_query(sql, name, binds) }
23
+ else
24
+ do_exec_query(sql, name, binds)
25
+ end
26
+ end
27
+
28
+ def exec_insert(sql, name, binds)
29
+ exec_query sql, name, binds, :insert => true
30
+ end
31
+
32
+ def exec_delete(sql, name, binds)
33
+ sql << "; SELECT @@ROWCOUNT AS AffectedRows"
34
+ super.rows.first.first
35
+ end
36
+
37
+ def exec_update(sql, name, binds)
38
+ sql << "; SELECT @@ROWCOUNT AS AffectedRows"
39
+ super.rows.first.first
40
+ end
41
+
42
+ def outside_transaction?
43
+ info_schema_query { select_value("SELECT @@TRANCOUNT") == 0 }
44
+ end
45
+
46
+ def supports_statement_cache?
47
+ true
48
+ end
49
+
50
+ def transaction(options = {})
51
+ if retry_deadlock_victim?
52
+ block_given? ? transaction_with_retry_deadlock_victim(options) { yield } : transaction_with_retry_deadlock_victim(options)
53
+ else
54
+ block_given? ? super(options) { yield } : super(options)
55
+ end
56
+ end
57
+
58
+ def begin_db_transaction
59
+ do_execute "BEGIN TRANSACTION"
60
+ end
61
+
62
+ def commit_db_transaction
63
+ disable_auto_reconnect { do_execute "COMMIT TRANSACTION" }
64
+ end
65
+
66
+ def rollback_db_transaction
67
+ do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
68
+ end
69
+
70
+ def create_savepoint
71
+ disable_auto_reconnect { do_execute "SAVE TRANSACTION #{current_savepoint_name}" }
72
+ end
73
+
74
+ def release_savepoint
75
+ end
76
+
77
+ def rollback_to_savepoint
78
+ disable_auto_reconnect { do_execute "ROLLBACK TRANSACTION #{current_savepoint_name}" }
79
+ end
80
+
81
+ def add_limit_offset!(sql, options)
82
+ raise NotImplementedError, 'This has been moved to the SQLServerCompiler in Arel.'
83
+ end
84
+
85
+ def empty_insert_statement_value
86
+ "DEFAULT VALUES"
87
+ end
88
+
89
+ def case_sensitive_modifier(node)
90
+ node.acts_like?(:string) ? Arel::Nodes::Bin.new(node) : node
91
+ end
92
+
93
+ # === SQLServer Specific ======================================== #
94
+
95
+ def execute_procedure(proc_name, *variables)
96
+ vars = variables.map{ |v| quote(v) }.join(', ')
97
+ sql = "EXEC #{proc_name} #{vars}".strip
98
+ name = 'Execute Procedure'
99
+ log(sql, name) do
100
+ case @connection_options[:mode]
101
+ when :dblib
102
+ result = @connection.execute(sql)
103
+ result.each(:as => :hash, :cache_rows => true) do |row|
104
+ r = row.with_indifferent_access
105
+ yield(r) if block_given?
106
+ end
107
+ result.each.map{ |row| row.is_a?(Hash) ? row.with_indifferent_access : row }
108
+ when :odbc
109
+ results = []
110
+ raw_connection_run(sql) do |handle|
111
+ get_rows = lambda {
112
+ rows = handle_to_names_and_values handle, :fetch => :all
113
+ rows.each_with_index { |r,i| rows[i] = r.with_indifferent_access }
114
+ results << rows
115
+ }
116
+ get_rows.call
117
+ while handle_more_results?(handle)
118
+ get_rows.call
119
+ end
120
+ end
121
+ results.many? ? results : results.first
122
+ end
123
+ end
124
+ end
125
+
126
+ def use_database(database=nil)
127
+ return if sqlserver_azure?
128
+ database ||= @connection_options[:database]
129
+ do_execute "USE #{quote_table_name(database)}" unless database.blank?
130
+ end
131
+
132
+ def user_options
133
+ return {} if sqlserver_azure?
134
+ info_schema_query do
135
+ select_rows("dbcc useroptions").inject(HashWithIndifferentAccess.new) do |values,row|
136
+ set_option = row[0].gsub(/\s+/,'_')
137
+ user_value = row[1]
138
+ values[set_option] = user_value
139
+ values
140
+ end
141
+ end
142
+ end
143
+
144
+ def user_options_dateformat
145
+ if sqlserver_azure?
146
+ info_schema_query { select_value "SELECT [dateformat] FROM [sys].[syslanguages] WHERE [langid] = @@LANGID" }
147
+ else
148
+ user_options['dateformat']
149
+ end
150
+ end
151
+
152
+ def user_options_isolation_level
153
+ if sqlserver_azure?
154
+ info_schema_query do
155
+ sql = %|SELECT CASE [transaction_isolation_level]
156
+ WHEN 0 THEN NULL
157
+ WHEN 1 THEN 'READ UNCOMITTED'
158
+ WHEN 2 THEN 'READ COMITTED'
159
+ WHEN 3 THEN 'REPEATABLE'
160
+ WHEN 4 THEN 'SERIALIZABLE'
161
+ WHEN 5 THEN 'SNAPSHOT' END AS [isolation_level]
162
+ FROM [sys].[dm_exec_sessions]
163
+ WHERE [session_id] = @@SPID|.squish
164
+ select_value(sql)
165
+ end
166
+ else
167
+ user_options['isolation_level']
168
+ end
169
+ end
170
+
171
+ def user_options_language
172
+ if sqlserver_azure?
173
+ info_schema_query { select_value "SELECT @@LANGUAGE AS [language]" }
174
+ else
175
+ user_options['language']
176
+ end
177
+ end
178
+
179
+ def run_with_isolation_level(isolation_level)
180
+ raise ArgumentError, "Invalid isolation level, #{isolation_level}. Supported levels include #{valid_isolation_levels.to_sentence}." if !valid_isolation_levels.include?(isolation_level.upcase)
181
+ initial_isolation_level = user_options_isolation_level || "READ COMMITTED"
182
+ do_execute "SET TRANSACTION ISOLATION LEVEL #{isolation_level}"
183
+ begin
184
+ yield
185
+ ensure
186
+ do_execute "SET TRANSACTION ISOLATION LEVEL #{initial_isolation_level}"
187
+ end if block_given?
188
+ end
189
+
190
+ def newid_function
191
+ select_value "SELECT NEWID()"
192
+ end
193
+
194
+ def newsequentialid_function
195
+ select_value "SELECT NEWSEQUENTIALID()"
196
+ end
197
+
198
+ def activity_stats
199
+ select_all %|
200
+ SELECT
201
+ [session_id] = s.session_id,
202
+ [user_process] = CONVERT(CHAR(1), s.is_user_process),
203
+ [login] = s.login_name,
204
+ [database] = ISNULL(db_name(r.database_id), N''),
205
+ [task_state] = ISNULL(t.task_state, N''),
206
+ [command] = ISNULL(r.command, N''),
207
+ [application] = ISNULL(s.program_name, N''),
208
+ [wait_time_ms] = ISNULL(w.wait_duration_ms, 0),
209
+ [wait_type] = ISNULL(w.wait_type, N''),
210
+ [wait_resource] = ISNULL(w.resource_description, N''),
211
+ [blocked_by] = ISNULL(CONVERT (varchar, w.blocking_session_id), ''),
212
+ [head_blocker] =
213
+ CASE
214
+ -- session has an active request, is blocked, but is blocking others
215
+ WHEN r2.session_id IS NOT NULL AND r.blocking_session_id = 0 THEN '1'
216
+ -- session is idle but has an open tran and is blocking others
217
+ WHEN r.session_id IS NULL THEN '1'
218
+ ELSE ''
219
+ END,
220
+ [total_cpu_ms] = s.cpu_time,
221
+ [total_physical_io_mb] = (s.reads + s.writes) * 8 / 1024,
222
+ [memory_use_kb] = s.memory_usage * 8192 / 1024,
223
+ [open_transactions] = ISNULL(r.open_transaction_count,0),
224
+ [login_time] = s.login_time,
225
+ [last_request_start_time] = s.last_request_start_time,
226
+ [host_name] = ISNULL(s.host_name, N''),
227
+ [net_address] = ISNULL(c.client_net_address, N''),
228
+ [execution_context_id] = ISNULL(t.exec_context_id, 0),
229
+ [request_id] = ISNULL(r.request_id, 0),
230
+ [workload_group] = N''
231
+ FROM sys.dm_exec_sessions s LEFT OUTER JOIN sys.dm_exec_connections c ON (s.session_id = c.session_id)
232
+ LEFT OUTER JOIN sys.dm_exec_requests r ON (s.session_id = r.session_id)
233
+ LEFT OUTER JOIN sys.dm_os_tasks t ON (r.session_id = t.session_id AND r.request_id = t.request_id)
234
+ LEFT OUTER JOIN
235
+ (SELECT *, ROW_NUMBER() OVER (PARTITION BY waiting_task_address ORDER BY wait_duration_ms DESC) AS row_num
236
+ FROM sys.dm_os_waiting_tasks
237
+ ) w ON (t.task_address = w.waiting_task_address) AND w.row_num = 1
238
+ LEFT OUTER JOIN sys.dm_exec_requests r2 ON (r.session_id = r2.blocking_session_id)
239
+ WHERE db_name(r.database_id) = '#{current_database}'
240
+ ORDER BY s.session_id|
241
+ end
242
+
243
+ # === SQLServer Specific (Rake/Test Helpers) ==================== #
244
+
245
+ def recreate_database
246
+ remove_database_connections_and_rollback do
247
+ do_execute "EXEC sp_MSforeachtable 'DROP TABLE ?'"
248
+ end
249
+ end
250
+
251
+ def recreate_database!(database=nil)
252
+ current_db = current_database
253
+ database ||= current_db
254
+ this_db = database.to_s == current_db
255
+ do_execute 'USE master' if this_db
256
+ drop_database(database)
257
+ create_database(database)
258
+ ensure
259
+ use_database(current_db) if this_db
260
+ end
261
+
262
+ def drop_database(database)
263
+ retry_count = 0
264
+ max_retries = 1
265
+ begin
266
+ do_execute "DROP DATABASE #{quote_table_name(database)}"
267
+ rescue ActiveRecord::StatementInvalid => err
268
+ if err.message =~ /because it is currently in use/i
269
+ raise if retry_count >= max_retries
270
+ retry_count += 1
271
+ remove_database_connections_and_rollback(database)
272
+ retry
273
+ elsif err.message =~ /does not exist/i
274
+ nil
275
+ else
276
+ raise
277
+ end
278
+ end
279
+ end
280
+
281
+ def create_database(database)
282
+ do_execute "CREATE DATABASE #{quote_table_name(database)}"
283
+ end
284
+
285
+ def current_database
286
+ select_value 'SELECT DB_NAME()'
287
+ end
288
+
289
+ def charset
290
+ select_value "SELECT SERVERPROPERTY('SqlCharSetName')"
291
+ end
292
+
293
+
294
+ protected
295
+
296
+ def select(sql, name = nil, binds = [])
297
+ exec_query(sql, name, binds).to_a
298
+ end
299
+
300
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
301
+ sql = "#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"# unless binds.empty?
302
+ super
303
+ end
304
+
305
+ def last_inserted_id(result)
306
+ super || select_value("SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident")
307
+ end
308
+
309
+ # === SQLServer Specific ======================================== #
310
+
311
+ def valid_isolation_levels
312
+ ["READ COMMITTED", "READ UNCOMMITTED", "REPEATABLE READ", "SERIALIZABLE", "SNAPSHOT"]
313
+ end
314
+
315
+ # === SQLServer Specific (Executing) ============================ #
316
+
317
+ def do_execute(sql, name = nil)
318
+ name ||= 'EXECUTE'
319
+ log(sql, name) do
320
+ with_sqlserver_error_handling { raw_connection_do(sql) }
321
+ end
322
+ end
323
+
324
+ def do_exec_query(sql, name, binds)
325
+ statement = quote(sql)
326
+ names_and_types = []
327
+ params = []
328
+ binds.each_with_index do |(column,value),index|
329
+ ar_column = column.is_a?(ActiveRecord::ConnectionAdapters::Column)
330
+ next if ar_column && column.sql_type == 'timestamp'
331
+ v = value
332
+ names_and_types << if ar_column
333
+ v = value.to_i if column.is_integer? && value.present?
334
+ "@#{index} #{column.sql_type_for_statement}"
335
+ elsif column.acts_like?(:string)
336
+ "@#{index} varchar(256)"
337
+ elsif column.is_a?(Fixnum)
338
+ v = value.to_i
339
+ "@#{index} int"
340
+ else
341
+ "@#{index} int"
342
+ #raise "Unknown bind columns. We can account for this."
343
+ end
344
+ quoted_value = ar_column ? quote(v,column) : quote(v,nil)
345
+ params << "@#{index} = #{quoted_value}"
346
+ end
347
+ sql = "EXEC sp_executesql #{statement}"
348
+ sql << ", #{quote(names_and_types.join(', '))}, #{params.join(', ')}" unless binds.empty?
349
+ raw_select sql, name, binds, :ar_result => true
350
+ end
351
+
352
+ def raw_connection_do(sql)
353
+ case @connection_options[:mode]
354
+ when :dblib
355
+ @connection.execute(sql).do
356
+ when :odbc
357
+ @connection.do(sql)
358
+ end
359
+ ensure
360
+ @update_sql = false
361
+ end
362
+
363
+ # === SQLServer Specific (Selecting) ============================ #
364
+
365
+ def raw_select(sql, name=nil, binds=[], options={})
366
+ log(sql,name,binds) { _raw_select(sql, options) }
367
+ end
368
+
369
+ def _raw_select(sql, options={})
370
+ begin
371
+ handle = raw_connection_run(sql)
372
+ handle_to_names_and_values(handle, options)
373
+ ensure
374
+ finish_statement_handle(handle)
375
+ end
376
+ end
377
+
378
+ def raw_connection_run(sql)
379
+ with_sqlserver_error_handling do
380
+ case @connection_options[:mode]
381
+ when :dblib
382
+ @connection.execute(sql)
383
+ when :odbc
384
+ block_given? ? @connection.run_block(sql) { |handle| yield(handle) } : @connection.run(sql)
385
+ end
386
+ end
387
+ end
388
+
389
+ def handle_more_results?(handle)
390
+ case @connection_options[:mode]
391
+ when :dblib
392
+ when :odbc
393
+ handle.more_results
394
+ end
395
+ end
396
+
397
+ def handle_to_names_and_values(handle, options={})
398
+ case @connection_options[:mode]
399
+ when :dblib
400
+ handle_to_names_and_values_dblib(handle, options)
401
+ when :odbc
402
+ handle_to_names_and_values_odbc(handle, options)
403
+ end
404
+ end
405
+
406
+ def handle_to_names_and_values_dblib(handle, options={})
407
+ query_options = {}.tap do |qo|
408
+ qo[:timezone] = ActiveRecord::Base.default_timezone || :utc
409
+ qo[:as] = (options[:ar_result] || options[:fetch] == :rows) ? :array : :hash
410
+ end
411
+ results = handle.each(query_options)
412
+ columns = lowercase_schema_reflection ? handle.fields.map { |c| c.downcase } : handle.fields
413
+ options[:ar_result] ? ActiveRecord::Result.new(columns, results) : results
414
+ end
415
+
416
+ def handle_to_names_and_values_odbc(handle, options={})
417
+ @connection.use_utc = ActiveRecord::Base.default_timezone == :utc
418
+ if options[:ar_result]
419
+ columns = lowercase_schema_reflection ? handle.columns(true).map { |c| c.name.downcase } : handle.columns(true).map { |c| c.name }
420
+ rows = handle.fetch_all || []
421
+ ActiveRecord::Result.new(columns, rows)
422
+ else
423
+ case options[:fetch]
424
+ when :all
425
+ handle.each_hash || []
426
+ when :rows
427
+ handle.fetch_all || []
428
+ end
429
+ end
430
+ end
431
+
432
+ def finish_statement_handle(handle)
433
+ case @connection_options[:mode]
434
+ when :dblib
435
+ handle.cancel if handle
436
+ when :odbc
437
+ handle.drop if handle && handle.respond_to?(:drop) && !handle.finished?
438
+ end
439
+ handle
440
+ end
441
+
442
+ end
443
+ end
444
+ end
445
+ end