tiny_tds 2.1.5 → 3.2.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 +4 -4
- data/.github/workflows/ci.yml +590 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +32 -1
- data/Gemfile +1 -8
- data/ISSUE_TEMPLATE.md +1 -1
- data/README.md +75 -88
- data/Rakefile +44 -30
- data/VERSION +1 -1
- data/docker-compose.yml +20 -8
- data/ext/tiny_tds/client.c +10 -15
- data/ext/tiny_tds/extconf.rb +183 -66
- data/ext/tiny_tds/extconsts.rb +4 -11
- data/ext/tiny_tds/result.c +28 -35
- data/ext/tiny_tds/tiny_tds_ext.c +4 -1
- data/lib/tiny_tds/bin.rb +12 -26
- data/lib/tiny_tds/client.rb +38 -42
- data/lib/tiny_tds/error.rb +0 -2
- data/lib/tiny_tds/gem.rb +5 -14
- data/lib/tiny_tds/result.rb +0 -2
- data/lib/tiny_tds/version.rb +1 -1
- data/lib/tiny_tds.rb +28 -47
- data/setup_cimgruby_dev.sh +25 -0
- data/start_dev.sh +21 -0
- data/tasks/native_gem.rake +12 -10
- data/tasks/package.rake +1 -3
- data/tasks/ports.rake +14 -75
- data/tasks/test.rake +3 -5
- data/test/bin/install-freetds.sh +2 -4
- data/test/bin/install-mssql.ps1 +42 -0
- data/test/bin/install-mssqltools.sh +9 -0
- data/test/bin/restore-from-native-gem.ps1 +10 -0
- data/test/bin/setup_tinytds_db.sh +7 -0
- data/test/bin/setup_volume_permissions.sh +10 -0
- data/test/client_test.rb +111 -120
- data/test/gem_test.rb +32 -111
- data/test/result_test.rb +259 -365
- data/test/schema_test.rb +369 -395
- data/test/sql/db-create.sql +18 -0
- data/test/sql/db-login.sql +38 -0
- data/test/test_helper.rb +75 -102
- data/test/thread_test.rb +22 -31
- data/tiny_tds.gemspec +28 -27
- metadata +70 -57
- data/.travis.yml +0 -25
- data/appveyor.yml +0 -72
- data/tasks/ports/freetds.rb +0 -37
- data/tasks/ports/libiconv.rb +0 -43
- data/tasks/ports/openssl.rb +0 -62
- data/tasks/ports/recipe.rb +0 -52
- data/test/appveyor/dbsetup.ps1 +0 -27
- data/test/appveyor/dbsetup.sql +0 -9
- data/test/benchmark/query.rb +0 -77
- data/test/benchmark/query_odbc.rb +0 -106
- data/test/benchmark/query_tinytds.rb +0 -126
- 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
@@ -1,43 +1,40 @@
|
|
1
|
-
|
2
|
-
require 'test_helper'
|
1
|
+
require "test_helper"
|
3
2
|
|
4
3
|
class ResultTest < TinyTds::TestCase
|
5
|
-
|
6
|
-
describe 'Basic query and result' do
|
7
|
-
|
4
|
+
describe "Basic query and result" do
|
8
5
|
before do
|
9
6
|
@@current_schema_loaded ||= load_current_schema
|
10
7
|
@client = new_connection
|
11
|
-
@query1 =
|
8
|
+
@query1 = "SELECT 1 AS [one]"
|
12
9
|
end
|
13
10
|
|
14
|
-
it
|
11
|
+
it "has included Enumerable" do
|
15
12
|
assert TinyTds::Result.ancestors.include?(Enumerable)
|
16
13
|
end
|
17
14
|
|
18
|
-
it
|
15
|
+
it "responds to #each" do
|
19
16
|
result = @client.execute(@query1)
|
20
17
|
assert result.respond_to?(:each)
|
21
18
|
end
|
22
19
|
|
23
|
-
it
|
20
|
+
it "returns all results for #each with no block" do
|
24
21
|
result = @client.execute(@query1)
|
25
22
|
data = result.each
|
26
23
|
row = data.first
|
27
24
|
assert_instance_of Array, data
|
28
25
|
assert_equal 1, data.size
|
29
|
-
assert_instance_of Hash, row,
|
26
|
+
assert_instance_of Hash, row, "hash is the default query option"
|
30
27
|
end
|
31
28
|
|
32
|
-
it
|
29
|
+
it "returns all results for #each with a block yielding a row at a time" do
|
33
30
|
result = @client.execute(@query1)
|
34
31
|
data = result.each do |row|
|
35
|
-
assert_instance_of Hash, row,
|
32
|
+
assert_instance_of Hash, row, "hash is the default query option"
|
36
33
|
end
|
37
34
|
assert_instance_of Array, data
|
38
35
|
end
|
39
36
|
|
40
|
-
it
|
37
|
+
it "allows successive calls to each returning the same data" do
|
41
38
|
result = @client.execute(@query1)
|
42
39
|
data = result.each
|
43
40
|
result.each
|
@@ -45,151 +42,150 @@ class ResultTest < TinyTds::TestCase
|
|
45
42
|
assert_equal data.first.object_id, result.each.first.object_id
|
46
43
|
end
|
47
44
|
|
48
|
-
it
|
45
|
+
it "returns hashes with string keys" do
|
49
46
|
result = @client.execute(@query1)
|
50
|
-
row = result.each(:
|
47
|
+
row = result.each(as: :hash, symbolize_keys: false).first
|
51
48
|
assert_instance_of Hash, row
|
52
|
-
assert_equal [
|
53
|
-
assert_equal [
|
49
|
+
assert_equal ["one"], row.keys
|
50
|
+
assert_equal ["one"], result.fields
|
54
51
|
end
|
55
52
|
|
56
|
-
it
|
53
|
+
it "returns hashes with symbol keys" do
|
57
54
|
result = @client.execute(@query1)
|
58
|
-
row = result.each(:
|
55
|
+
row = result.each(as: :hash, symbolize_keys: true).first
|
59
56
|
assert_instance_of Hash, row
|
60
57
|
assert_equal [:one], row.keys
|
61
58
|
assert_equal [:one], result.fields
|
62
59
|
end
|
63
60
|
|
64
|
-
it
|
61
|
+
it "returns arrays with string fields" do
|
65
62
|
result = @client.execute(@query1)
|
66
|
-
row = result.each(:
|
63
|
+
row = result.each(as: :array, symbolize_keys: false).first
|
67
64
|
assert_instance_of Array, row
|
68
|
-
assert_equal [
|
65
|
+
assert_equal ["one"], result.fields
|
69
66
|
end
|
70
67
|
|
71
|
-
it
|
68
|
+
it "returns arrays with symbol fields" do
|
72
69
|
result = @client.execute(@query1)
|
73
|
-
row = result.each(:
|
70
|
+
row = result.each(as: :array, symbolize_keys: true).first
|
74
71
|
assert_instance_of Array, row
|
75
72
|
assert_equal [:one], result.fields
|
76
73
|
end
|
77
74
|
|
78
|
-
it
|
75
|
+
it "allows sql concat + to work" do
|
79
76
|
rollback_transaction(@client) do
|
80
77
|
@client.execute("DELETE FROM [datatypes]").do
|
81
78
|
@client.execute("INSERT INTO [datatypes] ([char_10], [varchar_50]) VALUES ('1', '2')").do
|
82
|
-
result = @client.execute("SELECT TOP (1) [char_10] + 'test' + [varchar_50] AS [test] FROM [datatypes]").each.first[
|
79
|
+
result = @client.execute("SELECT TOP (1) [char_10] + 'test' + [varchar_50] AS [test] FROM [datatypes]").each.first["test"]
|
83
80
|
_(result).must_equal "1 test2"
|
84
81
|
end
|
85
82
|
end
|
86
83
|
|
87
|
-
it
|
84
|
+
it "must be able to turn :cache_rows option off" do
|
88
85
|
result = @client.execute(@query1)
|
89
86
|
local = []
|
90
|
-
result.each(:
|
87
|
+
result.each(cache_rows: false) do |row|
|
91
88
|
local << row
|
92
89
|
end
|
93
|
-
assert local.first,
|
94
|
-
assert_equal [], result.each,
|
95
|
-
assert_equal [
|
90
|
+
assert local.first, "should have iterated over each row"
|
91
|
+
assert_equal [], result.each, "should not have been cached"
|
92
|
+
assert_equal ["one"], result.fields, "should still cache field names"
|
96
93
|
end
|
97
94
|
|
98
|
-
it
|
95
|
+
it "must be able to get the first result row only" do
|
99
96
|
load_current_schema
|
100
97
|
big_query = "SELECT [id] FROM [datatypes]"
|
101
|
-
one = @client.execute(big_query).each(:
|
98
|
+
one = @client.execute(big_query).each(first: true)
|
102
99
|
many = @client.execute(big_query).each
|
103
100
|
assert many.size > 1
|
104
101
|
assert one.size == 1
|
105
102
|
end
|
106
103
|
|
107
|
-
it
|
108
|
-
data = @client.execute("SELECT [id] FROM [datatypes] WHERE [id] = -1").each(:
|
104
|
+
it "copes with no results when using first option" do
|
105
|
+
data = @client.execute("SELECT [id] FROM [datatypes] WHERE [id] = -1").each(first: true)
|
109
106
|
assert_equal [], data
|
110
107
|
end
|
111
108
|
|
112
|
-
it
|
109
|
+
it "must delete, insert and find data" do
|
113
110
|
rollback_transaction(@client) do
|
114
|
-
text =
|
111
|
+
text = "test insert and delete"
|
115
112
|
@client.execute("DELETE FROM [datatypes] WHERE [varchar_50] IS NOT NULL").do
|
116
113
|
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
117
114
|
row = @client.execute("SELECT [varchar_50] FROM [datatypes] WHERE [varchar_50] IS NOT NULL").each.first
|
118
115
|
assert row
|
119
|
-
assert_equal text, row[
|
116
|
+
assert_equal text, row["varchar_50"]
|
120
117
|
end
|
121
118
|
end
|
122
119
|
|
123
|
-
it
|
120
|
+
it "must insert and find unicode data" do
|
124
121
|
rollback_transaction(@client) do
|
125
|
-
text =
|
122
|
+
text = "😍"
|
126
123
|
@client.execute("DELETE FROM [datatypes] WHERE [nvarchar_50] IS NOT NULL").do
|
127
124
|
@client.execute("INSERT INTO [datatypes] ([nvarchar_50]) VALUES (N'#{text}')").do
|
128
125
|
row = @client.execute("SELECT [nvarchar_50] FROM [datatypes] WHERE [nvarchar_50] IS NOT NULL").each.first
|
129
|
-
assert_equal text, row[
|
126
|
+
assert_equal text, row["nvarchar_50"]
|
130
127
|
end
|
131
128
|
end
|
132
129
|
|
133
|
-
it
|
130
|
+
it "must delete and update with affected rows support and insert with identity support in native sql" do
|
134
131
|
rollback_transaction(@client) do
|
135
|
-
text =
|
132
|
+
text = "test affected rows sql"
|
136
133
|
@client.execute("DELETE FROM [datatypes]").do
|
137
|
-
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first[
|
138
|
-
_([
|
134
|
+
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first["AffectedRows"]
|
135
|
+
_(["Fixnum", "Integer"]).must_include afrows.class.name
|
139
136
|
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
140
|
-
pk1 = @client.execute(@client.identity_sql).each.first[
|
141
|
-
_([
|
137
|
+
pk1 = @client.execute(@client.identity_sql).each.first["Ident"]
|
138
|
+
_(["Fixnum", "Integer"]).must_include pk1.class.name, "we it be able to CAST to bigint"
|
142
139
|
@client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
|
143
|
-
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first[
|
140
|
+
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first["AffectedRows"]
|
144
141
|
assert_equal 1, afrows
|
145
142
|
end
|
146
143
|
end
|
147
144
|
|
148
|
-
it
|
145
|
+
it "has a #do method that cancels result rows and returns affected rows natively" do
|
149
146
|
rollback_transaction(@client) do
|
150
|
-
text =
|
151
|
-
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first[
|
147
|
+
text = "test affected rows native"
|
148
|
+
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first["count"]
|
152
149
|
deleted_rows = @client.execute("DELETE FROM [datatypes]").do
|
153
|
-
assert_equal count, deleted_rows,
|
150
|
+
assert_equal count, deleted_rows, "should have deleted rows equal to count"
|
154
151
|
inserted_rows = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
155
|
-
assert_equal 1, inserted_rows,
|
152
|
+
assert_equal 1, inserted_rows, "should have inserted row for one above"
|
156
153
|
updated_rows = @client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
|
157
|
-
assert_equal 1, updated_rows,
|
154
|
+
assert_equal 1, updated_rows, "should have updated row for one above"
|
158
155
|
end
|
159
156
|
end
|
160
157
|
|
161
|
-
it
|
158
|
+
it "allows native affected rows using #do to work under transaction" do
|
162
159
|
rollback_transaction(@client) do
|
163
|
-
text =
|
160
|
+
text = "test affected rows native in transaction"
|
164
161
|
@client.execute("BEGIN TRANSACTION").do
|
165
162
|
@client.execute("DELETE FROM [datatypes]").do
|
166
163
|
inserted_rows = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
167
|
-
assert_equal 1, inserted_rows,
|
164
|
+
assert_equal 1, inserted_rows, "should have inserted row for one above"
|
168
165
|
updated_rows = @client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
|
169
|
-
assert_equal 1, updated_rows,
|
166
|
+
assert_equal 1, updated_rows, "should have updated row for one above"
|
170
167
|
end
|
171
168
|
end
|
172
169
|
|
173
|
-
it
|
170
|
+
it "has an #insert method that cancels result rows and returns IDENTITY natively" do
|
174
171
|
rollback_transaction(@client) do
|
175
|
-
text =
|
172
|
+
text = "test scope identity rows native"
|
176
173
|
@client.execute("DELETE FROM [datatypes] WHERE [varchar_50] = '#{text}'").do
|
177
174
|
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
|
178
|
-
sql_identity = @client.execute(@client.identity_sql).each.first[
|
175
|
+
sql_identity = @client.execute(@client.identity_sql).each.first["Ident"]
|
179
176
|
native_identity = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").insert
|
180
|
-
assert_equal sql_identity+1, native_identity
|
177
|
+
assert_equal sql_identity + 1, native_identity
|
181
178
|
end
|
182
179
|
end
|
183
180
|
|
184
|
-
it
|
181
|
+
it "returns bigint for #insert when needed" do
|
185
182
|
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.
|
183
|
+
# 'CREATE TABLE' command is not allowed within a multi-statement transaction
|
184
|
+
# and and sp_helpindex creates a temporary table #spindtab.
|
189
185
|
rollback_transaction(@client) do
|
190
186
|
seed = 9223372036854775805
|
191
187
|
@client.execute("DELETE FROM [datatypes]").do
|
192
|
-
id_constraint_name = @client.execute("EXEC sp_helpindex [datatypes]").detect{ |row| row[
|
188
|
+
id_constraint_name = @client.execute("EXEC sp_helpindex [datatypes]").detect { |row| row["index_keys"] == "id" }["index_name"]
|
193
189
|
@client.execute("ALTER TABLE [datatypes] DROP CONSTRAINT [#{id_constraint_name}]").do
|
194
190
|
@client.execute("ALTER TABLE [datatypes] DROP COLUMN [id]").do
|
195
191
|
@client.execute("ALTER TABLE [datatypes] ADD [id] [bigint] NOT NULL IDENTITY(1,1) PRIMARY KEY").do
|
@@ -199,59 +195,59 @@ class ResultTest < TinyTds::TestCase
|
|
199
195
|
end
|
200
196
|
end
|
201
197
|
|
202
|
-
it
|
198
|
+
it "must be able to begin/commit transactions with raw sql" do
|
203
199
|
rollback_transaction(@client) do
|
204
200
|
@client.execute("BEGIN TRANSACTION").do
|
205
201
|
@client.execute("DELETE FROM [datatypes]").do
|
206
202
|
@client.execute("COMMIT TRANSACTION").do
|
207
|
-
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first[
|
203
|
+
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first["count"]
|
208
204
|
assert_equal 0, count
|
209
205
|
end
|
210
206
|
end
|
211
207
|
|
212
|
-
it
|
208
|
+
it "must be able to begin/rollback transactions with raw sql" do
|
213
209
|
load_current_schema
|
214
210
|
@client.execute("BEGIN TRANSACTION").do
|
215
211
|
@client.execute("DELETE FROM [datatypes]").do
|
216
212
|
@client.execute("ROLLBACK TRANSACTION").do
|
217
|
-
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first[
|
213
|
+
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first["count"]
|
218
214
|
_(count).wont_equal 0
|
219
215
|
end
|
220
216
|
|
221
|
-
it
|
217
|
+
it "has a #fields accessor with logic default and valid outcome" do
|
222
218
|
result = @client.execute(@query1)
|
223
|
-
_(result.fields).must_equal [
|
219
|
+
_(result.fields).must_equal ["one"]
|
224
220
|
result.each
|
225
|
-
_(result.fields).must_equal [
|
221
|
+
_(result.fields).must_equal ["one"]
|
226
222
|
end
|
227
223
|
|
228
|
-
it
|
224
|
+
it "always returns an array for fields for all sql" do
|
229
225
|
result = @client.execute("USE [tinytdstest]")
|
230
226
|
_(result.fields).must_equal []
|
231
227
|
result.do
|
232
228
|
_(result.fields).must_equal []
|
233
229
|
end
|
234
230
|
|
235
|
-
it
|
231
|
+
it "returns fields even when no results are found" do
|
236
232
|
no_results_query = "SELECT [id], [varchar_50] FROM [datatypes] WHERE [varchar_50] = 'NOTFOUND'"
|
237
233
|
# Fields before each.
|
238
234
|
result = @client.execute(no_results_query)
|
239
|
-
_(result.fields).must_equal [
|
235
|
+
_(result.fields).must_equal ["id", "varchar_50"]
|
240
236
|
result.each
|
241
|
-
_(result.fields).must_equal [
|
237
|
+
_(result.fields).must_equal ["id", "varchar_50"]
|
242
238
|
# Each then fields
|
243
239
|
result = @client.execute(no_results_query)
|
244
240
|
result.each
|
245
|
-
_(result.fields).must_equal [
|
241
|
+
_(result.fields).must_equal ["id", "varchar_50"]
|
246
242
|
end
|
247
243
|
|
248
|
-
it
|
244
|
+
it "allows the result to be canceled before reading" do
|
249
245
|
result = @client.execute(@query1)
|
250
246
|
result.cancel
|
251
247
|
@client.execute(@query1).each
|
252
248
|
end
|
253
249
|
|
254
|
-
it
|
250
|
+
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
251
|
# Default state.
|
256
252
|
@client = TinyTds::Client.new(connection_options)
|
257
253
|
_(@client.sqlsent?).must_equal false
|
@@ -263,21 +259,21 @@ class ResultTest < TinyTds::TestCase
|
|
263
259
|
result.cancel
|
264
260
|
_(@client.sqlsent?).must_equal false
|
265
261
|
_(@client.canceled?).must_equal true
|
266
|
-
assert result.cancel,
|
262
|
+
assert result.cancel, "must be safe to call again"
|
267
263
|
# With each and no block.
|
268
264
|
@client.execute(@query1).each
|
269
265
|
_(@client.sqlsent?).must_equal false
|
270
266
|
_(@client.canceled?).must_equal false
|
271
267
|
# With each and block.
|
272
268
|
@client.execute(@query1).each do |row|
|
273
|
-
_(@client.sqlsent?).must_equal true,
|
269
|
+
_(@client.sqlsent?).must_equal true, "when iterating over each row in a block"
|
274
270
|
_(@client.canceled?).must_equal false
|
275
271
|
end
|
276
272
|
_(@client.sqlsent?).must_equal false
|
277
273
|
_(@client.canceled?).must_equal false
|
278
274
|
# With each and block canceled half way thru.
|
279
|
-
count = @client.execute("SELECT COUNT([id]) AS [count] FROM [datatypes]").each[0][
|
280
|
-
assert count > 10,
|
275
|
+
count = @client.execute("SELECT COUNT([id]) AS [count] FROM [datatypes]").each[0]["count"]
|
276
|
+
assert count > 10, "since we want to cancel early for test"
|
281
277
|
result = @client.execute("SELECT [id] FROM [datatypes]")
|
282
278
|
index = 0
|
283
279
|
result.each do |row|
|
@@ -300,50 +296,53 @@ class ResultTest < TinyTds::TestCase
|
|
300
296
|
_(@client.canceled?).must_equal true
|
301
297
|
end
|
302
298
|
# With first
|
303
|
-
@client.execute("SELECT [id] FROM [datatypes]").each(:
|
299
|
+
@client.execute("SELECT [id] FROM [datatypes]").each(first: true)
|
304
300
|
_(@client.sqlsent?).must_equal false
|
305
301
|
_(@client.canceled?).must_equal true
|
306
302
|
end
|
307
303
|
|
308
|
-
it
|
304
|
+
it "use same string object for hash keys" do
|
309
305
|
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 }
|
306
|
+
assert_equal data.first.keys.map { |r| r.object_id }, data.last.keys.map { |r| r.object_id }
|
311
307
|
end
|
312
308
|
|
313
|
-
it
|
309
|
+
it "has properly encoded column names with symbol keys" do
|
314
310
|
col_name = "öäüß"
|
315
|
-
|
311
|
+
begin
|
312
|
+
@client.execute("DROP TABLE [test_encoding]").do
|
313
|
+
rescue
|
314
|
+
nil
|
315
|
+
end
|
316
316
|
@client.execute("CREATE TABLE [dbo].[test_encoding] ( [id] int NOT NULL IDENTITY(1,1) PRIMARY KEY, [#{col_name}] [nvarchar](10) NOT NULL )").do
|
317
317
|
@client.execute("INSERT INTO [test_encoding] ([#{col_name}]) VALUES (N'#{col_name}')").do
|
318
318
|
result = @client.execute("SELECT [#{col_name}] FROM [test_encoding]")
|
319
|
-
row = result.each(:
|
319
|
+
row = result.each(as: :hash, symbolize_keys: true).first
|
320
320
|
assert_instance_of Symbol, result.fields.first
|
321
321
|
assert_equal col_name.to_sym, result.fields.first
|
322
322
|
assert_instance_of Symbol, row.keys.first
|
323
323
|
assert_equal col_name.to_sym, row.keys.first
|
324
324
|
end
|
325
325
|
|
326
|
-
it
|
326
|
+
it "allows #return_code to work with stored procedures and reset per sql batch" do
|
327
327
|
assert_nil @client.return_code
|
328
328
|
result = @client.execute("EXEC tinytds_TestReturnCodes")
|
329
|
-
assert_equal [{"one"=>1}], result.each
|
329
|
+
assert_equal [{"one" => 1}], result.each
|
330
330
|
assert_equal 420, @client.return_code
|
331
331
|
assert_equal 420, result.return_code
|
332
|
-
result = @client.execute(
|
332
|
+
result = @client.execute("SELECT 1 as [one]")
|
333
333
|
result.each
|
334
334
|
assert_nil @client.return_code
|
335
335
|
assert_nil result.return_code
|
336
336
|
end
|
337
337
|
|
338
|
-
it
|
339
|
-
v = @client.execute("SELECT LOGINPROPERTY('sa', 'IsLocked') as v").first[
|
338
|
+
it "with LOGINPROPERTY function" do
|
339
|
+
v = @client.execute("SELECT LOGINPROPERTY('sa', 'IsLocked') as v").first["v"]
|
340
340
|
_(v).must_equal 0
|
341
341
|
end
|
342
342
|
|
343
|
-
describe
|
344
|
-
|
343
|
+
describe "with multiple result sets" do
|
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
|
@@ -357,50 +356,41 @@ class ResultTest < TinyTds::TestCase
|
|
357
356
|
SELECT 3 AS [rs3] WHERE 1 = 0"
|
358
357
|
end
|
359
358
|
|
360
|
-
it
|
359
|
+
it "handles a command buffer with double selects" do
|
361
360
|
result = @client.execute(@double_select)
|
362
361
|
result_sets = result.each
|
363
362
|
assert_equal 2, result_sets.size
|
364
|
-
assert_equal [{
|
365
|
-
assert_equal [{
|
366
|
-
assert_equal [[
|
367
|
-
assert_equal result.each.object_id, result.each.object_id,
|
363
|
+
assert_equal [{"rs1" => 1}], result_sets.first
|
364
|
+
assert_equal [{"rs2" => 2}], result_sets.last
|
365
|
+
assert_equal [["rs1"], ["rs2"]], result.fields
|
366
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
368
367
|
# As array
|
369
368
|
result = @client.execute(@double_select)
|
370
|
-
result_sets = result.each(:
|
369
|
+
result_sets = result.each(as: :array)
|
371
370
|
assert_equal 2, result_sets.size
|
372
371
|
assert_equal [[1]], result_sets.first
|
373
372
|
assert_equal [[2]], result_sets.last
|
374
|
-
assert_equal [[
|
375
|
-
assert_equal result.each.object_id, result.each.object_id,
|
373
|
+
assert_equal [["rs1"], ["rs2"]], result.fields
|
374
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
376
375
|
end
|
377
376
|
|
378
|
-
it
|
377
|
+
it "yields each row for each result set" do
|
379
378
|
data = []
|
380
379
|
result_sets = @client.execute(@double_select).each { |row| data << row }
|
381
380
|
assert_equal data.first, result_sets.first[0]
|
382
381
|
assert_equal data.last, result_sets.last[0]
|
383
382
|
end
|
384
383
|
|
385
|
-
it
|
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
|
384
|
+
it "works from a stored procedure" do
|
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
|
-
describe
|
403
|
-
|
393
|
+
describe "using :empty_sets TRUE" do
|
404
394
|
before do
|
405
395
|
close_client
|
406
396
|
@old_query_option_value = TinyTds::Client.default_query_options[:empty_sets]
|
@@ -412,76 +402,74 @@ class ResultTest < TinyTds::TestCase
|
|
412
402
|
TinyTds::Client.default_query_options[:empty_sets] = @old_query_option_value
|
413
403
|
end
|
414
404
|
|
415
|
-
it
|
405
|
+
it "handles a basic empty result set" do
|
416
406
|
result = @client.execute(@empty_select)
|
417
407
|
assert_equal [], result.each
|
418
|
-
assert_equal [
|
408
|
+
assert_equal ["rs1"], result.fields
|
419
409
|
end
|
420
410
|
|
421
|
-
it
|
411
|
+
it "includes empty result sets by default - using 1st empty buffer" do
|
422
412
|
result = @client.execute(@triple_select_1st_empty)
|
423
413
|
result_sets = result.each
|
424
414
|
assert_equal 3, result_sets.size
|
425
415
|
assert_equal [], result_sets[0]
|
426
|
-
assert_equal [{
|
427
|
-
assert_equal [{
|
428
|
-
assert_equal [[
|
429
|
-
assert_equal result.each.object_id, result.each.object_id,
|
416
|
+
assert_equal [{"rs2" => 2}], result_sets[1]
|
417
|
+
assert_equal [{"rs3" => 3}], result_sets[2]
|
418
|
+
assert_equal [["rs1"], ["rs2"], ["rs3"]], result.fields
|
419
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
430
420
|
# As array
|
431
421
|
result = @client.execute(@triple_select_1st_empty)
|
432
|
-
result_sets = result.each(:
|
422
|
+
result_sets = result.each(as: :array)
|
433
423
|
assert_equal 3, result_sets.size
|
434
424
|
assert_equal [], result_sets[0]
|
435
425
|
assert_equal [[2]], result_sets[1]
|
436
426
|
assert_equal [[3]], result_sets[2]
|
437
|
-
assert_equal [[
|
438
|
-
assert_equal result.each.object_id, result.each.object_id,
|
427
|
+
assert_equal [["rs1"], ["rs2"], ["rs3"]], result.fields
|
428
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
439
429
|
end
|
440
430
|
|
441
|
-
it
|
431
|
+
it "includes empty result sets by default - using 2nd empty buffer" do
|
442
432
|
result = @client.execute(@triple_select_2nd_empty)
|
443
433
|
result_sets = result.each
|
444
434
|
assert_equal 3, result_sets.size
|
445
|
-
assert_equal [{
|
435
|
+
assert_equal [{"rs1" => 1}], result_sets[0]
|
446
436
|
assert_equal [], result_sets[1]
|
447
|
-
assert_equal [{
|
448
|
-
assert_equal [[
|
449
|
-
assert_equal result.each.object_id, result.each.object_id,
|
437
|
+
assert_equal [{"rs3" => 3}], result_sets[2]
|
438
|
+
assert_equal [["rs1"], ["rs2"], ["rs3"]], result.fields
|
439
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
450
440
|
# As array
|
451
441
|
result = @client.execute(@triple_select_2nd_empty)
|
452
|
-
result_sets = result.each(:
|
442
|
+
result_sets = result.each(as: :array)
|
453
443
|
assert_equal 3, result_sets.size
|
454
444
|
assert_equal [[1]], result_sets[0]
|
455
445
|
assert_equal [], result_sets[1]
|
456
446
|
assert_equal [[3]], result_sets[2]
|
457
|
-
assert_equal [[
|
458
|
-
assert_equal result.each.object_id, result.each.object_id,
|
447
|
+
assert_equal [["rs1"], ["rs2"], ["rs3"]], result.fields
|
448
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
459
449
|
end
|
460
450
|
|
461
|
-
it
|
451
|
+
it "includes empty result sets by default - using 3rd empty buffer" do
|
462
452
|
result = @client.execute(@triple_select_3rd_empty)
|
463
453
|
result_sets = result.each
|
464
454
|
assert_equal 3, result_sets.size
|
465
|
-
assert_equal [{
|
466
|
-
assert_equal [{
|
455
|
+
assert_equal [{"rs1" => 1}], result_sets[0]
|
456
|
+
assert_equal [{"rs2" => 2}], result_sets[1]
|
467
457
|
assert_equal [], result_sets[2]
|
468
|
-
assert_equal [[
|
469
|
-
assert_equal result.each.object_id, result.each.object_id,
|
458
|
+
assert_equal [["rs1"], ["rs2"], ["rs3"]], result.fields
|
459
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
470
460
|
# As array
|
471
461
|
result = @client.execute(@triple_select_3rd_empty)
|
472
|
-
result_sets = result.each(:
|
462
|
+
result_sets = result.each(as: :array)
|
473
463
|
assert_equal 3, result_sets.size
|
474
464
|
assert_equal [[1]], result_sets[0]
|
475
465
|
assert_equal [[2]], result_sets[1]
|
476
466
|
assert_equal [], result_sets[2]
|
477
|
-
assert_equal [[
|
478
|
-
assert_equal result.each.object_id, result.each.object_id,
|
467
|
+
assert_equal [["rs1"], ["rs2"], ["rs3"]], result.fields
|
468
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
479
469
|
end
|
480
|
-
|
481
470
|
end
|
482
471
|
|
483
|
-
describe
|
484
|
-
|
472
|
+
describe "using :empty_sets FALSE" do
|
485
473
|
before do
|
486
474
|
close_client
|
487
475
|
@old_query_option_value = TinyTds::Client.default_query_options[:empty_sets]
|
@@ -493,313 +481,220 @@ class ResultTest < TinyTds::TestCase
|
|
493
481
|
TinyTds::Client.default_query_options[:empty_sets] = @old_query_option_value
|
494
482
|
end
|
495
483
|
|
496
|
-
it
|
484
|
+
it "handles a basic empty result set" do
|
497
485
|
result = @client.execute(@empty_select)
|
498
486
|
assert_equal [], result.each
|
499
|
-
assert_equal [
|
487
|
+
assert_equal ["rs1"], result.fields
|
500
488
|
end
|
501
489
|
|
502
|
-
it
|
490
|
+
it "must not include empty result sets by default - using 1st empty buffer" do
|
503
491
|
result = @client.execute(@triple_select_1st_empty)
|
504
492
|
result_sets = result.each
|
505
493
|
assert_equal 2, result_sets.size
|
506
|
-
assert_equal [{
|
507
|
-
assert_equal [{
|
508
|
-
assert_equal [[
|
509
|
-
assert_equal result.each.object_id, result.each.object_id,
|
494
|
+
assert_equal [{"rs2" => 2}], result_sets[0]
|
495
|
+
assert_equal [{"rs3" => 3}], result_sets[1]
|
496
|
+
assert_equal [["rs2"], ["rs3"]], result.fields
|
497
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
510
498
|
# As array
|
511
499
|
result = @client.execute(@triple_select_1st_empty)
|
512
|
-
result_sets = result.each(:
|
500
|
+
result_sets = result.each(as: :array)
|
513
501
|
assert_equal 2, result_sets.size
|
514
502
|
assert_equal [[2]], result_sets[0]
|
515
503
|
assert_equal [[3]], result_sets[1]
|
516
|
-
assert_equal [[
|
517
|
-
assert_equal result.each.object_id, result.each.object_id,
|
504
|
+
assert_equal [["rs2"], ["rs3"]], result.fields
|
505
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
518
506
|
end
|
519
507
|
|
520
|
-
it
|
508
|
+
it "must not include empty result sets by default - using 2nd empty buffer" do
|
521
509
|
result = @client.execute(@triple_select_2nd_empty)
|
522
510
|
result_sets = result.each
|
523
511
|
assert_equal 2, result_sets.size
|
524
|
-
assert_equal [{
|
525
|
-
assert_equal [{
|
526
|
-
assert_equal [[
|
527
|
-
assert_equal result.each.object_id, result.each.object_id,
|
512
|
+
assert_equal [{"rs1" => 1}], result_sets[0]
|
513
|
+
assert_equal [{"rs3" => 3}], result_sets[1]
|
514
|
+
assert_equal [["rs1"], ["rs3"]], result.fields
|
515
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
528
516
|
# As array
|
529
517
|
result = @client.execute(@triple_select_2nd_empty)
|
530
|
-
result_sets = result.each(:
|
518
|
+
result_sets = result.each(as: :array)
|
531
519
|
assert_equal 2, result_sets.size
|
532
520
|
assert_equal [[1]], result_sets[0]
|
533
521
|
assert_equal [[3]], result_sets[1]
|
534
|
-
assert_equal [[
|
535
|
-
assert_equal result.each.object_id, result.each.object_id,
|
522
|
+
assert_equal [["rs1"], ["rs3"]], result.fields
|
523
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
536
524
|
end
|
537
525
|
|
538
|
-
it
|
526
|
+
it "must not include empty result sets by default - using 3rd empty buffer" do
|
539
527
|
result = @client.execute(@triple_select_3rd_empty)
|
540
528
|
result_sets = result.each
|
541
529
|
assert_equal 2, result_sets.size
|
542
|
-
assert_equal [{
|
543
|
-
assert_equal [{
|
544
|
-
assert_equal [[
|
545
|
-
assert_equal result.each.object_id, result.each.object_id,
|
530
|
+
assert_equal [{"rs1" => 1}], result_sets[0]
|
531
|
+
assert_equal [{"rs2" => 2}], result_sets[1]
|
532
|
+
assert_equal [["rs1"], ["rs2"]], result.fields
|
533
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
546
534
|
# As array
|
547
535
|
result = @client.execute(@triple_select_3rd_empty)
|
548
|
-
result_sets = result.each(:
|
536
|
+
result_sets = result.each(as: :array)
|
549
537
|
assert_equal 2, result_sets.size
|
550
538
|
assert_equal [[1]], result_sets[0]
|
551
539
|
assert_equal [[2]], result_sets[1]
|
552
|
-
assert_equal [[
|
553
|
-
assert_equal result.each.object_id, result.each.object_id,
|
540
|
+
assert_equal [["rs1"], ["rs2"]], result.fields
|
541
|
+
assert_equal result.each.object_id, result.each.object_id, "same cached rows"
|
554
542
|
end
|
555
|
-
|
556
543
|
end
|
557
|
-
|
558
544
|
end
|
559
545
|
|
560
|
-
|
546
|
+
unless sqlserver_azure?
|
547
|
+
describe "Complex query with multiple results sets but no actual results" do
|
548
|
+
let(:backup_file) { 'C:\\Users\\Public\\tinytdstest.bak' }
|
561
549
|
|
562
|
-
|
550
|
+
after { File.delete(backup_file) if File.exist?(backup_file) }
|
563
551
|
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
@client.execute("BACKUP DATABASE tinytdstest TO DISK = '#{backup_file}'").do
|
552
|
+
it "must not cancel the query until complete" do
|
553
|
+
@client.execute("BACKUP DATABASE tinytdstest TO DISK = '#{backup_file}'").do
|
554
|
+
end
|
568
555
|
end
|
556
|
+
end
|
569
557
|
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
it 'returns fixnum for 1' do
|
575
|
-
value = @client.execute('SELECT 1 AS [fixnum]').each.first['fixnum']
|
558
|
+
describe "when casting to native ruby values" do
|
559
|
+
it "returns fixnum for 1" do
|
560
|
+
value = @client.execute("SELECT 1 AS [fixnum]").each.first["fixnum"]
|
576
561
|
assert_equal 1, value
|
577
562
|
end
|
578
563
|
|
579
|
-
it
|
580
|
-
value = @client.execute(
|
564
|
+
it "returns nil for NULL" do
|
565
|
+
value = @client.execute("SELECT NULL AS [null]").each.first["null"]
|
581
566
|
assert_nil value
|
582
567
|
end
|
583
|
-
|
584
568
|
end
|
585
569
|
|
586
|
-
describe
|
587
|
-
|
588
|
-
describe 'char max' do
|
589
|
-
|
570
|
+
describe "with data type" do
|
571
|
+
describe "char max" do
|
590
572
|
before do
|
591
|
-
@big_text =
|
592
|
-
@old_textsize = @client.execute("SELECT @@TEXTSIZE AS [textsize]").each.first[
|
593
|
-
@client.execute("SET TEXTSIZE #{(@big_text.length*2)+1}").do
|
573
|
+
@big_text = "x" * 2_000_000
|
574
|
+
@old_textsize = @client.execute("SELECT @@TEXTSIZE AS [textsize]").each.first["textsize"].inspect
|
575
|
+
@client.execute("SET TEXTSIZE #{(@big_text.length * 2) + 1}").do
|
594
576
|
end
|
595
577
|
|
596
|
-
it
|
578
|
+
it "must insert and select large varchar_max" do
|
597
579
|
insert_and_select_datatype :varchar_max
|
598
580
|
end
|
599
581
|
|
600
|
-
it
|
582
|
+
it "must insert and select large nvarchar_max" do
|
601
583
|
insert_and_select_datatype :nvarchar_max
|
602
584
|
end
|
603
|
-
|
604
|
-
end unless sqlserver_2000? || sybase_ase?
|
605
|
-
|
585
|
+
end
|
606
586
|
end
|
607
587
|
|
608
|
-
describe
|
609
|
-
|
610
|
-
it 'copes with nil or empty buffer' do
|
588
|
+
describe "when shit happens" do
|
589
|
+
it "copes with nil or empty buffer" do
|
611
590
|
assert_raises(TypeError) { @client.execute(nil) }
|
612
|
-
assert_equal [], @client.execute(
|
591
|
+
assert_equal [], @client.execute("").each
|
613
592
|
end
|
614
593
|
|
615
|
-
|
594
|
+
describe "using :message_handler option" do
|
595
|
+
let(:messages) { [] }
|
616
596
|
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
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
|
597
|
+
before do
|
598
|
+
close_client
|
599
|
+
@client = new_connection message_handler: proc { |m| messages << m }
|
600
|
+
end
|
628
601
|
|
629
|
-
|
630
|
-
|
631
|
-
|
602
|
+
after do
|
603
|
+
messages.clear
|
604
|
+
end
|
632
605
|
|
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
|
606
|
+
it "has a message handler that responds to call" do
|
607
|
+
assert @client.message_handler.respond_to?(:call)
|
608
|
+
end
|
646
609
|
|
647
|
-
|
610
|
+
it "calls the provided message handler when severity is 10 or less" do
|
611
|
+
(1..10).to_a.each do |severity|
|
648
612
|
messages.clear
|
649
|
-
msg =
|
650
|
-
|
613
|
+
msg = "Test #{severity} severity"
|
614
|
+
state = rand(1..255)
|
615
|
+
@client.execute("RAISERROR(N'#{msg}', #{severity}, #{state})").do
|
651
616
|
m = messages.first
|
652
|
-
assert_equal 1, messages.length,
|
653
|
-
assert_equal msg, m.message,
|
654
|
-
|
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
|
617
|
+
assert_equal 1, messages.length, "there should be one message after one raiserror"
|
618
|
+
assert_equal msg, m.message, "message text"
|
619
|
+
assert_equal severity, m.severity, "message severity" unless severity == 10 && m.severity.to_i == 0
|
620
|
+
assert_equal state, m.os_error_number, "message state"
|
696
621
|
end
|
697
622
|
end
|
698
623
|
|
699
|
-
it
|
700
|
-
|
701
|
-
|
702
|
-
|
624
|
+
it "calls the provided message handler for `print` messages" do
|
625
|
+
messages.clear
|
626
|
+
msg = "hello"
|
627
|
+
@client.execute("PRINT '#{msg}'").do
|
628
|
+
m = messages.first
|
629
|
+
assert_equal 1, messages.length, "there should be one message after one print statement"
|
630
|
+
assert_equal msg, m.message, "message text"
|
703
631
|
end
|
704
632
|
|
705
|
-
it
|
706
|
-
|
633
|
+
it "must raise an error preceded by a `print` message" do
|
634
|
+
messages.clear
|
635
|
+
action = lambda { @client.execute("EXEC tinytds_TestPrintWithError").do }
|
707
636
|
assert_raise_tinytds_error(action) do |e|
|
708
|
-
assert_equal "
|
709
|
-
|
637
|
+
assert_equal "hello", messages.first.message, "message text"
|
638
|
+
|
639
|
+
assert_equal "Error following print", e.message
|
640
|
+
assert_equal 16, e.severity
|
710
641
|
assert_equal 50000, e.db_error_number
|
711
642
|
end
|
712
643
|
end
|
713
644
|
|
714
|
-
|
645
|
+
it "calls the provided message handler for each of a series of `print` messages" do
|
646
|
+
messages.clear
|
647
|
+
@client.execute("EXEC tinytds_TestSeveralPrints").do
|
648
|
+
assert_equal ["hello 1", "hello 2", "hello 3"], messages.map { |e| e.message }, "message list"
|
649
|
+
end
|
715
650
|
|
716
|
-
it
|
717
|
-
|
651
|
+
it "should flush info messages before raising error in cases of timeout" do
|
652
|
+
@client = new_connection timeout: 1, message_handler: proc { |m| messages << m }
|
653
|
+
action = lambda { @client.execute("print 'hello'; waitfor delay '00:00:02'").do }
|
654
|
+
messages.clear
|
718
655
|
assert_raise_tinytds_error(action) do |e|
|
719
|
-
|
720
|
-
assert_equal
|
721
|
-
assert_equal
|
656
|
+
assert_match %r{timed out}i, e.message, "ignore if non-english test run"
|
657
|
+
assert_equal 6, e.severity
|
658
|
+
assert_equal 20003, e.db_error_number
|
659
|
+
assert_equal "hello", messages.first&.message, "message text"
|
722
660
|
end
|
723
|
-
assert_followup_query
|
724
661
|
end
|
725
662
|
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
663
|
+
it "should print info messages before raising error in cases of timeout" do
|
664
|
+
@client = new_connection timeout: 1, message_handler: proc { |m| messages << m }
|
665
|
+
action = lambda { @client.execute("raiserror('hello', 1, 1) with nowait; waitfor delay '00:00:02'").do }
|
666
|
+
messages.clear
|
667
|
+
assert_raise_tinytds_error(action) do |e|
|
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"
|
672
|
+
end
|
735
673
|
end
|
736
674
|
end
|
737
675
|
|
738
|
-
it
|
739
|
-
|
740
|
-
|
741
|
-
pattern = sybase_ase? ? /foobar not found/ : %r|invalid object name.*foobar|i
|
742
|
-
assert_match pattern, e.message
|
743
|
-
assert_equal 16, e.severity
|
744
|
-
assert_equal 208, e.db_error_number
|
676
|
+
it "must not raise an error when severity is 10 or less" do
|
677
|
+
(1..10).to_a.each do |severity|
|
678
|
+
@client.execute("RAISERROR(N'Test #{severity} severity', #{severity}, 1)").do
|
745
679
|
end
|
746
|
-
assert_followup_query
|
747
680
|
end
|
748
681
|
|
749
|
-
it
|
750
|
-
action = lambda { @client.execute('
|
682
|
+
it "raises an error when severity is greater than 10" do
|
683
|
+
action = lambda { @client.execute("RAISERROR(N'Test 11 severity', 11, 1)").do }
|
751
684
|
assert_raise_tinytds_error(action) do |e|
|
752
|
-
|
753
|
-
assert_equal
|
754
|
-
assert_equal
|
755
|
-
end
|
756
|
-
assert_followup_query
|
757
|
-
end
|
758
|
-
|
759
|
-
it 'must not error at all from reading non-convertable charcters and just use ? marks' do
|
760
|
-
close_client
|
761
|
-
@client = new_connection :encoding => 'ASCII'
|
762
|
-
_(@client.charset).must_equal 'ASCII'
|
763
|
-
_(find_value(202, :nvarchar_50)).must_equal 'test nvarchar_50 ??'
|
764
|
-
end
|
765
|
-
|
766
|
-
it 'must error gracefully from writing non-convertable characters' do
|
767
|
-
close_client
|
768
|
-
@client = new_connection :encoding => 'ASCII'
|
769
|
-
_(@client.charset).must_equal 'ASCII'
|
770
|
-
rollback_transaction(@client) do
|
771
|
-
text = 'Test ✓'
|
772
|
-
@client.execute("DELETE FROM [datatypes] WHERE [nvarchar_50] IS NOT NULL").do
|
773
|
-
action = lambda { @client.execute("INSERT INTO [datatypes] ([nvarchar_50]) VALUES ('#{text}')").do }
|
774
|
-
assert_raise_tinytds_error(action) do |e|
|
775
|
-
_(e.message).must_match %r{Unclosed quotation mark}i
|
776
|
-
_(e.severity).must_equal 15
|
777
|
-
_(e.db_error_number).must_equal 105
|
778
|
-
end
|
779
|
-
assert_followup_query
|
685
|
+
assert_equal "Test 11 severity", e.message
|
686
|
+
assert_equal 11, e.severity
|
687
|
+
assert_equal 50000, e.db_error_number
|
780
688
|
end
|
781
689
|
end
|
782
|
-
|
783
|
-
it 'errors gracefully with incorrect syntax in sp_executesql' do
|
784
|
-
action = lambda { @client.execute("EXEC sp_executesql N'this will not work'").each }
|
785
|
-
assert_raise_tinytds_error(action) do |e|
|
786
|
-
assert_match %r|incorrect syntax|i, e.message
|
787
|
-
assert_equal 15, e.severity
|
788
|
-
assert_equal 156, e.db_error_number
|
789
|
-
end
|
790
|
-
assert_followup_query
|
791
|
-
end unless sybase_ase?
|
792
|
-
|
793
690
|
end
|
794
|
-
|
795
691
|
end
|
796
692
|
|
797
|
-
|
798
693
|
protected
|
799
694
|
|
800
695
|
def assert_followup_query
|
801
696
|
result = @client.execute(@query1)
|
802
|
-
assert_equal 1, result.each.first[
|
697
|
+
assert_equal 1, result.each.first["one"]
|
803
698
|
end
|
804
699
|
|
805
700
|
def insert_and_select_datatype(datatype)
|
@@ -810,5 +705,4 @@ class ResultTest < TinyTds::TestCase
|
|
810
705
|
flunk "Large #{datatype} data with a length of #{@big_text.length} did not match found text with length of #{found_text.length}" unless @big_text == found_text
|
811
706
|
end
|
812
707
|
end
|
813
|
-
|
814
708
|
end
|