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 +14 -0
- data/README.rdoc +8 -0
- data/ext/tiny_tds/client.c +77 -15
- data/ext/tiny_tds/client.h +8 -0
- data/ext/tiny_tds/result.c +17 -1
- data/lib/tiny_tds.rb +1 -1
- metadata +3 -4
- data/lib/tiny_tds/tiny_tds.bundle +0 -0
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
|
|
data/ext/tiny_tds/client.c
CHANGED
@@ -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
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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 (
|
113
|
-
|
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 */
|
data/ext/tiny_tds/client.h
CHANGED
@@ -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
|
data/ext/tiny_tds/result.c
CHANGED
@@ -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
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
|
-
|
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:
|
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
|