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 +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
|