tiny_tds 3.2.0-x86_64-linux-gnu

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +20 -0
  3. data/.gitattributes +1 -0
  4. data/.github/workflows/ci.yml +590 -0
  5. data/.gitignore +22 -0
  6. data/.rubocop.yml +31 -0
  7. data/CHANGELOG.md +305 -0
  8. data/CODE_OF_CONDUCT.md +31 -0
  9. data/Gemfile +2 -0
  10. data/ISSUE_TEMPLATE.md +38 -0
  11. data/MIT-LICENSE +23 -0
  12. data/README.md +493 -0
  13. data/Rakefile +67 -0
  14. data/VERSION +1 -0
  15. data/bin/defncopy-ttds +3 -0
  16. data/bin/tsql-ttds +3 -0
  17. data/docker-compose.yml +34 -0
  18. data/exe/.keep +0 -0
  19. data/ext/tiny_tds/client.c +492 -0
  20. data/ext/tiny_tds/client.h +53 -0
  21. data/ext/tiny_tds/extconf.rb +190 -0
  22. data/ext/tiny_tds/extconsts.rb +8 -0
  23. data/ext/tiny_tds/result.c +626 -0
  24. data/ext/tiny_tds/result.h +32 -0
  25. data/ext/tiny_tds/tiny_tds_ext.c +15 -0
  26. data/ext/tiny_tds/tiny_tds_ext.h +17 -0
  27. data/lib/tiny_tds/2.7/tiny_tds.so +0 -0
  28. data/lib/tiny_tds/3.0/tiny_tds.so +0 -0
  29. data/lib/tiny_tds/3.1/tiny_tds.so +0 -0
  30. data/lib/tiny_tds/3.2/tiny_tds.so +0 -0
  31. data/lib/tiny_tds/3.3/tiny_tds.so +0 -0
  32. data/lib/tiny_tds/3.4/tiny_tds.so +0 -0
  33. data/lib/tiny_tds/bin.rb +90 -0
  34. data/lib/tiny_tds/client.rb +132 -0
  35. data/lib/tiny_tds/error.rb +12 -0
  36. data/lib/tiny_tds/gem.rb +23 -0
  37. data/lib/tiny_tds/result.rb +5 -0
  38. data/lib/tiny_tds/version.rb +3 -0
  39. data/lib/tiny_tds.rb +42 -0
  40. data/patches/freetds/1.00.27/0001-mingw_missing_inet_pton.diff +34 -0
  41. data/patches/freetds/1.00.27/0002-Don-t-use-MSYS2-file-libws2_32.diff +28 -0
  42. data/patches/libiconv/1.14/1-avoid-gets-error.patch +17 -0
  43. data/ports/x86_64-linux-gnu/bin/defncopy +0 -0
  44. data/ports/x86_64-linux-gnu/bin/tsql +0 -0
  45. data/ports/x86_64-linux-gnu/lib/libsybdb.so.5 +0 -0
  46. data/setup_cimgruby_dev.sh +25 -0
  47. data/start_dev.sh +21 -0
  48. data/tasks/native_gem.rake +16 -0
  49. data/tasks/package.rake +6 -0
  50. data/tasks/ports.rake +24 -0
  51. data/tasks/test.rake +7 -0
  52. data/test/bin/install-freetds.sh +18 -0
  53. data/test/bin/install-mssql.ps1 +42 -0
  54. data/test/bin/install-mssqltools.sh +9 -0
  55. data/test/bin/install-openssl.sh +18 -0
  56. data/test/bin/restore-from-native-gem.ps1 +10 -0
  57. data/test/bin/setup_tinytds_db.sh +7 -0
  58. data/test/bin/setup_volume_permissions.sh +10 -0
  59. data/test/client_test.rb +266 -0
  60. data/test/gem_test.rb +100 -0
  61. data/test/result_test.rb +708 -0
  62. data/test/schema/1px.gif +0 -0
  63. data/test/schema/sqlserver_2017.sql +140 -0
  64. data/test/schema/sqlserver_azure.sql +140 -0
  65. data/test/schema_test.rb +417 -0
  66. data/test/sql/db-create.sql +18 -0
  67. data/test/sql/db-login.sql +38 -0
  68. data/test/test_helper.rb +244 -0
  69. data/test/thread_test.rb +89 -0
  70. data/tiny_tds.gemspec +31 -0
  71. metadata +259 -0
