tiny_tds 0.4.5.rc1-x86-mingw32

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.
@@ -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')