tiny_tds 0.2.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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