tiny_tds 0.2.3 → 0.3.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.
data/CHANGELOG CHANGED
@@ -1,4 +1,18 @@
1
1
 
2
+ * 0.3.1 *
3
+
4
+ * Fix bad gem build.
5
+
6
+
7
+ * 0.3.0 *
8
+
9
+ * Access stored procedure return codes.
10
+
11
+ * Make sure dead or not enabled connections are handled.
12
+
13
+ * Fix bad client after timeout & read from server errors.
14
+
15
+
2
16
  * 0.2.3 *
3
17
 
4
18
  * Do not use development ruby/version, but simple memoize an eval check on init to find out, for 1.8.6 reflection.
data/README.rdoc CHANGED
@@ -136,6 +136,14 @@ The result object can handle multiple result sets form batched SQL or stored pro
136
136
  # 2nd: [{"bigint"=>-9223372036854775807}, {"bigint"=>9223372036854775806}]
137
137
  end
138
138
 
139
+ It is possible to get the return code after executing a stored procedure from either the result or client object.
140
+
141
+ client.return_code # => nil
142
+
143
+ result = client.execute("EXEC tinytds_TestReturnCodes")
144
+ result.return_code # => 420
145
+ client.return_code # => 420
146
+
139
147
 
140
148
  == Query Options
141
149
 
@@ -15,8 +15,11 @@ VALUE opt_escape_regex, opt_escape_dblquote;
15
15
  tinytds_client_wrapper *cwrap; \
16
16
  Data_Get_Struct(self, tinytds_client_wrapper, cwrap)
17
17
 
18
+ #define GET_CLIENT_USERDATA(dbproc) \
19
+ tinytds_client_userdata *userdata = (tinytds_client_userdata *)dbgetuserdata(dbproc);
20
+
18
21
  #define REQUIRE_OPEN_CLIENT(cwrap) \
19
- if(cwrap->closed) { \
22
+ if (cwrap->closed || cwrap->userdata->closed) { \
20
23
  rb_raise(cTinyTdsError, "closed connection"); \
21
24
  return Qnil; \
22
25
  }
@@ -25,7 +28,13 @@ VALUE opt_escape_regex, opt_escape_dblquote;
25
28
  // Lib Backend (Helpers)
26
29
 
27
30
  static VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, char *error, char *source, int severity, int dberr, int oserr) {
28
- if (cancel) { dbsqlok(dbproc); dbcancel(dbproc); }
31
+ GET_CLIENT_USERDATA(dbproc);
32
+ if (cancel && !dbdead(dbproc) && userdata && !userdata->closed) {
33
+ userdata->dbsqlok_sent = 1;
34
+ dbsqlok(dbproc);
35
+ userdata->dbcancel_sent = 1;
36
+ dbcancel(dbproc);
37
+ }
29
38
  VALUE e = rb_exc_new2(cTinyTdsError, error);
30
39
  rb_funcall(e, intern_source_eql, 1, rb_str_new2(source));
31
40
  if (severity)
@@ -33,7 +42,7 @@ static VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, char *error,
33
42
  if (dberr)
34
43
  rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(dberr));
35
44
  if (oserr)
36
- rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(oserr));
45
+ rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(oserr));
37
46
  rb_exc_raise(e);
38
47
  return Qnil;
39
48
  }
@@ -41,12 +50,40 @@ static VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, char *error,
41
50
 
42
51
  // Lib Backend (Memory Management & Handlers)
43
52
 
