diff options
author | Olli Hauer <ohauer@FreeBSD.org> | 2013-01-13 22:26:01 +0000 |
---|---|---|
committer | Olli Hauer <ohauer@FreeBSD.org> | 2013-01-13 22:26:01 +0000 |
commit | 0fff18ce57b2c16c992b0de553605ef1403e6042 (patch) | |
tree | 284046f66022efdde567a16b1a147e976ea41759 /devel | |
parent | ae655e5d4af7e69d3921ce2ea5ee85460e18191f (diff) | |
download | ports-0fff18ce57b2c16c992b0de553605ef1403e6042.tar.gz ports-0fff18ce57b2c16c992b0de553605ef1403e6042.zip |
Notes
Diffstat (limited to 'devel')
-rw-r--r-- | devel/apr1/Makefile | 17 | ||||
-rw-r--r-- | devel/apr1/files/patch-apr-util__dbd__apr_dbd_freetds.c | 560 | ||||
-rw-r--r-- | devel/apr1/pkg-plist | 4 |
3 files changed, 576 insertions, 5 deletions
diff --git a/devel/apr1/Makefile b/devel/apr1/Makefile index 2dbfe298d41e..0788069e3a99 100644 --- a/devel/apr1/Makefile +++ b/devel/apr1/Makefile @@ -19,7 +19,7 @@ MAKE_JOBS_SAFE= yes NO_OPTIONS_SORT=yes OPTIONS_GROUP= APR APU OPTIONS_GROUP_APR= THREADS IPV6 DEVRANDOM -OPTIONS_GROUP_APU= BDB GDBM LDAP MYSQL NDBM PGSQL SQLITE +OPTIONS_GROUP_APU= BDB GDBM LDAP MYSQL NDBM PGSQL SQLITE FREETDS OPTIONS_RADIO= CRYPTO OPTIONS_RADIO_CRYPTO= SSL OPTIONS_DEFAULT= THREADS IPV6 DEVRANDOM BDB GDBM SSL @@ -115,6 +115,16 @@ PLIST_SUB+= LDAP="@comment " APU_CONF_ARGS+= --without-ldap .endif +.if ${PORT_OPTIONS:MFREETDS} +APU_EXTRAS= yes +PLIST_SUB+= FREETDS="" +APU_CONF_ARGS+= --with-freetds=${LOCALBASE} +LIB_DEPENDS= sybdb:${PORTSDIR}/databases/freetds +.else +PLIST_SUB+= FREETDS="@comment " +APU_CONF_ARGS+= --without-freetds +.endif + .if ${PORT_OPTIONS:MMYSQL} APU_EXTRAS= yes PLIST_SUB+= MYSQL="" @@ -185,7 +195,7 @@ PLIST_SUB+= APU_EXTRAS="" PLIST_SUB+= APU_EXTRAS="@comment " .endif -post-patch: +post-patch: .SILENT ${REINPLACE_CMD} -e 's/OSVERSION/${OSVERSION}/g' \ ${APR_WRKDIR}/build/apr_hints.m4 ${FIND} ${APR_WRKDIR} ${APU_WRKDIR} -name "Makefile.in*" | ${XARGS} ${REINPLACE_CMD} -e \ @@ -197,9 +207,6 @@ post-patch: ${APR_WRKDIR}/build/gen-build.py ${REINPLACE_CMD} -e 's/void main/int main/' ${APR_WRKDIR}/build/apr_network.m4 -# http://svn.apache.org/viewvc?view=revision&revision=1362895 - ${REINPLACE_CMD} -e 's|sql = apr_palloc|sql = apr_pcalloc|' ${APU_WRKDIR}/dbd/apr_dbd_freetds.c - run-autotools:: cd ${APR_WRKDIR} ; \ ${SETENV} ${CONFIGURE_ENV} ${SH} ./buildconf diff --git a/devel/apr1/files/patch-apr-util__dbd__apr_dbd_freetds.c b/devel/apr1/files/patch-apr-util__dbd__apr_dbd_freetds.c new file mode 100644 index 000000000000..b1ca50ebfd11 --- /dev/null +++ b/devel/apr1/files/patch-apr-util__dbd__apr_dbd_freetds.c @@ -0,0 +1,560 @@ +# http://lists.freebsd.org/pipermail/freebsd-apache/2013-January/003020.html +# +# From: "Mikhail T." <mi+thun@aldan.algebra.com> +# I've made the FreeTDS-driver work again -- and submitted the patch to Apache: +# https://issues.apache.org/bugzilla/show_bug.cgi?id=53666 +=================================================================================== +--- ./apr-util-1.4.1/dbd/apr_dbd_freetds.c.orig 2009-02-13 07:04:00.000000000 +0100 ++++ ./apr-util-1.4.1/dbd/apr_dbd_freetds.c 2013-01-13 22:17:09.000000000 +0100 +@@ -40,12 +40,12 @@ + #include <freetds/sybdb.h> + #endif + #ifdef HAVE_SYBDB_H ++#include <sybfront.h> + #include <sybdb.h> + #endif + + #include <stdio.h> + #include <sys/types.h> +-#include <regex.h> + + /* This probably needs to change for different applications */ + #define MAX_COL_LEN 256 +@@ -67,6 +67,7 @@ + apr_dbd_transaction_t *trans; + apr_pool_t *pool; + const char *params; ++ const char *lasterror; + RETCODE err; + }; + +@@ -80,20 +81,20 @@ + + struct apr_dbd_row_t { + apr_dbd_results_t *res; +- BYTE buf[MAX_COL_LEN]; ++ apr_pool_t *pool; + }; + + struct apr_dbd_prepared_t { + int nargs; +- regex_t **taint; +- int *sz; +- char *fmt; ++ int fmtlen; ++ const char *fmt, *label; ++ apr_dbd_type_e *types; ++ int offsets[]; + }; + +-#define dbd_freetds_is_success(x) (x == SUCCEED) ++const apr_dbd_driver_t apr_dbd_freetds_driver; /* Forward declaration */ + +-static int labelnum = 0; /* FIXME */ +-static regex_t dbd_freetds_find_arg; ++#define dbd_freetds_is_success(x) (x == SUCCEED) + + /* execute a query that doesn't return a result set, mop up, + * and return and APR-flavoured status +@@ -102,7 +103,11 @@ + int want_results, int *nrows) + { + /* TBD */ +- RETCODE rv = dbcmd(proc, query); ++ RETCODE rv = dbcmd(proc, ++#ifndef TDS_STATIC_CAST /* if not compiling against FreeTDS, drop const :-( */ ++ (char *) ++#endif ++ query); + if (rv != SUCCEED) { + return rv; + } +@@ -143,6 +148,7 @@ + * Ignore seek + */ + ++ sql->lasterror = NULL; + sql->err = freetds_exec(sql->proc, query, 1, NULL); + if (!dbd_freetds_is_success(sql->err)) { + if (sql->trans) { +@@ -190,51 +196,38 @@ + #endif + return (sql->err == SUCCEED) ? 0 : 1; + } +-static const char *dbd_untaint(apr_pool_t *pool, regex_t *rx, const char *val) +-{ +- regmatch_t match[1]; +- if (rx == NULL) { +- /* no untaint expression */ +- return val; +- } +- if (regexec(rx, val, 1, match, 0) == 0) { +- return apr_pstrndup(pool, val+match[0].rm_so, +- match[0].rm_eo - match[0].rm_so); +- } +- return ""; +-} ++ + static const char *dbd_statement(apr_pool_t *pool, +- apr_dbd_prepared_t *stmt, +- int nargs, const char **args) ++ const apr_dbd_prepared_t *stmt, ++ const char **args) + { + int i; + int len; +- const char *var; + char *ret; +- const char *p_in; ++ const char *p_in, *format; + char *p_out; +- char *q; + +- /* compute upper bound on length (since untaint shrinks) */ +- len = strlen(stmt->fmt) +1; +- for (i=0; i<nargs; ++i) { +- len += strlen(args[i]) - 2; ++ len = stmt->fmtlen; ++ for (i=0; i < stmt->nargs; ++i) { ++ len += strlen(args[i]); ++ switch (stmt->types[i]) { ++ case APR_DBD_TYPE_STRING: len += 2; break; /* For the quotes */ ++ default: break;/* Other types are all taken verbatim at the moment */ ++ } + } +- i = 0; + p_in = stmt->fmt; + p_out = ret = apr_palloc(pool, len); +- /* FIXME silly bug - this'll catch %%s */ +- while (q = strstr(p_in, "%s"), q != NULL) { +- len = q-p_in; +- strncpy(p_out, p_in, len); +- p_in += len; +- p_out += len; +- var = dbd_untaint(pool, stmt->taint[i], args[i]); +- len = strlen(var); +- strncpy(p_out, var, len); +- p_in += 2; +- p_out += len; +- ++i; ++ for (i = 0; i < stmt->nargs; i++) { ++ len = stmt->offsets[i]; ++ switch (stmt->types[i]) { ++ case APR_DBD_TYPE_STRING: ++ format = "%.*s'%s'"; ++ break; ++ default: ++ format = "%.*s%s"; ++ } ++ p_out += sprintf(p_out, format, len, p_in, args[i]); ++ p_in += (len + 1); + } + strcpy(p_out, p_in); + return ret; +@@ -244,8 +237,7 @@ + apr_dbd_prepared_t *statement, + int seek, const char **values) + { +- const char *query = dbd_statement(pool, statement, +- statement->nargs, values); ++ const char *query = dbd_statement(pool, statement, values); + return dbd_freetds_select(pool, sql, results, query, seek); + } + static int dbd_freetds_pvselect(apr_pool_t *pool, apr_dbd_t *sql, +@@ -273,8 +265,7 @@ + int *nrows, apr_dbd_prepared_t *statement, + const char **values) + { +- const char *query = dbd_statement(pool, statement, +- statement->nargs, values); ++ const char *query = dbd_statement(pool, statement, values); + return dbd_freetds_query(sql, nrows, query); + } + static int dbd_freetds_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, +@@ -301,11 +292,13 @@ + RETCODE rv = 0; + apr_dbd_row_t *row = *rowp; + int sequential = ((rownum >= 0) && res->random) ? 0 : 1; ++ apr_dbd_t *sql = (void *)dbgetuserdata(res->proc); + + if (row == NULL) { + row = apr_palloc(pool, sizeof(apr_dbd_row_t)); + *rowp = row; + row->res = res; ++ row->pool = pool; /* For subsequent calls to get_entry */ + } + /* + else { +@@ -321,18 +314,37 @@ + rv = dbnextrow(res->proc); + } + else { ++ /* XXX dbgetrow() only works if DBBUFFER-option is set */ + rv = (rownum >= 0) ? dbgetrow(res->proc, rownum) : NO_MORE_ROWS; + } + switch (rv) { + case SUCCEED: return 0; + case REG_ROW: return 0; + case NO_MORE_ROWS: +- apr_pool_cleanup_run(pool, res->proc, clear_result); ++ if (dbisopt(res->proc, DBBUFFER, NULL) || sequential) { ++ sql->lasterror = apr_pstrcat(sql->pool, ++ "NO_MORE_ROWS (count: ", apr_itoa(sql->pool, DBCOUNT(res->proc)), ++ ", first: ", apr_itoa(sql->pool, DBFIRSTROW(res->proc)), ++ ", current: ", apr_itoa(sql->pool, DBCURROW(res->proc)), ++ ", last: ", apr_itoa(sql->pool, DBLASTROW(res->proc)), ++ ")", NULL);; ++ } else { ++ sql->lasterror = "NO_MORE_ROWS (DBBUFFER option must be on " ++ "for dbgetrow() to work)"; ++ } ++ apr_pool_cleanup_run(res->pool, res->proc, clear_result); + *rowp = NULL; + return -1; +- case FAIL: return 1; +- case BUF_FULL: return 2; /* FIXME */ +- default: return 3; ++ case FAIL: ++ sql->lasterror = "FAIL"; ++ return 1; ++ case BUF_FULL: ++ sql->lasterror = "BUF_FULL"; ++ return 2; /* FIXME */ ++ default: ++ sql->lasterror = apr_pstrcat(res->pool, ++ "Unexpected error number ", apr_itoa(res->pool, rv), NULL); ++ return 3; + } + + return 0; +@@ -340,24 +352,27 @@ + + static const char *dbd_freetds_get_entry(const apr_dbd_row_t *row, int n) + { +- /* FIXME: support different data types */ +- /* this fails - bind gets some vars but not others +- return (const char*)row->res->vars[n].data; +- */ + DBPROCESS* proc = row->res->proc; +- BYTE *ptr = dbdata(proc, n+1); ++ BYTE *ptr = dbdata(proc, n+1); /* XXX No error checking! */ + int t = dbcoltype(proc, n+1); +- int l = dbcollen(proc, n+1); ++ int l = dbdatlen(proc, n+1); ++ if (l == -1) ++ return NULL; + if (dbwillconvert(t, SYBCHAR)) { +- dbconvert(proc, t, ptr, l, SYBCHAR, (BYTE *)row->buf, -1); +- return (const char*)row->buf; ++ char *buf = apr_palloc(row->pool, l + 1); ++ dbconvert(proc, t, ptr, l, SYBCHAR, buf, -1); ++ return buf; + } + return (char*)ptr; + } + + static const char *dbd_freetds_error(apr_dbd_t *sql, int n) + { +- /* XXX this doesn't seem to exist in the API ??? */ ++ const char *err = sql->lasterror; ++ ++ sql->lasterror = NULL; /* Reset, so we stop appending */ ++ if (err) ++ return err; + return apr_psprintf(sql->pool, "Error %d", sql->err); + } + +@@ -367,6 +382,7 @@ + return sql->trans->errnum; + } + *nrows = 0; ++ sql->lasterror = NULL; + sql->err = freetds_exec(sql->proc, query, 0, nrows); + + if (sql->err != SUCCEED) { +@@ -384,114 +400,39 @@ + return arg; + } + +-static apr_status_t freetds_regfree(void *rx) +-{ +- regfree((regex_t*)rx); +- return APR_SUCCESS; +-} +-static int recurse_args(apr_pool_t *pool, int n, const char *query, +- apr_dbd_prepared_t *stmt, int offs) +-{ +- +- /* we only support %s arguments for now */ +- int ret; +- char arg[256]; +- regmatch_t matches[3]; +- if (regexec(&dbd_freetds_find_arg, query, 3, matches, 0) != 0) { +- /* No more args */ +- stmt->nargs = n; +- stmt->taint = apr_palloc(pool, n*sizeof(regex_t*)); +- stmt->sz = apr_palloc(pool, n*sizeof(int)); +- ret = 0; +- } +- else { +- int i; +- int sz = 0; +- int len = matches[1].rm_eo - matches[1].rm_so - 2; +- if (len > 255) { +- return 9999; +- } +- +- ret = recurse_args(pool, n+1, query+matches[0].rm_eo, +- stmt, offs+matches[0].rm_eo); +- +- memmove(stmt->fmt + offs + matches[1].rm_so, +- stmt->fmt + offs + matches[0].rm_eo-1, +- strlen(stmt->fmt+offs+matches[0].rm_eo)+2); +- +- /* compile untaint to a regex if found */ +- if (matches[1].rm_so == -1) { +- stmt->taint[n] = NULL; +- } +- else { +- strncpy(arg, query+matches[1].rm_so+1, +- matches[1].rm_eo - matches[1].rm_so - 2); +- arg[matches[1].rm_eo - matches[1].rm_so - 2] = '\0'; +- stmt->taint[n] = apr_palloc(pool, sizeof(regex_t)); +- if (regcomp(stmt->taint[n], arg, REG_ICASE|REG_EXTENDED) != 0) { +- ++ret; +- } +- else { +- apr_pool_cleanup_register(pool, stmt->taint[n], freetds_regfree, +- apr_pool_cleanup_null); +- } +- } +- +- /* record length if specified */ +- for (i=matches[2].rm_so; i<matches[2].rm_eo; ++i) { +- sz = 10*sz + (query[i]-'\0'); +- } +- } +- return ret; +-} +- + static int dbd_freetds_prepare(apr_pool_t *pool, apr_dbd_t *sql, + const char *query, const char *label, + int nargs, int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t **statement) + { ++ int i; ++ const char *p, *op; + apr_dbd_prepared_t *stmt; + +- if (label == NULL) { +- label = apr_psprintf(pool, "%d", labelnum++); ++ if (!*statement && ++ (*statement = apr_palloc(pool, ++ sizeof(apr_dbd_prepared_t) + nargs*sizeof(int))) == NULL) { ++ return APR_EGENERAL; + } + +- if (!*statement) { +- *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t)); +- } + stmt = *statement; ++ stmt->nargs = nargs; ++ stmt->fmt = query; ++ stmt->fmtlen = strlen(query) - nargs + 1; ++ stmt->types = types; ++ stmt->label = label; /* XXX Not used anywhere at the moment */ + +-#if 0 +- /* count args */ +- stmt->fmt = apr_pstrdup(pool, query); +- stmt->fmt = recurse_args(pool, 0, query, stmt, stmt->fmt); +- +- /* overestimate by a byte or two to simplify */ +- len = strlen("CREATE PROC apr.") +- + strlen(label) +- + stmt->nargs * strlen(" @arg1 varchar(len1),") +- + strlen(" AS begin ") +- + strlen(stmt->fmt) +- + strlen(" end "); /* extra byte for terminator */ +- +- pquery = apr_pcalloc(pool, len); +- sprintf(pquery, "CREATE PROC apr.%s", label); +- for (i=0; i<stmt->nargs; ++i) { +- sprintf(pquery+strlen(pquery), " @arg%d varchar(%d)", i, stmt->sz[i]); +- if (i < stmt->nargs-1) { +- pquery[strlen(pquery)] = ','; +- } ++ /* ++ * Run through the query-template looking for the special character, ++ * which the dbd_prepare inserted into it on our behalf ++ */ ++ for (i = 0, op = query; i < nargs; i++) { ++ p = strchr(op, apr_dbd_freetds_driver.pformat[0]); ++ stmt->offsets[i] = p - op; ++ op = p + 1; + } +- strcat(pquery, " AS BEGIN "); +- strcat(pquery, stmt->fmt); +- strcat(pquery, " END"); +- +- return (freetds_exec(sql->proc, pquery, 0, &i) == SUCCEED) ? 0 : 1; +-#else +- stmt->fmt = apr_pstrdup(pool, query); +- return recurse_args(pool, 0, query, stmt, 0); +-#endif + ++ return APR_SUCCESS; + } + + static int dbd_freetds_start_transaction(apr_pool_t *pool, apr_dbd_t *handle, +@@ -541,9 +482,9 @@ + DBPROCESS *process; + LOGINREC *login; + static const char *delims = " \r\n\t;|,"; +- char *ptr; +- char *key; +- char *value; ++ const char *ptr; ++ const char *key; ++ const char *value; + int vlen; + int klen; + char *buf; +@@ -564,7 +505,7 @@ + } + for (key = ptr-1; apr_isspace(*key); --key); + klen = 0; +- while (apr_isalpha(*key)) { ++ while (key >= params && apr_isalpha(*key)) { + --key; + ++klen; + } +@@ -627,10 +568,11 @@ + if (process == NULL) { + return NULL; + } +- sql = apr_palloc (pool, sizeof (apr_dbd_t)); ++ sql = apr_pcalloc(pool, sizeof (apr_dbd_t)); + sql->pool = pool; + sql->proc = process; + sql->params = params; ++ dbsetuserdata(process, (BYTE *)sql); + return sql; + } + +@@ -686,24 +628,73 @@ + static apr_status_t freetds_term(void *dummy) + { + dbexit(); +- regfree(&dbd_freetds_find_arg); + return APR_SUCCESS; + } ++ ++static int freetds_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, ++ int severity, char *msgtext, char *srvname, ++ char *procname, int line) ++{ ++ char *value; ++ apr_dbd_t *sql; ++ ++ if (dbproc == NULL || (sql = (void *)dbgetuserdata(dbproc)) == NULL) { ++ /* Initial messages are not interesting */ ++ return 0; ++ } ++ ++ value = apr_psprintf(sql->pool, "%s: %s", srvname, msgtext); ++ if (procname && procname[0]) ++ value = apr_pstrcat(sql->pool, value, " In procedure ", ++ procname, NULL); ++ if (line) ++ value = apr_pstrcat(sql->pool, value, ++ procname && procname[0] ? ", line " : " Line ", ++ apr_itoa(sql->pool, line), NULL); ++ ++ if (sql->lasterror) ++ sql->lasterror = apr_pstrcat(sql->pool, sql->lasterror, "\n", value, NULL); ++ else ++ sql->lasterror = value; ++ ++ return 0; ++} ++ + static int freetds_err_handler(DBPROCESS *dbproc, int severity, int dberr, + int oserr, char *dberrstr, char *oserrstr) + { ++ char *value; ++ apr_dbd_t *sql; ++ ++ if (dbproc == NULL || (sql = (void *)dbgetuserdata(dbproc)) == NULL) { ++ fprintf(stderr, "%s\n", dberrstr); ++ return INT_CANCEL; ++ } ++ /* ++ * Do not append the useless "general error", if details ++ * are already recorded (by the msg_handler). Just return. ++ * XXX: this skipping currently only works with Sybase's OpenClient ++ * XXX: because FreeTDS implementation uses bogus dberr values: ++ * XXX: https://sourceforge.net/tracker/?func=detail&aid=3555777&group_id=33106&atid=407806 ++ */ ++ if (dberr == SYBESMSG && sql->lasterror) ++ return INT_CANCEL; ++ ++ value = apr_psprintf(sql->pool, "%d: %s", dberr, dberrstr); ++ if (oserrstr) { ++ value = apr_pstrcat(sql->pool, ". (", oserrstr, ")", NULL); ++ } ++ if (sql->lasterror) ++ sql->lasterror = apr_pstrcat(sql->pool, sql->lasterror, "\n", value, NULL); ++ else ++ sql->lasterror = value; + return INT_CANCEL; /* never exit */ + } + static void dbd_freetds_init(apr_pool_t *pool) + { +- int rv = regcomp(&dbd_freetds_find_arg, +- "%(\\{[^}]*\\})?([0-9]*)[A-Za-z]", REG_EXTENDED); +- if (rv != 0) { +- char errmsg[256]; +- regerror(rv, &dbd_freetds_find_arg, errmsg, 256); +- fprintf(stderr, "regcomp failed: %s\n", errmsg); +- } +- dbinit(); ++ if (dbinit() == FAIL) ++ fprintf(stderr, "dbinit() failed\n"); ++ dbmsghandle(freetds_msg_handler); + dberrhandle(freetds_err_handler); + apr_pool_cleanup_register(pool, NULL, freetds_term, apr_pool_cleanup_null); + } +@@ -765,7 +756,11 @@ + #endif + + APU_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_freetds_driver = { ++#ifndef TI_MODULE_NAME + "freetds", ++#else ++ TI_MODULE_NAME, ++#endif + dbd_freetds_init, + dbd_freetds_native, + dbd_freetds_open, +@@ -787,19 +782,14 @@ + dbd_freetds_pvselect, + dbd_freetds_pquery, + dbd_freetds_pselect, +- /* this is only implemented to support httpd/2.2 standard usage, +- * as in the original DBD implementation. Everything else is NOTIMPL. +- */ +-#ifdef COMPILE_STUBS + dbd_freetds_get_name, + dbd_freetds_transaction_mode_get, + dbd_freetds_transaction_mode_set, +- "", ++ "\1", /* Would not occur in a real query... */ + dbd_freetds_pvbquery, + dbd_freetds_pvbselect, + dbd_freetds_pbquery, + dbd_freetds_pbselect, + dbd_freetds_datum_get +-#endif + }; + #endif diff --git a/devel/apr1/pkg-plist b/devel/apr1/pkg-plist index f6264f3bb878..2e055279f922 100644 --- a/devel/apr1/pkg-plist +++ b/devel/apr1/pkg-plist @@ -77,6 +77,10 @@ include/apr-1/apu_want.h %%SSL%%lib/apr-util-1/apr_crypto_openssl.a %%SSL%%lib/apr-util-1/apr_crypto_openssl.la %%SSL%%lib/apr-util-1/apr_crypto_openssl.so +%%FREETDS%%lib/apr-util-1/apr_dbd_freetds-1.so +%%FREETDS%%lib/apr-util-1/apr_dbd_freetds.a +%%FREETDS%%lib/apr-util-1/apr_dbd_freetds.la +%%FREETDS%%lib/apr-util-1/apr_dbd_freetds.so %%MYSQL%%lib/apr-util-1/apr_dbd_mysql-1.so %%MYSQL%%lib/apr-util-1/apr_dbd_mysql.a %%MYSQL%%lib/apr-util-1/apr_dbd_mysql.la |