tiny_tds 2.1.4.pre → 2.1.4.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +3 -3
- data/README.md +8 -5
- data/VERSION +1 -1
- data/docker-compose.yml +22 -0
- data/ext/tiny_tds/client.c +38 -37
- data/ext/tiny_tds/client.h +1 -1
- data/ext/tiny_tds/result.c +12 -9
- data/test/client_test.rb +37 -15
- data/test/result_test.rb +24 -0
- data/test/test_helper.rb +20 -3
- data/tiny_tds.gemspec +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87a9fdb063e15f668ba85a3efd1c40f8b05cce8e38a4969a5c21175ad1392761
|
4
|
+
data.tar.gz: ad2c0b72448fd1ddab27dfbfee62329be786d826188de35c86bc3d8c542a0a13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd0f15ad1042902fe858e662375256389d0b8738c4815280f30b13b80147391ebc3583e840b5eb3709f158c3907742c90f303e6a0dc4b48b2b48f21bba9c349a
|
7
|
+
data.tar.gz: d127aeb91246d9024c38d0617c3d634b8f5848deb5e63cb8a70d38b63f03009e463a13175d71be6d9a4e10ad2e409ff5542c306870076e31ce1f2b7859dfc474
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
## 2.1.4
|
4
4
|
|
5
|
-
*
|
6
|
-
*
|
5
|
+
* Raise error if client is unable to execute statement
|
6
|
+
* Improve handling of network related timeouts
|
7
|
+
* Fix error reporting when preceeded by info message
|
7
8
|
|
8
9
|
## 2.1.3
|
9
10
|
|
@@ -267,4 +268,3 @@ Use both dbsetversion() vs. dbsetlversion. Partially reverts #62.
|
|
267
268
|
|
268
269
|
|
269
270
|
## 0.1.0 Initial release!
|
270
|
-
|
data/README.md
CHANGED
@@ -328,7 +328,7 @@ TinyTDS will raise a `TinyTDS::Error` when a timeout is reached based on the opt
|
|
328
328
|
|
329
329
|
## Binstubs
|
330
330
|
|
331
|
-
The TinyTDS gem uses binstub wrappers which mirror compiled [FreeTDS Utilities](
|
331
|
+
The TinyTDS gem uses binstub wrappers which mirror compiled [FreeTDS Utilities](https://www.freetds.org/userguide/usefreetds.html) binaries. These native executables are usually installed at the system level when installing FreeTDS. However, when using MiniPortile to install TinyTDS as we do with Windows binaries, these binstubs will find and prefer local gem `exe` directory executables. These are the following binstubs we wrap.
|
332
332
|
|
333
333
|
* tsql - Used to test connections and debug compile time settings.
|
334
334
|
* defncopy - Used to dump schema structures.
|
@@ -423,17 +423,20 @@ First, clone the repo using the command line or your Git GUI of choice.
|
|
423
423
|
$ git clone git@github.com:rails-sqlserver/tiny_tds.git
|
424
424
|
```
|
425
425
|
|
426
|
-
After that, the quickest way to get setup for development is to use [Docker](https://www.docker.com/). Assuming you have [downloaded docker](https://www.docker.com/products/docker) for your platform
|
426
|
+
After that, the quickest way to get setup for development is to use [Docker](https://www.docker.com/). Assuming you have [downloaded docker](https://www.docker.com/products/docker) for your platform, you can use [docker-compose](https://docs.docker.com/compose/install/) to run the necessary containers for testing.
|
427
427
|
|
428
428
|
```shell
|
429
|
-
$
|
429
|
+
$ docker-compose up -d
|
430
430
|
```
|
431
431
|
|
432
|
-
This will download our SQL Server for Linux Docker image based from [microsoft/mssql-server-linux/](https://hub.docker.com/r/microsoft/mssql-server-linux/). Our image already has the `[tinytdstest]` DB and `tinytds` users created. Basically, it does the following.
|
432
|
+
This will download our SQL Server for Linux Docker image based from [microsoft/mssql-server-linux/](https://hub.docker.com/r/microsoft/mssql-server-linux/). Our image already has the `[tinytdstest]` DB and `tinytds` users created. This will also download a [toxiproxy](https://github.com/shopify/toxiproxy) Docker image which we can use to simulate network failures for tests. Basically, it does the following.
|
433
433
|
|
434
434
|
```shell
|
435
|
+
$ docker network create main-network
|
435
436
|
$ docker pull metaskills/mssql-server-linux-tinytds
|
436
|
-
$ docker run -p 1433:1433 -d metaskills/mssql-server-linux-tinytds
|
437
|
+
$ docker run -p 1433:1433 -d --name sqlserver --network main-network metaskills/mssql-server-linux-tinytds
|
438
|
+
$ docker pull shopify/toxiproxy
|
439
|
+
$ docker run -p 8474:8474 -p 1234:1234 -d --name toxiproxy --network main-network shopify/toxiproxy
|
437
440
|
```
|
438
441
|
|
439
442
|
If you are using your own database. Make sure to run these SQL commands as SA to get the test database and user installed.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.4.
|
1
|
+
2.1.4.pre2
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
version: '3'
|
2
|
+
|
3
|
+
networks:
|
4
|
+
main-network:
|
5
|
+
|
6
|
+
services:
|
7
|
+
mssql:
|
8
|
+
image: metaskills/mssql-server-linux-tinytds:2017-GA
|
9
|
+
container_name: sqlserver
|
10
|
+
ports:
|
11
|
+
- "1433:1433"
|
12
|
+
networks:
|
13
|
+
- main-network
|
14
|
+
|
15
|
+
toxiproxy:
|
16
|
+
image: shopify/toxiproxy
|
17
|
+
container_name: toxiproxy
|
18
|
+
ports:
|
19
|
+
- "8474:8474"
|
20
|
+
- "1234:1234"
|
21
|
+
networks:
|
22
|
+
- main-network
|
data/ext/tiny_tds/client.c
CHANGED
@@ -24,25 +24,25 @@ VALUE opt_escape_regex, opt_escape_dblquote;
|
|
24
24
|
|
25
25
|
// Lib Backend (Helpers)
|
26
26
|
|
27
|
-
VALUE rb_tinytds_raise_error(DBPROCESS *dbproc,
|
27
|
+
VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, tinytds_errordata error) {
|
28
28
|
VALUE e;
|
29
29
|
GET_CLIENT_USERDATA(dbproc);
|
30
|
-
if (cancel && !dbdead(dbproc) && userdata && !userdata->closed) {
|
30
|
+
if (error.cancel && !dbdead(dbproc) && userdata && !userdata->closed) {
|
31
31
|
userdata->dbsqlok_sent = 1;
|
32
32
|
dbsqlok(dbproc);
|
33
33
|
userdata->dbcancel_sent = 1;
|
34
34
|
dbcancel(dbproc);
|
35
35
|
}
|
36
|
-
e = rb_exc_new2(cTinyTdsError, error);
|
37
|
-
rb_funcall(e, intern_source_eql, 1, rb_str_new2(source));
|
38
|
-
if (severity)
|
39
|
-
rb_funcall(e, intern_severity_eql, 1, INT2FIX(severity));
|
40
|
-
if (dberr)
|
41
|
-
rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(dberr));
|
42
|
-
if (oserr)
|
43
|
-
rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(oserr));
|
44
|
-
|
45
|
-
if (severity <= 10 && is_message) {
|
36
|
+
e = rb_exc_new2(cTinyTdsError, error.error);
|
37
|
+
rb_funcall(e, intern_source_eql, 1, rb_str_new2(error.source));
|
38
|
+
if (error.severity)
|
39
|
+
rb_funcall(e, intern_severity_eql, 1, INT2FIX(error.severity));
|
40
|
+
if (error.dberr)
|
41
|
+
rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(error.dberr));
|
42
|
+
if (error.oserr)
|
43
|
+
rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(error.oserr));
|
44
|
+
|
45
|
+
if (error.severity <= 10 && error.is_message) {
|
46
46
|
VALUE message_handler = userdata && userdata->message_handler ? userdata->message_handler : Qnil;
|
47
47
|
if (message_handler && message_handler != Qnil && rb_respond_to(message_handler, intern_call) != 0) {
|
48
48
|
rb_funcall(message_handler, intern_call, 1, e);
|
@@ -115,6 +115,16 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
|
|
115
115
|
break;
|
116
116
|
}
|
117
117
|
|
118
|
+
tinytds_errordata error_data = {
|
119
|
+
.is_message = 0,
|
120
|
+
.cancel = cancel,
|
121
|
+
.severity = severity,
|
122
|
+
.dberr = dberr,
|
123
|
+
.oserr = oserr
|
124
|
+
};
|
125
|
+
strncpy(error_data.error, dberrstr, ERROR_MSG_SIZE);
|
126
|
+
strncpy(error_data.source, source, ERROR_MSG_SIZE);
|
127
|
+
|
118
128
|
/*
|
119
129
|
When in non-blocking mode we need to store the exception data to throw it
|
120
130
|
once the blocking call returns, otherwise we will segfault ruby since part
|
@@ -126,19 +136,9 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
|
|
126
136
|
dbcancel(dbproc);
|
127
137
|
userdata->dbcancel_sent = 1;
|
128
138
|
}
|
129
|
-
|
130
|
-
tinytds_errordata error = {
|
131
|
-
.is_message = 0,
|
132
|
-
.cancel = cancel,
|
133
|
-
.severity = severity,
|
134
|
-
.dberr = dberr,
|
135
|
-
.oserr = oserr
|
136
|
-
};
|
137
|
-
strncpy(error.error, dberrstr, ERROR_MSG_SIZE);
|
138
|
-
strncpy(error.source, source, ERROR_MSG_SIZE);
|
139
|
-
push_userdata_error(userdata, error);
|
139
|
+
push_userdata_error(userdata, error_data);
|
140
140
|
} else {
|
141
|
-
rb_tinytds_raise_error(dbproc,
|
141
|
+
rb_tinytds_raise_error(dbproc, error_data);
|
142
142
|
}
|
143
143
|
|
144
144
|
return return_value;
|
@@ -150,6 +150,16 @@ int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severi
|
|
150
150
|
|
151
151
|
int is_message_an_error = severity > 10 ? 1 : 0;
|
152
152
|
|
153
|
+
tinytds_errordata error_data = {
|
154
|
+
.is_message = !is_message_an_error,
|
155
|
+
.cancel = is_message_an_error,
|
156
|
+
.severity = severity,
|
157
|
+
.dberr = msgno,
|
158
|
+
.oserr = msgstate
|
159
|
+
};
|
160
|
+
strncpy(error_data.error, msgtext, ERROR_MSG_SIZE);
|
161
|
+
strncpy(error_data.source, source, ERROR_MSG_SIZE);
|
162
|
+
|
153
163
|
// See tinytds_err_handler() for info about why we do this
|
154
164
|
if (userdata && userdata->nonblocking) {
|
155
165
|
/*
|
@@ -157,23 +167,14 @@ int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severi
|
|
157
167
|
(including errors). We keep track of those here so they can be processed once the
|
158
168
|
non-blocking call returns.
|
159
169
|
*/
|
160
|
-
|
161
|
-
.is_message = !is_message_an_error,
|
162
|
-
.cancel = is_message_an_error,
|
163
|
-
.severity = severity,
|
164
|
-
.dberr = msgno,
|
165
|
-
.oserr = msgstate
|
166
|
-
};
|
167
|
-
strncpy(error.error, msgtext, ERROR_MSG_SIZE);
|
168
|
-
strncpy(error.source, source, ERROR_MSG_SIZE);
|
169
|
-
push_userdata_error(userdata, error);
|
170
|
+
push_userdata_error(userdata, error_data);
|
170
171
|
|
171
172
|
if (is_message_an_error && !dbdead(dbproc) && !userdata->closed) {
|
172
173
|
dbcancel(dbproc);
|
173
174
|
userdata->dbcancel_sent = 1;
|
174
175
|
}
|
175
176
|
} else {
|
176
|
-
rb_tinytds_raise_error(dbproc,
|
177
|
+
rb_tinytds_raise_error(dbproc, error_data);
|
177
178
|
}
|
178
179
|
return 0;
|
179
180
|
}
|
@@ -295,8 +296,8 @@ static VALUE rb_tinytds_execute(VALUE self, VALUE sql) {
|
|
295
296
|
REQUIRE_OPEN_CLIENT(cwrap);
|
296
297
|
dbcmd(cwrap->client, StringValueCStr(sql));
|
297
298
|
if (dbsqlsend(cwrap->client) == FAIL) {
|
298
|
-
|
299
|
-
return
|
299
|
+
rb_raise(cTinyTdsError, "failed to execute statement");
|
300
|
+
return self;
|
300
301
|
}
|
301
302
|
cwrap->userdata->dbsql_sent = 1;
|
302
303
|
result = rb_tinytds_new_result_obj(cwrap);
|
data/ext/tiny_tds/client.h
CHANGED
@@ -42,7 +42,7 @@ typedef struct {
|
|
42
42
|
rb_encoding *encoding;
|
43
43
|
} tinytds_client_wrapper;
|
44
44
|
|
45
|
-
VALUE rb_tinytds_raise_error(DBPROCESS *dbproc,
|
45
|
+
VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, tinytds_errordata error);
|
46
46
|
|
47
47
|
// Lib Macros
|
48
48
|
|
data/ext/tiny_tds/result.c
CHANGED
@@ -101,15 +101,18 @@ static void nogvl_cleanup(DBPROCESS *client) {
|
|
101
101
|
*/
|
102
102
|
for (short int i = 0; i < userdata->nonblocking_errors_length; i++) {
|
103
103
|
tinytds_errordata error = userdata->nonblocking_errors[i];
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
104
|
+
|
105
|
+
// lookahead to drain any info messages ahead of raising error
|
106
|
+
if (!error.is_message) {
|
107
|
+
for (short int j = i; j < userdata->nonblocking_errors_length; j++) {
|
108
|
+
tinytds_errordata msg_error = userdata->nonblocking_errors[j];
|
109
|
+
if (msg_error.is_message) {
|
110
|
+
rb_tinytds_raise_error(client, msg_error);
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
rb_tinytds_raise_error(client, error);
|
113
116
|
}
|
114
117
|
|
115
118
|
free(userdata->nonblocking_errors);
|
data/test/client_test.rb
CHANGED
@@ -68,6 +68,9 @@ class ClientTest < TinyTds::TestCase
|
|
68
68
|
end
|
69
69
|
|
70
70
|
describe 'With in-valid options' do
|
71
|
+
before(:all) do
|
72
|
+
init_toxiproxy
|
73
|
+
end
|
71
74
|
|
72
75
|
it 'raises an argument error when no :host given and :dataserver is blank' do
|
73
76
|
assert_raises(ArgumentError) { new_connection :dataserver => nil, :host => nil }
|
@@ -129,27 +132,46 @@ class ClientTest < TinyTds::TestCase
|
|
129
132
|
end
|
130
133
|
end
|
131
134
|
|
132
|
-
it 'raises TinyTds exception with
|
135
|
+
it 'raises TinyTds exception with tcp socket network failure' do
|
133
136
|
skip if ENV['CI'] && ENV['APPVEYOR_BUILD_FOLDER'] # only CI using docker
|
134
137
|
begin
|
135
|
-
client = new_connection timeout: 2
|
138
|
+
client = new_connection timeout: 2, port: 1234
|
136
139
|
assert_client_works(client)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
140
|
+
action = lambda { client.execute("waitfor delay '00:00:05'").do }
|
141
|
+
|
142
|
+
# Use toxiproxy to close the TCP socket after 1 second.
|
143
|
+
# We want TinyTds to execute the statement, hit the timeout configured above, and then not be able to use the network to cancel
|
144
|
+
# the network connection needs to close after the sql batch is sent and before the timeout above is hit
|
145
|
+
Toxiproxy[:sqlserver_test].toxic(:slow_close, delay: 1000).apply do
|
146
|
+
assert_raise_tinytds_error(action) do |e|
|
147
|
+
assert_equal 20003, e.db_error_number
|
148
|
+
assert_equal 6, e.severity
|
149
|
+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
|
150
|
+
end
|
143
151
|
end
|
144
152
|
ensure
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
153
|
+
assert_new_connections_work
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'raises TinyTds exception with dead connection network failure' do
|
158
|
+
skip if ENV['CI'] && ENV['APPVEYOR_BUILD_FOLDER'] # only CI using docker
|
159
|
+
begin
|
160
|
+
client = new_connection timeout: 2, port: 1234
|
161
|
+
assert_client_works(client)
|
162
|
+
action = lambda { client.execute("waitfor delay '00:00:05'").do }
|
163
|
+
|
164
|
+
# Use toxiproxy to close the network connection after 1 second.
|
165
|
+
# We want TinyTds to execute the statement, hit the timeout configured above, and then not be able to use the network to cancel
|
166
|
+
# the network connection needs to close after the sql batch is sent and before the timeout above is hit
|
167
|
+
Toxiproxy[:sqlserver_test].toxic(:timeout, timeout: 1000).apply do
|
168
|
+
assert_raise_tinytds_error(action) do |e|
|
169
|
+
assert_equal 20047, e.db_error_number
|
170
|
+
assert_includes [1,9], e.severity
|
171
|
+
assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
|
172
|
+
end
|
151
173
|
end
|
152
|
-
|
174
|
+
ensure
|
153
175
|
assert_new_connections_work
|
154
176
|
end
|
155
177
|
end
|
data/test/result_test.rb
CHANGED
@@ -670,6 +670,30 @@ class ResultTest < TinyTds::TestCase
|
|
670
670
|
@client.execute("EXEC tinytds_TestSeveralPrints").do
|
671
671
|
assert_equal ['hello 1', 'hello 2', 'hello 3'], messages.map { |e| e.message }, 'message list'
|
672
672
|
end
|
673
|
+
|
674
|
+
it 'should flush info messages before raising error in cases of timeout' do
|
675
|
+
@client = new_connection timeout: 1, message_handler: Proc.new { |m| messages << m }
|
676
|
+
action = lambda { @client.execute("print 'hello'; waitfor delay '00:00:02'").do }
|
677
|
+
messages.clear
|
678
|
+
assert_raise_tinytds_error(action) do |e|
|
679
|
+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
|
680
|
+
assert_equal 6, e.severity
|
681
|
+
assert_equal 20003, e.db_error_number
|
682
|
+
assert_equal 'hello', messages.first&.message, 'message text'
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
it 'should print info messages before raising error in cases of timeout' do
|
687
|
+
@client = new_connection timeout: 1, message_handler: Proc.new { |m| messages << m }
|
688
|
+
action = lambda { @client.execute("raiserror('hello', 1, 1) with nowait; waitfor delay '00:00:02'").do }
|
689
|
+
messages.clear
|
690
|
+
assert_raise_tinytds_error(action) do |e|
|
691
|
+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
|
692
|
+
assert_equal 6, e.severity
|
693
|
+
assert_equal 20003, e.db_error_number
|
694
|
+
assert_equal 'hello', messages.first&.message, 'message text'
|
695
|
+
end
|
696
|
+
end
|
673
697
|
end
|
674
698
|
|
675
699
|
it 'must not raise an error when severity is 10 or less' do
|
data/test/test_helper.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'bundler' ; Bundler.require :development, :test
|
3
3
|
require 'tiny_tds'
|
4
4
|
require 'minitest/autorun'
|
5
|
+
require 'toxiproxy'
|
5
6
|
|
6
7
|
TINYTDS_SCHEMAS = ['sqlserver_2000', 'sqlserver_2005', 'sqlserver_2008', 'sqlserver_2014', 'sqlserver_azure', 'sybase_ase'].freeze
|
7
8
|
|
@@ -246,9 +247,25 @@ module TinyTds
|
|
246
247
|
client.execute("ROLLBACK TRANSACTION").do
|
247
248
|
end
|
248
249
|
|
249
|
-
def
|
250
|
-
|
251
|
-
|
250
|
+
def init_toxiproxy
|
251
|
+
return if ENV['APPVEYOR_BUILD_FOLDER'] # only for CI using docker
|
252
|
+
|
253
|
+
# In order for toxiproxy to work for local docker instances of mssql, the containers must be on the same network
|
254
|
+
# and the host used below must match the mssql container name so toxiproxy knows where to proxy to.
|
255
|
+
# localhost from the perspective of toxiproxy's container is its own container an *not* the mssql container it needs to proxy to.
|
256
|
+
# docker-compose.yml handles this automatically for us. In instances where someone is using their own local mssql container they'll
|
257
|
+
# need to set up the networks manually and set TINYTDS_UNIT_HOST to their mssql container name
|
258
|
+
# For anything other than localhost just use the environment config
|
259
|
+
env_host = ENV['TINYTDS_UNIT_HOST_TEST'] || ENV['TINYTDS_UNIT_HOST'] || 'localhost'
|
260
|
+
host = ['localhost', '127.0.0.1', '0.0.0.0'].include?(env_host) ? 'sqlserver' : env_host
|
261
|
+
port = ENV['TINYTDS_UNIT_PORT'] || 1433
|
262
|
+
Toxiproxy.populate([
|
263
|
+
{
|
264
|
+
name: "sqlserver_test",
|
265
|
+
listen: "0.0.0.0:1234",
|
266
|
+
upstream: "#{host}:#{port}"
|
267
|
+
}
|
268
|
+
])
|
252
269
|
end
|
253
270
|
end
|
254
271
|
end
|
data/tiny_tds.gemspec
CHANGED
@@ -26,4 +26,5 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_development_dependency 'rake-compiler-dock', '~> 1.0'
|
27
27
|
s.add_development_dependency 'minitest', '~> 5.6'
|
28
28
|
s.add_development_dependency 'connection_pool', '~> 2.2'
|
29
|
+
s.add_development_dependency 'toxiproxy', '~> 2.0.0'
|
29
30
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tiny_tds
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.4.
|
4
|
+
version: 2.1.4.pre2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken Collins
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-03-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: mini_portile2
|
@@ -96,6 +96,20 @@ dependencies:
|
|
96
96
|
- - "~>"
|
97
97
|
- !ruby/object:Gem::Version
|
98
98
|
version: '2.2'
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: toxiproxy
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - "~>"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: 2.0.0
|
106
|
+
type: :development
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - "~>"
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 2.0.0
|
99
113
|
description: TinyTDS - A modern, simple and fast FreeTDS library for Ruby using DB-Library.
|
100
114
|
Developed for the ActiveRecord SQL Server adapter.
|
101
115
|
email:
|
@@ -124,6 +138,7 @@ files:
|
|
124
138
|
- appveyor.yml
|
125
139
|
- bin/defncopy-ttds
|
126
140
|
- bin/tsql-ttds
|
141
|
+
- docker-compose.yml
|
127
142
|
- exe/.keep
|
128
143
|
- ext/tiny_tds/client.c
|
129
144
|
- ext/tiny_tds/client.h
|