activerecord-sqlserver-adapter-2000 3.0.15
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 +400 -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 +414 -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 +403 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +470 -0
- data/lib/activerecord-sqlserver-adapter.rb +1 -0
- data/lib/arel/visitors/sqlserver.rb +330 -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,414 @@
|
|
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 "ROLLBACK TRANSACTION" rescue nil
|
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
|
+
when :odbc
|
403
|
+
handle.drop if handle && handle.respond_to?(:drop) && !handle.finished?
|
404
|
+
when :adonet
|
405
|
+
handle.close if handle && handle.respond_to?(:close) && !handle.is_closed
|
406
|
+
handle.dispose if handle && handle.respond_to?(:dispose)
|
407
|
+
end
|
408
|
+
handle
|
409
|
+
end
|
410
|
+
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|