tiny_tds 2.1.3-x64-mingw32 → 2.1.4.pre-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e512a3fac65015371dff5419a96d735ad548ba9c7215956a798c820aa1829e62
4
- data.tar.gz: 56e856f74da1a557a1a2050376bfcaff8dfd90745c00f7ab406ac7d70a66e96b
3
+ metadata.gz: 9d21aa286ec1e3be47f2a80b776f1a3b50aa118fa8e9b441897cc83457308523
4
+ data.tar.gz: e655d5cc98d23af01089fdce4d2d83d5cfe5088b47ad0e8816186299342e5a75
5
5
  SHA512:
6
- metadata.gz: 7b3941293d3dfffb05c06a18e02e1705f17e619efc242b6ddf518a7f9d03860a48d733e2ca9b66748220872f16b55f4ce8c5103e7c91865a0a6149b6b5b8f717
7
- data.tar.gz: e50f0c8d362a3b402029d12ddd0305f2d41ffa577b056bf044342569eac6c53060096162e593ae8692a0c98f595d501360e8b1c73af57ddea5c0583c105f6da0
6
+ metadata.gz: a396a55809900ef33ea42b3c67f2f78e2747ad7759fdabd362564b83e25a6737be7419576aecfa4148504f4fba7aed32079712483c7210928ab7b8664b609b27
7
+ data.tar.gz: 2193592e960cd22d8e85a9f929550b3bcde916959dacc6dc4d4c187fc47a7437aa350dbadf594cfded077fa57693afd52f872cbd1478d2e2dac6a1e1555e431f
@@ -1,5 +1,10 @@
1
1
  ## (unreleased)
2
2
 
3
+ ## 2.1.4
4
+
5
+ * todo: changelog for info messages
6
+ * todo: changelog for network timeouts
7
+
3
8
  ## 2.1.3
4
9
 
5
10
  * Removed old/unused appveyor config
data/README.md CHANGED
@@ -110,7 +110,7 @@ Creating a new client takes a hash of options. For valid iconv encoding options,
110
110
  * :appname - Short string seen in SQL Servers process/activity window.
111
111
  * :tds_version - TDS version. Defaults to "7.3".
112
112
  * :login_timeout - Seconds to wait for login. Default to 60 seconds.
