tiny_tds 2.1.2 → 3.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.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +470 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +39 -1
- data/Gemfile +0 -7
- data/ISSUE_TEMPLATE.md +1 -1
- data/README.md +50 -59
- data/Rakefile +15 -10
- data/VERSION +1 -1
- data/docker-compose.yml +34 -0
- data/ext/tiny_tds/client.c +100 -59
- data/ext/tiny_tds/client.h +5 -3
- data/ext/tiny_tds/extconf.rb +38 -16
- data/ext/tiny_tds/extconsts.rb +4 -10
- data/ext/tiny_tds/result.c +52 -45
- data/ext/tiny_tds/tiny_tds_ext.c +4 -1
- data/lib/tiny_tds/gem.rb +1 -6
- data/setup_cimgruby_dev.sh +25 -0
- data/start_dev.sh +21 -0
- data/tasks/native_gem.rake +15 -6
- data/tasks/ports/freetds.rb +1 -6
- data/tasks/ports/libiconv.rb +0 -17
- data/tasks/ports/openssl.rb +2 -18
- data/tasks/ports/recipe.rb +16 -4
- data/tasks/ports.rake +61 -40
- data/test/bin/install-mssql.ps1 +42 -0
- data/test/bin/install-mssqltools.sh +9 -0
- data/test/bin/setup_tinytds_db.sh +7 -0
- data/test/bin/setup_volume_permissions.sh +10 -0
- data/test/client_test.rb +101 -59
- data/test/gem_test.rb +25 -28
- data/test/result_test.rb +130 -182
- data/test/schema_test.rb +366 -388
- data/test/sql/db-create.sql +18 -0
- data/test/sql/db-login.sql +38 -0
- data/test/test_helper.rb +63 -31
- data/test/thread_test.rb +1 -1
- data/tiny_tds.gemspec +10 -7
- metadata +70 -52
- data/.travis.yml +0 -24
- data/BACKERS.md +0 -32
- data/appveyor.yml +0 -51
- data/test/appveyor/dbsetup.ps1 +0 -27
- data/test/appveyor/dbsetup.sql +0 -9
- data/test/bin/setup.sh +0 -19
- data/test/schema/sqlserver_2000.sql +0 -140
- data/test/schema/sqlserver_2005.sql +0 -140
- data/test/schema/sqlserver_2014.sql +0 -140
- data/test/schema/sqlserver_2016.sql +0 -140
- data/test/schema/sybase_ase.sql +0 -138
- /data/test/schema/{sqlserver_2008.sql → sqlserver_2017.sql} +0 -0
data/test/result_test.rb
CHANGED
@@ -80,7 +80,7 @@ class ResultTest < TinyTds::TestCase
|
|
80
80
|
@client.execute("DELETE FROM [datatypes]").do
|
81
81
|
@client.execute("INSERT INTO [datatypes] ([char_10], [varchar_50]) VALUES ('1', '2')").do
|
82
82
|
result = @client.execute("SELECT TOP (1) [char_10] + 'test' + [varchar_50] AS [test] FROM [datatypes]").each.first['test']
|
83
|
-
result.must_equal "1 test2"
|
83
|
+
_(result).must_equal "1 test2"
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -135,10 +135,10 @@ class ResultTest < TinyTds::TestCase
|
|
135
135
|
text = 'test affected rows sql'
|
136
136
|
@client.execute("DELETE FROM [datatypes]").do
|
137
137
|
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first['AffectedRows']
|
138
|
-
['Fixnum', 'Integer'].must_include afrows.class.name
|
138
|
+
_(['Fixnum', 'Integer']).must_include afrows.class.name
|
139
139
|
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
140
140
|
pk1 = @client.execute(@client.identity_sql).each.first['Ident']
|
141
|
-
['Fixnum', 'Integer'].must_include pk1.class.name, 'we it be able to CAST to bigint'
|
141
|
+
_(['Fixnum', 'Integer']).must_include pk1.class.name, 'we it be able to CAST to bigint'
|
142
142
|
@client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
|
143
143
|
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first['AffectedRows']
|
144
144
|
assert_equal 1, afrows
|
@@ -154,7 +154,7 @@ class ResultTest < TinyTds::TestCase
|
|
154
154
|
inserted_rows = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
155
155
|
assert_equal 1, inserted_rows, 'should have inserted row for one above'
|
156
156
|
updated_rows = @client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
|
157
|
-
assert_equal 1, updated_rows, 'should have updated row for one above'
|
157
|
+
assert_equal 1, updated_rows, 'should have updated row for one above'
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
@@ -166,7 +166,7 @@ class ResultTest < TinyTds::TestCase
|
|
166
166
|
inserted_rows = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
167
167
|
assert_equal 1, inserted_rows, 'should have inserted row for one above'
|
168
168
|
updated_rows = @client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
|
169
|
-
assert_equal 1, updated_rows, 'should have updated row for one above'
|
169
|
+
assert_equal 1, updated_rows, 'should have updated row for one above'
|
170
170
|
end
|
171
171
|
end
|
172
172
|
|
@@ -177,19 +177,18 @@ class ResultTest < TinyTds::TestCase
|
|
177
177
|
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
178
178
|
sql_identity = @client.execute(@client.identity_sql).each.first['Ident']
|
179
179
|
native_identity = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").insert
|
180
|
-
assert_equal sql_identity+1, native_identity
|
180
|
+
assert_equal sql_identity + 1, native_identity
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
184
184
|
it 'returns bigint for #insert when needed' do
|
185
185
|
return if sqlserver_azure? # We can not alter clustered index like this test does.
|
186
|
-
|
187
|
-
|
188
|
-
# and and sp_helpindex creates a temporary table #spindtab.
|
186
|
+
# 'CREATE TABLE' command is not allowed within a multi-statement transaction
|
187
|
+
# and and sp_helpindex creates a temporary table #spindtab.
|
189
188
|
rollback_transaction(@client) do
|
190
189
|
seed = 9223372036854775805
|
191
190
|
@client.execute("DELETE FROM [datatypes]").do
|
192
|
-
id_constraint_name = @client.execute("EXEC sp_helpindex [datatypes]").detect{ |row| row['index_keys'] == 'id' }['index_name']
|
191
|
+
id_constraint_name = @client.execute("EXEC sp_helpindex [datatypes]").detect { |row| row['index_keys'] == 'id' }['index_name']
|
193
192
|
@client.execute("ALTER TABLE [datatypes] DROP CONSTRAINT [#{id_constraint_name}]").do
|
194
193
|
@client.execute("ALTER TABLE [datatypes] DROP COLUMN [id]").do
|
195
194
|
@client.execute("ALTER TABLE [datatypes] ADD [id] [bigint] NOT NULL IDENTITY(1,1) PRIMARY KEY").do
|
@@ -215,34 +214,34 @@ class ResultTest < TinyTds::TestCase
|
|
215
214
|
@client.execute("DELETE FROM [datatypes]").do
|
216
215
|
@client.execute("ROLLBACK TRANSACTION").do
|
217
216
|
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first['count']
|
218
|
-
|
217
|
+
_(count).wont_equal 0
|
219
218
|
end
|
220
219
|
|
221
220
|
it 'has a #fields accessor with logic default and valid outcome' do
|
222
221
|
result = @client.execute(@query1)
|
223
|
-
result.fields.must_equal ['one']
|
222
|
+
_(result.fields).must_equal ['one']
|
224
223
|
result.each
|
225
|
-
result.fields.must_equal ['one']
|
224
|
+
_(result.fields).must_equal ['one']
|
226
225
|
end
|
227
226
|
|
228
227
|
it 'always returns an array for fields for all sql' do
|
229
228
|
result = @client.execute("USE [tinytdstest]")
|
230
|
-
result.fields.must_equal []
|
229
|
+
_(result.fields).must_equal []
|
231
230
|
result.do
|
232
|
-
result.fields.must_equal []
|
231
|
+
_(result.fields).must_equal []
|
233
232
|
end
|
234
233
|
|
235
234
|
it 'returns fields even when no results are found' do
|
236
235
|
no_results_query = "SELECT [id], [varchar_50] FROM [datatypes] WHERE [varchar_50] = 'NOTFOUND'"
|
237
236
|
# Fields before each.
|
238
237
|
result = @client.execute(no_results_query)
|
239
|
-
result.fields.must_equal ['id','varchar_50']
|
238
|
+
_(result.fields).must_equal ['id', 'varchar_50']
|
240
239
|
result.each
|
241
|
-
result.fields.must_equal ['id','varchar_50']
|
240
|
+
_(result.fields).must_equal ['id', 'varchar_50']
|
242
241
|
# Each then fields
|
243
242
|
result = @client.execute(no_results_query)
|
244
243
|
result.each
|
245
|
-
result.fields.must_equal ['id','varchar_50']
|
244
|
+
_(result.fields).must_equal ['id', 'varchar_50']
|
246
245
|
end
|
247
246
|
|
248
247
|
it 'allows the result to be canceled before reading' do
|
@@ -254,27 +253,27 @@ class ResultTest < TinyTds::TestCase
|
|
254
253
|
it 'works in tandem with the client when needing to find out if client has sql sent and result is canceled or not' do
|
255
254
|
# Default state.
|
256
255
|
@client = TinyTds::Client.new(connection_options)
|
257
|
-
@client.sqlsent
|
258
|
-
@client.canceled
|
256
|
+
_(@client.sqlsent?).must_equal false
|
257
|
+
_(@client.canceled?).must_equal false
|
259
258
|
# With active result before and after cancel.
|
260
259
|
result = @client.execute(@query1)
|
261
|
-
@client.sqlsent
|
262
|
-
@client.canceled
|
260
|
+
_(@client.sqlsent?).must_equal true
|
261
|
+
_(@client.canceled?).must_equal false
|
263
262
|
result.cancel
|
264
|
-
@client.sqlsent
|
265
|
-
@client.canceled
|
263
|
+
_(@client.sqlsent?).must_equal false
|
264
|
+
_(@client.canceled?).must_equal true
|
266
265
|
assert result.cancel, 'must be safe to call again'
|
267
266
|
# With each and no block.
|
268
267
|
@client.execute(@query1).each
|
269
|
-
@client.sqlsent
|
270
|
-
@client.canceled
|
268
|
+
_(@client.sqlsent?).must_equal false
|
269
|
+
_(@client.canceled?).must_equal false
|
271
270
|
# With each and block.
|
272
271
|
@client.execute(@query1).each do |row|
|
273
|
-
@client.sqlsent
|
274
|
-
@client.canceled
|
272
|
+
_(@client.sqlsent?).must_equal true, 'when iterating over each row in a block'
|
273
|
+
_(@client.canceled?).must_equal false
|
275
274
|
end
|
276
|
-
@client.sqlsent
|
277
|
-
@client.canceled
|
275
|
+
_(@client.sqlsent?).must_equal false
|
276
|
+
_(@client.canceled?).must_equal false
|
278
277
|
# With each and block canceled half way thru.
|
279
278
|
count = @client.execute("SELECT COUNT([id]) AS [count] FROM [datatypes]").each[0]['count']
|
280
279
|
assert count > 10, 'since we want to cancel early for test'
|
@@ -284,30 +283,30 @@ class ResultTest < TinyTds::TestCase
|
|
284
283
|
break if index > 10
|
285
284
|
index += 1
|
286
285
|
end
|
287
|
-
@client.sqlsent
|
288
|
-
@client.canceled
|
286
|
+
_(@client.sqlsent?).must_equal true
|
287
|
+
_(@client.canceled?).must_equal false
|
289
288
|
result.cancel
|
290
|
-
@client.sqlsent
|
291
|
-
@client.canceled
|
289
|
+
_(@client.sqlsent?).must_equal false
|
290
|
+
_(@client.canceled?).must_equal true
|
292
291
|
# With do method.
|
293
292
|
@client.execute(@query1).do
|
294
|
-
@client.sqlsent
|
295
|
-
@client.canceled
|
293
|
+
_(@client.sqlsent?).must_equal false
|
294
|
+
_(@client.canceled?).must_equal true
|
296
295
|
# With insert method.
|
297
296
|
rollback_transaction(@client) do
|
298
297
|
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('test')").insert
|
299
|
-
@client.sqlsent
|
300
|
-
@client.canceled
|
298
|
+
_(@client.sqlsent?).must_equal false
|
299
|
+
_(@client.canceled?).must_equal true
|
301
300
|
end
|
302
301
|
# With first
|
303
302
|
@client.execute("SELECT [id] FROM [datatypes]").each(:first => true)
|
304
|
-
@client.sqlsent
|
305
|
-
@client.canceled
|
303
|
+
_(@client.sqlsent?).must_equal false
|
304
|
+
_(@client.canceled?).must_equal true
|
306
305
|
end
|
307
306
|
|
308
307
|
it 'use same string object for hash keys' do
|
309
308
|
data = @client.execute("SELECT [id], [bigint] FROM [datatypes]").each
|
310
|
-
assert_equal data.first.keys.map{ |r| r.object_id }, data.last.keys.map{ |r| r.object_id }
|
309
|
+
assert_equal data.first.keys.map { |r| r.object_id }, data.last.keys.map { |r| r.object_id }
|
311
310
|
end
|
312
311
|
|
313
312
|
it 'has properly encoded column names with symbol keys' do
|
@@ -326,7 +325,7 @@ class ResultTest < TinyTds::TestCase
|
|
326
325
|
it 'allows #return_code to work with stored procedures and reset per sql batch' do
|
327
326
|
assert_nil @client.return_code
|
328
327
|
result = @client.execute("EXEC tinytds_TestReturnCodes")
|
329
|
-
assert_equal [{"one"=>1}], result.each
|
328
|
+
assert_equal [{ "one" => 1 }], result.each
|
330
329
|
assert_equal 420, @client.return_code
|
331
330
|
assert_equal 420, result.return_code
|
332
331
|
result = @client.execute('SELECT 1 as [one]')
|
@@ -337,13 +336,13 @@ class ResultTest < TinyTds::TestCase
|
|
337
336
|
|
338
337
|
it 'with LOGINPROPERTY function' do
|
339
338
|
v = @client.execute("SELECT LOGINPROPERTY('sa', 'IsLocked') as v").first['v']
|
340
|
-
v.must_equal 0
|
339
|
+
_(v).must_equal 0
|
341
340
|
end
|
342
341
|
|
343
342
|
describe 'with multiple result sets' do
|
344
343
|
|
345
344
|
before do
|
346
|
-
@empty_select
|
345
|
+
@empty_select = "SELECT 1 AS [rs1] WHERE 1 = 0"
|
347
346
|
@double_select = "SELECT 1 AS [rs1]
|
348
347
|
SELECT 2 AS [rs2]"
|
349
348
|
@triple_select_1st_empty = "SELECT 1 AS [rs1] WHERE 1 = 0
|
@@ -361,8 +360,8 @@ class ResultTest < TinyTds::TestCase
|
|
361
360
|
result = @client.execute(@double_select)
|
362
361
|
result_sets = result.each
|
363
362
|
assert_equal 2, result_sets.size
|
364
|
-
assert_equal [{'rs1' => 1}], result_sets.first
|
365
|
-
assert_equal [{'rs2' => 2}], result_sets.last
|
363
|
+
assert_equal [{ 'rs1' => 1 }], result_sets.first
|
364
|
+
assert_equal [{ 'rs2' => 2 }], result_sets.last
|
366
365
|
assert_equal [['rs1'], ['rs2']], result.fields
|
367
366
|
assert_equal result.each.object_id, result.each.object_id, 'same cached rows'
|
368
367
|
# As array
|
@@ -383,20 +382,12 @@ class ResultTest < TinyTds::TestCase
|
|
383
382
|
end
|
384
383
|
|
385
384
|
it 'works from a stored procedure' do
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
assert constraint_info.key?("constraint_name")
|
393
|
-
elsif sybase_ase?
|
394
|
-
results1, results2 = @client.execute("EXEC sp_helpconstraint 'datatypes'").each
|
395
|
-
assert results1['name'] =~ /^datatypes_bit/
|
396
|
-
assert results1['defintion'] == 'DEFAULT 0'
|
397
|
-
assert results2['name'] =~ /^datatypes_id/
|
398
|
-
assert results2['defintion'] =~ /^PRIMARY KEY/
|
399
|
-
end
|
385
|
+
results1, results2 = @client.execute("EXEC sp_helpconstraint '[datatypes]'").each
|
386
|
+
assert_equal [{ "Object Name" => "[datatypes]" }], results1
|
387
|
+
constraint_info = results2.first
|
388
|
+
assert constraint_info.key?("constraint_keys")
|
389
|
+
assert constraint_info.key?("constraint_type")
|
390
|
+
assert constraint_info.key?("constraint_name")
|
400
391
|
end
|
401
392
|
|
402
393
|
describe 'using :empty_sets TRUE' do
|
@@ -423,8 +414,8 @@ class ResultTest < TinyTds::TestCase
|
|
423
414
|
result_sets = result.each
|
424
415
|
assert_equal 3, result_sets.size
|
425
416
|
assert_equal [], result_sets[0]
|
426
|
-
assert_equal [{'rs2' => 2}], result_sets[1]
|
427
|
-
assert_equal [{'rs3' => 3}], result_sets[2]
|
417
|
+
assert_equal [{ 'rs2' => 2 }], result_sets[1]
|
418
|
+
assert_equal [{ 'rs3' => 3 }], result_sets[2]
|
428
419
|
assert_equal [['rs1'], ['rs2'], ['rs3']], result.fields
|
429
420
|
assert_equal result.each.object_id, result.each.object_id, 'same cached rows'
|
430
421
|
# As array
|
@@ -442,9 +433,9 @@ class ResultTest < TinyTds::TestCase
|
|
442
433
|
result = @client.execute(@triple_select_2nd_empty)
|
443
434
|
result_sets = result.each
|
444
435
|
assert_equal 3, result_sets.size
|
445
|
-
assert_equal [{'rs1' => 1}], result_sets[0]
|
436
|
+
assert_equal [{ 'rs1' => 1 }], result_sets[0]
|
446
437
|
assert_equal [], result_sets[1]
|
447
|
-
assert_equal [{'rs3' => 3}], result_sets[2]
|
438
|
+
assert_equal [{ 'rs3' => 3 }], result_sets[2]
|
448
439
|
assert_equal [['rs1'], ['rs2'], ['rs3']], result.fields
|
449
440
|
assert_equal result.each.object_id, result.each.object_id, 'same cached rows'
|
450
441
|
# As array
|
@@ -462,8 +453,8 @@ class ResultTest < TinyTds::TestCase
|
|
462
453
|
result = @client.execute(@triple_select_3rd_empty)
|
463
454
|
result_sets = result.each
|
464
455
|
assert_equal 3, result_sets.size
|
465
|
-
assert_equal [{'rs1' => 1}], result_sets[0]
|
466
|
-
assert_equal [{'rs2' => 2}], result_sets[1]
|
456
|
+
assert_equal [{ 'rs1' => 1 }], result_sets[0]
|
457
|
+
assert_equal [{ 'rs2' => 2 }], result_sets[1]
|
467
458
|
assert_equal [], result_sets[2]
|
468
459
|
assert_equal [['rs1'], ['rs2'], ['rs3']], result.fields
|
469
460
|
assert_equal result.each.object_id, result.each.object_id, 'same cached rows'
|
@@ -503,8 +494,8 @@ class ResultTest < TinyTds::TestCase
|
|
503
494
|
result = @client.execute(@triple_select_1st_empty)
|
504
495
|
result_sets = result.each
|
505
496
|
assert_equal 2, result_sets.size
|
506
|
-
assert_equal [{'rs2' => 2}], result_sets[0]
|
507
|
-
assert_equal [{'rs3' => 3}], result_sets[1]
|
497
|
+
assert_equal [{ 'rs2' => 2 }], result_sets[0]
|
498
|
+
assert_equal [{ 'rs3' => 3 }], result_sets[1]
|
508
499
|
assert_equal [['rs2'], ['rs3']], result.fields
|
509
500
|
assert_equal result.each.object_id, result.each.object_id, 'same cached rows'
|
510
501
|
# As array
|
@@ -521,8 +512,8 @@ class ResultTest < TinyTds::TestCase
|
|
521
512
|
result = @client.execute(@triple_select_2nd_empty)
|
522
513
|
result_sets = result.each
|
523
514
|
assert_equal 2, result_sets.size
|
524
|
-
assert_equal [{'rs1' => 1}], result_sets[0]
|
525
|
-
assert_equal [{'rs3' => 3}], result_sets[1]
|
515
|
+
assert_equal [{ 'rs1' => 1 }], result_sets[0]
|
516
|
+
assert_equal [{ 'rs3' => 3 }], result_sets[1]
|
526
517
|
assert_equal [['rs1'], ['rs3']], result.fields
|
527
518
|
assert_equal result.each.object_id, result.each.object_id, 'same cached rows'
|
528
519
|
# As array
|
@@ -539,8 +530,8 @@ class ResultTest < TinyTds::TestCase
|
|
539
530
|
result = @client.execute(@triple_select_3rd_empty)
|
540
531
|
result_sets = result.each
|
541
532
|
assert_equal 2, result_sets.size
|
542
|
-
assert_equal [{'rs1' => 1}], result_sets[0]
|
543
|
-
assert_equal [{'rs2' => 2}], result_sets[1]
|
533
|
+
assert_equal [{ 'rs1' => 1 }], result_sets[0]
|
534
|
+
assert_equal [{ 'rs2' => 2 }], result_sets[1]
|
544
535
|
assert_equal [['rs1'], ['rs2']], result.fields
|
545
536
|
assert_equal result.each.object_id, result.each.object_id, 'same cached rows'
|
546
537
|
# As array
|
@@ -590,7 +581,7 @@ class ResultTest < TinyTds::TestCase
|
|
590
581
|
before do
|
591
582
|
@big_text = 'x' * 2_000_000
|
592
583
|
@old_textsize = @client.execute("SELECT @@TEXTSIZE AS [textsize]").each.first['textsize'].inspect
|
593
|
-
@client.execute("SET TEXTSIZE #{(@big_text.length*2)+1}").do
|
584
|
+
@client.execute("SET TEXTSIZE #{(@big_text.length * 2) + 1}").do
|
594
585
|
end
|
595
586
|
|
596
587
|
it 'must insert and select large varchar_max' do
|
@@ -601,7 +592,7 @@ class ResultTest < TinyTds::TestCase
|
|
601
592
|
insert_and_select_datatype :nvarchar_max
|
602
593
|
end
|
603
594
|
|
604
|
-
end
|
595
|
+
end
|
605
596
|
|
606
597
|
end
|
607
598
|
|
@@ -612,147 +603,105 @@ class ResultTest < TinyTds::TestCase
|
|
612
603
|
assert_equal [], @client.execute('').each
|
613
604
|
end
|
614
605
|
|
615
|
-
|
616
|
-
|
617
|
-
describe 'using :message_handler option' do
|
618
|
-
let(:messages) { Array.new }
|
606
|
+
describe 'using :message_handler option' do
|
607
|
+
let(:messages) { Array.new }
|
619
608
|
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
after do
|
626
|
-
messages.clear
|
627
|
-
end
|
609
|
+
before do
|
610
|
+
close_client
|
611
|
+
@client = new_connection message_handler: Proc.new { |m| messages << m }
|
612
|
+
end
|
628
613
|
|
629
|
-
|
630
|
-
|
631
|
-
|
614
|
+
after do
|
615
|
+
messages.clear
|
616
|
+
end
|
632
617
|
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
msg = "Test #{severity} severity"
|
637
|
-
state = rand(1..255)
|
638
|
-
@client.execute("RAISERROR(N'#{msg}', #{severity}, #{state})").do
|
639
|
-
m = messages.first
|
640
|
-
assert_equal 1, messages.length, 'there should be one message after one raiserror'
|
641
|
-
assert_equal msg, m.message, 'message text'
|
642
|
-
assert_equal severity, m.severity, 'message severity' unless severity == 10 && m.severity.to_i == 0
|
643
|
-
assert_equal state, m.os_error_number, 'message state'
|
644
|
-
end
|
645
|
-
end
|
618
|
+
it 'has a message handler that responds to call' do
|
619
|
+
assert @client.message_handler.respond_to?(:call)
|
620
|
+
end
|
646
621
|
|
647
|
-
|
622
|
+
it 'calls the provided message handler when severity is 10 or less' do
|
623
|
+
(1..10).to_a.each do |severity|
|
648
624
|
messages.clear
|
649
|
-
msg =
|
650
|
-
|
625
|
+
msg = "Test #{severity} severity"
|
626
|
+
state = rand(1..255)
|
627
|
+
@client.execute("RAISERROR(N'#{msg}', #{severity}, #{state})").do
|
651
628
|
m = messages.first
|
652
|
-
assert_equal 1, messages.length, 'there should be one message after one
|
629
|
+
assert_equal 1, messages.length, 'there should be one message after one raiserror'
|
653
630
|
assert_equal msg, m.message, 'message text'
|
631
|
+
assert_equal severity, m.severity, 'message severity' unless severity == 10 && m.severity.to_i == 0
|
632
|
+
assert_equal state, m.os_error_number, 'message state'
|
654
633
|
end
|
655
634
|
end
|
656
635
|
|
657
|
-
it '
|
658
|
-
|
659
|
-
|
660
|
-
|
636
|
+
it 'calls the provided message handler for `print` messages' do
|
637
|
+
messages.clear
|
638
|
+
msg = 'hello'
|
639
|
+
@client.execute("PRINT '#{msg}'").do
|
640
|
+
m = messages.first
|
641
|
+
assert_equal 1, messages.length, 'there should be one message after one print statement'
|
642
|
+
assert_equal msg, m.message, 'message text'
|
661
643
|
end
|
662
644
|
|
663
|
-
it '
|
664
|
-
|
645
|
+
it 'must raise an error preceded by a `print` message' do
|
646
|
+
messages.clear
|
647
|
+
action = lambda { @client.execute("EXEC tinytds_TestPrintWithError").do }
|
665
648
|
assert_raise_tinytds_error(action) do |e|
|
666
|
-
assert_equal
|
667
|
-
|
649
|
+
assert_equal 'hello', messages.first.message, 'message text'
|
650
|
+
|
651
|
+
assert_equal "Error following print", e.message
|
652
|
+
assert_equal 16, e.severity
|
668
653
|
assert_equal 50000, e.db_error_number
|
669
654
|
end
|
670
655
|
end
|
671
656
|
|
672
|
-
|
657
|
+
it 'calls the provided message handler for each of a series of `print` messages' do
|
658
|
+
messages.clear
|
659
|
+
@client.execute("EXEC tinytds_TestSeveralPrints").do
|
660
|
+
assert_equal ['hello 1', 'hello 2', 'hello 3'], messages.map { |e| e.message }, 'message list'
|
661
|
+
end
|
673
662
|
|
674
|
-
it '
|
675
|
-
|
663
|
+
it 'should flush info messages before raising error in cases of timeout' do
|
664
|
+
@client = new_connection timeout: 1, message_handler: Proc.new { |m| messages << m }
|
665
|
+
action = lambda { @client.execute("print 'hello'; waitfor delay '00:00:02'").do }
|
666
|
+
messages.clear
|
676
667
|
assert_raise_tinytds_error(action) do |e|
|
677
|
-
|
678
|
-
assert_equal
|
679
|
-
assert_equal
|
668
|
+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
|
669
|
+
assert_equal 6, e.severity
|
670
|
+
assert_equal 20003, e.db_error_number
|
671
|
+
assert_equal 'hello', messages.first&.message, 'message text'
|
680
672
|
end
|
681
|
-
assert_followup_query
|
682
673
|
end
|
683
674
|
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
675
|
+
it 'should print info messages before raising error in cases of timeout' do
|
676
|
+
@client = new_connection timeout: 1, message_handler: Proc.new { |m| messages << m }
|
677
|
+
action = lambda { @client.execute("raiserror('hello', 1, 1) with nowait; waitfor delay '00:00:02'").do }
|
678
|
+
messages.clear
|
679
|
+
assert_raise_tinytds_error(action) do |e|
|
680
|
+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
|
681
|
+
assert_equal 6, e.severity
|
682
|
+
assert_equal 20003, e.db_error_number
|
683
|
+
assert_equal 'hello', messages.first&.message, 'message text'
|
684
|
+
end
|
693
685
|
end
|
694
686
|
end
|
695
687
|
|
696
|
-
it 'must error
|
697
|
-
|
698
|
-
|
699
|
-
pattern = sybase_ase? ? /foobar not found/ : %r|invalid object name.*foobar|i
|
700
|
-
assert_match pattern, e.message
|
701
|
-
assert_equal 16, e.severity
|
702
|
-
assert_equal 208, e.db_error_number
|
688
|
+
it 'must not raise an error when severity is 10 or less' do
|
689
|
+
(1..10).to_a.each do |severity|
|
690
|
+
@client.execute("RAISERROR(N'Test #{severity} severity', #{severity}, 1)").do
|
703
691
|
end
|
704
|
-
assert_followup_query
|
705
692
|
end
|
706
693
|
|
707
|
-
it '
|
708
|
-
action = lambda { @client.execute('
|
694
|
+
it 'raises an error when severity is greater than 10' do
|
695
|
+
action = lambda { @client.execute("RAISERROR(N'Test 11 severity', 11, 1)").do }
|
709
696
|
assert_raise_tinytds_error(action) do |e|
|
710
|
-
|
711
|
-
assert_equal
|
712
|
-
assert_equal
|
713
|
-
end
|
714
|
-
assert_followup_query
|
715
|
-
end
|
716
|
-
|
717
|
-
it 'must not error at all from reading non-convertable charcters and just use ? marks' do
|
718
|
-
close_client
|
719
|
-
@client = new_connection :encoding => 'ASCII'
|
720
|
-
@client.charset.must_equal 'ASCII'
|
721
|
-
find_value(202, :nvarchar_50).must_equal 'test nvarchar_50 ??'
|
722
|
-
end
|
723
|
-
|
724
|
-
it 'must error gracefully from writing non-convertable characters' do
|
725
|
-
close_client
|
726
|
-
@client = new_connection :encoding => 'ASCII'
|
727
|
-
@client.charset.must_equal 'ASCII'
|
728
|
-
rollback_transaction(@client) do
|
729
|
-
text = 'Test ✓'
|
730
|
-
@client.execute("DELETE FROM [datatypes] WHERE [nvarchar_50] IS NOT NULL").do
|
731
|
-
action = lambda { @client.execute("INSERT INTO [datatypes] ([nvarchar_50]) VALUES ('#{text}')").do }
|
732
|
-
assert_raise_tinytds_error(action) do |e|
|
733
|
-
e.message.must_match %r{Unclosed quotation mark}i
|
734
|
-
e.severity.must_equal 15
|
735
|
-
e.db_error_number.must_equal 105
|
736
|
-
end
|
737
|
-
assert_followup_query
|
697
|
+
assert_equal "Test 11 severity", e.message
|
698
|
+
assert_equal 11, e.severity
|
699
|
+
assert_equal 50000, e.db_error_number
|
738
700
|
end
|
739
701
|
end
|
740
|
-
|
741
|
-
it 'errors gracefully with incorrect syntax in sp_executesql' do
|
742
|
-
action = lambda { @client.execute("EXEC sp_executesql N'this will not work'").each }
|
743
|
-
assert_raise_tinytds_error(action) do |e|
|
744
|
-
assert_match %r|incorrect syntax|i, e.message
|
745
|
-
assert_equal 15, e.severity
|
746
|
-
assert_equal 156, e.db_error_number
|
747
|
-
end
|
748
|
-
assert_followup_query
|
749
|
-
end unless sybase_ase?
|
750
|
-
|
751
702
|
end
|
752
|
-
|
753
703
|
end
|
754
704
|
|
755
|
-
|
756
705
|
protected
|
757
706
|
|
758
707
|
def assert_followup_query
|
@@ -770,4 +719,3 @@ class ResultTest < TinyTds::TestCase
|
|
770
719
|
end
|
771
720
|
|
772
721
|
end
|
773
|
-
|