tiny_tds 2.1.2 → 3.2.1
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 +571 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +56 -1
- data/Gemfile +1 -8
- data/ISSUE_TEMPLATE.md +1 -1
- data/README.md +89 -89
- data/Rakefile +44 -30
- 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 +173 -52
- data/ext/tiny_tds/extconsts.rb +4 -11
- data/ext/tiny_tds/result.c +52 -45
- 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 -77
- 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 +152 -116
- data/test/gem_test.rb +39 -118
- data/test/result_test.rb +285 -350
- 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 +112 -85
- data/test/thread_test.rb +22 -31
- data/tiny_tds.gemspec +28 -26
- metadata +85 -59
- data/.travis.yml +0 -24
- data/BACKERS.md +0 -32
- data/appveyor.yml +0 -51
- data/tasks/ports/freetds.rb +0 -37
- data/tasks/ports/libiconv.rb +0 -43
- data/tasks/ports/openssl.rb +0 -78
- 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[
|
83
|
-
result.must_equal "1 test2"
|
79
|
+
result = @client.execute("SELECT TOP (1) [char_10] + 'test' + [varchar_50] AS [test] FROM [datatypes]").each.first["test"]
|
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,151 +195,154 @@ 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[
|
218
|
-
|
213
|
+
count = @client.execute("SELECT COUNT(*) AS [count] FROM [datatypes]").each.first["count"]
|
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
|
-
result.fields.must_equal []
|
226
|
+
_(result.fields).must_equal []
|
231
227
|
result.do
|
232
|
-
result.fields.must_equal []
|
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
|
-
@client.sqlsent
|
258
|
-
@client.canceled
|
253
|
+
_(@client.sqlsent?).must_equal false
|
254
|
+
_(@client.canceled?).must_equal false
|
259
255
|
# With active result before and after cancel.
|
260
256
|
result = @client.execute(@query1)
|
261
|
-
@client.sqlsent
|
262
|
-
@client.canceled
|
257
|
+
_(@client.sqlsent?).must_equal true
|
258
|
+
_(@client.canceled?).must_equal false
|
263
259
|
result.cancel
|
264
|
-
@client.sqlsent
|
265
|
-
@client.canceled
|
266
|
-
assert result.cancel,
|
260
|
+
_(@client.sqlsent?).must_equal false
|
261
|
+
_(@client.canceled?).must_equal true
|
262
|
+
assert result.cancel, "must be safe to call again"
|
267
263
|
# With each and no block.
|
268
264
|
@client.execute(@query1).each
|
269
|
-
@client.sqlsent
|
270
|
-
@client.canceled
|
265
|
+
_(@client.sqlsent?).must_equal false
|
266
|
+
_(@client.canceled?).must_equal false
|
271
267
|
# With each and block.
|
272
268
|
@client.execute(@query1).each do |row|
|
273
|
-
@client.sqlsent
|
274
|
-
@client.canceled
|
269
|
+
_(@client.sqlsent?).must_equal true, "when iterating over each row in a block"
|
270
|
+
_(@client.canceled?).must_equal false
|
275
271
|
end
|
276
|
-
@client.sqlsent
|
277
|
-
@client.canceled
|
272
|
+
_(@client.sqlsent?).must_equal false
|
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|
|
284
280
|
break if index > 10
|
285
281
|
index += 1
|
286
282
|
end
|
287
|
-
@client.sqlsent
|
288
|
-
@client.canceled
|
283
|
+
_(@client.sqlsent?).must_equal true
|
284
|
+
_(@client.canceled?).must_equal false
|
289
285
|
result.cancel
|
290
|
-
@client.sqlsent
|
291
|
-
@client.canceled
|
286
|
+
_(@client.sqlsent?).must_equal false
|
287
|
+
_(@client.canceled?).must_equal true
|
292
288
|
# With do method.
|
293
289
|
@client.execute(@query1).do
|
294
|
-
@client.sqlsent
|
295
|
-
@client.canceled
|
290
|
+
_(@client.sqlsent?).must_equal false
|
291
|
+
_(@client.canceled?).must_equal true
|
296
292
|
# With insert method.
|
297
293
|
rollback_transaction(@client) do
|
298
294
|
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('test')").insert
|
299
|
-
@client.sqlsent
|
300
|
-
@client.canceled
|
295
|
+
_(@client.sqlsent?).must_equal false
|
296
|
+
_(@client.canceled?).must_equal true
|
301
297
|
end
|
302
298
|
# With first
|
303
|
-
@client.execute("SELECT [id] FROM [datatypes]").each(:
|
304
|
-
@client.sqlsent
|
305
|
-
@client.canceled
|
299
|
+
@client.execute("SELECT [id] FROM [datatypes]").each(first: true)
|
300
|
+
_(@client.sqlsent?).must_equal false
|
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[
|
340
|
-
v.must_equal 0
|
338
|
+
it "with LOGINPROPERTY function" do
|
339
|
+
v = @client.execute("SELECT LOGINPROPERTY('sa', 'IsLocked') as v").first["v"]
|
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,271 +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,
|
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"
|
654
621
|
end
|
655
622
|
end
|
656
623
|
|
657
|
-
it
|
658
|
-
|
659
|
-
|
660
|
-
|
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"
|
661
631
|
end
|
662
632
|
|
663
|
-
it
|
664
|
-
|
633
|
+
it "must raise an error preceded by a `print` message" do
|
634
|
+
messages.clear
|
635
|
+
action = lambda { @client.execute("EXEC tinytds_TestPrintWithError").do }
|
665
636
|
assert_raise_tinytds_error(action) do |e|
|
666
|
-
assert_equal "
|
667
|
-
|
637
|
+
assert_equal "hello", messages.first.message, "message text"
|
638
|
+
|
639
|
+
assert_equal "Error following print", e.message
|
640
|
+
assert_equal 16, e.severity
|
668
641
|
assert_equal 50000, e.db_error_number
|
669
642
|
end
|
670
643
|
end
|
671
644
|
|
672
|
-
|
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
|
673
650
|
|
674
|
-
it
|
675
|
-
|
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
|
676
655
|
assert_raise_tinytds_error(action) do |e|
|
677
|
-
|
678
|
-
assert_equal
|
679
|
-
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"
|
680
660
|
end
|
681
|
-
assert_followup_query
|
682
661
|
end
|
683
662
|
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
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
|
693
673
|
end
|
694
674
|
end
|
695
675
|
|
696
|
-
it
|
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
|
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
|
703
679
|
end
|
704
|
-
assert_followup_query
|
705
680
|
end
|
706
681
|
|
707
|
-
it
|
708
|
-
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 }
|
709
684
|
assert_raise_tinytds_error(action) do |e|
|
710
|
-
|
711
|
-
assert_equal
|
712
|
-
assert_equal
|
685
|
+
assert_equal "Test 11 severity", e.message
|
686
|
+
assert_equal 11, e.severity
|
687
|
+
assert_equal 50000, e.db_error_number
|
713
688
|
end
|
714
|
-
assert_followup_query
|
715
689
|
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
|
738
|
-
end
|
739
|
-
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
690
|
end
|
752
|
-
|
753
691
|
end
|
754
692
|
|
755
|
-
|
756
693
|
protected
|
757
694
|
|
758
695
|
def assert_followup_query
|
759
696
|
result = @client.execute(@query1)
|
760
|
-
assert_equal 1, result.each.first[
|
697
|
+
assert_equal 1, result.each.first["one"]
|
761
698
|
end
|
762
699
|
|
763
700
|
def insert_and_select_datatype(datatype)
|
@@ -768,6 +705,4 @@ class ResultTest < TinyTds::TestCase
|
|
768
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
|
769
706
|
end
|
770
707
|
end
|
771
|
-
|
772
708
|
end
|
773
|
-
|