@@ -0,0 +1,266 @@
1
+ require "test_helper"
2
+
3
+ class ClientTest < TinyTds::TestCase
4
+ describe "with valid credentials" do
5
+ before do
6
+ @client = new_connection
7
+ end
8
+
9
+ it "must not be closed" do
10
+ assert !@client.closed?
11
+ assert @client.active?
12
+ end
13
+
14
+ it "allows client connection to be closed" do
15
+ assert @client.close
16
+ assert @client.closed?
17
+ assert !@client.active?
18
+ assert @client.dead?
19
+ action = lambda { @client.execute("SELECT 1 as [one]").each }
20
+ assert_raise_tinytds_error(action) do |e|
21
+ assert_match %r{closed connection}i, e.message, "ignore if non-english test run"
22
+ end
23
+ end
24
+
25
+ it "has getters for the tds version information (brittle since conf takes precedence)" do
26
+ if @client.tds_73?
27
+ assert_equal 11, @client.tds_version
28
+ assert_equal "DBTDS_7_3 - Microsoft SQL Server 2008", @client.tds_version_info
29
+ else
30
+ assert_equal 9, @client.tds_version
31
+ assert_equal "DBTDS_7_1/DBTDS_8_0 - Microsoft SQL Server 2000", @client.tds_version_info
32
+ end
33
+ end
34
+
35
+ it "uses UTF-8 client charset/encoding by default" do
36
+ assert_equal "UTF-8", @client.charset
37
+ assert_equal Encoding.find("UTF-8"), @client.encoding
38
+ end
39
+
40
+ it "has a #escape method used for quote strings" do
41
+ assert_equal "''hello''", @client.escape("'hello'")
42
+ end
43
+
44
+ ["CP850", "CP1252", "ISO-8859-1"].each do |encoding|
45
+ it "allows valid iconv character set - #{encoding}" do
46
+ client = new_connection(encoding: encoding)
47
+ assert_equal encoding, client.charset
48
+ assert_equal Encoding.find(encoding), client.encoding
49
+ ensure
50
+ client&.close
51
+ end
52
+ end
53
+
54
+ unless sqlserver_azure?
55
+ it "must be able to use :host/:port connection" do
56
+ host = ENV["TINYTDS_UNIT_HOST_TEST"] || ENV["TINYTDS_UNIT_HOST"] || "localhost"
57
+ port = ENV["TINYTDS_UNIT_PORT_TEST"] || ENV["TINYTDS_UNIT_PORT"] || 1433
58
+ begin
59
+ client = new_connection dataserver: nil, host: host, port: port
60
+ ensure
61
+ client&.close
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "With in-valid options" do
68
+ before(:all) do
69
+ init_toxiproxy
70
+ end
71
+
72
+ it "raises an argument error when no :host given and :dataserver is blank" do
73
+ assert_raises(ArgumentError) { new_connection dataserver: nil, host: nil }
74
+ end
75
+
76
+ it "raises an argument error when no :username is supplied" do
77
+ assert_raises(ArgumentError) { TinyTds::Client.new username: nil }
78
+ end
79
+
80
+ it "raises TinyTds exception with undefined :dataserver" do
81
+ options = connection_options login_timeout: 1, dataserver: "DOESNOTEXIST"
82
+ action = lambda { new_connection(options) }
83
+ assert_raise_tinytds_error(action) do |e|
84
+ # Not sure why tese are different.
85
+ if ruby_darwin?
86
+ assert_equal 20009, e.db_error_number
87
+ assert_equal 9, e.severity
88
+ assert_match %r{is unavailable or does not exist}i, e.message, "ignore if non-english test run"
89
+ else
90
+ assert_equal 20012, e.db_error_number
91
+ assert_equal 2, e.severity
92
+ assert_match %r{server name not found in configuration files}i, e.message, "ignore if non-english test run"
93
+ end
94
+ end
95
+ assert_new_connections_work
96
+ end
97
+
98
+ it "raises TinyTds exception with long query past :timeout option" do
99
+ client = new_connection timeout: 1
100
+ action = lambda { client.execute("WaitFor Delay '00:00:02'").do }
101
+ assert_raise_tinytds_error(action) do |e|
102
+ assert_equal 20003, e.db_error_number
103
+ assert_equal 6, e.severity
104
+ assert_match %r{timed out}i, e.message, "ignore if non-english test run"
105
+ end
106
+ assert_client_works(client)
107
+ close_client(client)
108
+ assert_new_connections_work
109
+ end
110
+
111
+ it "must not timeout per sql batch when not under transaction" do
112
+ client = new_connection timeout: 2
113
+ client.execute("WaitFor Delay '00:00:01'").do
114
+ client.execute("WaitFor Delay '00:00:01'").do
115
+ client.execute("WaitFor Delay '00:00:01'").do
116
+ close_client(client)
117
+ end
118
+
119
+ it "must not timeout per sql batch when under transaction" do
120
+ client = new_connection timeout: 2
121
+ begin
122
+ client.execute("BEGIN TRANSACTION").do
123
+ client.execute("WaitFor Delay '00:00:01'").do
124
+ client.execute("WaitFor Delay '00:00:01'").do
125
+ client.execute("WaitFor Delay '00:00:01'").do
126
+ ensure
127
+ client.execute("COMMIT TRANSACTION").do
128
+ close_client(client)
129
+ end
130
+ end
131
+
132
+ it "raises TinyTds exception with tcp socket network failure" do
133
+ client = new_connection timeout: 2, port: 1234, host: ENV["TOXIPROXY_HOST"]
134
+ assert_client_works(client)
135
+ action = lambda { client.execute("waitfor delay '00:00:05'").do }
136
+
137
+ # Use toxiproxy to close the TCP socket after 1 second.
138
+ # We want TinyTds to execute the statement, hit the timeout configured above, and then not be able to use the network to cancel
139
+ # the network connection needs to close after the sql batch is sent and before the timeout above is hit
140
+ Toxiproxy[:sqlserver_test].toxic(:slow_close, delay: 1000).apply do
141
+ assert_raise_tinytds_error(action) do |e|
142
+ assert_equal 20003, e.db_error_number
143
+ assert_equal 6, e.severity
144
+ assert_match %r{timed out}i, e.message, "ignore if non-english test run"
145
+ end
146
+ end
147
+ ensure
148
+ assert_new_connections_work
149
+ end
150
+
151
+ it "raises TinyTds exception with dead connection network failure" do
152
+ skip if ruby_windows?
153
+
154
+ begin
155
+ client = new_connection timeout: 2, port: 1234, host: ENV["TOXIPROXY_HOST"]
156
+ assert_client_works(client)
157
+ action = lambda { client.execute("waitfor delay '00:00:05'").do }
158
+
159
+ # Use toxiproxy to close the network connection after 1 second.
160
+ # We want TinyTds to execute the statement, hit the timeout configured above, and then not be able to use the network to cancel
161
+ # the network connection needs to close after the sql batch is sent and before the timeout above is hit
162
+ Toxiproxy[:sqlserver_test].toxic(:timeout, timeout: 1000).apply do
163
+ assert_raise_tinytds_error(action) do |e|
164
+ assert_equal 20047, e.db_error_number
165
+ assert_includes [1, 9], e.severity
166
+ assert_match %r{dead or not enabled}i, e.message, "ignore if non-english test run"
167
+ end
168
+ end
169
+ ensure
170
+ assert_new_connections_work
171
+ end
172
+ end
173
+
174
+ it "raises TinyTds exception with login timeout" do
175
+ action = lambda do
176
+ Toxiproxy[:sqlserver_test].toxic(:timeout, timeout: 0).apply do
177
+ new_connection login_timeout: 1, port: 1234, host: ENV["TOXIPROXY_HOST"]
178
+ end
179
+ end
180
+ assert_raise_tinytds_error(action) do |e|
181
+ assert_equal 20003, e.db_error_number
182
+ assert_equal 6, e.severity
183
+ assert_match %r{timed out}i, e.message, "ignore if non-english test run"
184
+ end
185
+ ensure
186
+ assert_new_connections_work
187
+ end
188
+
189
+ it "raises TinyTds exception with wrong :username" do
190
+ skip if ENV["CI"] && sqlserver_azure? # Some issue with db_error_number.
191
+ options = connection_options username: "willnotwork"
192
+ action = lambda { new_connection(options) }
193
+ assert_raise_tinytds_error(action) do |e|
194
+ assert_equal 18456, e.db_error_number
195
+ assert_equal 14, e.severity
196
+ assert_match %r{login failed}i, e.message, "ignore if non-english test run"
197
+ end
198
+ assert_new_connections_work
199
+ end
200
+ end
201
+
202
+ describe "#parse_username" do
203
+ let(:client) { @client = new_connection }
204
+
205
+ it "returns username if azure is not true" do
206
+ _(
207
+ client.send(:parse_username, username: "user@abc123.database.windows.net")
208
+ ).must_equal "user@abc123.database.windows.net"
209
+ end
210
+
211
+ it "returns short username if azure is true" do
212
+ _(
213
+ client.send(
214
+ :parse_username,
215
+ username: "user@abc123.database.windows.net",
216
+ host: "abc123.database.windows.net",
217
+ azure: true
218
+ )
219
+ ).must_equal "user@abc123"
220
+ end
221
+
222
+ it "returns full username if azure is false" do
223
+ _(
224
+ client.send(
225
+ :parse_username,
226
+ username: "user@abc123.database.windows.net",
227
+ host: "abc123.database.windows.net",
228
+ azure: false
229
+ )
230
+ ).must_equal "user@abc123.database.windows.net"
231
+ end
232
+
233
+ it "returns short username if passed and azure is true" do
234
+ _(
235
+ client.send(
236
+ :parse_username,
237
+ username: "user@abc123",
238
+ host: "abc123.database.windows.net",
239
+ azure: true
240
+ )
241
+ ).must_equal "user@abc123"
242
+ end
243
+
244
+ it "returns username with servername if passed and azure is true" do
245
+ _(
246
+ client.send(
247
+ :parse_username,
248
+ username: "user",
249
+ host: "abc123.database.windows.net",
250
+ azure: true
251
+ )
252
+ ).must_equal "user@abc123"
253
+ end
254
+
255
+ it "returns username with servername if passed and azure is false" do
256
+ _(
257
+ client.send(
258
+ :parse_username,
259
+ username: "user",
260
+ host: "abc123.database.windows.net",
261
+ azure: false
262
+ )
263
+ ).must_equal "user"
264
+ end
265
+ end
266
+ end
data/test/gem_test.rb ADDED
@@ -0,0 +1,100 @@
1
+ require "test_helper"
2
+ require "tiny_tds/gem"
3
+
4
+ class GemTest < Minitest::Spec
5
+ gem_root ||= File.expand_path "../..", __FILE__
6
+
7
+ describe TinyTds::Gem do
8
+ # We're going to muck with some system globals so lets make sure
9
+ # they get set back later
10
+ original_platform = RbConfig::CONFIG["arch"]
11
+ original_pwd = Dir.pwd
12
+
13
+ after do
14
+ RbConfig::CONFIG["arch"] = original_platform
15
+ Dir.chdir original_pwd
16
+ end
17
+
18
+ describe "#root_path" do
19
+ let(:root_path) { TinyTds::Gem.root_path }
20
+
21
+ it "should be the root path" do
22
+ _(root_path).must_equal gem_root
23
+ end
24
+
25
+ it "should be the root path no matter the cwd" do
26
+ Dir.chdir "/"
27
+
28
+ _(root_path).must_equal gem_root
29
+ end
30
+ end
31
+
32
+ describe "#ports_root_path" do
33
+ let(:ports_root_path) { TinyTds::Gem.ports_root_path }
34
+
35
+ it "should be the ports path" do
36
+ _(ports_root_path).must_equal File.join(gem_root, "ports")
37
+ end
38
+
39
+ it "should be the ports path no matter the cwd" do
40
+ Dir.chdir "/"
41
+
42
+ _(ports_root_path).must_equal File.join(gem_root, "ports")
43
+ end
44
+ end
45
+
46
+ describe "#ports_bin_paths" do
47
+ let(:ports_bin_paths) { TinyTds::Gem.ports_bin_paths }
48
+
49
+ describe "when the ports directories exist" do
50
+ let(:fake_bin_paths) do
51
+ ports_host_root = File.join(gem_root, "ports", "fake-host-with-dirs")
52
+ [
53
+ File.join("a", "bin"),
54
+ File.join("a", "inner", "bin"),
55
+ File.join("b", "bin")
56
+ ].map do |p|
57
+ File.join(ports_host_root, p)
58
+ end
59
+ end
60
+
61
+ before do
62
+ RbConfig::CONFIG["arch"] = "fake-host-with-dirs"
63
+ fake_bin_paths.each do |path|
64
+ FileUtils.mkdir_p(path)
65
+ end
66
+ end
67
+
68
+ after do
69
+ FileUtils.remove_entry_secure(
70
+ File.join(gem_root, "ports", "fake-host-with-dirs"), true
71
+ )
72
+ end
73
+
74
+ it "should return all the bin directories" do
75
+ _(ports_bin_paths.sort).must_equal fake_bin_paths.sort
76
+ end
77
+
78
+ it "should return all the bin directories regardless of cwd" do
79
+ Dir.chdir "/"
80
+ _(ports_bin_paths.sort).must_equal fake_bin_paths.sort
81
+ end
82
+ end
83
+
84
+ describe "when the ports directories are missing" do
85
+ before do
86
+ RbConfig::CONFIG["arch"] = "fake-host-without-dirs"
87
+ end
88
+
89
+ it "should return no directories" do
90
+ _(ports_bin_paths).must_be_empty
91
+ end
92
+
93
+ it "should return no directories regardless of cwd" do
94
+ Dir.chdir "/"
95
+ _(ports_bin_paths).must_be_empty
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end