44
- int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) {
45
- static char *source = "error";
46
- if (dberr == SYBESMSG)
47
- return INT_CONTINUE;
48
- rb_tinytds_raise_error(dbproc, 0, dberrstr, source, severity, dberr, oserr);
49
- return INT_CONTINUE;
53
+ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) {
54
+ static char *source = "error";
55
+ GET_CLIENT_USERDATA(dbproc);
56
+ int return_value = INT_CONTINUE;
57
+ int cancel = 0;
58
+ switch(dberr) {
59
+ case SYBESMSG:
60
+ return return_value;
61
+ case SYBEFCON:
62
+ case SYBESOCK:
63
+ case SYBECONN:
64
+ return_value = INT_EXIT;
65
+ break;
66
+ case SYBESEOF: {
67
+ if (userdata && userdata->timing_out)
68
+ return_value = INT_TIMEOUT;
69
+ }
70
+ case SYBETIME: {
71
+ if (userdata) {
72
+ if (userdata->timing_out) {
73
+ return INT_CONTINUE;
74
+ } else {
75
+ userdata->timing_out = 1;
76
+ }
77
+ }
78
+ cancel = 1;
79
+ break;
80
+ }
81
+ case SYBEREAD:
82
+ cancel = 1;
83
+ break;
84
+ }
85
+ rb_tinytds_raise_error(dbproc, cancel, dberrstr, source, severity, dberr, oserr);
86
+ return return_value;
50
87
  }
51
88
 
52
89
  int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line) {
@@ -56,6 +93,12 @@ int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severi
56
93
  return 0;
57
94
  }
58
95
 
