tiny_tds 1.0.4 → 2.1.5
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/.codeclimate.yml +20 -0
- data/.gitattributes +1 -0
- data/.rubocop.yml +31 -0
- data/.travis.yml +25 -0
- data/{CHANGELOG → CHANGELOG.md} +102 -26
- data/Gemfile +4 -1
- data/ISSUE_TEMPLATE.md +35 -2
- data/README.md +131 -56
- data/Rakefile +31 -88
- data/VERSION +1 -1
- data/appveyor.yml +38 -17
- data/docker-compose.yml +22 -0
- data/ext/tiny_tds/client.c +147 -60
- data/ext/tiny_tds/client.h +11 -5
- data/ext/tiny_tds/extconf.rb +41 -297
- data/ext/tiny_tds/extconsts.rb +7 -7
- data/ext/tiny_tds/result.c +40 -15
- data/lib/tiny_tds/bin.rb +45 -27
- data/lib/tiny_tds/client.rb +46 -34
- data/lib/tiny_tds/error.rb +0 -1
- data/lib/tiny_tds/gem.rb +32 -0
- data/lib/tiny_tds/result.rb +2 -3
- data/lib/tiny_tds/version.rb +1 -1
- data/lib/tiny_tds.rb +38 -14
- data/{ports/patches/freetds/1.00 → patches/freetds/1.00.27}/0001-mingw_missing_inet_pton.diff +4 -4
- data/patches/freetds/1.00.27/0002-Don-t-use-MSYS2-file-libws2_32.diff +28 -0
- data/patches/libiconv/1.14/1-avoid-gets-error.patch +17 -0
- data/tasks/native_gem.rake +14 -0
- data/tasks/package.rake +8 -0
- data/tasks/ports/freetds.rb +37 -0
- data/tasks/ports/libiconv.rb +43 -0
- data/tasks/ports/openssl.rb +62 -0
- data/tasks/ports/recipe.rb +52 -0
- data/tasks/ports.rake +85 -0
- data/tasks/test.rake +9 -0
- data/test/appveyor/dbsetup.ps1 +1 -1
- data/test/bin/install-freetds.sh +20 -0
- data/test/bin/install-openssl.sh +18 -0
- data/test/bin/setup.sh +19 -0
- data/test/client_test.rb +124 -66
- data/test/gem_test.rb +179 -0
- data/test/result_test.rb +128 -42
- data/test/schema/sqlserver_2016.sql +140 -0
- data/test/schema_test.rb +23 -23
- data/test/test_helper.rb +65 -7
- data/test/thread_test.rb +1 -1
- data/tiny_tds.gemspec +9 -7
- metadata +60 -20
- /data/bin/{defncopy → defncopy-ttds} +0 -0
- /data/bin/{tsql → tsql-ttds} +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
|
-
|
|
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
|
-
|
|
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
|
|
@@ -215,34 +215,34 @@ class ResultTest < TinyTds::TestCase
|
|
|
215
215
|
@client.execute("DELETE FROM [datatypes]").do
|
|
216
216
|
@client.execute("ROLLBACK TRANSACTION").do
|
|
217
217
|
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first['count']
|
|
218
|
-
|
|
218
|
+
_(count).wont_equal 0
|
|
219
219
|
end
|
|
220
220
|
|
|
221
221
|
it 'has a #fields accessor with logic default and valid outcome' do
|
|
222
222
|
result = @client.execute(@query1)
|
|
223
|
-
result.fields.must_equal ['one']
|
|
223
|
+
_(result.fields).must_equal ['one']
|
|
224
224
|
result.each
|
|
225
|
-
result.fields.must_equal ['one']
|
|
225
|
+
_(result.fields).must_equal ['one']
|
|
226
226
|
end
|
|
227
227
|
|
|
228
228
|
it 'always returns an array for fields for all sql' do
|
|
229
229
|
result = @client.execute("USE [tinytdstest]")
|
|
230
|
-
result.fields.must_equal []
|
|
230
|
+
_(result.fields).must_equal []
|
|
231
231
|
result.do
|
|
232
|
-
result.fields.must_equal []
|
|
232
|
+
_(result.fields).must_equal []
|
|
233
233
|
end
|
|
234
234
|
|
|
235
235
|
it 'returns fields even when no results are found' do
|
|
236
236
|
no_results_query = "SELECT [id], [varchar_50] FROM [datatypes] WHERE [varchar_50] = 'NOTFOUND'"
|
|
237
237
|
# Fields before each.
|
|
238
238
|
result = @client.execute(no_results_query)
|
|
239
|
-
result.fields.must_equal ['id','varchar_50']
|
|
239
|
+
_(result.fields).must_equal ['id','varchar_50']
|
|
240
240
|
result.each
|
|
241
|
-
result.fields.must_equal ['id','varchar_50']
|
|
241
|
+
_(result.fields).must_equal ['id','varchar_50']
|
|
242
242
|
# Each then fields
|
|
243
243
|
result = @client.execute(no_results_query)
|
|
244
244
|
result.each
|
|
245
|
-
result.fields.must_equal ['id','varchar_50']
|
|
245
|
+
_(result.fields).must_equal ['id','varchar_50']
|
|
246
246
|
end
|
|
247
247
|
|
|
248
248
|
it 'allows the result to be canceled before reading' do
|
|
@@ -254,27 +254,27 @@ class ResultTest < TinyTds::TestCase
|
|
|
254
254
|
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
255
|
# Default state.
|
|
256
256
|
@client = TinyTds::Client.new(connection_options)
|
|
257
|
-
@client.sqlsent
|
|
258
|
-
@client.canceled
|
|
257
|
+
_(@client.sqlsent?).must_equal false
|
|
258
|
+
_(@client.canceled?).must_equal false
|
|
259
259
|
# With active result before and after cancel.
|
|
260
260
|
result = @client.execute(@query1)
|
|
261
|
-
@client.sqlsent
|
|
262
|
-
@client.canceled
|
|
261
|
+
_(@client.sqlsent?).must_equal true
|
|
262
|
+
_(@client.canceled?).must_equal false
|
|
263
263
|
result.cancel
|
|
264
|
-
@client.sqlsent
|
|
265
|
-
@client.canceled
|
|
264
|
+
_(@client.sqlsent?).must_equal false
|
|
265
|
+
_(@client.canceled?).must_equal true
|
|
266
266
|
assert result.cancel, 'must be safe to call again'
|
|
267
267
|
# With each and no block.
|
|
268
268
|
@client.execute(@query1).each
|
|
269
|
-
@client.sqlsent
|
|
270
|
-
@client.canceled
|
|
269
|
+
_(@client.sqlsent?).must_equal false
|
|
270
|
+
_(@client.canceled?).must_equal false
|
|
271
271
|
# With each and block.
|
|
272
272
|
@client.execute(@query1).each do |row|
|
|
273
|
-
@client.sqlsent
|
|
274
|
-
@client.canceled
|
|
273
|
+
_(@client.sqlsent?).must_equal true, 'when iterating over each row in a block'
|
|
274
|
+
_(@client.canceled?).must_equal false
|
|
275
275
|
end
|
|
276
|
-
@client.sqlsent
|
|
277
|
-
@client.canceled
|
|
276
|
+
_(@client.sqlsent?).must_equal false
|
|
277
|
+
_(@client.canceled?).must_equal false
|
|
278
278
|
# With each and block canceled half way thru.
|
|
279
279
|
count = @client.execute("SELECT COUNT([id]) AS [count] FROM [datatypes]").each[0]['count']
|
|
280
280
|
assert count > 10, 'since we want to cancel early for test'
|
|
@@ -284,25 +284,25 @@ class ResultTest < TinyTds::TestCase
|
|
|
284
284
|
break if index > 10
|
|
285
285
|
index += 1
|
|
286
286
|
end
|
|
287
|
-
@client.sqlsent
|
|
288
|
-
@client.canceled
|
|
287
|
+
_(@client.sqlsent?).must_equal true
|
|
288
|
+
_(@client.canceled?).must_equal false
|
|
289
289
|
result.cancel
|
|
290
|
-
@client.sqlsent
|
|
291
|
-
@client.canceled
|
|
290
|
+
_(@client.sqlsent?).must_equal false
|
|
291
|
+
_(@client.canceled?).must_equal true
|
|
292
292
|
# With do method.
|
|
293
293
|
@client.execute(@query1).do
|
|
294
|
-
@client.sqlsent
|
|
295
|
-
@client.canceled
|
|
294
|
+
_(@client.sqlsent?).must_equal false
|
|
295
|
+
_(@client.canceled?).must_equal true
|
|
296
296
|
# With insert method.
|
|
297
297
|
rollback_transaction(@client) do
|
|
298
298
|
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('test')").insert
|
|
299
|
-
@client.sqlsent
|
|
300
|
-
@client.canceled
|
|
299
|
+
_(@client.sqlsent?).must_equal false
|
|
300
|
+
_(@client.canceled?).must_equal true
|
|
301
301
|
end
|
|
302
302
|
# With first
|
|
303
303
|
@client.execute("SELECT [id] FROM [datatypes]").each(:first => true)
|
|
304
|
-
@client.sqlsent
|
|
305
|
-
@client.canceled
|
|
304
|
+
_(@client.sqlsent?).must_equal false
|
|
305
|
+
_(@client.canceled?).must_equal true
|
|
306
306
|
end
|
|
307
307
|
|
|
308
308
|
it 'use same string object for hash keys' do
|
|
@@ -335,6 +335,11 @@ class ResultTest < TinyTds::TestCase
|
|
|
335
335
|
assert_nil result.return_code
|
|
336
336
|
end
|
|
337
337
|
|
|
338
|
+
it 'with LOGINPROPERTY function' do
|
|
339
|
+
v = @client.execute("SELECT LOGINPROPERTY('sa', 'IsLocked') as v").first['v']
|
|
340
|
+
_(v).must_equal 0
|
|
341
|
+
end
|
|
342
|
+
|
|
338
343
|
describe 'with multiple result sets' do
|
|
339
344
|
|
|
340
345
|
before do
|
|
@@ -573,7 +578,7 @@ class ResultTest < TinyTds::TestCase
|
|
|
573
578
|
|
|
574
579
|
it 'returns nil for NULL' do
|
|
575
580
|
value = @client.execute('SELECT NULL AS [null]').each.first['null']
|
|
576
|
-
|
|
581
|
+
assert_nil value
|
|
577
582
|
end
|
|
578
583
|
|
|
579
584
|
end
|
|
@@ -609,6 +614,88 @@ class ResultTest < TinyTds::TestCase
|
|
|
609
614
|
|
|
610
615
|
if sqlserver?
|
|
611
616
|
|
|
617
|
+
describe 'using :message_handler option' do
|
|
618
|
+
let(:messages) { Array.new }
|
|
619
|
+
|
|
620
|
+
before do
|
|
621
|
+
close_client
|
|
622
|
+
@client = new_connection message_handler: Proc.new { |m| messages << m }
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
after do
|
|
626
|
+
messages.clear
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
it 'has a message handler that responds to call' do
|
|
630
|
+
assert @client.message_handler.respond_to?(:call)
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
it 'calls the provided message handler when severity is 10 or less' do
|
|
634
|
+
(1..10).to_a.each do |severity|
|
|
635
|
+
messages.clear
|
|
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
|
|
646
|
+
|
|
647
|
+
it 'calls the provided message handler for `print` messages' do
|
|
648
|
+
messages.clear
|
|
649
|
+
msg = 'hello'
|
|
650
|
+
@client.execute("PRINT '#{msg}'").do
|
|
651
|
+
m = messages.first
|
|
652
|
+
assert_equal 1, messages.length, 'there should be one message after one print statement'
|
|
653
|
+
assert_equal msg, m.message, 'message text'
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
it 'must raise an error preceded by a `print` message' do
|
|
657
|
+
messages.clear
|
|
658
|
+
action = lambda { @client.execute("EXEC tinytds_TestPrintWithError").do }
|
|
659
|
+
assert_raise_tinytds_error(action) do |e|
|
|
660
|
+
assert_equal 'hello', messages.first.message, 'message text'
|
|
661
|
+
|
|
662
|
+
assert_equal "Error following print", e.message
|
|
663
|
+
assert_equal 16, e.severity
|
|
664
|
+
assert_equal 50000, e.db_error_number
|
|
665
|
+
end
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
it 'calls the provided message handler for each of a series of `print` messages' do
|
|
669
|
+
messages.clear
|
|
670
|
+
@client.execute("EXEC tinytds_TestSeveralPrints").do
|
|
671
|
+
assert_equal ['hello 1', 'hello 2', 'hello 3'], messages.map { |e| e.message }, 'message list'
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
it 'should flush info messages before raising error in cases of timeout' do
|
|
675
|
+
@client = new_connection timeout: 1, message_handler: Proc.new { |m| messages << m }
|
|
676
|
+
action = lambda { @client.execute("print 'hello'; waitfor delay '00:00:02'").do }
|
|
677
|
+
messages.clear
|
|
678
|
+
assert_raise_tinytds_error(action) do |e|
|
|
679
|
+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
|
|
680
|
+
assert_equal 6, e.severity
|
|
681
|
+
assert_equal 20003, e.db_error_number
|
|
682
|
+
assert_equal 'hello', messages.first&.message, 'message text'
|
|
683
|
+
end
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
it 'should print info messages before raising error in cases of timeout' do
|
|
687
|
+
@client = new_connection timeout: 1, message_handler: Proc.new { |m| messages << m }
|
|
688
|
+
action = lambda { @client.execute("raiserror('hello', 1, 1) with nowait; waitfor delay '00:00:02'").do }
|
|
689
|
+
messages.clear
|
|
690
|
+
assert_raise_tinytds_error(action) do |e|
|
|
691
|
+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
|
|
692
|
+
assert_equal 6, e.severity
|
|
693
|
+
assert_equal 20003, e.db_error_number
|
|
694
|
+
assert_equal 'hello', messages.first&.message, 'message text'
|
|
695
|
+
end
|
|
696
|
+
end
|
|
697
|
+
end
|
|
698
|
+
|
|
612
699
|
it 'must not raise an error when severity is 10 or less' do
|
|
613
700
|
(1..10).to_a.each do |severity|
|
|
614
701
|
@client.execute("RAISERROR(N'Test #{severity} severity', #{severity}, 1)").do
|
|
@@ -639,7 +726,7 @@ class ResultTest < TinyTds::TestCase
|
|
|
639
726
|
end
|
|
640
727
|
|
|
641
728
|
it 'throws an error when you execute another query with other results pending' do
|
|
642
|
-
|
|
729
|
+
@client.execute(@query1)
|
|
643
730
|
action = lambda { @client.execute(@query1) }
|
|
644
731
|
assert_raise_tinytds_error(action) do |e|
|
|
645
732
|
assert_match %r|with results pending|i, e.message
|
|
@@ -672,22 +759,22 @@ class ResultTest < TinyTds::TestCase
|
|
|
672
759
|
it 'must not error at all from reading non-convertable charcters and just use ? marks' do
|
|
673
760
|
close_client
|
|
674
761
|
@client = new_connection :encoding => 'ASCII'
|
|
675
|
-
@client.charset.must_equal 'ASCII'
|
|
676
|
-
find_value(202, :nvarchar_50).must_equal 'test nvarchar_50 ??'
|
|
762
|
+
_(@client.charset).must_equal 'ASCII'
|
|
763
|
+
_(find_value(202, :nvarchar_50)).must_equal 'test nvarchar_50 ??'
|
|
677
764
|
end
|
|
678
765
|
|
|
679
766
|
it 'must error gracefully from writing non-convertable characters' do
|
|
680
767
|
close_client
|
|
681
768
|
@client = new_connection :encoding => 'ASCII'
|
|
682
|
-
@client.charset.must_equal 'ASCII'
|
|
769
|
+
_(@client.charset).must_equal 'ASCII'
|
|
683
770
|
rollback_transaction(@client) do
|
|
684
771
|
text = 'Test ✓'
|
|
685
772
|
@client.execute("DELETE FROM [datatypes] WHERE [nvarchar_50] IS NOT NULL").do
|
|
686
773
|
action = lambda { @client.execute("INSERT INTO [datatypes] ([nvarchar_50]) VALUES ('#{text}')").do }
|
|
687
774
|
assert_raise_tinytds_error(action) do |e|
|
|
688
|
-
e.message.must_match %r{Unclosed quotation mark}i
|
|
689
|
-
e.severity.must_equal 15
|
|
690
|
-
e.db_error_number.must_equal 105
|
|
775
|
+
_(e.message).must_match %r{Unclosed quotation mark}i
|
|
776
|
+
_(e.severity).must_equal 15
|
|
777
|
+
_(e.db_error_number).must_equal 105
|
|
691
778
|
end
|
|
692
779
|
assert_followup_query
|
|
693
780
|
end
|
|
@@ -725,4 +812,3 @@ class ResultTest < TinyTds::TestCase
|
|
|
725
812
|
end
|
|
726
813
|
|
|
727
814
|
end
|
|
728
|
-
|
|
@@ -0,0 +1,140 @@
|
|
|
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
|
+
[datetime2_2] [datetime2](2) NULL,
|
|
26
|
+
[datetimeoffset_2] [datetimeoffset](2) NULL,
|
|
27
|
+
[datetimeoffset_7] [datetimeoffset](7) NULL,
|
|
28
|
+
[decimal_9_2] [decimal](9, 2) NULL,
|
|
29
|
+
[decimal_16_4] [decimal](16, 4) NULL,
|
|
30
|
+
[float] [float] NULL,
|
|
31
|
+
[geography] [geography] NULL,
|
|
32
|
+
[geometry] [geometry] NULL,
|
|
33
|
+
[hierarchyid] [hierarchyid] NULL,
|
|
34
|
+
[image] [image] NULL,
|
|
35
|
+
[int] [int] NULL,
|
|
36
|
+
[money] [money] NULL,
|
|
37
|
+
[nchar_10] [nchar](10) NULL,
|
|
38
|
+
[ntext] [ntext] NULL,
|
|
39
|
+
[numeric_18_0] [numeric](18, 0) NULL,
|
|
40
|
+
[numeric_36_2] [numeric](36, 2) NULL,
|
|
41
|
+
[nvarchar_50] [nvarchar](50) NULL,
|
|
42
|
+
[nvarchar_max] [nvarchar](max) NULL,
|
|
43
|
+
[real] [real] NULL,
|
|
44
|
+
[smalldatetime] [smalldatetime] NULL,
|
|
45
|
+
[smallint] [smallint] NULL,
|
|
46
|
+
[smallmoney] [smallmoney] NULL,
|
|
47
|
+
[text] [text] NULL,
|
|
48
|
+
[time_2] [time](2) NULL,
|
|
49
|
+
[time_7] [time](7) NULL,
|
|
50
|
+
[timestamp] [timestamp] NULL,
|
|
51
|
+
[tinyint] [tinyint] NULL,
|
|
52
|
+
[uniqueidentifier] [uniqueidentifier] NULL,
|
|
53
|
+
[varbinary_50] [varbinary](50) NULL,
|
|
54
|
+
[varbinary_max] [varbinary](max) NULL,
|
|
55
|
+
[varchar_50] [varchar](50) NULL,
|
|
56
|
+
[varchar_max] [varchar](max) NULL,
|
|
57
|
+
[xml] [xml] NULL
|
|
58
|
+
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
|
|
59
|
+
|
|
60
|
+
SET IDENTITY_INSERT [datatypes] ON
|
|
61
|
+
|
|
62
|
+
INSERT INTO [datatypes] ([id], [bigint]) VALUES ( 11, -9223372036854775807 )
|
|
63
|
+
INSERT INTO [datatypes] ([id], [bigint]) VALUES ( 12, 9223372036854775806 )
|
|
64
|
+
INSERT INTO [datatypes] ([id], [binary_50]) VALUES ( 21, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
|
65
|
+
INSERT INTO [datatypes] ([id], [bit]) VALUES ( 31, 1 )
|
|
66
|
+
INSERT INTO [datatypes] ([id], [bit]) VALUES ( 32, 0 )
|
|
67
|
+
INSERT INTO [datatypes] ([id], [char_10]) VALUES ( 41, '1234567890' )
|
|
68
|
+
INSERT INTO [datatypes] ([id], [char_10]) VALUES ( 42, '12345678' )
|
|
69
|
+
INSERT INTO [datatypes] ([id], [date]) VALUES ( 51, '0001-01-01' )
|
|
70
|
+
INSERT INTO [datatypes] ([id], [date]) VALUES ( 52, '9999-12-31' )
|
|
71
|
+
INSERT INTO [datatypes] ([id], [datetime]) VALUES ( 61, '1753-01-01T00:00:00.000' )
|
|
72
|
+
INSERT INTO [datatypes] ([id], [datetime]) VALUES ( 62, '9999-12-31T23:59:59.997' )
|
|
73
|
+
INSERT INTO [datatypes] ([id], [datetime]) VALUES ( 63, '2010-01-01T12:34:56.123' )
|
|
74
|
+
INSERT INTO [datatypes] ([id], [datetime2_7]) VALUES ( 71, '0001-01-01 00:00:00.0000000' )
|
|
75
|
+
INSERT INTO [datatypes] ([id], [datetime2_7]) VALUES ( 72, '1984-01-24 04:20:00.0000000' )
|
|
76
|
+
INSERT INTO [datatypes] ([id], [datetime2_7]) VALUES ( 73, '9999-12-31 23:59:59.9999999' )
|
|
77
|
+
INSERT INTO [datatypes] ([id], [datetime2_2]) VALUES ( 74, '9999-12-31 23:59:59.123456789' )
|
|
78
|
+
INSERT INTO [datatypes] ([id], [datetimeoffset_2]) VALUES ( 81, '1984-01-24T04:20:00.1234567-08:00' ) -- 1984-01-24 04:20:00.00 -08:00
|
|
79
|
+
INSERT INTO [datatypes] ([id], [datetimeoffset_2]) VALUES ( 82, '1984-01-24T04:20:00.0000000Z' ) -- 1984-01-24 04:20:00.00 +00:00
|
|
80
|
+
INSERT INTO [datatypes] ([id], [datetimeoffset_2]) VALUES ( 83, '9999-12-31T23:59:59.9999999Z' ) -- 9999-12-31 23:59:59.99 +00:00
|
|
81
|
+
INSERT INTO [datatypes] ([id], [datetimeoffset_7]) VALUES ( 84, '1984-01-24T04:20:59.1234567-08:00' ) -- 1984-01-24 04:20:59.1234567 -08:00
|
|
82
|
+
INSERT INTO [datatypes] ([id], [datetimeoffset_7]) VALUES ( 85, '1984-01-24T04:20:00.0000000Z' ) -- 1984-01-24 04:20:00.0000000 +00:00
|
|
83
|
+
INSERT INTO [datatypes] ([id], [datetimeoffset_7]) VALUES ( 86, '9999-12-31T23:59:59.9999999Z' ) -- 9999-12-31 23:59:59.9999999 +00:00
|
|
84
|
+
INSERT INTO [datatypes] ([id], [decimal_9_2]) VALUES ( 91, 12345.01 )
|
|
85
|
+
INSERT INTO [datatypes] ([id], [decimal_9_2]) VALUES ( 92, 1234567.89 )
|
|
86
|
+
INSERT INTO [datatypes] ([id], [decimal_16_4]) VALUES ( 93, 0.0 )
|
|
87
|
+
INSERT INTO [datatypes] ([id], [decimal_16_4]) VALUES ( 94, 123456789012.3456 )
|
|
88
|
+
INSERT INTO [datatypes] ([id], [float]) VALUES ( 101, 123.00000001 )
|
|
89
|
+
INSERT INTO [datatypes] ([id], [float]) VALUES ( 102, 0.0 )
|
|
90
|
+
INSERT INTO [datatypes] ([id], [float]) VALUES ( 103, 123.45 )
|
|
91
|
+
INSERT INTO [datatypes] ([id], [geography]) VALUES ( 111, geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326) ) -- 0xE610000001148716D9CEF7D34740D7A3703D0A975EC08716D9CEF7D34740CBA145B6F3955EC0
|
|
92
|
+
INSERT INTO [datatypes] ([id], [geometry]) VALUES ( 121, geometry::STGeomFromText('LINESTRING (100 100, 20 180, 180 180)', 0) ) -- 0x0000000001040300000000000000000059400000000000005940000000000000344000000000008066400000000000806640000000000080664001000000010000000001000000FFFFFFFF0000000002
|
|
93
|
+
INSERT INTO [datatypes] ([id], [hierarchyid]) VALUES ( 131, CAST('/1/' AS hierarchyid) ) -- 0x58
|
|
94
|
+
INSERT INTO [datatypes] ([id], [hierarchyid]) VALUES ( 132, CAST('/2/' AS hierarchyid) ) -- 0x68
|
|
95
|
+
INSERT INTO [datatypes] ([id], [image]) VALUES ( 141, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
|
96
|
+
INSERT INTO [datatypes] ([id], [int]) VALUES ( 151, -2147483647 )
|
|
97
|
+
INSERT INTO [datatypes] ([id], [int]) VALUES ( 152, 2147483646 )
|
|
98
|
+
INSERT INTO [datatypes] ([id], [money]) VALUES ( 161, 4.20 )
|
|
99
|
+
INSERT INTO [datatypes] ([id], [money]) VALUES ( 162, -922337203685477.5807 )
|
|
100
|
+
INSERT INTO [datatypes] ([id], [money]) VALUES ( 163, 922337203685477.5806 )
|
|
101
|
+
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 171, N'1234567890' )
|
|
102
|
+
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 172, N'123456åå' )
|
|
103
|
+
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 173, N'abc123' )
|
|
104
|
+
INSERT INTO [datatypes] ([id], [ntext]) VALUES ( 181, N'test ntext' )
|
|
105
|
+
INSERT INTO [datatypes] ([id], [ntext]) VALUES ( 182, N'test ntext åå' )
|
|
106
|
+
INSERT INTO [datatypes] ([id], [numeric_18_0]) VALUES ( 191, 191 )
|
|
107
|
+
INSERT INTO [datatypes] ([id], [numeric_18_0]) VALUES ( 192, 123456789012345678 )
|
|
108
|
+
INSERT INTO [datatypes] ([id], [numeric_36_2]) VALUES ( 193, 12345678901234567890.01 )
|
|
109
|
+
INSERT INTO [datatypes] ([id], [numeric_36_2]) VALUES ( 194, 123.46 )
|
|
110
|
+
INSERT INTO [datatypes] ([id], [nvarchar_50]) VALUES ( 201, N'test nvarchar_50' )
|
|
111
|
+
INSERT INTO [datatypes] ([id], [nvarchar_50]) VALUES ( 202, N'test nvarchar_50 åå' )
|
|
112
|
+
INSERT INTO [datatypes] ([id], [nvarchar_max]) VALUES ( 211, N'test nvarchar_max' )
|
|
113
|
+
INSERT INTO [datatypes] ([id], [nvarchar_max]) VALUES ( 212, N'test nvarchar_max åå' )
|
|
114
|
+
INSERT INTO [datatypes] ([id], [real]) VALUES ( 221, 123.45 )
|
|
115
|
+
INSERT INTO [datatypes] ([id], [real]) VALUES ( 222, 0.0 )
|
|
116
|
+
INSERT INTO [datatypes] ([id], [real]) VALUES ( 223, 0.00001 )
|
|
117
|
+
INSERT INTO [datatypes] ([id], [smalldatetime]) VALUES ( 231, '1901-01-01T15:45:00.000Z' ) -- 1901-01-01 15:45:00
|
|
118
|
+
INSERT INTO [datatypes] ([id], [smalldatetime]) VALUES ( 232, '2078-06-05T04:20:00.000Z' ) -- 2078-06-05 04:20:00
|
|
119
|
+
INSERT INTO [datatypes] ([id], [smallint]) VALUES ( 241, -32767 )
|
|
120
|
+
INSERT INTO [datatypes] ([id], [smallint]) VALUES ( 242, 32766 )
|
|
121
|
+
INSERT INTO [datatypes] ([id], [smallmoney]) VALUES ( 251, 4.20 )
|
|
122
|
+
INSERT INTO [datatypes] ([id], [smallmoney]) VALUES ( 252, -214748.3647 )
|
|
123
|
+
INSERT INTO [datatypes] ([id], [smallmoney]) VALUES ( 253, 214748.3646 )
|
|
124
|
+
INSERT INTO [datatypes] ([id], [text]) VALUES ( 271, 'test text' )
|
|
125
|
+
INSERT INTO [datatypes] ([id], [time_2]) VALUES ( 281, '15:45:00.709714966' ) -- 15:45:00.71
|
|
126
|
+
INSERT INTO [datatypes] ([id], [time_2]) VALUES ( 282, '04:20:00.288321545' ) -- 04:20:00.29
|
|
127
|
+
INSERT INTO [datatypes] ([id], [time_7]) VALUES ( 283, '15:45:00.709714966' ) -- 15:45:00.709714900
|
|
128
|
+
INSERT INTO [datatypes] ([id], [time_7]) VALUES ( 284, '04:20:00.288321545' ) -- 04:20:00.288321500
|
|
129
|
+
INSERT INTO [datatypes] ([id], [tinyint]) VALUES ( 301, 0 )
|
|
130
|
+
INSERT INTO [datatypes] ([id], [tinyint]) VALUES ( 302, 255 )
|
|
131
|
+
INSERT INTO [datatypes] ([id], [uniqueidentifier]) VALUES ( 311, NEWID() )
|
|
132
|
+
INSERT INTO [datatypes] ([id], [varbinary_50]) VALUES ( 321, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
|
133
|
+
INSERT INTO [datatypes] ([id], [varbinary_max]) VALUES ( 331, 0x47494638396101000100910000fffffffffffffe010200000021f904041400ff002c00000000010001000002024401003b )
|
|
134
|
+
INSERT INTO [datatypes] ([id], [varchar_50]) VALUES ( 341, 'test varchar_50' )
|
|
135
|
+
INSERT INTO [datatypes] ([id], [varchar_max]) VALUES ( 351, 'test varchar_max' )
|
|
136
|
+
INSERT INTO [datatypes] ([id], [xml]) VALUES ( 361, '<foo><bar>batz</bar></foo>' )
|
|
137
|
+
|
|
138
|
+
SET IDENTITY_INSERT [datatypes] OFF
|
|
139
|
+
|
|
140
|
+
|
data/test/schema_test.rb
CHANGED
|
@@ -14,7 +14,7 @@ class SchemaTest < TinyTds::TestCase
|
|
|
14
14
|
describe 'for shared types' do
|
|
15
15
|
|
|
16
16
|
it 'casts bigint' do
|
|
17
|
-
assert_equal -9223372036854775807, find_value(11, :bigint)
|
|
17
|
+
assert_equal (-9223372036854775807), find_value(11, :bigint)
|
|
18
18
|
assert_equal 9223372036854775806, find_value(12, :bigint)
|
|
19
19
|
end
|
|
20
20
|
|
|
@@ -27,7 +27,7 @@ class SchemaTest < TinyTds::TestCase
|
|
|
27
27
|
it 'casts bit' do
|
|
28
28
|
assert_equal true, find_value(31, :bit)
|
|
29
29
|
assert_equal false, find_value(32, :bit)
|
|
30
|
-
|
|
30
|
+
assert_nil find_value(21, :bit)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
it 'casts char' do
|
|
@@ -76,10 +76,10 @@ class SchemaTest < TinyTds::TestCase
|
|
|
76
76
|
|
|
77
77
|
it 'casts decimal' do
|
|
78
78
|
assert_instance_of BigDecimal, find_value(91, :decimal_9_2)
|
|
79
|
-
assert_equal BigDecimal
|
|
80
|
-
assert_equal BigDecimal
|
|
81
|
-
assert_equal BigDecimal
|
|
82
|
-
assert_equal BigDecimal
|
|
79
|
+
assert_equal BigDecimal('12345.01'), find_value(91, :decimal_9_2)
|
|
80
|
+
assert_equal BigDecimal('1234567.89'), find_value(92, :decimal_9_2)
|
|
81
|
+
assert_equal BigDecimal('0.0'), find_value(93, :decimal_16_4)
|
|
82
|
+
assert_equal BigDecimal('123456789012.3456'), find_value(94, :decimal_16_4)
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
it 'casts float' do
|
|
@@ -96,15 +96,15 @@ class SchemaTest < TinyTds::TestCase
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
it 'casts int' do
|
|
99
|
-
assert_equal -2147483647, find_value(151, :int)
|
|
99
|
+
assert_equal (-2147483647), find_value(151, :int)
|
|
100
100
|
assert_equal 2147483646, find_value(152, :int)
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
it 'casts money' do
|
|
104
104
|
assert_instance_of BigDecimal, find_value(161, :money)
|
|
105
|
-
assert_equal BigDecimal
|
|
106
|
-
assert_equal BigDecimal
|
|
107
|
-
assert_equal BigDecimal
|
|
105
|
+
assert_equal BigDecimal('4.20'), find_value(161, :money)
|
|
106
|
+
assert_equal BigDecimal('922337203685477.5806'), find_value(163 ,:money)
|
|
107
|
+
assert_equal BigDecimal('-922337203685477.5807'), find_value(162 ,:money)
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
it 'casts nchar' do
|
|
@@ -170,15 +170,15 @@ class SchemaTest < TinyTds::TestCase
|
|
|
170
170
|
end
|
|
171
171
|
|
|
172
172
|
it 'casts smallint' do
|
|
173
|
-
assert_equal -32767, find_value(241, :smallint)
|
|
173
|
+
assert_equal (-32767), find_value(241, :smallint)
|
|
174
174
|
assert_equal 32766, find_value(242, :smallint)
|
|
175
175
|
end
|
|
176
176
|
|
|
177
177
|
it 'casts smallmoney' do
|
|
178
178
|
assert_instance_of BigDecimal, find_value(251, :smallmoney)
|
|
179
|
-
assert_equal BigDecimal
|
|
180
|
-
assert_equal BigDecimal
|
|
181
|
-
assert_equal BigDecimal
|
|
179
|
+
assert_equal BigDecimal("4.20"), find_value(251, :smallmoney)
|
|
180
|
+
assert_equal BigDecimal("-214748.3647"), find_value(252, :smallmoney)
|
|
181
|
+
assert_equal BigDecimal("214748.3646"), find_value(253, :smallmoney)
|
|
182
182
|
end
|
|
183
183
|
|
|
184
184
|
it 'casts text' do
|
|
@@ -396,15 +396,15 @@ class SchemaTest < TinyTds::TestCase
|
|
|
396
396
|
if @client.tds_73?
|
|
397
397
|
assertions = lambda {
|
|
398
398
|
assert_instance_of Time, v
|
|
399
|
-
assert_equal 1984, v.year,
|
|
400
|
-
assert_equal 1, v.month,
|
|
401
|
-
assert_equal 24, v.day,
|
|
402
|
-
assert_equal 4, v.hour,
|
|
403
|
-
assert_equal 20, v.min,
|
|
404
|
-
assert_equal 59, v.sec,
|
|
405
|
-
assert_equal 123456, v.usec,
|
|
406
|
-
assert_equal 123456700, v.nsec,
|
|
407
|
-
assert_equal -28800, v.utc_offset, 'Offset'
|
|
399
|
+
assert_equal 1984, v.year, 'Year'
|
|
400
|
+
assert_equal 1, v.month, 'Month'
|
|
401
|
+
assert_equal 24, v.day, 'Day'
|
|
402
|
+
assert_equal 4, v.hour, 'Hour'
|
|
403
|
+
assert_equal 20, v.min, 'Minute'
|
|
404
|
+
assert_equal 59, v.sec, 'Second'
|
|
405
|
+
assert_equal 123456, v.usec, 'Microseconds'
|
|
406
|
+
assert_equal 123456700, v.nsec, 'Nanoseconds'
|
|
407
|
+
assert_equal (-28800), v.utc_offset, 'Offset'
|
|
408
408
|
}
|
|
409
409
|
assertions.call
|
|
410
410
|
v = find_value 84, :datetimeoffset_7, timezone: :local
|
data/test/test_helper.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
require 'bundler' ; Bundler.require :development, :test
|
|
3
3
|
require 'tiny_tds'
|
|
4
4
|
require 'minitest/autorun'
|
|
5
|
+
require 'toxiproxy'
|
|
5
6
|
|
|
6
7
|
TINYTDS_SCHEMAS = ['sqlserver_2000', 'sqlserver_2005', 'sqlserver_2008', 'sqlserver_2014', 'sqlserver_azure', 'sybase_ase'].freeze
|
|
7
8
|
|
|
@@ -75,8 +76,8 @@ module TinyTds
|
|
|
75
76
|
username = (sqlserver_azure? ? ENV['TINYTDS_UNIT_AZURE_USER'] : ENV['TINYTDS_UNIT_USER']) || 'tinytds'
|
|
76
77
|
password = (sqlserver_azure? ? ENV['TINYTDS_UNIT_AZURE_PASS'] : ENV['TINYTDS_UNIT_PASS']) || ''
|
|
77
78
|
{ :dataserver => sqlserver_azure? ? nil : ENV['TINYTDS_UNIT_DATASERVER'],
|
|
78
|
-
:host => ENV['TINYTDS_UNIT_HOST'],
|
|
79
|
-
:port => ENV['TINYTDS_UNIT_PORT'],
|
|
79
|
+
:host => ENV['TINYTDS_UNIT_HOST'] || 'localhost',
|
|
80
|
+
:port => ENV['TINYTDS_UNIT_PORT'] || '1433',
|
|
80
81
|
:tds_version => ENV['TINYTDS_UNIT_VERSION'],
|
|
81
82
|
:username => username,
|
|
82
83
|
:password => password,
|
|
@@ -89,11 +90,11 @@ module TinyTds
|
|
|
89
90
|
end
|
|
90
91
|
|
|
91
92
|
def connection_timeout
|
|
92
|
-
sqlserver_azure? ? 20 :
|
|
93
|
+
sqlserver_azure? ? 20 : 8
|
|
93
94
|
end
|
|
94
95
|
|
|
95
96
|
def assert_client_works(client)
|
|
96
|
-
client.execute("SELECT 'client_works' as [client_works]").each.must_equal [{'client_works' => 'client_works'}]
|
|
97
|
+
_(client.execute("SELECT 'client_works' as [client_works]").each).must_equal [{'client_works' => 'client_works'}]
|
|
97
98
|
end
|
|
98
99
|
|
|
99
100
|
def assert_new_connections_work
|
|
@@ -142,6 +143,10 @@ module TinyTds
|
|
|
142
143
|
RbConfig::CONFIG['host_os'] =~ /ming/
|
|
143
144
|
end
|
|
144
145
|
|
|
146
|
+
def ruby_darwin?
|
|
147
|
+
RbConfig::CONFIG['host_os'] =~ /darwin/
|
|
148
|
+
end
|
|
149
|
+
|
|
145
150
|
def load_current_schema
|
|
146
151
|
loader = new_connection
|
|
147
152
|
schema_file = File.expand_path File.join(File.dirname(__FILE__), 'schema', "#{current_schema}.sql")
|
|
@@ -149,6 +154,8 @@ module TinyTds
|
|
|
149
154
|
loader.execute(drop_sql).do
|
|
150
155
|
loader.execute(schema_sql).do
|
|
151
156
|
loader.execute(sp_sql).do
|
|
157
|
+
loader.execute(sp_error_sql).do
|
|
158
|
+
loader.execute(sp_several_prints_sql).do
|
|
152
159
|
loader.close
|
|
153
160
|
true
|
|
154
161
|
end
|
|
@@ -163,7 +170,16 @@ module TinyTds
|
|
|
163
170
|
) DROP TABLE datatypes
|
|
164
171
|
IF EXISTS(
|
|
165
172
|
SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'tinytds_TestReturnCodes'
|
|
166
|
-
) DROP PROCEDURE tinytds_TestReturnCodes
|
|
173
|
+
) DROP PROCEDURE tinytds_TestReturnCodes
|
|
174
|
+
IF EXISTS(
|
|
175
|
+
SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'tinytds_TestPrintWithError'
|
|
176
|
+
) DROP PROCEDURE tinytds_TestPrintWithError
|
|
177
|
+
IF EXISTS(
|
|
178
|
+
SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'tinytds_TestPrintWithError'
|
|
179
|
+
) DROP PROCEDURE tinytds_TestPrintWithError
|
|
180
|
+
IF EXISTS(
|
|
181
|
+
SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'tinytds_TestSeveralPrints'
|
|
182
|
+
) DROP PROCEDURE tinytds_TestSeveralPrints|
|
|
167
183
|
end
|
|
168
184
|
|
|
169
185
|
def drop_sql_microsoft
|
|
@@ -177,7 +193,15 @@ module TinyTds
|
|
|
177
193
|
IF EXISTS (
|
|
178
194
|
SELECT name FROM sysobjects
|
|
179
195
|
WHERE name = 'tinytds_TestReturnCodes' AND type = 'P'
|
|
180
|
-
) DROP PROCEDURE tinytds_TestReturnCodes
|
|
196
|
+
) DROP PROCEDURE tinytds_TestReturnCodes
|
|
197
|
+
IF EXISTS (
|
|
198
|
+
SELECT name FROM sysobjects
|
|
199
|
+
WHERE name = 'tinytds_TestPrintWithError' AND type = 'P'
|
|
200
|
+
) DROP PROCEDURE tinytds_TestPrintWithError
|
|
201
|
+
IF EXISTS (
|
|
202
|
+
SELECT name FROM sysobjects
|
|
203
|
+
WHERE name = 'tinytds_TestSeveralPrints' AND type = 'P'
|
|
204
|
+
) DROP PROCEDURE tinytds_TestSeveralPrints|
|
|
181
205
|
end
|
|
182
206
|
|
|
183
207
|
def sp_sql
|
|
@@ -187,6 +211,21 @@ module TinyTds
|
|
|
187
211
|
RETURN(420) |
|
|
188
212
|
end
|
|
189
213
|
|
|
214
|
+
def sp_error_sql
|
|
215
|
+
%|CREATE PROCEDURE tinytds_TestPrintWithError
|
|
216
|
+
AS
|
|
217
|
+
PRINT 'hello'
|
|
218
|
+
RAISERROR('Error following print', 16, 1)|
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def sp_several_prints_sql
|
|
222
|
+
%|CREATE PROCEDURE tinytds_TestSeveralPrints
|
|
223
|
+
AS
|
|
224
|
+
PRINT 'hello 1'
|
|
225
|
+
PRINT 'hello 2'
|
|
226
|
+
PRINT 'hello 3'|
|
|
227
|
+
end
|
|
228
|
+
|
|
190
229
|
def find_value(id, column, query_options={})
|
|
191
230
|
query_options[:timezone] ||= :utc
|
|
192
231
|
sql = "SELECT [#{column}] FROM [datatypes] WHERE [id] = #{id}"
|
|
@@ -208,6 +247,25 @@ module TinyTds
|
|
|
208
247
|
client.execute("ROLLBACK TRANSACTION").do
|
|
209
248
|
end
|
|
210
249
|
|
|
250
|
+
def init_toxiproxy
|
|
251
|
+
return if ENV['APPVEYOR_BUILD_FOLDER'] # only for CI using docker
|
|
252
|
+
|
|
253
|
+
# In order for toxiproxy to work for local docker instances of mssql, the containers must be on the same network
|
|
254
|
+
# and the host used below must match the mssql container name so toxiproxy knows where to proxy to.
|
|
255
|
+
# localhost from the perspective of toxiproxy's container is its own container an *not* the mssql container it needs to proxy to.
|
|
256
|
+
# docker-compose.yml handles this automatically for us. In instances where someone is using their own local mssql container they'll
|
|
257
|
+
# need to set up the networks manually and set TINYTDS_UNIT_HOST to their mssql container name
|
|
258
|
+
# For anything other than localhost just use the environment config
|
|
259
|
+
env_host = ENV['TINYTDS_UNIT_HOST_TEST'] || ENV['TINYTDS_UNIT_HOST'] || 'localhost'
|
|
260
|
+
host = ['localhost', '127.0.0.1', '0.0.0.0'].include?(env_host) ? 'sqlserver' : env_host
|
|
261
|
+
port = ENV['TINYTDS_UNIT_PORT'] || 1433
|
|
262
|
+
Toxiproxy.populate([
|
|
263
|
+
{
|
|
264
|
+
name: "sqlserver_test",
|
|
265
|
+
listen: "0.0.0.0:1234",
|
|
266
|
+
upstream: "#{host}:#{port}"
|
|
267
|
+
}
|
|
268
|
+
])
|
|
269
|
+
end
|
|
211
270
|
end
|
|
212
271
|
end
|
|
213
|
-
|