tiny_tds 3.2.1 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,12 +8,54 @@ static ID intern_source_eql, intern_severity_eql, intern_db_error_number_eql, in
8
8
  static ID intern_new, intern_dup, intern_transpose_iconv_encoding, intern_local_offset, intern_gsub, intern_call;
9
9
  VALUE opt_escape_regex, opt_escape_dblquote;
10
10
 
11
+ static void rb_tinytds_client_mark(void *ptr)
12
+ {
13
+ tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
14
+
15
+ if (cwrap) {
16
+ rb_gc_mark(cwrap->charset);
17
+ }
18
+ }
19
+
20
+ static void rb_tinytds_client_free(void *ptr)
21
+ {
22
+ tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
23
+
24
+ if (cwrap->login) {
25
+ dbloginfree(cwrap->login);
26
+ }
27
+
28
+ if (cwrap->client && !cwrap->closed) {
29
+ dbclose(cwrap->client);
30
+ cwrap->client = NULL;
31
+ cwrap->closed = 1;
32
+ cwrap->userdata->closed = 1;
33
+ }
34
+
35
+ xfree(cwrap->userdata);
36
+ xfree(ptr);
37
+ }
38
+
39
+ static size_t tinytds_client_wrapper_size(const void* data)
40
+ {
41
+ return sizeof(tinytds_client_wrapper);
42
+ }
43
+
44
+ static const rb_data_type_t tinytds_client_wrapper_type = {
45
+ .wrap_struct_name = "tinytds_client_wrapper",
46
+ .function = {
47
+ .dmark = rb_tinytds_client_mark,
48
+ .dfree = rb_tinytds_client_free,
49
+ .dsize = tinytds_client_wrapper_size,
50
+ },
51
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
52
+ };
11
53
 
12
54
  // Lib Macros
13
55
 
14
56
  #define GET_CLIENT_WRAPPER(self) \
15
57
  tinytds_client_wrapper *cwrap; \
16
- Data_Get_Struct(self, tinytds_client_wrapper, cwrap)
58
+ TypedData_Get_Struct(self, tinytds_client_wrapper, &tinytds_client_wrapper_type, cwrap)
17
59
 
18
60
  #define REQUIRE_OPEN_CLIENT(cwrap) \
19
61
  if (cwrap->closed || cwrap->userdata->closed) { \
@@ -24,26 +66,36 @@ VALUE opt_escape_regex, opt_escape_dblquote;
24
66
 
25
67
  // Lib Backend (Helpers)
26
68
 
27
- VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, tinytds_errordata error) {
69
+ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, tinytds_errordata error)
70
+ {
28
71
  VALUE e;
29
72
  GET_CLIENT_USERDATA(dbproc);
73
+
30
74
  if (error.cancel && !dbdead(dbproc) && userdata && !userdata->closed) {
31
75
  userdata->dbsqlok_sent = 1;
32
76
  dbsqlok(dbproc);
33
77
  userdata->dbcancel_sent = 1;
34
78
  dbcancel(dbproc);
35
79
  }
80
+
36
81
  e = rb_exc_new2(cTinyTdsError, error.error);
37
82
  rb_funcall(e, intern_source_eql, 1, rb_str_new2(error.source));
38
- if (error.severity)
83
+
84
+ if (error.severity) {
39
85
  rb_funcall(e, intern_severity_eql, 1, INT2FIX(error.severity));
40
- if (error.dberr)
86
+ }
87
+
88
+ if (error.dberr) {
41
89
  rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(error.dberr));
42
- if (error.oserr)
90
+ }
91
+
92
+ if (error.oserr) {
43
93
  rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(error.oserr));
94
+ }
44
95
 
