tiny_tds 0.4.5.rc1-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/CHANGELOG +99 -0
- data/Gemfile +18 -0
- data/MIT-LICENSE +22 -0
- data/NOTES +11 -0
- data/README.rdoc +277 -0
- data/Rakefile +52 -0
- data/ext/tiny_tds/client.c +347 -0
- data/ext/tiny_tds/client.h +35 -0
- data/ext/tiny_tds/extconf.rb +84 -0
- data/ext/tiny_tds/result.c +493 -0
- data/ext/tiny_tds/result.h +36 -0
- data/ext/tiny_tds/tiny_tds_ext.c +12 -0
- data/ext/tiny_tds/tiny_tds_ext.h +18 -0
- data/lib/tiny_tds/1.8/tiny_tds.so +0 -0
- data/lib/tiny_tds/1.9/tiny_tds.so +0 -0
- data/lib/tiny_tds/client.rb +79 -0
- data/lib/tiny_tds/error.rb +29 -0
- data/lib/tiny_tds/result.rb +8 -0
- data/lib/tiny_tds/version.rb +3 -0
- data/lib/tiny_tds.rb +19 -0
- data/tasks/ports.rake +58 -0
- data/test/benchmark/query.rb +77 -0
- data/test/benchmark/query_odbc.rb +106 -0
- data/test/benchmark/query_tinytds.rb +111 -0
- data/test/client_test.rb +163 -0
- data/test/result_test.rb +437 -0
- data/test/schema/1px.gif +0 -0
- data/test/schema/sqlserver_2000.sql +138 -0
- data/test/schema/sqlserver_2005.sql +138 -0
- data/test/schema/sqlserver_2008.sql +138 -0
- data/test/schema/sqlserver_azure.sql +138 -0
- data/test/schema_test.rb +284 -0
- data/test/test_helper.rb +190 -0
- metadata +117 -0
data/test/result_test.rb
ADDED
@@ -0,0 +1,437 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class ResultTest < TinyTds::TestCase
|
5
|
+
|
6
|
+
context 'Basic query and result' do
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@@current_schema_loaded ||= load_current_schema
|
10
|
+
@client = new_connection
|
11
|
+
@query1 = 'SELECT 1 AS [one]'
|
12
|
+
end
|
13
|
+
|
14
|
+
should 'have included Enumerable' do
|
15
|
+
assert TinyTds::Result.ancestors.include?(Enumerable)
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'respond to #each' do
|
19
|
+
result = @client.execute(@query1)
|
20
|
+
assert result.respond_to?(:each)
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'return all results for #each with no block' do
|
24
|
+
result = @client.execute(@query1)
|
25
|
+
data = result.each
|
26
|
+
row = data.first
|
27
|
+
assert_instance_of Array, data
|
28
|
+
assert_equal 1, data.size
|
29
|
+
assert_instance_of Hash, row, 'hash is the default query option'
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'return all results for #each with a block yielding a row at a time' do
|
33
|
+
result = @client.execute(@query1)
|
34
|
+
data = result.each do |row|
|
35
|
+
assert_instance_of Hash, row, 'hash is the default query option'
|
36
|
+
end
|
37
|
+
assert_instance_of Array, data
|
38
|
+
end
|
39
|
+
|
40
|
+
should 'allow successive calls to each returning the same data' do
|
41
|
+
result = @client.execute(@query1)
|
42
|
+
data = result.each
|
43
|
+
result.each
|
44
|
+
assert_equal data.object_id, result.each.object_id
|
45
|
+
assert_equal data.first.object_id, result.each.first.object_id
|
46
|
+
end
|
47
|
+
|
48
|
+
should 'return hashes with string keys' do
|
49
|
+
result = @client.execute(@query1)
|
50
|
+
row = result.each(:as => :hash, :symbolize_keys => false).first
|
51
|
+
assert_instance_of Hash, row
|
52
|
+
assert_equal ['one'], row.keys
|
53
|
+
assert_equal ['one'], result.fields
|
54
|
+
end
|
55
|
+
|
56
|
+
should 'return hashes with symbol keys' do
|
57
|
+
result = @client.execute(@query1)
|
58
|
+
row = result.each(:as => :hash, :symbolize_keys => true).first
|
59
|
+
assert_instance_of Hash, row
|
60
|
+
assert_equal [:one], row.keys
|
61
|
+
assert_equal [:one], result.fields
|
62
|
+
end
|
63
|
+
|
64
|
+
should 'return arrays with string fields' do
|
65
|
+
result = @client.execute(@query1)
|
66
|
+
row = result.each(:as => :array, :symbolize_keys => false).first
|
67
|
+
assert_instance_of Array, row
|
68
|
+
assert_equal ['one'], result.fields
|
69
|
+
end
|
70
|
+
|
71
|
+
should 'return arrays with symbol fields' do
|
72
|
+
result = @client.execute(@query1)
|
73
|
+
row = result.each(:as => :array, :symbolize_keys => true).first
|
74
|
+
assert_instance_of Array, row
|
75
|
+
assert_equal [:one], result.fields
|
76
|
+
end
|
77
|
+
|
78
|
+
should 'be able to turn :cache_rows option off' do
|
79
|
+
result = @client.execute(@query1)
|
80
|
+
local = []
|
81
|
+
result.each(:cache_rows => false) do |row|
|
82
|
+
local << row
|
83
|
+
end
|
84
|
+
assert local.first, 'should have iterated over each row'
|
85
|
+
assert_equal [], result.each, 'should not have been cached'
|
86
|
+
assert_equal ['one'], result.fields, 'should still cache field names'
|
87
|
+
end
|
88
|
+
|
89
|
+
should 'be able to get the first result row only' do
|
90
|
+
load_current_schema
|
91
|
+
big_query = "SELECT [id] FROM [datatypes]"
|
92
|
+
one = @client.execute(big_query).each(:first => true)
|
93
|
+
many = @client.execute(big_query).each
|
94
|
+
assert many.size > 1
|
95
|
+
assert one.size == 1
|
96
|
+
end
|
97
|
+
|
98
|
+
should 'cope with no results when using first option' do
|
99
|
+
data = @client.execute("SELECT [id] FROM [datatypes] WHERE [id] = -1").each(:first => true)
|
100
|
+
assert_equal [], data
|
101
|
+
end
|
102
|
+
|
103
|
+
should 'delete, insert and find data' do
|
104
|
+
rollback_transaction(@client) do
|
105
|
+
text = 'test insert and delete'
|
106
|
+
@client.execute("DELETE FROM [datatypes] WHERE [varchar_50] IS NOT NULL").do
|
107
|
+
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
108
|
+
row = @client.execute("SELECT [varchar_50] FROM [datatypes] WHERE [varchar_50] IS NOT NULL").each.first
|
109
|
+
assert row
|
110
|
+
assert_equal text, row['varchar_50']
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
should 'insert and find unicode data' do
|
115
|
+
rollback_transaction(@client) do
|
116
|
+
text = '✓'
|
117
|
+
@client.execute("DELETE FROM [datatypes] WHERE [nvarchar_50] IS NOT NULL").do
|
118
|
+
@client.execute("INSERT INTO [datatypes] ([nvarchar_50]) VALUES (N'#{text}')").do
|
119
|
+
row = @client.execute("SELECT [nvarchar_50] FROM [datatypes] WHERE [nvarchar_50] IS NOT NULL").each.first
|
120
|
+
assert_equal text, row['nvarchar_50']
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
should 'delete and update with affected rows support and insert with identity support in native sql' do
|
125
|
+
rollback_transaction(@client) do
|
126
|
+
text = 'test affected rows sql'
|
127
|
+
@client.execute("DELETE FROM [datatypes]").do
|
128
|
+
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first['AffectedRows']
|
129
|
+
assert_instance_of Fixnum, afrows
|
130
|
+
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
131
|
+
pk1 = @client.execute("SELECT SCOPE_IDENTITY() AS Ident").each.first['Ident']
|
132
|
+
assert_instance_of BigDecimal, pk1, 'native is numeric(38,0) for SCOPE_IDENTITY() function'
|
133
|
+
pk2 = @client.execute("SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident").each.first['Ident']
|
134
|
+
assert_instance_of Fixnum, pk2, 'we should be able to CAST to bigint'
|
135
|
+
assert_equal pk2, pk1.to_i, 'just making sure the 2 line up'
|
136
|
+
@client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
|
137
|
+
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first['AffectedRows']
|
138
|
+
assert_equal 1, afrows
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
should 'have a #do method that cancels result rows and returns affected rows natively' do
|
143
|
+
rollback_transaction(@client) do
|
144
|
+
text = 'test affected rows native'
|
145
|
+
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first['count']
|
146
|
+
deleted_rows = @client.execute("DELETE FROM [datatypes]").do
|
147
|
+
assert_equal count, deleted_rows, 'should have deleted rows equal to count'
|
148
|
+
inserted_rows = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
149
|
+
assert_equal 1, inserted_rows, 'should have inserted row for one above'
|
150
|
+
updated_rows = @client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
|
151
|
+
assert_equal 1, updated_rows, 'should have updated row for one above' unless sqlserver_2000? # Will report -1
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
should 'allow native affected rows using #do to work under transaction' do
|
156
|
+
rollback_transaction(@client) do
|
157
|
+
text = 'test affected rows native in transaction'
|
158
|
+
@client.execute("BEGIN TRANSACTION").do
|
159
|
+
@client.execute("DELETE FROM [datatypes]").do
|
160
|
+
inserted_rows = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
161
|
+
assert_equal 1, inserted_rows, 'should have inserted row for one above'
|
162
|
+
updated_rows = @client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
|
163
|
+
assert_equal 1, updated_rows, 'should have updated row for one above' unless sqlserver_2000? # Will report -1
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
should 'have an #insert method that cancels result rows and returns the SCOPE_IDENTITY() natively' do
|
168
|
+
rollback_transaction(@client) do
|
169
|
+
text = 'test scope identity rows native'
|
170
|
+
@client.execute("DELETE FROM [datatypes] WHERE [varchar_50] = '#{text}'").do
|
171
|
+
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
172
|
+
sql_identity = @client.execute("SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident").each.first['Ident']
|
173
|
+
native_identity = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").insert
|
174
|
+
assert_equal sql_identity+1, native_identity
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
should 'be able to begin/commit transactions with raw sql' do
|
179
|
+
rollback_transaction(@client) do
|
180
|
+
@client.execute("BEGIN TRANSACTION").do
|
181
|
+
@client.execute("DELETE FROM [datatypes]").do
|
182
|
+
@client.execute("COMMIT TRANSACTION").do
|
183
|
+
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first['count']
|
184
|
+
assert_equal 0, count
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
should 'be able to begin/rollback transactions with raw sql' do
|
189
|
+
load_current_schema
|
190
|
+
@client.execute("BEGIN TRANSACTION").do
|
191
|
+
@client.execute("DELETE FROM [datatypes]").do
|
192
|
+
@client.execute("ROLLBACK TRANSACTION").do
|
193
|
+
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first['count']
|
194
|
+
0.wont_equal count
|
195
|
+
end
|
196
|
+
|
197
|
+
should 'have a #fields accessor with logic default and valid outcome' do
|
198
|
+
result = @client.execute(@query1)
|
199
|
+
result.fields.must_equal ['one']
|
200
|
+
result.each
|
201
|
+
result.fields.must_equal ['one']
|
202
|
+
end
|
203
|
+
|
204
|
+
should 'always return an array for fields for all sql' do
|
205
|
+
result = @client.execute("USE [tinytdstest]")
|
206
|
+
result.fields.must_equal []
|
207
|
+
result.do
|
208
|
+
result.fields.must_equal []
|
209
|
+
end
|
210
|
+
|
211
|
+
should 'return fields even when no results are found' do
|
212
|
+
no_results_query = "SELECT [id], [varchar_50] FROM [datatypes] WHERE [varchar_50] = 'NOTFOUND'"
|
213
|
+
# Fields before each.
|
214
|
+
result = @client.execute(no_results_query)
|
215
|
+
result.fields.must_equal ['id','varchar_50']
|
216
|
+
result.each
|
217
|
+
result.fields.must_equal ['id','varchar_50']
|
218
|
+
# Each then fields
|
219
|
+
result = @client.execute(no_results_query)
|
220
|
+
result.each
|
221
|
+
result.fields.must_equal ['id','varchar_50']
|
222
|
+
end
|
223
|
+
|
224
|
+
should 'allow the result to be canceled before reading' do
|
225
|
+
result = @client.execute(@query1)
|
226
|
+
result.cancel
|
227
|
+
@client.execute(@query1).each
|
228
|
+
end
|
229
|
+
|
230
|
+
should 'work in tandem with the client when needing to find out if client has sql sent and result is canceled or not' do
|
231
|
+
# Default state.
|
232
|
+
@client = TinyTds::Client.new(connection_options)
|
233
|
+
@client.sqlsent?.must_equal false
|
234
|
+
@client.canceled?.must_equal false
|
235
|
+
# With active result before and after cancel.
|
236
|
+
result = @client.execute(@query1)
|
237
|
+
@client.sqlsent?.must_equal true
|
238
|
+
@client.canceled?.must_equal false
|
239
|
+
result.cancel
|
240
|
+
@client.sqlsent?.must_equal false
|
241
|
+
@client.canceled?.must_equal true
|
242
|
+
assert result.cancel, 'must be safe to call again'
|
243
|
+
# With each and no block.
|
244
|
+
@client.execute(@query1).each
|
245
|
+
@client.sqlsent?.must_equal false
|
246
|
+
@client.canceled?.must_equal false
|
247
|
+
# With each and block.
|
248
|
+
@client.execute(@query1).each do |row|
|
249
|
+
@client.sqlsent?.must_equal true, 'when iterating over each row in a block'
|
250
|
+
@client.canceled?.must_equal false
|
251
|
+
end
|
252
|
+
@client.sqlsent?.must_equal false
|
253
|
+
@client.canceled?.must_equal false
|
254
|
+
# With each and block canceled half way thru.
|
255
|
+
count = @client.execute("SELECT COUNT([id]) AS [count] FROM [datatypes]").each[0]['count']
|
256
|
+
assert count > 10, 'since we want to cancel early for test'
|
257
|
+
result = @client.execute("SELECT [id] FROM [datatypes]")
|
258
|
+
index = 0
|
259
|
+
result.each do |row|
|
260
|
+
break if index > 10
|
261
|
+
index += 1
|
262
|
+
end
|
263
|
+
@client.sqlsent?.must_equal true
|
264
|
+
@client.canceled?.must_equal false
|
265
|
+
result.cancel
|
266
|
+
@client.sqlsent?.must_equal false
|
267
|
+
@client.canceled?.must_equal true
|
268
|
+
# With do method.
|
269
|
+
@client.execute(@query1).do
|
270
|
+
@client.sqlsent?.must_equal false
|
271
|
+
@client.canceled?.must_equal true
|
272
|
+
# With insert method.
|
273
|
+
rollback_transaction(@client) do
|
274
|
+
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('test')").insert
|
275
|
+
@client.sqlsent?.must_equal false
|
276
|
+
@client.canceled?.must_equal true
|
277
|
+
end
|
278
|
+
# With first
|
279
|
+
@client.execute("SELECT [id] FROM [datatypes]").each(:first => true)
|
280
|
+
@client.sqlsent?.must_equal false
|
281
|
+
@client.canceled?.must_equal true
|
282
|
+
end
|
283
|
+
|
284
|
+
should 'use same string object for hash keys' do
|
285
|
+
data = @client.execute("SELECT [id], [bigint] FROM [datatypes]").each
|
286
|
+
assert_equal data.first.keys.map{ |r| r.object_id }, data.last.keys.map{ |r| r.object_id }
|
287
|
+
end
|
288
|
+
|
289
|
+
should 'have properly encoded column names' do
|
290
|
+
col_name = "öäüß"
|
291
|
+
@client.execute("DROP TABLE [test_encoding]").do rescue nil
|
292
|
+
@client.execute("CREATE TABLE [dbo].[test_encoding] ( [#{col_name}] [nvarchar](10) NOT NULL )").do
|
293
|
+
@client.execute("INSERT INTO [test_encoding] ([#{col_name}]) VALUES (N'#{col_name}')").do
|
294
|
+
result = @client.execute("SELECT [#{col_name}] FROM [test_encoding]")
|
295
|
+
row = result.each.first
|
296
|
+
assert_equal col_name, result.fields.first
|
297
|
+
assert_equal col_name, row.keys.first
|
298
|
+
assert_utf8_encoding result.fields.first
|
299
|
+
assert_utf8_encoding row.keys.first
|
300
|
+
end unless sqlserver_azure?
|
301
|
+
|
302
|
+
should 'allow #return_code to work with stored procedures and reset per sql batch' do
|
303
|
+
assert_nil @client.return_code
|
304
|
+
result = @client.execute("EXEC tinytds_TestReturnCodes")
|
305
|
+
assert_equal [{"one"=>1}], result.each
|
306
|
+
assert_equal 420, @client.return_code
|
307
|
+
assert_equal 420, result.return_code
|
308
|
+
result = @client.execute('SELECT 1 as [one]')
|
309
|
+
result.each
|
310
|
+
assert_nil @client.return_code
|
311
|
+
assert_nil result.return_code
|
312
|
+
end
|
313
|
+
|
314
|
+
context 'with multiple result sets' do
|
315
|
+
|
316
|
+
setup do
|
317
|
+
@double_select = "SELECT 1 AS [rs1]\nSELECT 2 AS [rs2]"
|
318
|
+
end
|
319
|
+
|
320
|
+
should 'handle a command buffer with double selects' do
|
321
|
+
result = @client.execute(@double_select)
|
322
|
+
result_sets = result.each
|
323
|
+
assert_equal 2, result_sets.size
|
324
|
+
assert_equal [{'rs1' => 1}], result_sets.first
|
325
|
+
assert_equal [{'rs2' => 2}], result_sets.last
|
326
|
+
assert_equal [['rs1'],['rs2']], result.fields
|
327
|
+
assert_equal result.each.object_id, result.each.object_id, 'same cached rows'
|
328
|
+
# As array
|
329
|
+
result = @client.execute(@double_select)
|
330
|
+
result_sets = result.each(:as => :array)
|
331
|
+
assert_equal 2, result_sets.size
|
332
|
+
assert_equal [[1]], result_sets.first
|
333
|
+
assert_equal [[2]], result_sets.last
|
334
|
+
assert_equal [['rs1'],['rs2']], result.fields
|
335
|
+
assert_equal result.each.object_id, result.each.object_id, 'same cached rows'
|
336
|
+
end
|
337
|
+
|
338
|
+
should 'yield each row for each result set' do
|
339
|
+
data = []
|
340
|
+
result_sets = @client.execute(@double_select).each { |row| data << row }
|
341
|
+
assert_equal data.first, result_sets.first[0]
|
342
|
+
assert_equal data.last, result_sets.last[0]
|
343
|
+
end
|
344
|
+
|
345
|
+
should 'from a stored procedure' do
|
346
|
+
results1, results2 = @client.execute("EXEC sp_helpconstraint '[datatypes]'").each
|
347
|
+
assert_equal [{"Object Name"=>"[datatypes]"}], results1
|
348
|
+
constraint_info = results2.first
|
349
|
+
assert constraint_info.key?("constraint_keys")
|
350
|
+
assert constraint_info.key?("constraint_type")
|
351
|
+
assert constraint_info.key?("constraint_name")
|
352
|
+
end
|
353
|
+
|
354
|
+
should 'ignore empty result sets' do
|
355
|
+
rollback_transaction(@client) do
|
356
|
+
@client.execute("DELETE FROM [datatypes]").do
|
357
|
+
id = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('test empty result sets')").insert
|
358
|
+
sql = %|
|
359
|
+
SET NOCOUNT ON
|
360
|
+
DECLARE @row_number TABLE (row int identity(1,1), id int)
|
361
|
+
INSERT INTO @row_number (id)
|
362
|
+
SELECT [datatypes].[id] FROM [datatypes]
|
363
|
+
SET NOCOUNT OFF
|
364
|
+
SELECT id FROM @row_number|
|
365
|
+
result = @client.execute(sql)
|
366
|
+
result.each.must_equal [{"id"=>id}]
|
367
|
+
result.fields.must_equal ['id']
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
context 'when casting to native ruby values' do
|
374
|
+
|
375
|
+
should 'return fixnum for 1' do
|
376
|
+
value = @client.execute('SELECT 1 AS [fixnum]').each.first['fixnum']
|
377
|
+
assert_equal 1, value
|
378
|
+
end
|
379
|
+
|
380
|
+
should 'return nil for NULL' do
|
381
|
+
value = @client.execute('SELECT NULL AS [null]').each.first['null']
|
382
|
+
assert_equal nil, value
|
383
|
+
end
|
384
|
+
|
385
|
+
end
|
386
|
+
|
387
|
+
context 'when shit happens' do
|
388
|
+
|
389
|
+
should 'cope with nil or empty buffer' do
|
390
|
+
assert_raises(TypeError) { @client.execute(nil) }
|
391
|
+
assert_equal [], @client.execute('').each
|
392
|
+
end
|
393
|
+
|
394
|
+
should 'throw an error when you execute another query with other results pending' do
|
395
|
+
result1 = @client.execute(@query1)
|
396
|
+
action = lambda { @client.execute(@query1) }
|
397
|
+
assert_raise_tinytds_error(action) do |e|
|
398
|
+
assert_match %r|with results pending|i, e.message
|
399
|
+
assert_equal 7, e.severity
|
400
|
+
assert_equal 20019, e.db_error_number
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
should 'error gracefully with bad table name' do
|
405
|
+
action = lambda { @client.execute('SELECT * FROM [foobar]').each }
|
406
|
+
assert_raise_tinytds_error(action) do |e|
|
407
|
+
assert_match %r|invalid object name.*foobar|i, e.message
|
408
|
+
assert_equal 16, e.severity
|
409
|
+
assert_equal 208, e.db_error_number
|
410
|
+
end
|
411
|
+
assert_followup_query
|
412
|
+
end
|
413
|
+
|
414
|
+
should 'error gracefully with invalid syntax' do
|
415
|
+
action = lambda { @client.execute('this will not work').each }
|
416
|
+
assert_raise_tinytds_error(action) do |e|
|
417
|
+
assert_match %r|incorrect syntax|i, e.message
|
418
|
+
assert_equal 15, e.severity
|
419
|
+
assert_equal 156, e.db_error_number
|
420
|
+
end
|
421
|
+
assert_followup_query
|
422
|
+
end
|
423
|
+
|
424
|
+
end
|
425
|
+
|
426
|
+
end
|
427
|
+
|
428
|
+
|
429
|
+
protected
|
430
|
+
|
431
|
+
def assert_followup_query
|
432
|
+
result = @client.execute(@query1)
|
433
|
+
assert_equal 1, result.each.first['one']
|
434
|
+
end
|
435
|
+
|
436
|
+
end
|
437
|
+
|
data/test/schema/1px.gif
ADDED
Binary file
|
@@ -0,0 +1,138 @@
|
|
1
|
+
|
2
|
+
/*
|
3
|
+
|
4
|
+
* Binary Data - Our test binary data is a 1 pixel gif. The basic (raw) data is below. Quoting this data
|
5
|
+
would involve this (encode) method and be (encoded) with the 0x prefix for raw SQL. In other clients the
|
6
|
+
(raw_db) value without the 0x prefix would need to be (packed) again yield the original (raw) value.
|
7
|
+
|
8
|
+
(raw) - "GIF89a\001\000\001\000\221\000\000\377\377\377\377\377\377\376\001\002\000\000\000!\371\004\004\024\000\377\000,\000\000\000\000\001\000\001\000\000\002\002D\001\000;"
|
9
|
+
(encode) - "0x#{raw.unpack("H*")[0]}"
|
10
|
+
(encoded) - "0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b"
|
11
|
+
(raw_db) - "47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b"
|
12
|
+
(packed) - [raw_db].pack('H*')
|
13
|
+
|
14
|
+
*/
|
15
|
+
|
16
|
+
CREATE TABLE [dbo].[datatypes] (
|
17
|
+
[id] [int] NOT NULL IDENTITY(1,1) PRIMARY KEY,
|
18
|
+
[bigint] [bigint] NULL,
|
19
|
+
[binary_50] [binary](50) NULL,
|
20
|
+
[bit] [bit] NULL,
|
21
|
+
[char_10] [char](10) NULL,
|
22
|
+
-- [date] [date] NULL,
|
23
|
+
[datetime] [datetime] NULL,
|
24
|
+
-- [datetime2_7] [datetime2](7) NULL,
|
25
|
+
-- [datetimeoffset_2] [datetimeoffset](2) NULL,
|
26
|
+
-- [datetimeoffset_7] [datetimeoffset](7) NULL,
|
27
|
+
[decimal_9_2] [decimal](9, 2) NULL,
|
28
|
+
[decimal_16_4] [decimal](16, 4) NULL,
|
29
|
+
[float] [float] NULL,
|
30
|
+
-- [geography] [geography] NULL,
|
31
|
+
-- [geometry] [geometry] NULL,
|
32
|
+
-- [hierarchyid] [hierarchyid] NULL,
|
33
|
+
[image] [image] NULL,
|
34
|
+
[int] [int] NULL,
|
35
|
+
[money] [money] NULL,
|
36
|
+
[nchar_10] [nchar](10) NULL,
|
37
|
+
[ntext] [ntext] NULL,
|
38
|
+
[numeric_18_0] [numeric](18, 0) NULL,
|
39
|
+
[numeric_36_2] [numeric](36, 2) NULL,
|
40
|
+
[nvarchar_50] [nvarchar](50) NULL,
|
41
|
+
-- [nvarchar_max] [nvarchar](max) NULL,
|
42
|
+
[real] [real] NULL,
|
43
|
+
[smalldatetime] [smalldatetime] NULL,
|
44
|
+
[smallint] [smallint] NULL,
|
45
|
+
[smallmoney] [smallmoney] NULL,
|
46
|
+
[text] [text] NULL,
|
47
|
+
-- [time_2] [time](2) NULL,
|
48
|
+
-- [time_7] [time](7) NULL,
|
49
|
+
[timestamp] [timestamp] NULL,
|
50
|
+
[tinyint] [tinyint] NULL,
|
51
|
+
[uniqueidentifier] [uniqueidentifier] NULL,
|
52
|
+
[varbinary_50] [varbinary](50) NULL,
|
53
|
+
-- [varbinary_max] [varbinary](max) NULL,
|
54
|
+
[varchar_50] [varchar](50) NULL
|
55
|
+
-- [varchar_max] [varchar](max) NULL,
|
56
|
+
-- [xml] [xml] NULL
|
57
|
+
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
|
58
|
+
|
59
|
+
SET IDENTITY_INSERT [datatypes] ON
|
60
|
+
|
61
|
+
INSERT INTO [datatypes] ([id], [bigint]) VALUES ( 11, -9223372036854775807 )
|
62
|
+
INSERT INTO [datatypes] ([id], [bigint]) VALUES ( 12, 9223372036854775806 )
|
63
|
+
INSERT INTO [datatypes] ([id], [binary_50]) VALUES ( 21, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
64
|
+
INSERT INTO [datatypes] ([id], [bit]) VALUES ( 31, 1 )
|
65
|
+
INSERT INTO [datatypes] ([id], [bit]) VALUES ( 32, 0 )
|
66
|
+
INSERT INTO [datatypes] ([id], [char_10]) VALUES ( 41, '1234567890' )
|
67
|
+
INSERT INTO [datatypes] ([id], [char_10]) VALUES ( 42, '12345678' )
|
68
|
+
-- INSERT INTO [datatypes] ([id], [date]) VALUES ( 51, '0001-01-01' )
|
69
|
+
-- INSERT INTO [datatypes] ([id], [date]) VALUES ( 52, '9999-12-31' )
|
70
|
+
INSERT INTO [datatypes] ([id], [datetime]) VALUES ( 61, '1753-01-01T00:00:00.000' )
|
71
|
+
INSERT INTO [datatypes] ([id], [datetime]) VALUES ( 62, '9999-12-31T23:59:59.997' )
|
72
|
+
INSERT INTO [datatypes] ([id], [datetime]) VALUES ( 63, '2010-01-01T12:34:56.123' )
|
73
|
+
-- INSERT INTO [datatypes] ([id], [datetime2_7]) VALUES ( 71, '0001-01-01T00:00:00.0000000Z' )
|
74
|
+
-- INSERT INTO [datatypes] ([id], [datetime2_7]) VALUES ( 72, '1984-01-24T04:20:00.0000000-08:00' )
|
75
|
+
-- INSERT INTO [datatypes] ([id], [datetime2_7]) VALUES ( 73, '9999-12-31T23:59:59.9999999Z' )
|
76
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_2]) VALUES ( 81, '1984-01-24T04:20:00.0000000-08:00' ) -- 1984-01-24 04:20:00.00 -08:00
|
77
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_2]) VALUES ( 82, '1984-01-24T04:20:00.0000000Z' ) -- 1984-01-24 04:20:00.00 +00:00
|
78
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_2]) VALUES ( 83, '9999-12-31T23:59:59.9999999Z' ) -- 9999-12-31 23:59:59.99 +00:00
|
79
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_7]) VALUES ( 84, '1984-01-24T04:20:00.0000000-08:00' ) -- 1984-01-24 04:20:00.0000000 -08:00
|
80
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_7]) VALUES ( 85, '1984-01-24T04:20:00.0000000Z' ) -- 1984-01-24 04:20:00.0000000 +00:00
|
81
|
+
-- INSERT INTO [datatypes] ([id], [datetimeoffset_7]) VALUES ( 86, '9999-12-31T23:59:59.9999999Z' ) -- 9999-12-31 23:59:59.9999999 +00:00
|
82
|
+
INSERT INTO [datatypes] ([id], [decimal_9_2]) VALUES ( 91, 12345.01 )
|
83
|
+
INSERT INTO [datatypes] ([id], [decimal_9_2]) VALUES ( 92, 1234567.89 )
|
84
|
+
INSERT INTO [datatypes] ([id], [decimal_16_4]) VALUES ( 93, 0.0 )
|
85
|
+
INSERT INTO [datatypes] ([id], [decimal_16_4]) VALUES ( 94, 123456789012.3456 )
|
86
|
+
INSERT INTO [datatypes] ([id], [float]) VALUES ( 101, 123.00000001 )
|
87
|
+
INSERT INTO [datatypes] ([id], [float]) VALUES ( 102, 0.0 )
|
88
|
+
INSERT INTO [datatypes] ([id], [float]) VALUES ( 103, 123.45 )
|
89
|
+
-- INSERT INTO [datatypes] ([id], [geography]) VALUES ( 111, geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326) ) -- 0xE610000001148716D9CEF7D34740D7A3703D0A975EC08716D9CEF7D34740CBA145B6F3955EC0
|
90
|
+
-- INSERT INTO [datatypes] ([id], [geometry]) VALUES ( 121, geometry::STGeomFromText('LINESTRING (100 100, 20 180, 180 180)', 0) ) -- 0x0000000001040300000000000000000059400000000000005940000000000000344000000000008066400000000000806640000000000080664001000000010000000001000000FFFFFFFF0000000002
|
91
|
+
-- INSERT INTO [datatypes] ([id], [hierarchyid]) VALUES ( 131, CAST('/1/' AS hierarchyid) ) -- 0x58
|
92
|
+
-- INSERT INTO [datatypes] ([id], [hierarchyid]) VALUES ( 132, CAST('/2/' AS hierarchyid) ) -- 0x68
|
93
|
+
INSERT INTO [datatypes] ([id], [image]) VALUES ( 141, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
94
|
+
INSERT INTO [datatypes] ([id], [int]) VALUES ( 151, -2147483647 )
|
95
|
+
INSERT INTO [datatypes] ([id], [int]) VALUES ( 152, 2147483646 )
|
96
|
+
INSERT INTO [datatypes] ([id], [money]) VALUES ( 161, 4.20 )
|
97
|
+
INSERT INTO [datatypes] ([id], [money]) VALUES ( 162, -922337203685477.5807 )
|
98
|
+
INSERT INTO [datatypes] ([id], [money]) VALUES ( 163, 922337203685477.5806 )
|
99
|
+
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 171, N'1234567890' )
|
100
|
+
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 172, N'123456åå' )
|
101
|
+
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 173, N'abc123' )
|
102
|
+
INSERT INTO [datatypes] ([id], [ntext]) VALUES ( 181, N'test ntext' )
|
103
|
+
INSERT INTO [datatypes] ([id], [ntext]) VALUES ( 182, N'test ntext åå' )
|
104
|
+
INSERT INTO [datatypes] ([id], [numeric_18_0]) VALUES ( 191, 191 )
|
105
|
+
INSERT INTO [datatypes] ([id], [numeric_18_0]) VALUES ( 192, 123456789012345678 )
|
106
|
+
INSERT INTO [datatypes] ([id], [numeric_36_2]) VALUES ( 193, 12345678901234567890.01 )
|
107
|
+
INSERT INTO [datatypes] ([id], [numeric_36_2]) VALUES ( 194, 123.46 )
|
108
|
+
INSERT INTO [datatypes] ([id], [nvarchar_50]) VALUES ( 201, N'test nvarchar_50' )
|
109
|
+
INSERT INTO [datatypes] ([id], [nvarchar_50]) VALUES ( 202, N'test nvarchar_50 åå' )
|
110
|
+
-- INSERT INTO [datatypes] ([id], [nvarchar_max]) VALUES ( 211, N'test nvarchar_max' )
|
111
|
+
-- INSERT INTO [datatypes] ([id], [nvarchar_max]) VALUES ( 212, N'test nvarchar_max åå' )
|
112
|
+
INSERT INTO [datatypes] ([id], [real]) VALUES ( 221, 123.45 )
|
113
|
+
INSERT INTO [datatypes] ([id], [real]) VALUES ( 222, 0.0 )
|
114
|
+
INSERT INTO [datatypes] ([id], [real]) VALUES ( 223, 0.00001 )
|
115
|
+
INSERT INTO [datatypes] ([id], [smalldatetime]) VALUES ( 231, '1901-01-01T15:45:00.000' ) -- 1901-01-01 15:45:00
|
116
|
+
INSERT INTO [datatypes] ([id], [smalldatetime]) VALUES ( 232, '2078-06-05T04:20:00.000' ) -- 2078-06-05 04:20:00
|
117
|
+
INSERT INTO [datatypes] ([id], [smallint]) VALUES ( 241, -32767 )
|
118
|
+
INSERT INTO [datatypes] ([id], [smallint]) VALUES ( 242, 32766 )
|
119
|
+
INSERT INTO [datatypes] ([id], [smallmoney]) VALUES ( 251, 4.20 )
|
120
|
+
INSERT INTO [datatypes] ([id], [smallmoney]) VALUES ( 252, -214748.3647 )
|
121
|
+
INSERT INTO [datatypes] ([id], [smallmoney]) VALUES ( 253, 214748.3646 )
|
122
|
+
INSERT INTO [datatypes] ([id], [text]) VALUES ( 271, 'test text' )
|
123
|
+
-- INSERT INTO [datatypes] ([id], [time_2]) VALUES ( 281, '1901-01-01T15:45:00.0100001Z' ) -- 15:45:00.01
|
124
|
+
-- INSERT INTO [datatypes] ([id], [time_2]) VALUES ( 282, '1984-01-24T04:20:00.0000001-08:00' ) -- 04:20:00.00
|
125
|
+
-- INSERT INTO [datatypes] ([id], [time_7]) VALUES ( 283, '1901-01-01T15:45:00.0100001Z' ) -- 15:45:00.0100001
|
126
|
+
-- INSERT INTO [datatypes] ([id], [time_7]) VALUES ( 284, '1984-01-24T04:20:00.0000001-08:00' ) -- 04:20:00.0000001
|
127
|
+
INSERT INTO [datatypes] ([id], [tinyint]) VALUES ( 301, 0 )
|
128
|
+
INSERT INTO [datatypes] ([id], [tinyint]) VALUES ( 302, 255 )
|
129
|
+
INSERT INTO [datatypes] ([id], [uniqueidentifier]) VALUES ( 311, NEWID() )
|
130
|
+
INSERT INTO [datatypes] ([id], [varbinary_50]) VALUES ( 321, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
131
|
+
-- INSERT INTO [datatypes] ([id], [varbinary_max]) VALUES ( 331, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
132
|
+
INSERT INTO [datatypes] ([id], [varchar_50]) VALUES ( 341, 'test varchar_50' )
|
133
|
+
-- INSERT INTO [datatypes] ([id], [varchar_max]) VALUES ( 351, 'test varchar_max' )
|
134
|
+
-- INSERT INTO [datatypes] ([id], [xml]) VALUES ( 361, '<foo><bar>batz</bar></foo>' )
|
135
|
+
|
136
|
+
SET IDENTITY_INSERT [datatypes] OFF
|
137
|
+
|
138
|
+
|