96
+ static void rb_tinytds_client_reset_userdata(tinytds_client_userdata *userdata) {
97
+ userdata->timing_out = 0;
98
+ userdata->dbsqlok_sent = 0;
99
+ userdata->dbcancel_sent = 0;
100
+ }
101
+
59
102
  static void rb_tinytds_client_mark(void *ptr) {
60
103
  tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
61
104
  if (cwrap) {
@@ -70,7 +113,9 @@ static void rb_tinytds_client_free(void *ptr) {
70
113
  if (cwrap->client && !cwrap->closed) {
71
114
  dbclose(cwrap->client);
72
115
  cwrap->closed = 1;
116
+ cwrap->userdata->closed = 1;
73
117
  }
118
+ xfree(cwrap->userdata);
74
119
  xfree(ptr);
75
120
  }
76
121
 
@@ -80,6 +125,9 @@ static VALUE allocate(VALUE klass) {
80
125
  obj = Data_Make_Struct(klass, tinytds_client_wrapper, rb_tinytds_client_mark, rb_tinytds_client_free, cwrap);
81
126
  cwrap->closed = 1;
82
127
  cwrap->charset = Qnil;
128
+ cwrap->userdata = malloc(sizeof(tinytds_client_userdata));
129
+ cwrap->userdata->closed = 1;
130
+ rb_tinytds_client_reset_userdata(cwrap->userdata);
83
131
  return obj;
84
132
  }
85
133
 
@@ -96,22 +144,23 @@ static VALUE rb_tinytds_close(VALUE self) {
96
144
  if (cwrap->client && !cwrap->closed) {
97
145
  dbclose(cwrap->client);
98
146
  cwrap->closed = 1;
147
+ cwrap->userdata->closed = 1;
99
148
  }
100
149
  return Qtrue;
101
150
  }
102
151
 
103
152
  static VALUE rb_tinytds_closed(VALUE self) {
104
153
  GET_CLIENT_WRAPPER(self);
105
- return cwrap->closed ? Qtrue : Qfalse;
154
+ return (cwrap->closed || cwrap->userdata->closed) ? Qtrue : Qfalse;
106
155
  }
107
156
 
108
157
  static VALUE rb_tinytds_execute(VALUE self, VALUE sql) {
109
158
  GET_CLIENT_WRAPPER(self);
159
+ rb_tinytds_client_reset_userdata(cwrap->userdata);
110
160
  REQUIRE_OPEN_CLIENT(cwrap);
111
161
  dbcmd(cwrap->client, StringValuePtr(sql));
112
- if (dbsqlexec(cwrap->client) == FAIL) {
113
- // TODO: Account for dbsqlexec() returned FAIL.
114
- rb_warn("TinyTds: dbsqlexec() returned FAIL.\n");
162
+ if (dbsqlsend(cwrap->client) == FAIL) {
163
+ rb_warn("TinyTds: dbsqlsend() returned FAIL.\n");
115
164
  return Qfalse;
116
165
  }
117
166
  VALUE result = rb_tinytds_new_result_obj(cwrap->client);
@@ -148,6 +197,16 @@ static VALUE rb_tinytds_escape(VALUE self, VALUE string) {
148
197
  return new_string;
149
198
  }
150
199
 
200
+ /* Duplicated in result.c */
201
+ static VALUE rb_tinytds_return_code(VALUE self) {
202
+ GET_CLIENT_WRAPPER(self);
203
+ if (cwrap->client && dbhasretstat(cwrap->client)) {
204
+ return LONG2NUM((long)dbretstatus(cwrap->client));
205
+ } else {
206
+ return Qnil;
207
+ }
208
+ }
209
+
151
210
 
152
211
  // TinyTds::Client (protected)
153
212
 
@@ -175,11 +234,13 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE user, VALUE pass, VALUE datase
175
234
  if (!NIL_P(charset))
176
235
  DBSETLCHARSET(cwrap->login, StringValuePtr(charset));
177
236
  cwrap->client = dbopen(cwrap->login, StringValuePtr(dataserver));
178
- if (!NIL_P(database))
179
- dbuse(cwrap->client, StringValuePtr(database));
180
237
  if (cwrap->client) {
181
238
  cwrap->closed = 0;
182
239
  cwrap->charset = charset;
240
+ dbsetuserdata(cwrap->client, cwrap->userdata);
241
+ cwrap->userdata->closed = 0;
242
+ if (!NIL_P(database))
243
+ dbuse(cwrap->client, StringValuePtr(database));
183
244
  #ifdef HAVE_RUBY_ENCODING_H
184
245
  VALUE transposed_encoding = rb_funcall(cTinyTdsClient, intern_transpose_iconv_encoding, 1, charset);
185
246
  cwrap->encoding = rb_enc_find(StringValuePtr(transposed_encoding));
@@ -202,6 +263,7 @@ void init_tinytds_client() {
202
263
  rb_define_method(cTinyTdsClient, "charset", rb_tinytds_charset, 0);
203
264
  rb_define_method(cTinyTdsClient, "encoding", rb_tinytds_encoding, 0);
204
265
  rb_define_method(cTinyTdsClient, "escape", rb_tinytds_escape, 1);
266
+ rb_define_method(cTinyTdsClient, "return_code", rb_tinytds_return_code, 0);
205
267
  /* Define TinyTds::Client Protected Methods */
206
268
  rb_define_protected_method(cTinyTdsClient, "connect", rb_tinytds_connect, 9);
207
269
  /* Intern TinyTds::Error Accessors */
@@ -4,12 +4,20 @@
4
4
 
5
5
  void init_tinytds_client();
6
6
 
7
+ typedef struct {
8
+ short int closed;
9
+ short int timing_out;
10
+ short int dbsqlok_sent;
11
+ short int dbcancel_sent;
12
+ } tinytds_client_userdata;
13
+
7
14
  typedef struct {
8
15
  LOGINREC *login;
9
16
  RETCODE return_code;
10
17
  DBPROCESS *client;
11
18
  short int closed;
12
19
  VALUE charset;
20
+ tinytds_client_userdata *userdata;
13
21
  #ifdef HAVE_RUBY_ENCODING_H
14
22
  rb_encoding *encoding;
15
23
  #endif
@@ -243,9 +243,11 @@ static VALUE rb_tinytds_result_each(int argc, VALUE * argv, VALUE self) {
243
243
  /* Make The Results Or Yield Existing */
244
244
  if (NIL_P(rwrap->results)) {
245
245
  rwrap->results = rb_ary_new();
246
+ RETCODE dbsqlok_rc = 0;
246
247
  RETCODE dbresults_rc = 0;
248
+ dbsqlok_rc = dbsqlok(rwrap->client);
247
249
  dbresults_rc = dbresults(rwrap->client);
248
- while (dbresults_rc == SUCCEED) {
250
+ while ((dbsqlok_rc == SUCCEED) && (dbresults_rc == SUCCEED)) {
249
251
  /* Only do field and row work if there are rows in this result set. */
250
252
  int has_rows = (DBROWS(rwrap->client) == SUCCEED) ? 1 : 0;
251
253
  int number_of_fields = has_rows ? dbnumcols(rwrap->client) : 0;
@@ -321,6 +323,7 @@ static VALUE rb_tinytds_result_fields(VALUE self) {
321
323
  static VALUE rb_tinytds_result_cancel(VALUE self) {
322
324
  GET_RESULT_WRAPPER(self);
323
325
  if (rwrap->client)
326
+ dbsqlok(rwrap->client);
324
327
  dbcancel(rwrap->client);
325
328
  return Qtrue;
326
329
  }
@@ -328,6 +331,7 @@ static VALUE rb_tinytds_result_cancel(VALUE self) {
328
331
  static VALUE rb_tinytds_result_do(VALUE self) {
329
332
  GET_RESULT_WRAPPER(self);
330
333
  if (rwrap->client) {
334
+ dbsqlok(rwrap->client);
331
335
  dbcancel(rwrap->client);
332
336
  return LONG2NUM((long)dbcount(rwrap->client));
333
337
  } else {
@@ -344,9 +348,20 @@ static VALUE rb_tinytds_result_affected_rows(VALUE self) {
344
348
  }
345
349
  }
346
350
 
351
+ /* Duplicated in client.c */
352
+ static VALUE rb_tinytds_result_return_code(VALUE self) {
353
+ GET_RESULT_WRAPPER(self);
354
+ if (rwrap->client && dbhasretstat(rwrap->client)) {
355
+ return LONG2NUM((long)dbretstatus(rwrap->client));
356
+ } else {
357
+ return Qnil;
358
+ }
359
+ }
360
+
347
361
  static VALUE rb_tinytds_result_insert(VALUE self) {
348
362
  GET_RESULT_WRAPPER(self);
349
363
  if (rwrap->client) {
364
+ dbsqlok(rwrap->client);
350
365
  dbcancel(rwrap->client);
351
366
  VALUE identity = Qnil;
352
367
  dbcmd(rwrap->client, "SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident");
@@ -382,6 +397,7 @@ void init_tinytds_result() {
382
397
  rb_define_method(cTinyTdsResult, "cancel", rb_tinytds_result_cancel, 0);
383
398
  rb_define_method(cTinyTdsResult, "do", rb_tinytds_result_do, 0);
384
399
  rb_define_method(cTinyTdsResult, "affected_rows", rb_tinytds_result_affected_rows, 0);
400
+ rb_define_method(cTinyTdsResult, "return_code", rb_tinytds_result_return_code, 0);
385
401
  rb_define_method(cTinyTdsResult, "insert", rb_tinytds_result_insert, 0);
386
402
  /* Intern String Helpers */
387
403
  intern_new = rb_intern("new");
data/lib/tiny_tds.rb CHANGED
@@ -15,5 +15,5 @@ require 'tiny_tds/tiny_tds'
15
15
  #
16
16
  # Tiny Ruby Wrapper For FreeTDS Using DB-Library
17
17
  module TinyTds
18
- VERSION = '0.2.3'
18
+ VERSION = '0.3.1'
19
19
  end
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
9
8
  - 3
10
- version: 0.2.3
9
+ - 1
10
+ version: 0.3.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ken Collins
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-11-13 00:00:00 -05:00
19
+ date: 2011-01-13 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies: []
22
22
 
@@ -42,7 +42,6 @@ files:
42
42
  - lib/tiny_tds/client.rb
43
43
  - lib/tiny_tds/error.rb
44
44
  - lib/tiny_tds/result.rb
45
- - lib/tiny_tds/tiny_tds.bundle
46
45
  - lib/tiny_tds.rb
47
46
  has_rdoc: true
48
47
  homepage: http://github.com/rails-sqlserver/tiny_tds
Binary file