45
96
  if (error.severity <= 10 && error.is_message) {
46
97
  VALUE message_handler = userdata && userdata->message_handler ? userdata->message_handler : Qnil;
98
+
47
99
  if (message_handler && message_handler != Qnil && rb_respond_to(message_handler, intern_call) != 0) {
48
100
  rb_funcall(message_handler, intern_call, 1, e);
49
101
  }
@@ -57,7 +109,8 @@ VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, tinytds_errordata error) {
57
109
 
58
110
 
59
111
  // Lib Backend (Memory Management & Handlers)
60
- static void push_userdata_error(tinytds_client_userdata *userdata, tinytds_errordata error) {
112
+ static void push_userdata_error(tinytds_client_userdata *userdata, tinytds_errordata error)
113
+ {
61
114
  // reallocate memory for the array as needed
62
115
  if (userdata->nonblocking_errors_size == userdata->nonblocking_errors_length) {
63
116
  userdata->nonblocking_errors_size *= 2;
@@ -68,7 +121,8 @@ static void push_userdata_error(tinytds_client_userdata *userdata, tinytds_error
68
121
  userdata->nonblocking_errors_length++;
69
122
  }
70
123
 
71
- int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) {
124
+ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
125
+ {
72
126
  static const char *source = "error";
73
127
  /* Everything should cancel by default */
74
128
  int return_value = INT_CANCEL;
@@ -91,6 +145,7 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
91
145
  return return_value;
92
146
 
93
147
  case SYBETIME:
148
+
94
149
  /*
95
150
  SYBETIME is the only error that can send INT_TIMEOUT or INT_CONTINUE,
96
151
  but we don't ever want to automatically retry. Instead have the app
@@ -99,19 +154,23 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
99
154
  if (userdata && userdata->timing_out) {
100
155
  return INT_CANCEL;
101
156
  }
157
+
102
158
  // userdata will not be set if hitting timeout during login so check for it first
103
159
  if (userdata) {
104
160
  userdata->timing_out = 1;
105
161
  }
162
+
106
163
  return_value = INT_TIMEOUT;
107
164
  cancel = 1;
108
165
  break;
109
166
 
110
167
  case SYBEWRIT:
168
+
111
169
  /* Write errors may happen after we abort a statement */
112
170
  if (userdata && (userdata->dbsqlok_sent || userdata->dbcancel_sent)) {
113
171
  return return_value;
114
172
  }
173
+
115
174
  cancel = 1;
116
175
  break;
117
176
  }
@@ -137,6 +196,7 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
137
196
  dbcancel(dbproc);
138
197
  userdata->dbcancel_sent = 1;
139
198
  }
199
+
140
200
  push_userdata_error(userdata, error_data);
141
201
  } else {
142
202
  rb_tinytds_raise_error(dbproc, error_data);
@@ -145,7 +205,8 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c
145
205
  return return_value;
146
206
  }
147
207
 
148
- int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line) {
208
+ int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
209
+ {
149
210
  static const char *source = "message";
150
211
  GET_CLIENT_USERDATA(dbproc);
151
212
 
@@ -177,6 +238,7 @@ int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severi
177
238
  } else {
178
239
  rb_tinytds_raise_error(dbproc, error_data);
179
240
  }
241
+
180
242
  return 0;
181
243
  }
182
244
 
@@ -187,7 +249,8 @@ Right now, we only care about cases where a read from the server is
187
249
  taking longer than the specified timeout and dbcancel is not working.
188
250
  In these cases we decide that we actually want to handle the interrupt
189
251
  */
190
- static int check_interrupt(void *ptr) {
252
+ static int check_interrupt(void *ptr)
253
+ {
191
254
  GET_CLIENT_USERDATA((DBPROCESS *)ptr);
192
255
  return userdata->timing_out;
193
256
  }
@@ -199,15 +262,19 @@ Right now, this is only used in cases where a read from the server is
199
262
  taking longer than the specified timeout and dbcancel is not working.
200
263
  Return INT_CANCEL to abort the current command batch.
201
264
  */
202
- static int handle_interrupt(void *ptr) {
265
+ static int handle_interrupt(void *ptr)
266
+ {
203
267
  GET_CLIENT_USERDATA((DBPROCESS *)ptr);
268
+
204
269
  if (userdata->timing_out) {
205
270
  return INT_CANCEL;
206
271
  }
272
+
207
273
  return INT_CONTINUE;
208
274
  }
209
275
 
210
- static void rb_tinytds_client_reset_userdata(tinytds_client_userdata *userdata) {
276
+ static void rb_tinytds_client_reset_userdata(tinytds_client_userdata *userdata)
277
+ {
211
278
  userdata->timing_out = 0;
212
279
  userdata->dbsql_sent = 0;
213
280
  userdata->dbsqlok_sent = 0;
@@ -219,31 +286,11 @@ static void rb_tinytds_client_reset_userdata(tinytds_client_userdata *userdata)
219
286
  userdata->nonblocking_errors_size = 0;
220
287
  }
221
288
 
222
- static void rb_tinytds_client_mark(void *ptr) {
223
- tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
224
- if (cwrap) {
225
- rb_gc_mark(cwrap->charset);
226
- }
227
- }
228
-
229
- static void rb_tinytds_client_free(void *ptr) {
230
- tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
231
- if (cwrap->login)
232
- dbloginfree(cwrap->login);
233
- if (cwrap->client && !cwrap->closed) {
234
- dbclose(cwrap->client);
235
- cwrap->client = NULL;
236
- cwrap->closed = 1;
237
- cwrap->userdata->closed = 1;
238
- }
239
- xfree(cwrap->userdata);
240
- xfree(ptr);
241
- }
242
-
243
- static VALUE allocate(VALUE klass) {
289
+ static VALUE allocate(VALUE klass)
290
+ {
244
291
  VALUE obj;
245
292
  tinytds_client_wrapper *cwrap;
246
- obj = Data_Make_Struct(klass, tinytds_client_wrapper, rb_tinytds_client_mark, rb_tinytds_client_free, cwrap);
293
+ obj = TypedData_Make_Struct(klass, tinytds_client_wrapper, &tinytds_client_wrapper_type, cwrap);
247
294
  cwrap->closed = 1;
248
295
  cwrap->charset = Qnil;
249
296
  cwrap->userdata = malloc(sizeof(tinytds_client_userdata));
@@ -255,52 +302,63 @@ static VALUE allocate(VALUE klass) {
255
302
 
256
303
  // TinyTds::Client (public)
257
304
 
258
- static VALUE rb_tinytds_tds_version(VALUE self) {
305
+ static VALUE rb_tinytds_tds_version(VALUE self)
306
+ {
259
307
  GET_CLIENT_WRAPPER(self);
260
308
  return INT2FIX(dbtds(cwrap->client));
261
309
  }
262
310
 
263
- static VALUE rb_tinytds_close(VALUE self) {
311
+ static VALUE rb_tinytds_close(VALUE self)
312
+ {
264
313
  GET_CLIENT_WRAPPER(self);
314
+
265
315
  if (cwrap->client && !cwrap->closed) {
266
316
  dbclose(cwrap->client);
267
317
  cwrap->client = NULL;
268
318
  cwrap->closed = 1;
269
319
  cwrap->userdata->closed = 1;
270
320
  }
321
+
271
322
  return Qtrue;
272
323
  }
273
324
 
274
- static VALUE rb_tinytds_dead(VALUE self) {
325
+ static VALUE rb_tinytds_dead(VALUE self)
326
+ {
275
327
  GET_CLIENT_WRAPPER(self);
276
328
  return dbdead(cwrap->client) ? Qtrue : Qfalse;
277
329
  }
278
330
 
279
- static VALUE rb_tinytds_closed(VALUE self) {
331
+ static VALUE rb_tinytds_closed(VALUE self)
332
+ {
280
333
  GET_CLIENT_WRAPPER(self);
281
334
  return (cwrap->closed || cwrap->userdata->closed) ? Qtrue : Qfalse;
282
335
  }
283
336
 
284
- static VALUE rb_tinytds_canceled(VALUE self) {
337
+ static VALUE rb_tinytds_canceled(VALUE self)
338
+ {
285
339
  GET_CLIENT_WRAPPER(self);
286
340
  return cwrap->userdata->dbcancel_sent ? Qtrue : Qfalse;
287
341
  }
288
342
 
289
- static VALUE rb_tinytds_sqlsent(VALUE self) {
343
+ static VALUE rb_tinytds_sqlsent(VALUE self)
344
+ {
290
345
  GET_CLIENT_WRAPPER(self);
291
346
  return cwrap->userdata->dbsql_sent ? Qtrue : Qfalse;
292
347
  }
293
348
 
294
- static VALUE rb_tinytds_execute(VALUE self, VALUE sql) {
349
+ static VALUE rb_tinytds_execute(VALUE self, VALUE sql)
350
+ {
295
351
  VALUE result;
296
352
 
297
353
  GET_CLIENT_WRAPPER(self);
298
354
  rb_tinytds_client_reset_userdata(cwrap->userdata);
299
355
  REQUIRE_OPEN_CLIENT(cwrap);
300
356
  dbcmd(cwrap->client, StringValueCStr(sql));
357
+
301
358
  if (dbsqlsend(cwrap->client) == FAIL) {
302
359
  rb_raise(cTinyTdsError, "failed dbsqlsend() function");
303
360
  }
361
+
304
362
  cwrap->userdata->dbsql_sent = 1;
305
363
  result = rb_tinytds_new_result_obj(cwrap);
306
364
  rb_iv_set(result, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), intern_dup, 0));
@@ -312,17 +370,20 @@ static VALUE rb_tinytds_execute(VALUE self, VALUE sql) {
312
370
  }
313
371
  }
314
372
 
315
- static VALUE rb_tinytds_charset(VALUE self) {
373
+ static VALUE rb_tinytds_charset(VALUE self)
374
+ {
316
375
  GET_CLIENT_WRAPPER(self);
317
376
  return cwrap->charset;
318
377
  }
319
378
 
320
- static VALUE rb_tinytds_encoding(VALUE self) {
379
+ static VALUE rb_tinytds_encoding(VALUE self)
380
+ {
321
381
  GET_CLIENT_WRAPPER(self);
322
382
  return rb_enc_from_encoding(cwrap->encoding);
323
383
  }
324
384
 
325
- static VALUE rb_tinytds_escape(VALUE self, VALUE string) {
385
+ static VALUE rb_tinytds_escape(VALUE self, VALUE string)
386
+ {
326
387
  VALUE new_string;
327
388
  GET_CLIENT_WRAPPER(self);
328
389
 
@@ -333,8 +394,10 @@ static VALUE rb_tinytds_escape(VALUE self, VALUE string) {
333
394
  }
334
395
 
335
396
  /* Duplicated in result.c */
336
- static VALUE rb_tinytds_return_code(VALUE self) {
397
+ static VALUE rb_tinytds_return_code(VALUE self)
398
+ {
337
399
  GET_CLIENT_WRAPPER(self);
400
+
338
401
  if (cwrap->client && dbhasretstat(cwrap->client)) {
339
402
  return LONG2NUM((long)dbretstatus(cwrap->client));
340
403
  } else {
@@ -342,7 +405,8 @@ static VALUE rb_tinytds_return_code(VALUE self) {
342
405
  }
343
406
  }
344
407
 
345
- static VALUE rb_tinytds_identity_sql(VALUE self) {
408
+ static VALUE rb_tinytds_identity_sql(VALUE self)
409
+ {
346
410
  GET_CLIENT_WRAPPER(self);
347
411
  return rb_str_new2(cwrap->identity_insert_sql);
348
412
  }
@@ -351,7 +415,8 @@ static VALUE rb_tinytds_identity_sql(VALUE self) {
351
415
 
352
416
  // TinyTds::Client (protected)
353
417
 
354
- static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
418
+ static VALUE rb_tinytds_connect(VALUE self, VALUE opts)
419
+ {
355
420
  /* Parsing options hash to local vars. */
356
421
  VALUE user, pass, dataserver, database, app, version, ltimeout, timeout, charset, azure, contained, use_utf16;
357
422
  GET_CLIENT_WRAPPER(self);
@@ -369,44 +434,69 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
369
434
  contained = rb_hash_aref(opts, sym_contained);
370
435
  use_utf16 = rb_hash_aref(opts, sym_use_utf16);
371
436
  cwrap->userdata->message_handler = rb_hash_aref(opts, sym_message_handler);
437
+
372
438
  /* Dealing with options. */
373
439
  if (dbinit() == FAIL) {
374
440
  rb_raise(cTinyTdsError, "failed dbinit() function");
375
441
  return self;
376
442
  }
443
+
377
444
  dberrhandle(tinytds_err_handler);
378
445
  dbmsghandle(tinytds_msg_handler);
379
446
  cwrap->login = dblogin();
380
- if (!NIL_P(version))
447
+
448
+ if (!NIL_P(version)) {
381
449
  dbsetlversion(cwrap->login, NUM2INT(version));
382
- if (!NIL_P(user))
450
+ }
451
+
452
+ if (!NIL_P(user)) {
383
453
  dbsetluser(cwrap->login, StringValueCStr(user));
384
- if (!NIL_P(pass))
454
+ }
455
+
456
+ if (!NIL_P(pass)) {
385
457
  dbsetlpwd(cwrap->login, StringValueCStr(pass));
386
- if (!NIL_P(app))
458
+ }
459
+
460
+ if (!NIL_P(app)) {
387
461
  dbsetlapp(cwrap->login, StringValueCStr(app));
388
- if (!NIL_P(ltimeout))
462
+ }
463
+
464
+ if (!NIL_P(ltimeout)) {
389
465
  dbsetlogintime(NUM2INT(ltimeout));
390
- if (!NIL_P(charset))
466
+ }
467
+
468
+ if (!NIL_P(charset)) {
391
469
  DBSETLCHARSET(cwrap->login, StringValueCStr(charset));
470
+ }
471
+
392
472
  if (!NIL_P(database)) {
393
473
  if (azure == Qtrue || contained == Qtrue) {
394
474
  #ifdef DBSETLDBNAME
395
- DBSETLDBNAME(cwrap->login, StringValueCStr(database));
475
+ DBSETLDBNAME(cwrap->login, StringValueCStr(database));
396
476
  #else
397
- if (azure == Qtrue) {
398
- rb_warn("TinyTds: :azure option is not supported in this version of FreeTDS.\n");
399
- }
400
- if (contained == Qtrue) {
401
- rb_warn("TinyTds: :contained option is not supported in this version of FreeTDS.\n");
402
- }
477
+
478
+ if (azure == Qtrue) {
479
+ rb_warn("TinyTds: :azure option is not supported in this version of FreeTDS.\n");
480
+ }
481
+
482
+ if (contained == Qtrue) {
483
+ rb_warn("TinyTds: :contained option is not supported in this version of FreeTDS.\n");
484
+ }
485
+
403
486
  #endif
404
487
  }
405
488
  }
406
- if (use_utf16 == Qtrue) { DBSETLUTF16(cwrap->login, 1); }
407
- if (use_utf16 == Qfalse) { DBSETLUTF16(cwrap->login, 0); }
489
+
490
+ if (use_utf16 == Qtrue) {
491
+ DBSETLUTF16(cwrap->login, 1);
492
+ }
493
+
494
+ if (use_utf16 == Qfalse) {
495
+ DBSETLUTF16(cwrap->login, 0);
496
+ }
408
497
 
409
498
  cwrap->client = dbopen(cwrap->login, StringValueCStr(dataserver));
499
+
410
500
  if (cwrap->client) {
411
501
  if (dbtds(cwrap->client) < 11) {
412
502
  rb_raise(cTinyTdsError, "connecting with a TDS version older than 7.3!");
@@ -416,31 +506,40 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
416
506
 
417
507
  cwrap->closed = 0;
418
508
  cwrap->charset = charset;
419
- if (!NIL_P(version))
509
+
510
+ if (!NIL_P(version)) {
420
511
  dbsetversion(NUM2INT(version));
512
+ }
513
+
421
514
  if (!NIL_P(timeout)) {
422
515
  timeout_string = rb_sprintf("%"PRIsVALUE"", timeout);
516
+
423
517
  if (dbsetopt(cwrap->client, DBSETTIME, StringValueCStr(timeout_string), 0) == FAIL) {
424
518
  dbsettime(NUM2INT(timeout));
425
519
  }
426
520
  }
521
+
427
522
  dbsetuserdata(cwrap->client, (BYTE*)cwrap->userdata);
428
523
  dbsetinterrupt(cwrap->client, check_interrupt, handle_interrupt);
429
524
  cwrap->userdata->closed = 0;
525
+
430
526
  if (!NIL_P(database) && (azure != Qtrue)) {
431
527
  dbuse(cwrap->client, StringValueCStr(database));
432
528
  }
529
+
433
530
  transposed_encoding = rb_funcall(cTinyTdsClient, intern_transpose_iconv_encoding, 1, charset);
434
531
  cwrap->encoding = rb_enc_find(StringValueCStr(transposed_encoding));
435
532
  cwrap->identity_insert_sql = "SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident";
436
533
  }
534
+
437
535
  return self;
438
536
  }
439
537
 
440
538
 
441
539
  // Lib Init
442
540
 
443
- void init_tinytds_client() {
541
+ void init_tinytds_client()
542
+ {
444
543
  cTinyTdsClient = rb_define_class_under(mTinyTds, "Client", rb_cObject);
445
544
  rb_define_alloc_func(cTinyTdsClient, allocate);
446
545
  /* Define TinyTds::Client Public Methods */
@@ -1,8 +1,8 @@
1
1
  ICONV_VERSION = ENV["TINYTDS_ICONV_VERSION"] || "1.18"
2
2
  ICONV_SOURCE_URI = "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-#{ICONV_VERSION}.tar.gz"
3
3
 
4
- OPENSSL_VERSION = ENV["TINYTDS_OPENSSL_VERSION"] || "3.4.1"
4
+ OPENSSL_VERSION = ENV["TINYTDS_OPENSSL_VERSION"] || "3.5.2"
5
5
  OPENSSL_SOURCE_URI = "https://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz"
6
6
 
7
- FREETDS_VERSION = ENV["TINYTDS_FREETDS_VERSION"] || "1.4.26"
7
+ FREETDS_VERSION = ENV["TINYTDS_FREETDS_VERSION"] || "1.5.4"
8
8
  FREETDS_SOURCE_URI = "http://www.freetds.org/files/stable/freetds-#{FREETDS_VERSION}.tar.bz2"