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.
- data/.gitignore +17 -0
- data/CHANGELOG +99 -0
- data/Gemfile +18 -0
- data/MIT-LICENSE +22 -0
- data/NOTES +11 -0
- data/README.rdoc +277 -0
- data/Rakefile +52 -0
- data/ext/tiny_tds/client.c +347 -0
- data/ext/tiny_tds/client.h +35 -0
- data/ext/tiny_tds/extconf.rb +84 -0
- data/ext/tiny_tds/result.c +493 -0
- data/ext/tiny_tds/result.h +36 -0
- data/ext/tiny_tds/tiny_tds_ext.c +12 -0
- data/ext/tiny_tds/tiny_tds_ext.h +18 -0
- data/lib/tiny_tds/1.8/tiny_tds.so +0 -0
- data/lib/tiny_tds/1.9/tiny_tds.so +0 -0
- data/lib/tiny_tds/client.rb +79 -0
- data/lib/tiny_tds/error.rb +29 -0
- data/lib/tiny_tds/result.rb +8 -0
- data/lib/tiny_tds/version.rb +3 -0
- data/lib/tiny_tds.rb +19 -0
- data/tasks/ports.rake +58 -0
- data/test/benchmark/query.rb +77 -0
- data/test/benchmark/query_odbc.rb +106 -0
- data/test/benchmark/query_tinytds.rb +111 -0
- data/test/client_test.rb +163 -0
- data/test/result_test.rb +437 -0
- data/test/schema/1px.gif +0 -0
- data/test/schema/sqlserver_2000.sql +138 -0
- data/test/schema/sqlserver_2005.sql +138 -0
- data/test/schema/sqlserver_2008.sql +138 -0
- data/test/schema/sqlserver_azure.sql +138 -0
- data/test/schema_test.rb +284 -0
- data/test/test_helper.rb +190 -0
- metadata +117 -0
@@ -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')
|