activerecord-sqlserver-adapter-vailsys 3.0.20
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +430 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +176 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +58 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +57 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +415 -0
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +35 -0
- data/lib/active_record/connection_adapters/sqlserver/query_cache.rb +17 -0
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +55 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +404 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +484 -0
- data/lib/activerecord-sqlserver-adapter.rb +1 -0
- data/lib/arel/visitors/sqlserver.rb +329 -0
- metadata +103 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'active_record/version'
|
2
|
+
require 'active_support/core_ext/class/inheritable_attributes'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module ConnectionAdapters
|
6
|
+
module Sqlserver
|
7
|
+
module CoreExt
|
8
|
+
module ActiveRecord
|
9
|
+
|
10
|
+
def self.included(klass)
|
11
|
+
klass.extend ClassMethods
|
12
|
+
class << klass
|
13
|
+
alias_method_chain :reset_column_information, :sqlserver_cache_support
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
|
19
|
+
def execute_procedure(proc_name, *variables)
|
20
|
+
if connection.respond_to?(:execute_procedure)
|
21
|
+
connection.execute_procedure(proc_name,*variables)
|
22
|
+
else
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def coerce_sqlserver_date(*attributes)
|
28
|
+
write_inheritable_attribute :coerced_sqlserver_date_columns, Set.new(attributes.map(&:to_s))
|
29
|
+
end
|
30
|
+
|
31
|
+
def coerce_sqlserver_time(*attributes)
|
32
|
+
write_inheritable_attribute :coerced_sqlserver_time_columns, Set.new(attributes.map(&:to_s))
|
33
|
+
end
|
34
|
+
|
35
|
+
def coerced_sqlserver_date_columns
|
36
|
+
read_inheritable_attribute(:coerced_sqlserver_date_columns) || []
|
37
|
+
end
|
38
|
+
|
39
|
+
def coerced_sqlserver_time_columns
|
40
|
+
read_inheritable_attribute(:coerced_sqlserver_time_columns) || []
|
41
|
+
end
|
42
|
+
|
43
|
+
def reset_column_information_with_sqlserver_cache_support
|
44
|
+
connection.send(:initialize_sqlserver_caches) if connection.respond_to?(:sqlserver?)
|
45
|
+
reset_column_information_without_sqlserver_cache_support
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
ActiveRecord::Base.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::ActiveRecord
|
58
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
module CoreExt
|
5
|
+
module ODBC
|
6
|
+
|
7
|
+
module TimeStamp
|
8
|
+
|
9
|
+
def to_sqlserver_string
|
10
|
+
date, time, nanoseconds = to_s.split(' ')
|
11
|
+
"#{date} #{time}.#{sprintf("%03d",nanoseconds.to_i/1000000)}"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
module Statement
|
17
|
+
|
18
|
+
def finished?
|
19
|
+
begin
|
20
|
+
connected?
|
21
|
+
false
|
22
|
+
rescue *Database.parent_modules_error_exceptions
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
module Database
|
30
|
+
|
31
|
+
def self.parent_modules
|
32
|
+
@parent_module ||= ['ODBC','ODBC_UTF8','ODBC_NONE'].map{ |odbc_ns| odbc_ns.constantize rescue nil }.compact
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.parent_modules_error_exceptions
|
36
|
+
@parent_modules_error_exceptions ||= parent_modules.map { |odbc_ns| "::#{odbc_ns}::Error".constantize }
|
37
|
+
end
|
38
|
+
|
39
|
+
def run_block(*args)
|
40
|
+
yield sth = run(*args)
|
41
|
+
sth.drop
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
['ODBC','ODBC_UTF8','ODBC_NONE'].map{ |odbc_ns| odbc_ns.constantize rescue nil }.compact.each do |ns|
|
53
|
+
ns::TimeStamp.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::ODBC::TimeStamp
|
54
|
+
ns::Statement.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::ODBC::Statement
|
55
|
+
ns::Database.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::ODBC::Database
|
56
|
+
end
|
57
|
+
|
@@ -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,415 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
module DatabaseStatements
|
5
|
+
|
6
|
+
def select_one(sql, name = nil)
|
7
|
+
result = raw_select sql, name, :fetch => :one
|
8
|
+
(result && result.first.present?) ? result.first : nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def select_rows(sql, name = nil)
|
12
|
+
raw_select sql, name, :fetch => :rows
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(sql, name = nil, skip_logging = false)
|
16
|
+
if id_insert_table_name = query_requires_identity_insert?(sql)
|
17
|
+
with_identity_insert_enabled(id_insert_table_name) { do_execute(sql,name) }
|
18
|
+
else
|
19
|
+
do_execute(sql,name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def outside_transaction?
|
24
|
+
info_schema_query { select_value("SELECT @@TRANCOUNT") == 0 }
|
25
|
+
end
|
26
|
+
|
27
|
+
def begin_db_transaction
|
28
|
+
do_execute "BEGIN TRANSACTION"
|
29
|
+
end
|
30
|
+
|
31
|
+
def commit_db_transaction
|
32
|
+
do_execute "COMMIT TRANSACTION"
|
33
|
+
end
|
34
|
+
|
35
|
+
def rollback_db_transaction
|
36
|
+
do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_savepoint
|
40
|
+
do_execute "SAVE TRANSACTION #{current_savepoint_name}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def release_savepoint
|
44
|
+
end
|
45
|
+
|
46
|
+
def rollback_to_savepoint
|
47
|
+
do_execute "ROLLBACK TRANSACTION #{current_savepoint_name}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_limit_offset!(sql, options)
|
51
|
+
raise NotImplementedError, 'This has been moved to the SQLServerCompiler in Arel.'
|
52
|
+
end
|
53
|
+
|
54
|
+
def empty_insert_statement_value
|
55
|
+
"DEFAULT VALUES"
|
56
|
+
end
|
57
|
+
|
58
|
+
def case_sensitive_equality_operator
|
59
|
+
cs_equality_operator
|
60
|
+
end
|
61
|
+
|
62
|
+
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
|
63
|
+
match_data = where_sql.match(/^(.*?[\]\) ])WHERE[\[\( ]/)
|
64
|
+
limit = match_data[1]
|
65
|
+
where_sql.sub!(limit,'')
|
66
|
+
"WHERE #{quoted_primary_key} IN (SELECT #{limit} #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
|
67
|
+
end
|
68
|
+
|
69
|
+
# === SQLServer Specific ======================================== #
|
70
|
+
|
71
|
+
def execute_procedure(proc_name, *variables)
|
72
|
+
vars = variables.map{ |v| quote(v) }.join(', ')
|
73
|
+
sql = "EXEC #{proc_name} #{vars}".strip
|
74
|
+
name = 'Execute Procedure'
|
75
|
+
log(sql, name) do
|
76
|
+
case @connection_options[:mode]
|
77
|
+
when :dblib
|
78
|
+
result = @connection.execute(sql)
|
79
|
+
result.each(:as => :hash, :cache_rows => true) do |row|
|
80
|
+
r = row.with_indifferent_access
|
81
|
+
yield(r) if block_given?
|
82
|
+
end
|
83
|
+
result.each.map{ |row| row.is_a?(Hash) ? row.with_indifferent_access : row }
|
84
|
+
when :odbc
|
85
|
+
results = []
|
86
|
+
raw_connection_run(sql) do |handle|
|
87
|
+
get_rows = lambda {
|
88
|
+
rows = handle_to_names_and_values handle, :fetch => :all
|
89
|
+
rows.each_with_index { |r,i| rows[i] = r.with_indifferent_access }
|
90
|
+
results << rows
|
91
|
+
}
|
92
|
+
get_rows.call
|
93
|
+
while handle_more_results?(handle)
|
94
|
+
get_rows.call
|
95
|
+
end
|
96
|
+
end
|
97
|
+
results.many? ? results : results.first
|
98
|
+
when :adonet
|
99
|
+
results = []
|
100
|
+
results << select(sql, name).map { |r| r.with_indifferent_access }
|
101
|
+
results.many? ? results : results.first
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def use_database(database=nil)
|
107
|
+
return if sqlserver_azure?
|
108
|
+
database ||= @connection_options[:database]
|
109
|
+
do_execute "USE #{quote_table_name(database)}" unless database.blank?
|
110
|
+
end
|
111
|
+
|
112
|
+
def user_options
|
113
|
+
info_schema_query do
|
114
|
+
select_rows("dbcc useroptions").inject(HashWithIndifferentAccess.new) do |values,row|
|
115
|
+
set_option = row[0].gsub(/\s+/,'_')
|
116
|
+
user_value = row[1]
|
117
|
+
values[set_option] = user_value
|
118
|
+
values
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def run_with_isolation_level(isolation_level)
|
124
|
+
raise ArgumentError, "Invalid isolation level, #{isolation_level}. Supported levels include #{valid_isolation_levels.to_sentence}." if !valid_isolation_levels.include?(isolation_level.upcase)
|
125
|
+
initial_isolation_level = user_options[:isolation_level] || "READ COMMITTED"
|
126
|
+
do_execute "SET TRANSACTION ISOLATION LEVEL #{isolation_level}"
|
127
|
+
begin
|
128
|
+
yield
|
129
|
+
ensure
|
130
|
+
do_execute "SET TRANSACTION ISOLATION LEVEL #{initial_isolation_level}"
|
131
|
+
end if block_given?
|
132
|
+
end
|
133
|
+
|
134
|
+
def newid_function
|
135
|
+
select_value "SELECT NEWID()"
|
136
|
+
end
|
137
|
+
|
138
|
+
def newsequentialid_function
|
139
|
+
select_value "SELECT NEWSEQUENTIALID()"
|
140
|
+
end
|
141
|
+
|
142
|
+
# === SQLServer Specific (Rake/Test Helpers) ==================== #
|
143
|
+
|
144
|
+
def recreate_database
|
145
|
+
remove_database_connections_and_rollback do
|
146
|
+
do_execute "EXEC sp_MSforeachtable 'DROP TABLE ?'"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def recreate_database!(database=nil)
|
151
|
+
current_db = current_database
|
152
|
+
database ||= current_db
|
153
|
+
this_db = database.to_s == current_db
|
154
|
+
do_execute 'USE master' if this_db
|
155
|
+
drop_database(database)
|
156
|
+
create_database(database)
|
157
|
+
ensure
|
158
|
+
use_database(current_db) if this_db
|
159
|
+
end
|
160
|
+
|
161
|
+
def drop_database(database)
|
162
|
+
retry_count = 0
|
163
|
+
max_retries = 1
|
164
|
+
begin
|
165
|
+
do_execute "DROP DATABASE #{quote_table_name(database)}"
|
166
|
+
rescue ActiveRecord::StatementInvalid => err
|
167
|
+
if err.message =~ /because it is currently in use/i
|
168
|
+
raise if retry_count >= max_retries
|
169
|
+
retry_count += 1
|
170
|
+
remove_database_connections_and_rollback(database)
|
171
|
+
retry
|
172
|
+
else
|
173
|
+
raise
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def create_database(database)
|
179
|
+
do_execute "CREATE DATABASE #{quote_table_name(database)}"
|
180
|
+
end
|
181
|
+
|
182
|
+
def current_database
|
183
|
+
select_value 'SELECT DB_NAME()'
|
184
|
+
end
|
185
|
+
|
186
|
+
def charset
|
187
|
+
select_value "SELECT SERVERPROPERTY('SqlCharSetName')"
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
protected
|
192
|
+
|
193
|
+
def select(sql, name = nil)
|
194
|
+
raw_select sql, name, :fetch => :all
|
195
|
+
end
|
196
|
+
|
197
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
198
|
+
@insert_sql = true
|
199
|
+
case @connection_options[:mode]
|
200
|
+
when :dblib
|
201
|
+
execute(sql, name) || id_value
|
202
|
+
else
|
203
|
+
super || select_value("SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def update_sql(sql, name = nil)
|
208
|
+
@update_sql = true
|
209
|
+
case @connection_options[:mode]
|
210
|
+
when :dblib
|
211
|
+
execute(sql, name)
|
212
|
+
else
|
213
|
+
execute(sql, name)
|
214
|
+
select_value('SELECT @@ROWCOUNT AS AffectedRows')
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# === SQLServer Specific ======================================== #
|
219
|
+
|
220
|
+
def valid_isolation_levels
|
221
|
+
["READ COMMITTED", "READ UNCOMMITTED", "REPEATABLE READ", "SERIALIZABLE", "SNAPSHOT"]
|
222
|
+
end
|
223
|
+
|
224
|
+
# === SQLServer Specific (Executing) ============================ #
|
225
|
+
|
226
|
+
def do_execute(sql, name = nil)
|
227
|
+
name ||= 'EXECUTE'
|
228
|
+
log(sql, name) do
|
229
|
+
with_auto_reconnect { raw_connection_do(sql) }
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def raw_connection_do(sql)
|
234
|
+
case @connection_options[:mode]
|
235
|
+
when :dblib
|
236
|
+
@insert_sql ? @connection.execute(sql).insert : @connection.execute(sql).do
|
237
|
+
when :odbc
|
238
|
+
@connection.do(sql)
|
239
|
+
else :adonet
|
240
|
+
@connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_non_query
|
241
|
+
end
|
242
|
+
ensure
|
243
|
+
@insert_sql = false
|
244
|
+
@update_sql = false
|
245
|
+
end
|
246
|
+
|
247
|
+
# === SQLServer Specific (Selecting) ============================ #
|
248
|
+
|
249
|
+
def raw_select(sql, name=nil, options={})
|
250
|
+
log(sql,name) do
|
251
|
+
begin
|
252
|
+
handle = raw_connection_run(sql)
|
253
|
+
handle_to_names_and_values(handle, options)
|
254
|
+
ensure
|
255
|
+
finish_statement_handle(handle)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def raw_connection_run(sql)
|
261
|
+
with_auto_reconnect do
|
262
|
+
case @connection_options[:mode]
|
263
|
+
when :dblib
|
264
|
+
@connection.execute(sql)
|
265
|
+
when :odbc
|
266
|
+
block_given? ? @connection.run_block(sql) { |handle| yield(handle) } : @connection.run(sql)
|
267
|
+
else :adonet
|
268
|
+
@connection.create_command.tap{ |cmd| cmd.command_text = sql }.execute_reader
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def handle_more_results?(handle)
|
274
|
+
case @connection_options[:mode]
|
275
|
+
when :dblib
|
276
|
+
when :odbc
|
277
|
+
handle.more_results
|
278
|
+
when :adonet
|
279
|
+
handle.next_result
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def handle_to_names_and_values(handle, options={})
|
284
|
+
case @connection_options[:mode]
|
285
|
+
when :dblib
|
286
|
+
handle_to_names_and_values_dblib(handle, options)
|
287
|
+
when :odbc
|
288
|
+
handle_to_names_and_values_odbc(handle, options)
|
289
|
+
when :adonet
|
290
|
+
handle_to_names_and_values_adonet(handle, options)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def handle_to_names_and_values_dblib(handle, options={})
|
295
|
+
query_options = {}.tap do |qo|
|
296
|
+
qo[:timezone] = ActiveRecord::Base.default_timezone || :utc
|
297
|
+
qo[:first] = true if options[:fetch] == :one
|
298
|
+
qo[:as] = options[:fetch] == :rows ? :array : :hash
|
299
|
+
end
|
300
|
+
handle.each(query_options)
|
301
|
+
end
|
302
|
+
|
303
|
+
def handle_to_names_and_values_odbc(handle, options={})
|
304
|
+
@connection.use_utc = ActiveRecord::Base.default_timezone == :utc if @connection_supports_native_types
|
305
|
+
case options[:fetch]
|
306
|
+
when :all, :one
|
307
|
+
if @connection_supports_native_types
|
308
|
+
if options[:fetch] == :all
|
309
|
+
handle.each_hash || []
|
310
|
+
else
|
311
|
+
row = handle.fetch_hash
|
312
|
+
rows = row ? [row] : [[]]
|
313
|
+
end
|
314
|
+
else
|
315
|
+
rows = if options[:fetch] == :all
|
316
|
+
handle.fetch_all || []
|
317
|
+
else
|
318
|
+
row = handle.fetch
|
319
|
+
row ? [row] : [[]]
|
320
|
+
end
|
321
|
+
names = handle.columns(true).map{ |c| c.name }
|
322
|
+
names_and_values = []
|
323
|
+
rows.each do |row|
|
324
|
+
h = {}
|
325
|
+
i = 0
|
326
|
+
while i < row.size
|
327
|
+
v = row[i]
|
328
|
+
h[names[i]] = v.respond_to?(:to_sqlserver_string) ? v.to_sqlserver_string : v
|
329
|
+
i += 1
|
330
|
+
end
|
331
|
+
names_and_values << h
|
332
|
+
end
|
333
|
+
names_and_values
|
334
|
+
end
|
335
|
+
when :rows
|
336
|
+
rows = handle.fetch_all || []
|
337
|
+
return rows if @connection_supports_native_types
|
338
|
+
rows.each do |row|
|
339
|
+
i = 0
|
340
|
+
while i < row.size
|
341
|
+
v = row[i]
|
342
|
+
row[i] = v.to_sqlserver_string if v.respond_to?(:to_sqlserver_string)
|
343
|
+
i += 1
|
344
|
+
end
|
345
|
+
end
|
346
|
+
rows
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def handle_to_names_and_values_adonet(handle, options={})
|
351
|
+
if handle.has_rows
|
352
|
+
names = []
|
353
|
+
rows = []
|
354
|
+
fields_named = options[:fetch] == :rows
|
355
|
+
one_row_only = options[:fetch] == :one
|
356
|
+
while handle.read
|
357
|
+
row = []
|
358
|
+
handle.visible_field_count.times do |row_index|
|
359
|
+
value = handle.get_value(row_index)
|
360
|
+
value = case value
|
361
|
+
when System::String
|
362
|
+
value.to_s
|
363
|
+
when System::DBNull
|
364
|
+
nil
|
365
|
+
when System::DateTime
|
366
|
+
value.to_string("yyyy-MM-dd HH:mm:ss.fff").to_s
|
367
|
+
when @@array_of_bytes ||= System::Array[System::Byte]
|
368
|
+
String.new(value)
|
369
|
+
else
|
370
|
+
value
|
371
|
+
end
|
372
|
+
row << value
|
373
|
+
names << handle.get_name(row_index).to_s unless fields_named
|
374
|
+
break if one_row_only
|
375
|
+
end
|
376
|
+
rows << row
|
377
|
+
fields_named = true
|
378
|
+
end
|
379
|
+
else
|
380
|
+
rows = []
|
381
|
+
end
|
382
|
+
if options[:fetch] != :rows
|
383
|
+
names_and_values = []
|
384
|
+
rows.each do |row|
|
385
|
+
h = {}
|
386
|
+
i = 0
|
387
|
+
while i < row.size
|
388
|
+
h[names[i]] = row[i]
|
389
|
+
i += 1
|
390
|
+
end
|
391
|
+
names_and_values << h
|
392
|
+
end
|
393
|
+
names_and_values
|
394
|
+
else
|
395
|
+
rows
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
def finish_statement_handle(handle)
|
400
|
+
case @connection_options[:mode]
|
401
|
+
when :dblib
|
402
|
+
handle.cancel if handle
|
403
|
+
when :odbc
|
404
|
+
handle.drop if handle && handle.respond_to?(:drop) && !handle.finished?
|
405
|
+
when :adonet
|
406
|
+
handle.close if handle && handle.respond_to?(:close) && !handle.is_closed
|
407
|
+
handle.dispose if handle && handle.respond_to?(:dispose)
|
408
|
+
end
|
409
|
+
handle
|
410
|
+
end
|
411
|
+
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|