113
- * :timeout - Seconds to wait for a response to a SQL command. Default 5 seconds. Prior to 1.0rc5, FreeTDS was unable to set the timeout on a per-client basis, permitting only a global timeout value. This means that if you're using an older version, the timeout values for all clients will be overwritten each time you instantiate a new `TinyTds::Client` object. If you are using 1.0rc5 or later, all clients will have an independent timeout setting as you'd expect.
113
+ * :timeout - Seconds to wait for a response to a SQL command. Default 5 seconds. Prior to 1.0rc5, FreeTDS was unable to set the timeout on a per-client basis, permitting only a global timeout value. This means that if you're using an older version, the timeout values for all clients will be overwritten each time you instantiate a new `TinyTds::Client` object. If you are using 1.0rc5 or later, all clients will have an independent timeout setting as you'd expect. Timeouts caused by network failure will raise a timeout error 1 second after the configured timeout limit is hit (see [#481](https://github.com/rails-sqlserver/tiny_tds/pull/481) for details).
114
114
  * :encoding - Any valid iconv value like CP1251 or ISO-8859-1. Default UTF-8.
115
115
  * :azure - Pass true to signal that you are connecting to azure.
116
116
  * :contained - Pass true to signal that you are connecting with a contained database user.
@@ -322,6 +322,10 @@ By default row caching is turned on because the SQL Server adapter for ActiveRec
322
322
  TinyTDS takes an opinionated stance on how we handle encoding errors. First, we treat errors differently on reads vs. writes. Our opinion is that if you are reading bad data due to your client's encoding option, you would rather just find `?` marks in your strings vs being blocked with exceptions. This is how things wold work via ODBC or SMS. On the other hand, writes will raise an exception. In this case we raise the SYBEICONVO/2402 error message which has a description of `Error converting characters into server's character set. Some character(s) could not be converted.`. Even though the severity of this message is only a `4` and TinyTDS will automatically strip/ignore unknown characters, we feel you should know that you are inserting bad encodings. In this way, a transaction can be rolled back, etc. Remember, any database write that has bad characters due to the client encoding will still be written to the database, but it is up to you rollback said write if needed. Most ORMs like ActiveRecord handle this scenario just fine.
323
323
 
324
324
 
325
+ ## Timeout Error Handling
326
+
327
+ TinyTDS will raise a `TinyTDS::Error` when a timeout is reached based on the options supplied to the client. Depending on the reason for the timeout, the connection could be dead or alive. When db processing is the cause for the timeout, the connection should still be usable after the error is raised. When network failure is the cause of the timeout, the connection will be dead. If you attempt to execute another command batch on a dead connection you will see a `DBPROCESS is dead or not enabled` error. Therefore, it is recommended to check for a `dead?` connection before trying to execute another command batch.
328
+
325
329
  ## Binstubs
326
330
 
327
331
  The TinyTDS gem uses binstub wrappers which mirror compiled [FreeTDS Utilities](http://www.freetds.org/userguide/usefreetds.htm) 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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.3
1
+ 2.1.4.pre
@@ -19,7 +19,19 @@ install:
19
19
  - perl --version
20
20
  - ruby --version
21
21
  - gem --version
22
-
22
+ # Update keyring according to https://www.msys2.org/news/#2020-06-29-new-packagers
23
+ - C:\msys64\usr\bin\curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz
24
+ - C:\msys64\usr\bin\curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig
25
+ - ridk exec bash -c "pacman-key --verify msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig"
26
+ - ridk exec bash -c "pacman -U --noconfirm --config <(echo) msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz"
27
+ # Update zstd and pacman first https://github.com/msys2/MSYS2-packages/issues/2300
28
+ - C:\msys64\usr\bin\pacman --noconfirm --upgrade https://repo.msys2.org/msys/x86_64/zstd-1.4.7-1-x86_64.pkg.tar.xz # Must come First, or else pacman will install 1.4.8
29
+ - C:\msys64\usr\bin\pacman --noconfirm --upgrade https://repo.msys2.org/msys/x86_64/pacman-5.2.2-5-x86_64.pkg.tar.xz
30
+ # update packages
31
+ - C:\msys64\usr\bin\pacman --noconfirm --ask 20 --sync --refresh --refresh --sysupgrade --sysupgrade
32
+ # Kill all running msys2 binaries to avoid error "size of shared memory region changed".
33
+ # See https://github.com/msys2/MSYS2-packages/issues/258
34
+ - powershell -Command "Get-Process | Where-Object {$_.path -like 'C:\msys64*'} | Stop-Process"
23
35
  # prevent freetds to link to wrong ws2_32 lib on i686-w64-mingw32
24
36
  - c:/msys64/usr/bin/rm /usr/lib/w32api/libws2_32.a
25
37
  # Set up project prerequisits
@@ -57,6 +57,16 @@ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int is_message, int cancel, cons
57
57
 
58
58
 
59
59
  // Lib Backend (Memory Management & Handlers)
60
+ static void push_userdata_error(tinytds_client_userdata *userdata, tinytds_errordata error) {
61
+ // reallocate memory for the array as needed
62
+ if (userdata->nonblocking_errors_size == userdata->nonblocking_errors_length) {
63
+ userdata->nonblocking_errors_size *= 2;
64
+ userdata->nonblocking_errors = realloc(userdata->nonblocking_errors, userdata->nonblocking_errors_size * sizeof(tinytds_errordata));
65
+ }
66
+
67
+ userdata->nonblocking_errors[userdata->nonblocking_errors_length] = error;
68
+ userdata->nonblocking_errors_length++;
69
+ }
60
70
 
61
71
  int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) {
62
72
  static const char *source = "error";
@@ -86,7 +96,13 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
86
96
  but we don't ever want to automatically retry. Instead have the app
87
97
  decide what to do.
88
98
  */
89
- return_value = INT_TIMEOUT;
99
+ if (userdata->timing_out) {
100
+ return INT_CANCEL;
101
+ }
102
+ else {
103
+ userdata->timing_out = 1;
104
+ return_value = INT_TIMEOUT;
105
+ }
90
106
  cancel = 1;
91
107
  break;
92
108
 
@@ -111,24 +127,16 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
111
127
  userdata->dbcancel_sent = 1;
112
128
  }
113
129
 
114
- /*
115
- If we've already captured an error message, don't overwrite it. This is
116
- here because FreeTDS sends a generic "General SQL Server error" message
117
- that will overwrite the real message. This is not normally a problem
118
- because a ruby exception is normally thrown and we bail before the
119
- generic message can be sent.
120
- */
121
- if (!userdata->nonblocking_error.is_set) {
122
- userdata->nonblocking_error.is_message = 0;
123
- userdata->nonblocking_error.cancel = cancel;
124
- strncpy(userdata->nonblocking_error.error, dberrstr, ERROR_MSG_SIZE);
125
- strncpy(userdata->nonblocking_error.source, source, ERROR_MSG_SIZE);
126
- userdata->nonblocking_error.severity = severity;
127
- userdata->nonblocking_error.dberr = dberr;
128
- userdata->nonblocking_error.oserr = oserr;
129
- userdata->nonblocking_error.is_set = 1;
130
- }
131
-
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);
132
140
  } else {
133
141
  rb_tinytds_raise_error(dbproc, 0, cancel, dberrstr, source, severity, dberr, oserr);
134
142
  }
@@ -144,16 +152,21 @@ int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severi
144
152
 
145
153
  // See tinytds_err_handler() for info about why we do this
146
154
  if (userdata && userdata->nonblocking) {
147
- if (!userdata->nonblocking_error.is_set) {
148
- userdata->nonblocking_error.is_message = !is_message_an_error;
149
- userdata->nonblocking_error.cancel = is_message_an_error;
150
- strncpy(userdata->nonblocking_error.error, msgtext, ERROR_MSG_SIZE);
151
- strncpy(userdata->nonblocking_error.source, source, ERROR_MSG_SIZE);
152
- userdata->nonblocking_error.severity = severity;
153
- userdata->nonblocking_error.dberr = msgno;
154
- userdata->nonblocking_error.oserr = msgstate;
155
- userdata->nonblocking_error.is_set = 1;
156
- }
155
+ /*
156
+ In the case of non-blocking command batch execution we can receive multiple messages
157
+ (including errors). We keep track of those here so they can be processed once the
158
+ non-blocking call returns.
159
+ */
160
+ tinytds_errordata error = {
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);
157
170
 
158
171
  if (is_message_an_error && !dbdead(dbproc) && !userdata->closed) {
159
172
  dbcancel(dbproc);
@@ -165,13 +178,43 @@ int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severi
165
178
  return 0;
166
179
  }
167
180
 
181
+ /*
182
+ Used by dbsetinterrupt -
183
+ This gets called periodically while waiting on a read from the server
184
+ Right now, we only care about cases where a read from the server is
185
+ taking longer than the specified timeout and dbcancel is not working.
186
+ In these cases we decide that we actually want to handle the interrupt
187
+ */
188
+ static int check_interrupt(void *ptr) {
189
+ GET_CLIENT_USERDATA((DBPROCESS *)ptr);
190
+ return userdata->timing_out;
191
+ }
192
+
193
+ /*
194
+ Used by dbsetinterrupt -
195
+ This gets called if check_interrupt returns TRUE.
196
+ Right now, this is only used in cases where a read from the server is
197
+ taking longer than the specified timeout and dbcancel is not working.
198
+ Return INT_CANCEL to abort the current command batch.
199
+ */
200
+ static int handle_interrupt(void *ptr) {
201
+ GET_CLIENT_USERDATA((DBPROCESS *)ptr);
202
+ if (userdata->timing_out) {
203
+ return INT_CANCEL;
204
+ }
205
+ return INT_CONTINUE;
206
+ }
207
+
168
208
  static void rb_tinytds_client_reset_userdata(tinytds_client_userdata *userdata) {
169
209
  userdata->timing_out = 0;
170
210
  userdata->dbsql_sent = 0;
171
211
  userdata->dbsqlok_sent = 0;
172
212
  userdata->dbcancel_sent = 0;
173
213
  userdata->nonblocking = 0;
174
- userdata->nonblocking_error.is_set = 0;
214
+ // the following is mainly done for consistency since the values are reset accordingly in nogvl_setup/cleanup.
215
+ // the nonblocking_errors array does not need to be freed here. That is done as part of nogvl_cleanup.
216
+ userdata->nonblocking_errors_length = 0;
217
+ userdata->nonblocking_errors_size = 0;
175
218
  }
176
219
 
177
220
  static void rb_tinytds_client_mark(void *ptr) {
@@ -381,6 +424,7 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
381
424
  }
382
425
  }
383
426
  dbsetuserdata(cwrap->client, (BYTE*)cwrap->userdata);
427
+ dbsetinterrupt(cwrap->client, check_interrupt, handle_interrupt);
384
428
  cwrap->userdata->closed = 0;
385
429
  if (!NIL_P(database) && (azure != Qtrue)) {
386
430
  dbuse(cwrap->client, StringValueCStr(database));
@@ -5,9 +5,9 @@
5
5
  void init_tinytds_client();
6
6
 
7
7
  #define ERROR_MSG_SIZE 1024
8
+ #define ERRORS_STACK_INIT_SIZE 2
8
9
 
9
10
  typedef struct {
10
- short int is_set;
11
11
  int is_message;
12
12
  int cancel;
13
13
  char error[ERROR_MSG_SIZE];
@@ -25,7 +25,9 @@ typedef struct {
25
25
  RETCODE dbsqlok_retcode;
26
26
  short int dbcancel_sent;
27
27
  short int nonblocking;
28
- tinytds_errordata nonblocking_error;
28
+ short int nonblocking_errors_length;
29
+ short int nonblocking_errors_size;
30
+ tinytds_errordata *nonblocking_errors;
29
31
  VALUE message_handler;
30
32
  } tinytds_client_userdata;
31
33
 
@@ -86,26 +86,35 @@ static void dbcancel_ubf(DBPROCESS *client) {
86
86
  static void nogvl_setup(DBPROCESS *client) {
87
87
  GET_CLIENT_USERDATA(client);
88
88
  userdata->nonblocking = 1;
89
+ userdata->nonblocking_errors_length = 0;
90
+ userdata->nonblocking_errors = malloc(ERRORS_STACK_INIT_SIZE * sizeof(tinytds_errordata));
91
+ userdata->nonblocking_errors_size = ERRORS_STACK_INIT_SIZE;
89
92
  }
90
93
 
91
94
  static void nogvl_cleanup(DBPROCESS *client) {
92
95
  GET_CLIENT_USERDATA(client);
93
96
  userdata->nonblocking = 0;
97
+ userdata->timing_out = 0;
94
98
  /*
95
99
  Now that the blocking operation is done, we can finally throw any
96
100
  exceptions based on errors from SQL Server.
97
101
  */
98
- if (userdata->nonblocking_error.is_set) {
99
- userdata->nonblocking_error.is_set = 0;
102
+ for (short int i = 0; i < userdata->nonblocking_errors_length; i++) {
103
+ tinytds_errordata error = userdata->nonblocking_errors[i];
100
104
  rb_tinytds_raise_error(client,
101
- userdata->nonblocking_error.is_message,
102
- userdata->nonblocking_error.cancel,
103
- userdata->nonblocking_error.error,
104
- userdata->nonblocking_error.source,
105
- userdata->nonblocking_error.severity,
106
- userdata->nonblocking_error.dberr,
107
- userdata->nonblocking_error.oserr);
105
+ error.is_message,
106
+ error.cancel,
107
+ error.error,
108
+ error.source,
109
+ error.severity,
110
+ error.dberr,
111
+ error.oserr
112
+ );
108
113
  }
114
+
115
+ free(userdata->nonblocking_errors);
116
+ userdata->nonblocking_errors_length = 0;
117
+ userdata->nonblocking_errors_size = 0;
109
118
  }
110
119
 
111
120
  static RETCODE nogvl_dbsqlok(DBPROCESS *client) {
@@ -129,14 +129,12 @@ class ClientTest < TinyTds::TestCase
129
129
  end
130
130
  end
131
131
 
132
- it 'must run this test to prove we account for dropped connections' do
133
- skip
132
+ it 'raises TinyTds exception with sql batch timeout due to network failure' do
133
+ skip if ENV['CI'] && ENV['APPVEYOR_BUILD_FOLDER'] # only CI using docker
134
134
  begin
135
- client = new_connection :login_timeout => 2, :timeout => 2
135
+ client = new_connection timeout: 2
136
136
  assert_client_works(client)
137
- STDOUT.puts "Disconnect network!"
138
- sleep 10
139
- STDOUT.puts "This should not get stuck past 6 seconds!"
137
+ docker_container('pause', wait_for: 1)
140
138
  action = lambda { client.execute('SELECT 1 as [one]').each }
141
139
  assert_raise_tinytds_error(action) do |e|
142
140
  assert_equal 20003, e.db_error_number
@@ -144,12 +142,11 @@ class ClientTest < TinyTds::TestCase
144
142
  assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
145
143
  end
146
144
  ensure
147
- STDOUT.puts "Reconnect network!"
148
- sleep 10
145
+ docker_container('unpause', wait_for: 1)
149
146
  action = lambda { client.execute('SELECT 1 as [one]').each }
150
147
  assert_raise_tinytds_error(action) do |e|
151
148
  assert_equal 20047, e.db_error_number
152
- assert_equal 1, e.severity
149
+ assert_includes [1,9], e.severity
153
150
  assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
154
151
  end
155
152
  close_client(client)
@@ -652,6 +652,24 @@ class ResultTest < TinyTds::TestCase
652
652
  assert_equal 1, messages.length, 'there should be one message after one print statement'
653
653
  assert_equal msg, m.message, 'message text'
654
654
  end
655
+
656
+ it 'must raise an error preceded by a `print` message' do
657
+ messages.clear
658
+ action = lambda { @client.execute("EXEC tinytds_TestPrintWithError").do }
659
+ assert_raise_tinytds_error(action) do |e|
660
+ assert_equal 'hello', messages.first.message, 'message text'
661
+
662
+ assert_equal "Error following print", e.message
663
+ assert_equal 16, e.severity
664
+ assert_equal 50000, e.db_error_number
665
+ end
666
+ end
667
+
668
+ it 'calls the provided message handler for each of a series of `print` messages' do
669
+ messages.clear
670
+ @client.execute("EXEC tinytds_TestSeveralPrints").do
671
+ assert_equal ['hello 1', 'hello 2', 'hello 3'], messages.map { |e| e.message }, 'message list'
672
+ end
655
673
  end
656
674
 
657
675
  it 'must not raise an error when severity is 10 or less' do
@@ -770,4 +788,3 @@ class ResultTest < TinyTds::TestCase
770
788
  end
771
789
 
772
790
  end
773
-
@@ -153,6 +153,8 @@ module TinyTds
153
153
  loader.execute(drop_sql).do
154
154
  loader.execute(schema_sql).do
155
155
  loader.execute(sp_sql).do
156
+ loader.execute(sp_error_sql).do
157
+ loader.execute(sp_several_prints_sql).do
156
158
  loader.close
157
159
  true
158
160
  end
@@ -167,7 +169,16 @@ module TinyTds
167
169
  ) DROP TABLE datatypes
168
170
  IF EXISTS(
169
171
  SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'tinytds_TestReturnCodes'
170
- ) DROP PROCEDURE tinytds_TestReturnCodes|
172
+ ) DROP PROCEDURE tinytds_TestReturnCodes
173
+ IF EXISTS(
174
+ SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'tinytds_TestPrintWithError'
175
+ ) DROP PROCEDURE tinytds_TestPrintWithError
176
+ IF EXISTS(
177
+ SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'tinytds_TestPrintWithError'
178
+ ) DROP PROCEDURE tinytds_TestPrintWithError
179
+ IF EXISTS(
180
+ SELECT 1 FROM sysobjects WHERE type = 'P' AND name = 'tinytds_TestSeveralPrints'
181
+ ) DROP PROCEDURE tinytds_TestSeveralPrints|
171
182
  end
172
183
 
173
184
  def drop_sql_microsoft
@@ -181,7 +192,15 @@ module TinyTds
181
192
  IF EXISTS (
182
193
  SELECT name FROM sysobjects
183
194
  WHERE name = 'tinytds_TestReturnCodes' AND type = 'P'
184
- ) DROP PROCEDURE tinytds_TestReturnCodes|
195
+ ) DROP PROCEDURE tinytds_TestReturnCodes
196
+ IF EXISTS (
197
+ SELECT name FROM sysobjects
198
+ WHERE name = 'tinytds_TestPrintWithError' AND type = 'P'
199
+ ) DROP PROCEDURE tinytds_TestPrintWithError
200
+ IF EXISTS (
201
+ SELECT name FROM sysobjects
202
+ WHERE name = 'tinytds_TestSeveralPrints' AND type = 'P'
203
+ ) DROP PROCEDURE tinytds_TestSeveralPrints|
185
204
  end
186
205
 
187
206
  def sp_sql
@@ -191,6 +210,21 @@ module TinyTds
191
210
  RETURN(420) |
192
211
  end
193
212
 
213
+ def sp_error_sql
214
+ %|CREATE PROCEDURE tinytds_TestPrintWithError
215
+ AS
216
+ PRINT 'hello'
217
+ RAISERROR('Error following print', 16, 1)|
218
+ end
219
+
220
+ def sp_several_prints_sql
221
+ %|CREATE PROCEDURE tinytds_TestSeveralPrints
222
+ AS
223
+ PRINT 'hello 1'
224
+ PRINT 'hello 2'
225
+ PRINT 'hello 3'|
226
+ end
227
+
194
228
  def find_value(id, column, query_options={})
195
229
  query_options[:timezone] ||= :utc
196
230
  sql = "SELECT [#{column}] FROM [datatypes] WHERE [id] = #{id}"
@@ -212,6 +246,9 @@ module TinyTds
212
246
  client.execute("ROLLBACK TRANSACTION").do
213
247
  end
214
248
 
249
+ def docker_container(cmd, wait_for: 0)
250
+ system("docker #{cmd} $(docker ps --format '{{.Names}}' --filter 'ancestor=metaskills/mssql-server-linux-tinytds:2017-GA') > /dev/null")
251
+ sleep(wait_for) if wait_for > 0
252
+ end
215
253
  end
216
254
  end
217
-
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.3
4
+ version: 2.1.4.pre
5
5
  platform: x64-mingw32
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: 2020-09-28 00:00:00.000000000 Z
13
+ date: 2021-01-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: mini_portile2
@@ -225,9 +225,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
225
225
  version: 2.8.dev
226
226
  required_rubygems_version: !ruby/object:Gem::Requirement
227
227
  requirements:
228
- - - ">="
228
+ - - ">"
229
229
  - !ruby/object:Gem::Version
230
- version: '0'
230
+ version: 1.3.1
231
231
  requirements: []
232
232
  rubygems_version: 3.1.2
233
233
  signing_key: