tiny_tds 0.4.5.rc1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,347 @@
1
+
2
+ #include <tiny_tds_ext.h>
3
+ #include <errno.h>
4
+
5
+ VALUE cTinyTdsClient;
6
+ extern VALUE mTinyTds, cTinyTdsError;
7
+ static ID sym_username, sym_password, sym_dataserver, sym_database, sym_appname, sym_tds_version, sym_login_timeout, sym_timeout, sym_encoding, sym_azure;
8
+ static ID intern_source_eql, intern_severity_eql, intern_db_error_number_eql, intern_os_error_number_eql;
9
+ static ID intern_new, intern_dup, intern_transpose_iconv_encoding, intern_local_offset, intern_gsub;
10
+ VALUE opt_escape_regex, opt_escape_dblquote;
11
+
12
+
13
+ // Lib Macros
14
+
15
+ #define GET_CLIENT_WRAPPER(self) \
16
+ tinytds_client_wrapper *cwrap; \
17
+ Data_Get_Struct(self, tinytds_client_wrapper, cwrap)
18
+
19
+ #define REQUIRE_OPEN_CLIENT(cwrap) \
20
+ if (cwrap->closed || cwrap->userdata->closed) { \
21
+ rb_raise(cTinyTdsError, "closed connection"); \
22
+ return Qnil; \
23
+ }
24
+
25
+
26
+ // Lib Backend (Helpers)
27
+
28
+ static VALUE rb_tinytds_raise_error(DBPROCESS *dbproc, int cancel, char *error, char *source, int severity, int dberr, int oserr) {
29
+ GET_CLIENT_USERDATA(dbproc);
30
+ if (cancel && !dbdead(dbproc) && userdata && !userdata->closed) {
31
+ userdata->dbsqlok_sent = 1;
32
+ dbsqlok(dbproc);
33
+ userdata->dbcancel_sent = 1;
34
+ dbcancel(dbproc);
35
+ }
36
+ VALUE e = rb_exc_new2(cTinyTdsError, error);
37
+ rb_funcall(e, intern_source_eql, 1, rb_str_new2(source));
38
+ if (severity)
39
+ rb_funcall(e, intern_severity_eql, 1, INT2FIX(severity));
40
+ if (dberr)
41
+ rb_funcall(e, intern_db_error_number_eql, 1, INT2FIX(dberr));
42
+ if (oserr)
43
+ rb_funcall(e, intern_os_error_number_eql, 1, INT2FIX(oserr));
44
+ rb_exc_raise(e);
45
+ return Qnil;
46
+ }
47
+
48
+
49
+ // Lib Backend (Memory Management & Handlers)
50
+
51
+ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) {
52
+ static char *source = "error";
53
+ GET_CLIENT_USERDATA(dbproc);
54
+ int return_value = INT_CONTINUE;
55
+ int cancel = 0;
56
+ switch(dberr) {
57
+ case SYBESMSG:
58
+ return return_value;
59
+ case SYBEICONVI:
60
+ return INT_CANCEL;
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
+ return INT_CANCEL;
70
+ break;
71
+ }
72
+ case SYBETIME: {
73
+ if (userdata) {
74
+ if (userdata->timing_out) {
75
+ return INT_CONTINUE;
76
+ } else {
77
+ userdata->timing_out = 1;
78
+ }
79
+ }
80
+ cancel = 1;
81
+ break;
82
+ }
83
+ case SYBEWRIT: {
84
+ if (userdata && (userdata->dbsqlok_sent || userdata->dbcancel_sent))
85
+ return INT_CANCEL;
86
+ cancel = 1;
87
+ break;
88
+ }
89
+ case SYBEREAD:
90
+ cancel = 1;
91
+ break;
92
+ }
93
+ rb_tinytds_raise_error(dbproc, cancel, dberrstr, source, severity, dberr, oserr);
94
+ return return_value;
95
+ }
96
+
97
+ int tinytds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line) {
98
+ static char *source = "message";
99
+ if (severity)
100
+ rb_tinytds_raise_error(dbproc, 1, msgtext, source, severity, msgno, msgstate);
101
+ return 0;
102
+ }
103
+
104
+ static void rb_tinytds_client_reset_userdata(tinytds_client_userdata *userdata) {
105
+ userdata->timing_out = 0;
106
+ userdata->dbsql_sent = 0;
107
+ userdata->dbsqlok_sent = 0;
108
+ userdata->dbcancel_sent = 0;
109
+ }
110
+
111
+ static void rb_tinytds_client_mark(void *ptr) {
112
+ tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
113
+ if (cwrap) {
114
+ rb_gc_mark(cwrap->charset);
115
+ }
116
+ }
117
+
118
+ static void rb_tinytds_client_free(void *ptr) {
119
+ tinytds_client_wrapper *cwrap = (tinytds_client_wrapper *)ptr;
120
+ if (cwrap->login)
121
+ dbloginfree(cwrap->login);
122
+ if (cwrap->client && !cwrap->closed) {
123
+ dbclose(cwrap->client);
124
+ cwrap->closed = 1;
125
+ cwrap->userdata->closed = 1;
126
+ }
127
+ xfree(cwrap->userdata);
128
+ xfree(ptr);
129
+ }
130
+
131
+ static VALUE allocate(VALUE klass) {
132
+ VALUE obj;
133
+ tinytds_client_wrapper *cwrap;
134
+ obj = Data_Make_Struct(klass, tinytds_client_wrapper, rb_tinytds_client_mark, rb_tinytds_client_free, cwrap);
135
+ cwrap->closed = 1;
136
+ cwrap->charset = Qnil;
137
+ cwrap->userdata = malloc(sizeof(tinytds_client_userdata));
138
+ cwrap->userdata->closed = 1;
139
+ rb_tinytds_client_reset_userdata(cwrap->userdata);
140
+ return obj;
141
+ }
142
+
143
+
144
+ // TinyTds::Client (public)
145
+
146
+ static VALUE rb_tinytds_tds_version(VALUE self) {
147
+ GET_CLIENT_WRAPPER(self);
148
+ return INT2FIX(dbtds(cwrap->client));
149
+ }
150
+
151
+ static VALUE rb_tinytds_close(VALUE self) {
152
+ GET_CLIENT_WRAPPER(self);
153
+ if (cwrap->client && !cwrap->closed) {
154
+ dbclose(cwrap->client);
155
+ cwrap->closed = 1;
156
+ cwrap->userdata->closed = 1;
157
+ }
158
+ return Qtrue;
159
+ }
160
+
161
+ static VALUE rb_tinytds_dead(VALUE self) {
162
+ GET_CLIENT_WRAPPER(self);
163
+ return dbdead(cwrap->client) ? Qtrue : Qfalse;
164
+ }
165
+
166
+ static VALUE rb_tinytds_closed(VALUE self) {
167
+ GET_CLIENT_WRAPPER(self);
168
+ return (cwrap->closed || cwrap->userdata->closed) ? Qtrue : Qfalse;
169
+ }
170
+
171
+ static VALUE rb_tinytds_canceled(VALUE self) {
172
+ GET_CLIENT_WRAPPER(self);
173
+ return cwrap->userdata->dbcancel_sent ? Qtrue : Qfalse;
174
+ }
175
+
176
+ static VALUE rb_tinytds_sqlsent(VALUE self) {
177
+ GET_CLIENT_WRAPPER(self);
178
+ return cwrap->userdata->dbsql_sent ? Qtrue : Qfalse;
179
+ }
180
+
181
+ static VALUE rb_tinytds_execute(VALUE self, VALUE sql) {
182
+ GET_CLIENT_WRAPPER(self);
183
+ rb_tinytds_client_reset_userdata(cwrap->userdata);
184
+ REQUIRE_OPEN_CLIENT(cwrap);
185
+ dbcmd(cwrap->client, StringValuePtr(sql));
186
+ if (dbsqlsend(cwrap->client) == FAIL) {
187
+ rb_warn("TinyTds: dbsqlsend() returned FAIL.\n");
188
+ return Qfalse;
189
+ }
190
+ cwrap->userdata->dbsql_sent = 1;
191
+ VALUE result = rb_tinytds_new_result_obj(cwrap->client);
192
+ rb_iv_set(result, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), intern_dup, 0));
193
+ GET_RESULT_WRAPPER(result);
194
+ rwrap->local_offset = rb_funcall(cTinyTdsClient, intern_local_offset, 0);
195
+ #ifdef HAVE_RUBY_ENCODING_H
196
+ rwrap->encoding = cwrap->encoding;
197
+ #endif
198
+ return result;
199
+ }
200
+
201
+ static VALUE rb_tinytds_charset(VALUE self) {
202
+ GET_CLIENT_WRAPPER(self);
203
+ return cwrap->charset;
204
+ }
205
+
206
+ static VALUE rb_tinytds_encoding(VALUE self) {
207
+ GET_CLIENT_WRAPPER(self);
208
+ #ifdef HAVE_RUBY_ENCODING_H
209
+ return rb_enc_from_encoding(cwrap->encoding);
210
+ #else
211
+ return Qnil;
212
+ #endif
213
+ }
214
+
215
+ static VALUE rb_tinytds_escape(VALUE self, VALUE string) {
216
+ Check_Type(string, T_STRING);
217
+ GET_CLIENT_WRAPPER(self);
218
+ VALUE new_string = rb_funcall(string, intern_gsub, 2, opt_escape_regex, opt_escape_dblquote);
219
+ #ifdef HAVE_RUBY_ENCODING_H
220
+ rb_enc_associate(new_string, cwrap->encoding);
221
+ #endif
222
+ return new_string;
223
+ }
224
+
225
+ /* Duplicated in result.c */
226
+ static VALUE rb_tinytds_return_code(VALUE self) {
227
+ GET_CLIENT_WRAPPER(self);
228
+ if (cwrap->client && dbhasretstat(cwrap->client)) {
229
+ return LONG2NUM((long)dbretstatus(cwrap->client));
230
+ } else {
231
+ return Qnil;
232
+ }
233
+ }
234
+
235
+
236
+ // TinyTds::Client (protected)
237
+
238
+ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
239
+ /* Parsing options hash to local vars. */
240
+ VALUE user, pass, dataserver, database, app, version, ltimeout, timeout, charset, azure;
241
+ user = rb_hash_aref(opts, sym_username);
242
+ pass = rb_hash_aref(opts, sym_password);
243
+ dataserver = rb_hash_aref(opts, sym_dataserver);
244
+ database = rb_hash_aref(opts, sym_database);
245
+ app = rb_hash_aref(opts, sym_appname);
246
+ version = rb_hash_aref(opts, sym_tds_version);
247
+ ltimeout = rb_hash_aref(opts, sym_login_timeout);
248
+ timeout = rb_hash_aref(opts, sym_timeout);
249
+ charset = rb_hash_aref(opts, sym_encoding);
250
+ azure = rb_hash_aref(opts, sym_azure);
251
+ /* Dealing with options. */
252
+ if (dbinit() == FAIL) {
253
+ rb_raise(cTinyTdsError, "failed dbinit() function");
254
+ return self;
255
+ }
256
+ dberrhandle(tinytds_err_handler);
257
+ dbmsghandle(tinytds_msg_handler);
258
+ GET_CLIENT_WRAPPER(self);
259
+ cwrap->login = dblogin();
260
+ if (!NIL_P(user))
261
+ dbsetluser(cwrap->login, StringValuePtr(user));
262
+ if (!NIL_P(pass))
263
+ dbsetlpwd(cwrap->login, StringValuePtr(pass));
264
+ if (!NIL_P(app))
265
+ dbsetlapp(cwrap->login, StringValuePtr(app));
266
+ if (!NIL_P(version))
267
+ dbsetlversion(cwrap->login, NUM2INT(version));
268
+ if (!NIL_P(ltimeout))
269
+ dbsetlogintime(NUM2INT(ltimeout));
270
+ if (!NIL_P(timeout))
271
+ dbsettime(NUM2INT(timeout));
272
+ if (!NIL_P(charset))
273
+ DBSETLCHARSET(cwrap->login, StringValuePtr(charset));
274
+ if (!NIL_P(database) && (azure == Qtrue)) {
275
+ #ifdef DBSETLDBNAME
276
+ DBSETLDBNAME(cwrap->login, StringValuePtr(database));
277
+ #else
278
+ rb_warn("TinyTds: Azure connections not supported in this version of FreeTDS.\n");
279
+ #endif
280
+ }
281
+ cwrap->client = dbopen(cwrap->login, StringValuePtr(dataserver));
282
+ if (cwrap->client) {
283
+ cwrap->closed = 0;
284
+ cwrap->charset = charset;
285
+ dbsetuserdata(cwrap->client, (BYTE*)cwrap->userdata);
286
+ cwrap->userdata->closed = 0;
287
+ if (!NIL_P(database) && (azure != Qtrue)) {
288
+ dbuse(cwrap->client, StringValuePtr(database));
289
+ }
290
+ #ifdef HAVE_RUBY_ENCODING_H
291
+ VALUE transposed_encoding = rb_funcall(cTinyTdsClient, intern_transpose_iconv_encoding, 1, charset);
292
+ cwrap->encoding = rb_enc_find(StringValuePtr(transposed_encoding));
293
+ #endif
294
+ }
295
+ return self;
296
+ }
297
+
298
+
299
+ // Lib Init
300
+
301
+ void init_tinytds_client() {
302
+ cTinyTdsClient = rb_define_class_under(mTinyTds, "Client", rb_cObject);
303
+ rb_define_alloc_func(cTinyTdsClient, allocate);
304
+ /* Define TinyTds::Client Public Methods */
305
+ rb_define_method(cTinyTdsClient, "tds_version", rb_tinytds_tds_version, 0);
306
+ rb_define_method(cTinyTdsClient, "close", rb_tinytds_close, 0);
307
+ rb_define_method(cTinyTdsClient, "closed?", rb_tinytds_closed, 0);
308
+ rb_define_method(cTinyTdsClient, "canceled?", rb_tinytds_canceled, 0);
309
+ rb_define_method(cTinyTdsClient, "dead?", rb_tinytds_dead, 0);
310
+ rb_define_method(cTinyTdsClient, "sqlsent?", rb_tinytds_sqlsent, 0);
311
+ rb_define_method(cTinyTdsClient, "execute", rb_tinytds_execute, 1);
312
+ rb_define_method(cTinyTdsClient, "charset", rb_tinytds_charset, 0);
313
+ rb_define_method(cTinyTdsClient, "encoding", rb_tinytds_encoding, 0);
314
+ rb_define_method(cTinyTdsClient, "escape", rb_tinytds_escape, 1);
315
+ rb_define_method(cTinyTdsClient, "return_code", rb_tinytds_return_code, 0);
316
+ /* Define TinyTds::Client Protected Methods */
317
+ rb_define_protected_method(cTinyTdsClient, "connect", rb_tinytds_connect, 1);
318
+ /* Symbols For Connect */
319
+ sym_username = ID2SYM(rb_intern("username"));
320
+ sym_password = ID2SYM(rb_intern("password"));
321
+ sym_dataserver = ID2SYM(rb_intern("dataserver"));
322
+ sym_database = ID2SYM(rb_intern("database"));
323
+ sym_appname = ID2SYM(rb_intern("appname"));
324
+ sym_tds_version = ID2SYM(rb_intern("tds_version"));
325
+ sym_login_timeout = ID2SYM(rb_intern("login_timeout"));
326
+ sym_timeout = ID2SYM(rb_intern("timeout"));
327
+ sym_encoding = ID2SYM(rb_intern("encoding"));
328
+ sym_azure = ID2SYM(rb_intern("azure"));
329
+ /* Intern TinyTds::Error Accessors */
330
+ intern_source_eql = rb_intern("source=");
331
+ intern_severity_eql = rb_intern("severity=");
332
+ intern_db_error_number_eql = rb_intern("db_error_number=");
333
+ intern_os_error_number_eql = rb_intern("os_error_number=");
334
+ /* Intern Misc */
335
+ intern_new = rb_intern("new");
336
+ intern_dup = rb_intern("dup");
337
+ intern_transpose_iconv_encoding = rb_intern("transpose_iconv_encoding");
338
+ intern_local_offset = rb_intern("local_offset");
339
+ intern_gsub = rb_intern("gsub");
340
+ /* Escape Regexp Global */
341
+ opt_escape_regex = rb_funcall(rb_cRegexp, intern_new, 1, rb_str_new2("\\\'"));
342
+ opt_escape_dblquote = rb_str_new2("''");
343
+ rb_global_variable(&opt_escape_regex);
344
+ rb_global_variable(&opt_escape_dblquote);
345
+ }
346
+
347
+
@@ -0,0 +1,35 @@
1
+
2
+ #ifndef TINYTDS_CLIENT_H
3
+ #define TINYTDS_CLIENT_H
4
+
5
+ void init_tinytds_client();
6
+
7
+ typedef struct {
8
+ short int closed;
9
+ short int timing_out;
10
+ short int dbsql_sent;
11
+ short int dbsqlok_sent;
12
+ RETCODE dbsqlok_retcode;
13
+ short int dbcancel_sent;
14
+ } tinytds_client_userdata;
15
+
16
+ typedef struct {
17
+ LOGINREC *login;
18
+ RETCODE return_code;
19
+ DBPROCESS *client;
20
+ short int closed;
21
+ VALUE charset;
22
+ tinytds_client_userdata *userdata;
23
+ #ifdef HAVE_RUBY_ENCODING_H
24
+ rb_encoding *encoding;
25
+ #endif
26
+ } tinytds_client_wrapper;
27
+
28
+
29
+ // Lib Macros
30
+
31
+ #define GET_CLIENT_USERDATA(dbproc) \
32
+ tinytds_client_userdata *userdata = (tinytds_client_userdata *)dbgetuserdata(dbproc);
33
+
34
+
35
+ #endif
@@ -0,0 +1,84 @@
1
+ require 'mkmf'
2
+
3
+ FREETDS_LIBRARIES = ['sybdb']
4
+ FREETDS_LIBRARIES.unshift 'iconv' if enable_config('iconv')
5
+ FREETDS_HEADERS = ['sybfront.h', 'sybdb.h']
6
+
7
+ dir_config('iconv') if enable_config('iconv')
8
+ dir_config('freetds')
9
+
10
+ def root_paths
11
+ eop_regexp = /#{File::SEPARATOR}bin$/
12
+ paths = ENV['PATH']
13
+ paths = paths.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
14
+ paths = paths.split(File::PATH_SEPARATOR)
15
+ bin_paths = paths.select{ |p| p =~ eop_regexp }
16
+ bin_paths.map{ |p| p.sub(eop_regexp,'') }.compact.reject{ |p| p.empty? }.uniq
17
+ end
18
+
19
+ def have_freetds_libraries?(*libraries)
20
+ libraries.all? { |l| have_library(l) }
21
+ end
22
+
23
+ def find_freetds_libraries_path
24
+ root_paths.detect do |path|
25
+ [['lib'],['lib','freetds']].detect do |lpaths|
26
+ dir = File.join path, *lpaths
27
+ message = "looking for library directory #{dir} ..."
28
+ if File.directory?(dir)
29
+ puts "#{message} yes"
30
+ if with_ldflags("#{$LDFLAGS} -L#{dir}".strip) { have_freetds_libraries?(*FREETDS_LIBRARIES) }
31
+ $LDFLAGS = "-L#{dir} #{$LDFLAGS}".strip
32
+ true
33
+ else
34
+ false
35
+ end
36
+ else
37
+ puts "#{message} no"
38
+ false
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ def have_freetds_headers?(*headers)
45
+ headers.all? { |h| have_header(h) }
46
+ end
47
+
48
+ def find_freetds_include_path
49
+ root_paths.detect do |path|
50
+ [['include'],['include','freetds']].detect do |ipaths|
51
+ dir = File.join path, *ipaths
52
+ message = "looking for include directory #{dir} ..."
53
+ if File.directory?(dir)
54
+ puts "#{message} yes"
55
+ if with_cppflags("#{$CPPFLAGS} -I#{dir}".strip) { have_freetds_headers?(*FREETDS_HEADERS) }
56
+ $CPPFLAGS = "-I#{dir} #{$CPPFLAGS}".strip
57
+ true
58
+ else
59
+ false
60
+ end
61
+ else
62
+ puts "#{message} no"
63
+ false
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ def have_freetds?
70
+ find_freetds_libraries_path && find_freetds_include_path
71
+ end
72
+
73
+ if enable_config("lookup", true)
74
+ unless have_freetds?
75
+ abort "-----\nCan not find FreeTDS's db-lib or include directory.\n-----"
76
+ end
77
+ else
78
+ $LDFLAGS = ENV.fetch("LDFLAGS")
79
+ unless have_freetds_libraries?(*FREETDS_LIBRARIES) && have_freetds_headers?(*FREETDS_HEADERS)
80
+ abort "-----\nCan not find FreeTDS's db-lib or include directory.\n-----"
81
+ end
82
+ end
83
+
84
+ create_makefile('tiny_tds/tiny_tds')