Lines 41-44
Link Here
|
41 |
#endif |
41 |
#endif |
42 |
#ifdef HAVE_SYBDB_H |
42 |
#ifdef HAVE_SYBDB_H |
|
|
43 |
#include <sybfront.h> |
43 |
#include <sybdb.h> |
44 |
#include <sybdb.h> |
44 |
#endif |
45 |
#endif |
Lines 46-50
Link Here
|
46 |
#include <stdio.h> |
47 |
#include <stdio.h> |
47 |
#include <sys/types.h> |
48 |
#include <sys/types.h> |
48 |
#include <regex.h> |
|
|
49 |
|
49 |
|
50 |
/* This probably needs to change for different applications */ |
50 |
/* This probably needs to change for different applications */ |
Lines 68-71
Link Here
|
68 |
apr_pool_t *pool; |
68 |
apr_pool_t *pool; |
69 |
const char *params; |
69 |
const char *params; |
|
|
70 |
const char *lasterror; |
70 |
RETCODE err; |
71 |
RETCODE err; |
71 |
}; |
72 |
}; |
Lines 81-98
Link Here
|
81 |
struct apr_dbd_row_t { |
82 |
struct apr_dbd_row_t { |
82 |
apr_dbd_results_t *res; |
83 |
apr_dbd_results_t *res; |
83 |
BYTE buf[MAX_COL_LEN]; |
84 |
apr_pool_t *pool; |
84 |
}; |
85 |
}; |
85 |
|
86 |
|
86 |
struct apr_dbd_prepared_t { |
87 |
struct apr_dbd_prepared_t { |
87 |
int nargs; |
88 |
int nargs; |
88 |
regex_t **taint; |
89 |
int fmtlen; |
89 |
int *sz; |
90 |
const char *fmt, *label; |
90 |
char *fmt; |
91 |
apr_dbd_type_e *types; |
|
|
92 |
int offsets[]; |
91 |
}; |
93 |
}; |
92 |
|
94 |
|
93 |
#define dbd_freetds_is_success(x) (x == SUCCEED) |
95 |
const apr_dbd_driver_t apr_dbd_freetds_driver; /* Forward declaration */ |
94 |
|
96 |
|
95 |
static int labelnum = 0; /* FIXME */ |
97 |
#define dbd_freetds_is_success(x) (x == SUCCEED) |
96 |
static regex_t dbd_freetds_find_arg; |
|
|
97 |
|
98 |
|
98 |
/* execute a query that doesn't return a result set, mop up, |
99 |
/* execute a query that doesn't return a result set, mop up, |
Lines 103-107
Link Here
|
103 |
{ |
104 |
{ |
104 |
/* TBD */ |
105 |
/* TBD */ |
105 |
RETCODE rv = dbcmd(proc, query); |
106 |
RETCODE rv = dbcmd(proc, |
|
|
107 |
#ifndef TDS_STATIC_CAST /* if not compiling against FreeTDS, drop const :-( */ |
108 |
(char *) |
109 |
#endif |
110 |
query); |
106 |
if (rv != SUCCEED) { |
111 |
if (rv != SUCCEED) { |
107 |
return rv; |
112 |
return rv; |
Lines 144-147
Link Here
|
144 |
*/ |
149 |
*/ |
145 |
|
150 |
|
|
|
151 |
sql->lasterror = NULL; |
146 |
sql->err = freetds_exec(sql->proc, query, 1, NULL); |
152 |
sql->err = freetds_exec(sql->proc, query, 1, NULL); |
147 |
if (!dbd_freetds_is_success(sql->err)) { |
153 |
if (!dbd_freetds_is_success(sql->err)) { |
Lines 191-239
Link Here
|
191 |
return (sql->err == SUCCEED) ? 0 : 1; |
197 |
return (sql->err == SUCCEED) ? 0 : 1; |
192 |
} |
198 |
} |
193 |
static const char *dbd_untaint(apr_pool_t *pool, regex_t *rx, const char *val) |
199 |
|
194 |
{ |
|
|
195 |
regmatch_t match[1]; |
196 |
if (rx == NULL) { |
197 |
/* no untaint expression */ |
198 |
return val; |
199 |
} |
200 |
if (regexec(rx, val, 1, match, 0) == 0) { |
201 |
return apr_pstrndup(pool, val+match[0].rm_so, |
202 |
match[0].rm_eo - match[0].rm_so); |
203 |
} |
204 |
return ""; |
205 |
} |
206 |
static const char *dbd_statement(apr_pool_t *pool, |
200 |
static const char *dbd_statement(apr_pool_t *pool, |
207 |
apr_dbd_prepared_t *stmt, |
201 |
const apr_dbd_prepared_t *stmt, |
208 |
int nargs, const char **args) |
202 |
const char **args) |
209 |
{ |
203 |
{ |
210 |
int i; |
204 |
int i; |
211 |
int len; |
205 |
int len; |
212 |
const char *var; |
|
|
213 |
char *ret; |
206 |
char *ret; |
214 |
const char *p_in; |
207 |
const char *p_in, *format; |
215 |
char *p_out; |
208 |
char *p_out; |
216 |
char *q; |
|
|
217 |
|
209 |
|
218 |
/* compute upper bound on length (since untaint shrinks) */ |
210 |
len = stmt->fmtlen; |
219 |
len = strlen(stmt->fmt) +1; |
211 |
for (i=0; i < stmt->nargs; ++i) { |
220 |
for (i=0; i<nargs; ++i) { |
212 |
len += strlen(args[i]); |
221 |
len += strlen(args[i]) - 2; |
213 |
switch (stmt->types[i]) { |
|
|
214 |
case APR_DBD_TYPE_STRING: len += 2; break; /* For the quotes */ |
215 |
default: break;/* Other types are all taken verbatim at the moment */ |
216 |
} |
222 |
} |
217 |
} |
223 |
i = 0; |
|
|
224 |
p_in = stmt->fmt; |
218 |
p_in = stmt->fmt; |
225 |
p_out = ret = apr_palloc(pool, len); |
219 |
p_out = ret = apr_palloc(pool, len); |
226 |
/* FIXME silly bug - this'll catch %%s */ |
220 |
for (i = 0; i < stmt->nargs; i++) { |
227 |
while (q = strstr(p_in, "%s"), q != NULL) { |
221 |
len = stmt->offsets[i]; |
228 |
len = q-p_in; |
222 |
switch (stmt->types[i]) { |
229 |
strncpy(p_out, p_in, len); |
223 |
case APR_DBD_TYPE_STRING: |
230 |
p_in += len; |
224 |
format = "%.*s'%s'"; |
231 |
p_out += len; |
225 |
break; |
232 |
var = dbd_untaint(pool, stmt->taint[i], args[i]); |
226 |
default: |
233 |
len = strlen(var); |
227 |
format = "%.*s%s"; |
234 |
strncpy(p_out, var, len); |
228 |
} |
235 |
p_in += 2; |
229 |
p_out += sprintf(p_out, format, len, p_in, args[i]); |
236 |
p_out += len; |
230 |
p_in += (len + 1); |
237 |
++i; |
|
|
238 |
} |
231 |
} |
239 |
strcpy(p_out, p_in); |
232 |
strcpy(p_out, p_in); |
Lines 245-250
Link Here
|
245 |
int seek, const char **values) |
238 |
int seek, const char **values) |
246 |
{ |
239 |
{ |
247 |
const char *query = dbd_statement(pool, statement, |
240 |
const char *query = dbd_statement(pool, statement, values); |
248 |
statement->nargs, values); |
|
|
249 |
return dbd_freetds_select(pool, sql, results, query, seek); |
241 |
return dbd_freetds_select(pool, sql, results, query, seek); |
250 |
} |
242 |
} |
Lines 274-279
Link Here
|
274 |
const char **values) |
266 |
const char **values) |
275 |
{ |
267 |
{ |
276 |
const char *query = dbd_statement(pool, statement, |
268 |
const char *query = dbd_statement(pool, statement, values); |
277 |
statement->nargs, values); |
|
|
278 |
return dbd_freetds_query(sql, nrows, query); |
269 |
return dbd_freetds_query(sql, nrows, query); |
279 |
} |
270 |
} |
Lines 302-305
Link Here
|
302 |
apr_dbd_row_t *row = *rowp; |
293 |
apr_dbd_row_t *row = *rowp; |
303 |
int sequential = ((rownum >= 0) && res->random) ? 0 : 1; |
294 |
int sequential = ((rownum >= 0) && res->random) ? 0 : 1; |
|
|
295 |
apr_dbd_t *sql = (void *)dbgetuserdata(res->proc); |
304 |
|
296 |
|
305 |
if (row == NULL) { |
297 |
if (row == NULL) { |
Lines 307-310
Link Here
|
307 |
*rowp = row; |
299 |
*rowp = row; |
308 |
row->res = res; |
300 |
row->res = res; |
|
|
301 |
row->pool = pool; /* For subsequent calls to get_entry */ |
309 |
} |
302 |
} |
310 |
/* |
303 |
/* |
Lines 322-325
Link Here
|
322 |
} |
315 |
} |
323 |
else { |
316 |
else { |
|
|
317 |
/* XXX dbgetrow() only works if DBBUFFER-option is set */ |
324 |
rv = (rownum >= 0) ? dbgetrow(res->proc, rownum) : NO_MORE_ROWS; |
318 |
rv = (rownum >= 0) ? dbgetrow(res->proc, rownum) : NO_MORE_ROWS; |
325 |
} |
319 |
} |
Lines 328-337
Link Here
|
328 |
case REG_ROW: return 0; |
322 |
case REG_ROW: return 0; |
329 |
case NO_MORE_ROWS: |
323 |
case NO_MORE_ROWS: |
330 |
apr_pool_cleanup_run(pool, res->proc, clear_result); |
324 |
if (dbisopt(res->proc, DBBUFFER, NULL) || sequential) { |
|
|
325 |
sql->lasterror = apr_pstrcat(sql->pool, |
326 |
"NO_MORE_ROWS (count: ", apr_itoa(sql->pool, DBCOUNT(res->proc)), |
327 |
", first: ", apr_itoa(sql->pool, DBFIRSTROW(res->proc)), |
328 |
", current: ", apr_itoa(sql->pool, DBCURROW(res->proc)), |
329 |
", last: ", apr_itoa(sql->pool, DBLASTROW(res->proc)), |
330 |
")", NULL);; |
331 |
} else { |
332 |
sql->lasterror = "NO_MORE_ROWS (DBBUFFER option must be on " |
333 |
"for dbgetrow() to work)"; |
334 |
} |
335 |
apr_pool_cleanup_run(res->pool, res->proc, clear_result); |
331 |
*rowp = NULL; |
336 |
*rowp = NULL; |
332 |
return -1; |
337 |
return -1; |
333 |
case FAIL: return 1; |
338 |
case FAIL: |
334 |
case BUF_FULL: return 2; /* FIXME */ |
339 |
sql->lasterror = "FAIL"; |
335 |
default: return 3; |
340 |
return 1; |
|
|
341 |
case BUF_FULL: |
342 |
sql->lasterror = "BUF_FULL"; |
343 |
return 2; /* FIXME */ |
344 |
default: |
345 |
sql->lasterror = apr_pstrcat(res->pool, |
346 |
"Unexpected error number ", apr_itoa(res->pool, rv), NULL); |
347 |
return 3; |
336 |
} |
348 |
} |
337 |
|
349 |
|
Lines 341-355
Link Here
|
341 |
static const char *dbd_freetds_get_entry(const apr_dbd_row_t *row, int n) |
353 |
static const char *dbd_freetds_get_entry(const apr_dbd_row_t *row, int n) |
342 |
{ |
354 |
{ |
343 |
/* FIXME: support different data types */ |
|
|
344 |
/* this fails - bind gets some vars but not others |
345 |
return (const char*)row->res->vars[n].data; |
346 |
*/ |
347 |
DBPROCESS* proc = row->res->proc; |
355 |
DBPROCESS* proc = row->res->proc; |
348 |
BYTE *ptr = dbdata(proc, n+1); |
356 |
BYTE *ptr = dbdata(proc, n+1); /* XXX No error checking! */ |
349 |
int t = dbcoltype(proc, n+1); |
357 |
int t = dbcoltype(proc, n+1); |
350 |
int l = dbcollen(proc, n+1); |
358 |
int l = dbdatlen(proc, n+1); |
|
|
359 |
if (l == -1) |
360 |
return NULL; |
351 |
if (dbwillconvert(t, SYBCHAR)) { |
361 |
if (dbwillconvert(t, SYBCHAR)) { |
352 |
dbconvert(proc, t, ptr, l, SYBCHAR, (BYTE *)row->buf, -1); |
362 |
char *buf = apr_palloc(row->pool, l + 1); |
353 |
return (const char*)row->buf; |
363 |
dbconvert(proc, t, ptr, l, SYBCHAR, buf, -1); |
|
|
364 |
return buf; |
354 |
} |
365 |
} |
355 |
return (char*)ptr; |
366 |
return (char*)ptr; |
Lines 358-362
Link Here
|
358 |
static const char *dbd_freetds_error(apr_dbd_t *sql, int n) |
369 |
static const char *dbd_freetds_error(apr_dbd_t *sql, int n) |
359 |
{ |
370 |
{ |
360 |
/* XXX this doesn't seem to exist in the API ??? */ |
371 |
const char *err = sql->lasterror; |
|
|
372 |
|
373 |
sql->lasterror = NULL; /* Reset, so we stop appending */ |
374 |
if (err) |
375 |
return err; |
361 |
return apr_psprintf(sql->pool, "Error %d", sql->err); |
376 |
return apr_psprintf(sql->pool, "Error %d", sql->err); |
362 |
} |
377 |
} |
Lines 368-371
Link Here
|
368 |
} |
383 |
} |
369 |
*nrows = 0; |
384 |
*nrows = 0; |
|
|
385 |
sql->lasterror = NULL; |
370 |
sql->err = freetds_exec(sql->proc, query, 0, nrows); |
386 |
sql->err = freetds_exec(sql->proc, query, 0, nrows); |
371 |
|
387 |
|
Lines 385-449
Link Here
|
385 |
} |
401 |
} |
386 |
|
402 |
|
387 |
static apr_status_t freetds_regfree(void *rx) |
|
|
388 |
{ |
389 |
regfree((regex_t*)rx); |
390 |
return APR_SUCCESS; |
391 |
} |
392 |
static int recurse_args(apr_pool_t *pool, int n, const char *query, |
393 |
apr_dbd_prepared_t *stmt, int offs) |
394 |
{ |
395 |
|
396 |
/* we only support %s arguments for now */ |
397 |
int ret; |
398 |
char arg[256]; |
399 |
regmatch_t matches[3]; |
400 |
if (regexec(&dbd_freetds_find_arg, query, 3, matches, 0) != 0) { |
401 |
/* No more args */ |
402 |
stmt->nargs = n; |
403 |
stmt->taint = apr_palloc(pool, n*sizeof(regex_t*)); |
404 |
stmt->sz = apr_palloc(pool, n*sizeof(int)); |
405 |
ret = 0; |
406 |
} |
407 |
else { |
408 |
int i; |
409 |
int sz = 0; |
410 |
int len = matches[1].rm_eo - matches[1].rm_so - 2; |
411 |
if (len > 255) { |
412 |
return 9999; |
413 |
} |
414 |
|
415 |
ret = recurse_args(pool, n+1, query+matches[0].rm_eo, |
416 |
stmt, offs+matches[0].rm_eo); |
417 |
|
418 |
memmove(stmt->fmt + offs + matches[1].rm_so, |
419 |
stmt->fmt + offs + matches[0].rm_eo-1, |
420 |
strlen(stmt->fmt+offs+matches[0].rm_eo)+2); |
421 |
|
422 |
/* compile untaint to a regex if found */ |
423 |
if (matches[1].rm_so == -1) { |
424 |
stmt->taint[n] = NULL; |
425 |
} |
426 |
else { |
427 |
strncpy(arg, query+matches[1].rm_so+1, |
428 |
matches[1].rm_eo - matches[1].rm_so - 2); |
429 |
arg[matches[1].rm_eo - matches[1].rm_so - 2] = '\0'; |
430 |
stmt->taint[n] = apr_palloc(pool, sizeof(regex_t)); |
431 |
if (regcomp(stmt->taint[n], arg, REG_ICASE|REG_EXTENDED) != 0) { |
432 |
++ret; |
433 |
} |
434 |
else { |
435 |
apr_pool_cleanup_register(pool, stmt->taint[n], freetds_regfree, |
436 |
apr_pool_cleanup_null); |
437 |
} |
438 |
} |
439 |
|
440 |
/* record length if specified */ |
441 |
for (i=matches[2].rm_so; i<matches[2].rm_eo; ++i) { |
442 |
sz = 10*sz + (query[i]-'\0'); |
443 |
} |
444 |
} |
445 |
return ret; |
446 |
} |
447 |
|
448 |
static int dbd_freetds_prepare(apr_pool_t *pool, apr_dbd_t *sql, |
403 |
static int dbd_freetds_prepare(apr_pool_t *pool, apr_dbd_t *sql, |
449 |
const char *query, const char *label, |
404 |
const char *query, const char *label, |
Lines 451-496
Link Here
|
451 |
apr_dbd_prepared_t **statement) |
406 |
apr_dbd_prepared_t **statement) |
452 |
{ |
407 |
{ |
|
|
408 |
int i; |
409 |
const char *p, *op; |
453 |
apr_dbd_prepared_t *stmt; |
410 |
apr_dbd_prepared_t *stmt; |
454 |
|
411 |
|
455 |
if (label == NULL) { |
412 |
if (!*statement && |
456 |
label = apr_psprintf(pool, "%d", labelnum++); |
413 |
(*statement = apr_palloc(pool, |
|
|
414 |
sizeof(apr_dbd_prepared_t) + nargs*sizeof(int))) == NULL) { |
415 |
return APR_EGENERAL; |
457 |
} |
416 |
} |
458 |
|
417 |
|
459 |
if (!*statement) { |
|
|
460 |
*statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t)); |
461 |
} |
462 |
stmt = *statement; |
418 |
stmt = *statement; |
|
|
419 |
stmt->nargs = nargs; |
420 |
stmt->fmt = query; |
421 |
stmt->fmtlen = strlen(query) - nargs + 1; |
422 |
stmt->types = types; |
423 |
stmt->label = label; /* XXX Not used anywhere at the moment */ |
463 |
|
424 |
|
464 |
#if 0 |
425 |
/* |
465 |
/* count args */ |
426 |
* Run through the query-template looking for the special character, |
466 |
stmt->fmt = apr_pstrdup(pool, query); |
427 |
* which the dbd_prepare inserted into it on our behalf |
467 |
stmt->fmt = recurse_args(pool, 0, query, stmt, stmt->fmt); |
428 |
*/ |
468 |
|
429 |
for (i = 0, op = query; i < nargs; i++) { |
469 |
/* overestimate by a byte or two to simplify */ |
430 |
p = strchr(op, apr_dbd_freetds_driver.pformat[0]); |
470 |
len = strlen("CREATE PROC apr.") |
431 |
stmt->offsets[i] = p - op; |
471 |
+ strlen(label) |
432 |
op = p + 1; |
472 |
+ stmt->nargs * strlen(" @arg1 varchar(len1),") |
433 |
} |
473 |
+ strlen(" AS begin ") |
|
|
474 |
+ strlen(stmt->fmt) |
475 |
+ strlen(" end "); /* extra byte for terminator */ |
476 |
|
477 |
pquery = apr_pcalloc(pool, len); |
478 |
sprintf(pquery, "CREATE PROC apr.%s", label); |
479 |
for (i=0; i<stmt->nargs; ++i) { |
480 |
sprintf(pquery+strlen(pquery), " @arg%d varchar(%d)", i, stmt->sz[i]); |
481 |
if (i < stmt->nargs-1) { |
482 |
pquery[strlen(pquery)] = ','; |
483 |
} |
484 |
} |
485 |
strcat(pquery, " AS BEGIN "); |
486 |
strcat(pquery, stmt->fmt); |
487 |
strcat(pquery, " END"); |
488 |
|
489 |
return (freetds_exec(sql->proc, pquery, 0, &i) == SUCCEED) ? 0 : 1; |
490 |
#else |
491 |
stmt->fmt = apr_pstrdup(pool, query); |
492 |
return recurse_args(pool, 0, query, stmt, 0); |
493 |
#endif |
494 |
|
434 |
|
|
|
435 |
return APR_SUCCESS; |
495 |
} |
436 |
} |
496 |
|
437 |
|
Lines 542-548
Link Here
|
542 |
LOGINREC *login; |
483 |
LOGINREC *login; |
543 |
static const char *delims = " \r\n\t;|,"; |
484 |
static const char *delims = " \r\n\t;|,"; |
544 |
char *ptr; |
485 |
const char *ptr; |
545 |
char *key; |
486 |
const char *key; |
546 |
char *value; |
487 |
const char *value; |
547 |
int vlen; |
488 |
int vlen; |
548 |
int klen; |
489 |
int klen; |
Lines 565-569
Link Here
|
565 |
for (key = ptr-1; apr_isspace(*key); --key); |
506 |
for (key = ptr-1; apr_isspace(*key); --key); |
566 |
klen = 0; |
507 |
klen = 0; |
567 |
while (apr_isalpha(*key)) { |
508 |
while (key >= params && apr_isalpha(*key)) { |
568 |
--key; |
509 |
--key; |
569 |
++klen; |
510 |
++klen; |
Lines 628-635
Link Here
|
628 |
return NULL; |
569 |
return NULL; |
629 |
} |
570 |
} |
630 |
sql = apr_palloc (pool, sizeof (apr_dbd_t)); |
571 |
sql = apr_pcalloc(pool, sizeof (apr_dbd_t)); |
631 |
sql->pool = pool; |
572 |
sql->pool = pool; |
632 |
sql->proc = process; |
573 |
sql->proc = process; |
633 |
sql->params = params; |
574 |
sql->params = params; |
|
|
575 |
dbsetuserdata(process, (BYTE *)sql); |
634 |
return sql; |
576 |
return sql; |
635 |
} |
577 |
} |
Lines 687-708
Link Here
|
687 |
{ |
629 |
{ |
688 |
dbexit(); |
630 |
dbexit(); |
689 |
regfree(&dbd_freetds_find_arg); |
|
|
690 |
return APR_SUCCESS; |
631 |
return APR_SUCCESS; |
691 |
} |
632 |
} |
|
|
633 |
|
634 |
static int freetds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, |
635 |
int severity, char *msgtext, char *srvname, |
636 |
char *procname, int line) |
637 |
{ |
638 |
char *value; |
639 |
apr_dbd_t *sql; |
640 |
|
641 |
if (dbproc == NULL || (sql = (void *)dbgetuserdata(dbproc)) == NULL) { |
642 |
/* Initial messages are not interesting */ |
643 |
return 0; |
644 |
} |
645 |
|
646 |
value = apr_psprintf(sql->pool, "%s: %s", srvname, msgtext); |
647 |
if (procname && procname[0]) |
648 |
value = apr_pstrcat(sql->pool, value, " In procedure ", |
649 |
procname, NULL); |
650 |
if (line) |
651 |
value = apr_pstrcat(sql->pool, value, |
652 |
procname && procname[0] ? ", line " : " Line ", |
653 |
apr_itoa(sql->pool, line), NULL); |
654 |
|
655 |
if (sql->lasterror) |
656 |
sql->lasterror = apr_pstrcat(sql->pool, sql->lasterror, "\n", value, NULL); |
657 |
else |
658 |
sql->lasterror = value; |
659 |
|
660 |
return 0; |
661 |
} |
662 |
|
692 |
static int freetds_err_handler(DBPROCESS *dbproc, int severity, int dberr, |
663 |
static int freetds_err_handler(DBPROCESS *dbproc, int severity, int dberr, |
693 |
int oserr, char *dberrstr, char *oserrstr) |
664 |
int oserr, char *dberrstr, char *oserrstr) |
694 |
{ |
665 |
{ |
|
|
666 |
char *value; |
667 |
apr_dbd_t *sql; |
668 |
|
669 |
if (dbproc == NULL || (sql = (void *)dbgetuserdata(dbproc)) == NULL) { |
670 |
fprintf(stderr, "%s\n", dberrstr); |
671 |
return INT_CANCEL; |
672 |
} |
673 |
/* |
674 |
* Do not append the useless "general error", if details |
675 |
* are already recorded (by the msg_handler). Just return. |
676 |
* XXX: this skipping currently only works with Sybase's OpenClient |
677 |
* XXX: because FreeTDS implementation uses bogus dberr values: |
678 |
* XXX: https://sourceforge.net/tracker/?func=detail&aid=3555777&group_id=33106&atid=407806 |
679 |
*/ |
680 |
if (dberr == SYBESMSG && sql->lasterror) |
681 |
return INT_CANCEL; |
682 |
|
683 |
value = apr_psprintf(sql->pool, "%d: %s", dberr, dberrstr); |
684 |
if (oserrstr) { |
685 |
value = apr_pstrcat(sql->pool, ". (", oserrstr, ")", NULL); |
686 |
} |
687 |
if (sql->lasterror) |
688 |
sql->lasterror = apr_pstrcat(sql->pool, sql->lasterror, "\n", value, NULL); |
689 |
else |
690 |
sql->lasterror = value; |
695 |
return INT_CANCEL; /* never exit */ |
691 |
return INT_CANCEL; /* never exit */ |
696 |
} |
692 |
} |
697 |
static void dbd_freetds_init(apr_pool_t *pool) |
693 |
static void dbd_freetds_init(apr_pool_t *pool) |
698 |
{ |
694 |
{ |
699 |
int rv = regcomp(&dbd_freetds_find_arg, |
695 |
if (dbinit() == FAIL) |
700 |
"%(\\{[^}]*\\})?([0-9]*)[A-Za-z]", REG_EXTENDED); |
696 |
fprintf(stderr, "dbinit() failed\n"); |
701 |
if (rv != 0) { |
697 |
dbmsghandle(freetds_msg_handler); |
702 |
char errmsg[256]; |
|
|
703 |
regerror(rv, &dbd_freetds_find_arg, errmsg, 256); |
704 |
fprintf(stderr, "regcomp failed: %s\n", errmsg); |
705 |
} |
706 |
dbinit(); |
707 |
dberrhandle(freetds_err_handler); |
698 |
dberrhandle(freetds_err_handler); |
708 |
apr_pool_cleanup_register(pool, NULL, freetds_term, apr_pool_cleanup_null); |
699 |
apr_pool_cleanup_register(pool, NULL, freetds_term, apr_pool_cleanup_null); |
Lines 766-770
Link Here
|
766 |
|
757 |
|
767 |
APU_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_freetds_driver = { |
758 |
APU_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_freetds_driver = { |
|
|
759 |
#ifndef TI_MODULE_NAME |
768 |
"freetds", |
760 |
"freetds", |
|
|
761 |
#else |
762 |
TI_MODULE_NAME, |
763 |
#endif |
769 |
dbd_freetds_init, |
764 |
dbd_freetds_init, |
770 |
dbd_freetds_native, |
765 |
dbd_freetds_native, |
Lines 788-799
Link Here
|
788 |
dbd_freetds_pquery, |
783 |
dbd_freetds_pquery, |
789 |
dbd_freetds_pselect, |
784 |
dbd_freetds_pselect, |
790 |
/* this is only implemented to support httpd/2.2 standard usage, |
|
|
791 |
* as in the original DBD implementation. Everything else is NOTIMPL. |
792 |
*/ |
793 |
#ifdef COMPILE_STUBS |
794 |
dbd_freetds_get_name, |
785 |
dbd_freetds_get_name, |
795 |
dbd_freetds_transaction_mode_get, |
786 |
dbd_freetds_transaction_mode_get, |
796 |
dbd_freetds_transaction_mode_set, |
787 |
dbd_freetds_transaction_mode_set, |
797 |
"", |
788 |
"\1", /* Would not occur in a real query... */ |
798 |
dbd_freetds_pvbquery, |
789 |
dbd_freetds_pvbquery, |
799 |
dbd_freetds_pvbselect, |
790 |
dbd_freetds_pvbselect, |
Lines 801-805
Link Here
|
801 |
dbd_freetds_pbselect, |
792 |
dbd_freetds_pbselect, |
802 |
dbd_freetds_datum_get |
793 |
dbd_freetds_datum_get |
803 |
#endif |
|
|
804 |
}; |
794 |
}; |
805 |
#endif |
795 |
#endif |