You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by ni...@apache.org on 2007/09/04 14:05:36 UTC

svn commit: r572642 - in /apr/apr-util/trunk: CHANGES INSTALL.MySQL build/dbd.m4 configure.in dbd/apr_dbd_freetds.c dbd/apr_dbd_mysql.c

Author: niq
Date: Tue Sep  4 05:05:35 2007
New Revision: 572642

URL: http://svn.apache.org/viewvc?rev=572642&view=rev
Log:
Commit DBD MySQL driver (relicensed) and FreeTDS driver (new)

Added:
    apr/apr-util/trunk/dbd/apr_dbd_freetds.c
    apr/apr-util/trunk/dbd/apr_dbd_mysql.c
Removed:
    apr/apr-util/trunk/INSTALL.MySQL
Modified:
    apr/apr-util/trunk/CHANGES
    apr/apr-util/trunk/build/dbd.m4
    apr/apr-util/trunk/configure.in

Modified: apr/apr-util/trunk/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/CHANGES?rev=572642&r1=572641&r2=572642&view=diff
==============================================================================
--- apr/apr-util/trunk/CHANGES [utf-8] (original)
+++ apr/apr-util/trunk/CHANGES [utf-8] Tue Sep  4 05:05:35 2007
@@ -1,6 +1,10 @@
                                                      -*- coding: utf-8 -*-
 Changes with APR-util 1.3.0
 
+  *) Add limited apr_dbd_freetds driver (MSSQL and Sybase) [Nick Kew]
+
+  *) Commit relicensed apr_dbd_mysql driver to /trunk/  [Nick Kew]
+
   *) Support BerkeleyDB 4.6.  [Arfrever Frehtes Taifersar Arahesis]
 
   *) Support Tivoli ITDS LDAP client library.  [Paul Reder]

Modified: apr/apr-util/trunk/build/dbd.m4
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/build/dbd.m4?rev=572642&r1=572641&r2=572642&view=diff
==============================================================================
--- apr/apr-util/trunk/build/dbd.m4 (original)
+++ apr/apr-util/trunk/build/dbd.m4 Tue Sep  4 05:05:35 2007
@@ -365,6 +365,57 @@
   AC_SUBST(LDADD_dbd_oracle)
 ])
 
+dnl
+AC_DEFUN([APU_CHECK_DBD_FREETDS], [
+  apu_have_freetds=0
+
+  AC_ARG_WITH([freetds], [
+  --with-freetds=DIR         
+  ], [
+    apu_have_freetds=0
+    if test "$withval" = "yes"; then
+      AC_CHECK_HEADERS(sybdb.h, AC_CHECK_LIB(sybdb, tdsdbopen, [apu_have_freetds=1]))
+    elif test "$withval" = "no"; then
+      apu_have_freetds=0
+    else
+      old_cppflags="$CPPFLAGS"
+      old_ldflags="$LDFLAGS"
+
+      sybdb_CPPFLAGS="-I$withval/include"
+      sybdb_LDFLAGS="-L$withval/lib "
+
+      APR_ADDTO(CPPFLAGS, [$sybdb_CPPFLAGS])
+      APR_ADDTO(LDFLAGS, [$sybdb_LDFLAGS])
+
+      AC_MSG_NOTICE(checking for freetds in $withval)
+      AC_CHECK_HEADERS(sybdb.h, AC_CHECK_LIB(sybdb, tdsdbopen, [apu_have_freetds=1]))
+      if test "$apu_have_freetds" != "0"; then
+        APR_ADDTO(APRUTIL_LDFLAGS, [-L$withval/lib])
+        APR_ADDTO(APRUTIL_INCLUDES, [-I$withval/include])
+      fi
+
+      CPPFLAGS="$old_cppflags"
+      LDFLAGS="$old_ldflags"
+    fi
+  ], [
+    apu_have_freetds=0
+    AC_CHECK_HEADERS(sybdb.h, AC_CHECK_LIB(sybdb, tdsdbopen, [apu_have_freetds=1]))
+  ])
+
+  AC_SUBST(apu_have_freetds)
+
+  dnl Since we have already done the AC_CHECK_LIB tests, if we have it, 
+  dnl we know the library is there.
+  if test "$apu_have_freetds" = "1"; then
+    LDADD_dbd_freetds="$LDADD_dbd_freetds -lsybdb"
+    dnl Erm, I needed pcreposix, but I think that dependency has gone
+    dnl from the current code
+    dnl LDADD_dbd_freetds="$LDADD_dbd_freetds -lsybdb -lpcreposix"
+  fi
+  AC_SUBST(LDADD_dbd_freetds)
+])
+dnl
+
 AC_DEFUN([APU_CHECK_DBD_DSO], [
 
   AC_ARG_ENABLE([dbd-dso], 
@@ -379,6 +430,7 @@
      test $apu_have_mysql = 1 && dsos="$dsos dbd/apr_dbd_mysql.la"
      test $apu_have_sqlite2 = 1 && dsos="$dsos dbd/apr_dbd_sqlite2.la"
      test $apu_have_sqlite3 = 1 && dsos="$dsos dbd/apr_dbd_sqlite3.la"
+     test $apu_have_freetds = 1 && dsos="$dsos dbd/apr_dbd_freetds.la"
 
      APU_MODULES="$APU_MODULES $dsos"
   else
@@ -390,9 +442,10 @@
      test $apu_have_mysql = 1 && objs="$objs dbd/apr_dbd_mysql.lo"
      test $apu_have_sqlite2 = 1 && objs="$objs dbd/apr_dbd_sqlite2.lo"
      test $apu_have_sqlite3 = 1 && objs="$objs dbd/apr_dbd_sqlite3.lo"
+     test $apu_have_freetds = 1 && objs="$objs dbd/apr_dbd_freetds.lo"
      EXTRA_OBJECTS="$EXTRA_OBJECTS $objs"
 
-     APRUTIL_LIBS="$APRUTIL_LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql"
-     APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql"
+     APRUTIL_LIBS="$APRUTIL_LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql $LDADD_dbd_freetds"
+     APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql $LDADD_dbd_freetds"
   fi
 ])

Modified: apr/apr-util/trunk/configure.in
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/configure.in?rev=572642&r1=572641&r2=572642&view=diff
==============================================================================
--- apr/apr-util/trunk/configure.in (original)
+++ apr/apr-util/trunk/configure.in Tue Sep  4 05:05:35 2007
@@ -151,6 +151,7 @@
 APU_CHECK_DBD_SQLITE3
 APU_CHECK_DBD_SQLITE2
 APU_CHECK_DBD_ORACLE
+APU_CHECK_DBD_FREETDS
 dnl Enable DSO build; must be last:
 APU_CHECK_DBD_DSO
 APU_FIND_EXPAT

Added: apr/apr-util/trunk/dbd/apr_dbd_freetds.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd_freetds.c?rev=572642&view=auto
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd_freetds.c (added)
+++ apr/apr-util/trunk/dbd/apr_dbd_freetds.c Tue Sep  4 05:05:35 2007
@@ -0,0 +1,786 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apu.h"
+#include "apu_config.h"
+
+/* COMPILE_STUBS: compile stubs for unimplemented functions.
+ *
+ * This is required to compile in /trunk/, but can be
+ * undefined to compile a driver for httpd-2.2 and other
+ * APR-1.2 applications
+ */
+#define COMPILE_STUBS
+
+#if APU_HAVE_FREETDS
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "apr_strings.h"
+#include "apr_lib.h"
+
+#include "apr_pools.h"
+#include "apr_dbd_internal.h"
+
+#include <sybdb.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <regex.h>
+
+/* This probably needs to change for different applications */
+#define MAX_COL_LEN 256
+
+typedef struct freetds_cell_t {
+    int type;
+    DBINT len;
+    BYTE *data;
+} freetds_cell_t;
+
+struct apr_dbd_transaction_t {
+    int mode;
+    int errnum;
+    apr_dbd_t *handle;
+};
+
+struct apr_dbd_t {
+    DBPROCESS *proc;
+    apr_dbd_transaction_t *trans;
+    apr_pool_t *pool;
+    const char *params;
+    RETCODE err;
+};
+
+struct apr_dbd_results_t {
+    int random;
+    size_t ntuples;
+    size_t sz;
+    apr_pool_t *pool;
+    DBPROCESS *proc;
+};
+
+struct apr_dbd_row_t {
+    apr_dbd_results_t *res;
+    BYTE buf[MAX_COL_LEN];
+};
+
+struct apr_dbd_prepared_t {
+    int nargs;
+    regex_t **taint;
+    int *sz;
+    char *fmt;
+};
+
+#define dbd_freetds_is_success(x) (x == SUCCEED)
+
+static int labelnum = 0; /* FIXME */
+static regex_t dbd_freetds_find_arg;
+
+/* execute a query that doesn't return a result set, mop up,
+ * and return and APR-flavoured status
+ */
+static RETCODE freetds_exec(DBPROCESS *proc, const char *query,
+                            int want_results, int *nrows)
+{
+    /* TBD */
+    RETCODE rv = dbcmd(proc, query);
+    if (rv != SUCCEED) {
+        return rv;
+    }
+    rv = dbsqlexec(proc);
+    if (rv != SUCCEED) {
+        return rv;
+    }
+    if (!want_results) {
+        while (dbresults(proc) != NO_MORE_RESULTS) {
+            ++*nrows;
+        }
+    }
+    return SUCCEED;
+}
+static apr_status_t clear_result(void *data)
+{
+    /* clear cursor */
+    return (dbcanquery((DBPROCESS*)data) == SUCCEED)
+            ? APR_SUCCESS
+            : APR_EGENERAL;
+}
+
+static int dbd_freetds_select(apr_pool_t *pool, apr_dbd_t *sql,
+                              apr_dbd_results_t **results,
+                              const char *query, int seek)
+{
+    apr_dbd_results_t *res;
+    int i;
+    if (sql->trans && (sql->trans->errnum != SUCCEED)) {
+        return 1;
+    }
+    /* the core of this is
+     * dbcmd(proc, query);
+     * dbsqlexec(proc);
+     * while (dbnextrow(dbproc) != NO_MORE_ROWS) {
+     *     do things
+     * }
+     *
+     * Ignore seek
+     */
+
+    sql->err = freetds_exec(sql->proc, query, 1, NULL);
+    if (!dbd_freetds_is_success(sql->err)) {
+        if (sql->trans) {
+            sql->trans->errnum = sql->err;
+        }
+        return 1;
+    }
+
+    sql->err = dbresults(sql->proc);
+    if (sql->err != SUCCEED) {
+        if (sql->trans) {
+            sql->trans->errnum = sql->err;
+        }
+        return 1;
+    }
+
+    if (!*results) {
+        *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
+    }
+    res = *results;
+    res->proc = sql->proc;
+    res->random = seek;
+    res->pool = pool;
+    res->ntuples = dblastrow(sql->proc);
+    res->sz = dbnumcols(sql->proc);
+    apr_pool_cleanup_register(pool, sql->proc, clear_result,
+                              apr_pool_cleanup_null);
+
+#if 0
+    /* Now we have a result set.  We need to bind to its vars */
+    res->vars = apr_palloc(pool, res->sz * sizeof(freetds_cell_t*));
+    for (i=1; i <= res->sz; ++i) {
+        freetds_cell_t *cell = &res->vars[i-1];
+        cell->type = dbcoltype(sql->proc, i);
+        cell->len = dbcollen(sql->proc, i);
+        cell->data = apr_palloc(pool, cell->len);
+        sql->err = dbbind(sql->proc, i, /*cell->type */ STRINGBIND, cell->len, cell->data);
+        if (sql->err != SUCCEED) {
+            fprintf(stderr, "dbbind error: %d, %d, %d", i, cell->type, cell->len);
+        }
+        if ((sql->err != SUCCEED) && (sql->trans != NULL)) {
+            sql->trans->errnum = sql->err;
+        }
+    }
+#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)
+{
+    int i;
+    int len;
+    const char *var;
+    char *ret;
+    const char *p_in;
+    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;
+    }
+    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;
+    }
+    strcpy(p_out, p_in);
+    return ret;
+}
+static int dbd_freetds_pselect(apr_pool_t *pool, apr_dbd_t *sql,
+                               apr_dbd_results_t **results,
+                               apr_dbd_prepared_t *statement,
+                               int seek, int nargs, const char **values)
+{
+    const char *query = dbd_statement(pool, statement, nargs, values);
+    return dbd_freetds_select(pool, sql, results, query, seek);
+}
+static int dbd_freetds_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
+                                apr_dbd_results_t **results,
+                                apr_dbd_prepared_t *statement,
+                                int seek, va_list args)
+{
+    const char **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nargs);
+
+    for (i = 0; i < statement->nargs; i++) {
+        values[i] = va_arg(args, const char*);
+    }
+
+    return dbd_freetds_pselect(pool, sql, results, statement, seek,
+                               statement->nargs, values);
+}
+static int dbd_freetds_query(apr_dbd_t *sql, int *nrows, const char *query);
+static int dbd_freetds_pquery(apr_pool_t *pool, apr_dbd_t *sql,
+                              int *nrows, apr_dbd_prepared_t *statement,
+                              int nargs, const char **values)
+{
+    const char *query = dbd_statement(pool, statement, nargs, values);
+    return dbd_freetds_query(sql, nrows, query);
+}
+static int dbd_freetds_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
+                               apr_dbd_prepared_t *statement, va_list args)
+{
+    const char **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nargs);
+
+    for (i = 0; i < statement->nargs; i++) {
+        values[i] = va_arg(args, const char*);
+    }
+    return dbd_freetds_pquery(pool, sql, nrows, statement,
+                              statement->nargs, values);
+}
+
+static int dbd_freetds_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
+                               apr_dbd_row_t **rowp, int rownum)
+{
+    RETCODE rv = 0;
+    apr_dbd_row_t *row = *rowp;
+    int sequential = ((rownum >= 0) && res->random) ? 0 : 1;
+
+    if (row == NULL) {
+        row = apr_palloc(pool, sizeof(apr_dbd_row_t));
+        *rowp = row;
+        row->res = res;
+    }
+    /*
+    else {
+        if ( sequential ) {
+            ++row->n;
+        }
+        else {
+            row->n = rownum;
+        }
+    }
+    */
+    if (sequential) {
+        rv = dbnextrow(res->proc);
+    }
+    else {
+        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);
+        *rowp = NULL;
+        return -1;
+    case FAIL: return 1;
+    case BUF_FULL: return 2; /* FIXME */
+    default: return 3;
+    }
+
+    return 0;
+}
+
+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);
+    int t = dbcoltype(proc, n+1);
+    int l = dbcollen(proc, n+1);
+    if (dbwillconvert(t, SYBCHAR)) {
+      dbconvert(proc, t, ptr, l, SYBCHAR, row->buf, -1);
+      return (const char*)row->buf;
+    }
+    return ptr;
+}
+
+static const char *dbd_freetds_error(apr_dbd_t *sql, int n)
+{
+    /* XXX this doesn't seem to exist in the API ??? */
+    return apr_psprintf(sql->pool, "Error %d", sql->err);
+}
+
+static int dbd_freetds_query(apr_dbd_t *sql, int *nrows, const char *query)
+{
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+    *nrows = 0;
+    sql->err = freetds_exec(sql->proc, query, 0, nrows);
+
+    if (sql->err != SUCCEED) {
+        if (sql->trans) {
+            sql->trans->errnum = sql->err;
+        }
+        return 1;
+    }
+    return 0;
+}
+
+static const char *dbd_freetds_escape(apr_pool_t *pool, const char *arg,
+                                      apr_dbd_t *sql)
+{
+    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,
+                             apr_dbd_prepared_t **statement)
+{
+    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));
+    }
+    stmt = *statement;
+
+#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)] = ',';
+        }
+    }
+    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
+
+}
+
+static int dbd_freetds_start_transaction(apr_pool_t *pool, apr_dbd_t *handle,
+                                         apr_dbd_transaction_t **trans)
+{
+    int dummy;
+
+    /* XXX handle recursive transactions here */
+
+    handle->err = freetds_exec(handle->proc, "BEGIN TRANSACTION", 0, &dummy);
+
+    if (dbd_freetds_is_success(handle->err)) {
+        if (!*trans) {
+            *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
+        }
+        (*trans)->handle = handle;
+        handle->trans = *trans;
+        return 0;
+    }
+
+    return 1;
+}
+
+static int dbd_freetds_end_transaction(apr_dbd_transaction_t *trans)
+{
+    int dummy;
+    if (trans) {
+        /* rollback on error or explicit rollback request */
+        if (trans->errnum) {
+            trans->errnum = 0;
+            trans->handle->err = freetds_exec(trans->handle->proc,
+                                              "ROLLBACK", 0, &dummy);
+        }
+        else {
+            trans->handle->err = freetds_exec(trans->handle->proc,
+                                              "COMMIT", 0, &dummy);
+        }
+        trans->handle->trans = NULL;
+    }
+    return (trans->handle->err == SUCCEED) ? 0 : 1;
+}
+
+static DBPROCESS *freetds_open(apr_pool_t *pool, const char *params)
+{
+    char *server = NULL;
+    DBPROCESS *process;
+    LOGINREC *login;
+    static const char *delims = " \r\n\t;|,";
+    char *ptr;
+    char *key;
+    char *value;
+    int vlen;
+    int klen;
+    char *buf;
+    char *databaseName = NULL;
+
+    /* FIXME - this uses malloc */
+    login = dblogin();
+    if (login == NULL) {
+        return NULL;
+    }
+    /* now set login properties */
+    for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {
+        for (key = ptr-1; isspace(*key); --key);
+        klen = 0;
+        while (isalpha(*key)) {
+            --key;
+            ++klen;
+        }
+        ++key;
+        for (value = ptr+1; isspace(*value); ++value);
+
+        vlen = strcspn(value, delims);
+        buf = apr_pstrndup(pool, value, vlen);        /* NULL-terminated copy */
+
+        if (!strncasecmp(key, "username", klen)) {
+            DBSETLUSER(login, buf);
+        }
+        else if (!strncasecmp(key, "password", klen)) {
+            DBSETLPWD(login, buf);
+        }
+        else if (!strncasecmp(key, "appname", klen)) {
+            DBSETLAPP(login, buf);
+        }
+        else if (!strncasecmp(key, "dbname", klen)) {
+            databaseName = buf;
+        }
+        else if (!strncasecmp(key, "host", klen)) {
+            DBSETLHOST(login, buf);
+        }
+        else if (!strncasecmp(key, "charset", klen)) {
+            DBSETLCHARSET(login, buf);
+        }
+        else if (!strncasecmp(key, "lang", klen)) {
+            DBSETLNATLANG(login, buf);
+        }
+        else if (!strncasecmp(key, "server", klen)) {
+            server = buf;
+        }
+        else {
+            /* unknown param */
+        }
+        ptr = value+vlen;
+    }
+
+    process = dbopen(login, server);
+
+    fprintf(stderr, "databaseName [%s]\n", databaseName);
+
+    if (databaseName != NULL)
+    {
+        dbuse(process, databaseName);
+    }
+ 
+    dbloginfree(login);
+    if (process == NULL) {
+        return NULL;
+    }
+
+    return process;
+}
+static apr_dbd_t *dbd_freetds_open(apr_pool_t *pool, const char *params)
+{
+    apr_dbd_t *sql;
+    DBPROCESS *process = freetds_open(pool, params);
+    if (process == NULL) {
+        return NULL;
+    }
+    sql = apr_palloc (pool, sizeof (apr_dbd_t));
+    sql->pool = pool;
+    sql->proc = process;
+    sql->params = params;
+    return sql;
+}
+
+static apr_status_t dbd_freetds_close(apr_dbd_t *handle)
+{
+    dbclose(handle->proc);
+    return APR_SUCCESS;
+}
+
+static apr_status_t dbd_freetds_check_conn(apr_pool_t *pool,
+                                           apr_dbd_t *handle)
+{
+    if (dbdead(handle->proc)) {
+        /* try again */
+        dbclose(handle->proc);
+        handle->proc = freetds_open(handle->pool, handle->params);
+        if (!handle->proc || dbdead(handle->proc)) {
+            return APR_EGENERAL;
+        }
+    }
+    /* clear it, in case this is called in error handling */
+    dbcancel(handle->proc);
+    return APR_SUCCESS;
+}
+
+static int dbd_freetds_select_db(apr_pool_t *pool, apr_dbd_t *handle,
+                               const char *name)
+{
+    /* ouch, it's declared int.  But we can use APR 0/nonzero */
+    return (dbuse(handle->proc, (char*)name) == SUCCEED) ? APR_SUCCESS : APR_EGENERAL;
+}
+
+static void *dbd_freetds_native(apr_dbd_t *handle)
+{
+    return handle->proc;
+}
+
+static int dbd_freetds_num_cols(apr_dbd_results_t* res)
+{
+    return res->sz;
+}
+
+static int dbd_freetds_num_tuples(apr_dbd_results_t* res)
+{
+    if (res->random) {
+        return res->ntuples;
+    }
+    else {
+        return -1;
+    }
+}
+
+static apr_status_t freetds_term(void *dummy)
+{
+    dbexit();
+    regfree(&dbd_freetds_find_arg);
+    return APR_SUCCESS;
+}
+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();
+    apr_pool_cleanup_register(pool, NULL, freetds_term, apr_pool_cleanup_null);
+}
+
+#ifdef COMPILE_STUBS
+/* get_name is the only one of these that is implemented */
+static const char *dbd_freetds_get_name(const apr_dbd_results_t *res, int n)
+{
+    return (const char*) dbcolname(res->proc, n+1); /* numbering starts at 1 */
+}
+
+/* These are stubs: transaction modes not implemented here */
+#define DBD_NOTIMPL APR_ENOTIMPL;
+static int dbd_freetds_transaction_mode_get(apr_dbd_transaction_t *trans)
+{
+    return trans ? trans->mode : APR_DBD_TRANSACTION_COMMIT;
+}
+
+static int dbd_freetds_transaction_mode_set(apr_dbd_transaction_t *trans,
+                                            int mode)
+{
+    if (trans) {
+        trans->mode = mode & TXN_MODE_BITS;
+        return trans->mode;
+    }
+    return APR_DBD_TRANSACTION_COMMIT;
+}
+static int dbd_freetds_pvbquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
+                                apr_dbd_prepared_t *statement, va_list args)
+{
+    return DBD_NOTIMPL;
+}
+static int dbd_freetds_pbquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
+                               apr_dbd_prepared_t * statement,
+                               const void **values)
+{
+    return DBD_NOTIMPL;
+}
+
+static int dbd_freetds_pvbselect(apr_pool_t *pool, apr_dbd_t *sql,
+                                 apr_dbd_results_t **results,
+                                 apr_dbd_prepared_t *statement,
+                                 int seek, va_list args)
+{
+    return DBD_NOTIMPL;
+}
+static int dbd_freetds_pbselect(apr_pool_t *pool, apr_dbd_t *sql,
+                                apr_dbd_results_t **results,
+                                apr_dbd_prepared_t *statement,
+                                int seek, const void **values)
+{
+    return DBD_NOTIMPL;
+}
+static apr_status_t dbd_freetds_datum_get(const apr_dbd_row_t *row, int n,
+                                          apr_dbd_type_e type, void *data)
+{
+    return APR_ENOTIMPL;
+}
+#endif
+
+APU_DECLARE_DATA const apr_dbd_driver_t apr_dbd_freetds_driver = {
+    "freetds",
+    dbd_freetds_init,
+    dbd_freetds_native,
+    dbd_freetds_open,
+    dbd_freetds_check_conn,
+    dbd_freetds_close,
+    dbd_freetds_select_db,
+    dbd_freetds_start_transaction,
+    dbd_freetds_end_transaction,
+    dbd_freetds_query,
+    dbd_freetds_select,
+    dbd_freetds_num_cols,
+    dbd_freetds_num_tuples,
+    dbd_freetds_get_row,
+    dbd_freetds_get_entry,
+    dbd_freetds_error,
+    dbd_freetds_escape,
+    dbd_freetds_prepare,
+    dbd_freetds_pvquery,
+    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,
+    "",
+    dbd_freetds_pvbquery,
+    dbd_freetds_pvbselect,
+    dbd_freetds_pbquery,
+    dbd_freetds_pbselect,
+    dbd_freetds_datum_get
+#endif
+};
+#endif

Added: apr/apr-util/trunk/dbd/apr_dbd_mysql.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/dbd/apr_dbd_mysql.c?rev=572642&view=auto
==============================================================================
--- apr/apr-util/trunk/dbd/apr_dbd_mysql.c (added)
+++ apr/apr-util/trunk/dbd/apr_dbd_mysql.c Tue Sep  4 05:05:35 2007
@@ -0,0 +1,1594 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apu.h"
+#define HAVE_MYSQL_MYSQL_H
+
+#if APU_HAVE_MYSQL
+
+#include "apu_version.h"
+#include "apu_config.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#ifdef HAVE_MYSQL_H
+#include <mysql.h>
+#include <errmsg.h>
+#elif defined(HAVE_MYSQL_MYSQL_H)
+#include <mysql/mysql.h>
+#include <mysql/errmsg.h>
+#endif
+
+#include "apr_strings.h"
+#include "apr_buckets.h"
+
+#include "apr_dbd_internal.h"
+
+/* default maximum field size 1 MB */
+#define FIELDSIZE 1048575
+
+struct apr_dbd_prepared_t {
+    MYSQL_STMT* stmt;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    int nargs;
+    int nvals;
+    apr_dbd_type_e *types;
+#endif
+};
+
+struct apr_dbd_transaction_t {
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    int mode;
+#endif
+    int errnum;
+    apr_dbd_t *handle;
+};
+
+struct apr_dbd_t {
+    MYSQL* conn ;
+    apr_dbd_transaction_t* trans ;
+    unsigned long fldsz;
+};
+
+struct apr_dbd_results_t {
+    int random;
+    MYSQL_RES *res;
+    MYSQL_STMT *statement;
+    MYSQL_BIND *bind;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    apr_pool_t *pool;
+#endif
+};
+struct apr_dbd_row_t {
+    MYSQL_ROW row;
+    apr_dbd_results_t *res;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    unsigned long *len;
+#endif
+};
+
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+/* MySQL specific bucket for BLOB types */
+typedef struct apr_bucket_lob apr_bucket_lob;
+/**
+ * A bucket referring to a MySQL BLOB
+ */
+struct apr_bucket_lob {
+    /** Number of buckets using this memory */
+    apr_bucket_refcount  refcount;
+    /** The row this bucket refers to */
+    const apr_dbd_row_t *row;
+    /** The column this bucket refers to */
+    int col;
+    /** The pool into which any needed structures should
+     *  be created while reading from this bucket */
+    apr_pool_t *readpool;
+};
+
+static void lob_bucket_destroy(void *data);
+static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
+                                    apr_size_t *len, apr_read_type_e block);
+static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
+                                       const apr_dbd_row_t *row, int col,
+                                       apr_off_t offset, apr_size_t len,
+                                       apr_pool_t *p);
+static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
+                                         apr_off_t offset,
+                                         apr_size_t len, apr_pool_t *p,
+                                         apr_bucket_alloc_t *list);
+
+static const apr_bucket_type_t apr_bucket_type_lob = {
+    "LOB", 5, APR_BUCKET_DATA,
+    lob_bucket_destroy,
+    lob_bucket_read,
+    apr_bucket_setaside_notimpl,
+    apr_bucket_shared_split,
+    apr_bucket_shared_copy
+};
+
+static void lob_bucket_destroy(void *data)
+{
+    apr_bucket_lob *f = data;
+
+    if (apr_bucket_shared_destroy(f)) {
+        /* no need to destroy database objects here; it will get
+         * done automatically when the pool gets cleaned up */
+        apr_bucket_free(f);
+    }
+}
+
+static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
+                                    apr_size_t *len, apr_read_type_e block)
+{
+    apr_bucket_lob *a = e->data;
+    const apr_dbd_row_t *row = a->row;
+    apr_dbd_results_t *res = row->res;
+    int col = a->col;
+    apr_bucket *b = NULL;
+    int rv;
+    apr_size_t blength = e->length;  /* bytes remaining in file past offset */
+    apr_off_t boffset = e->start;
+    MYSQL_BIND *bind = &res->bind[col];
+
+    *str = NULL;  /* in case we die prematurely */
+
+    /* fetch from offset if not at the beginning */
+    if (boffset > 0) {
+        rv = mysql_stmt_fetch_column(res->statement, bind, col, boffset);
+        if (rv != 0) {
+            return APR_EGENERAL;
+        }
+    }
+    blength -= blength > bind->buffer_length ? bind->buffer_length : blength;
+    *len = e->length - blength;
+    *str = bind->buffer;
+
+    /* allocate new buffer, since we used this one for the bucket */
+    bind->buffer = apr_palloc(res->pool, bind->buffer_length);
+
+    /*
+     * Change the current bucket to refer to what we read,
+     * even if we read nothing because we hit EOF.
+     */
+    apr_bucket_pool_make(e, *str, *len, res->pool);
+
+    /* If we have more to read from the field, then create another bucket */
+    if (blength > 0) {
+        /* for efficiency, we can just build a new apr_bucket struct
+         * to wrap around the existing LOB bucket */
+        b = apr_bucket_alloc(sizeof(*b), e->list);
+        b->start  = boffset + *len;
+        b->length = blength;
+        b->data   = a;
+        b->type   = &apr_bucket_type_lob;
+        b->free   = apr_bucket_free;
+        b->list   = e->list;
+        APR_BUCKET_INSERT_AFTER(e, b);
+    }
+    else {
+        lob_bucket_destroy(a);
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
+                                       const apr_dbd_row_t *row, int col,
+                                       apr_off_t offset, apr_size_t len,
+                                       apr_pool_t *p)
+{
+    apr_bucket_lob *f;
+
+    f = apr_bucket_alloc(sizeof(*f), b->list);
+    f->row = row;
+    f->col = col;
+    f->readpool = p;
+
+    b = apr_bucket_shared_make(b, f, offset, len);
+    b->type = &apr_bucket_type_lob;
+
+    return b;
+}
+
+static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
+                                         apr_off_t offset,
+                                         apr_size_t len, apr_pool_t *p,
+                                         apr_bucket_alloc_t *list)
+{
+    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
+
+    APR_BUCKET_INIT(b);
+    b->free = apr_bucket_free;
+    b->list = list;
+    return apr_bucket_lob_make(b, row, col, offset, len, p);
+}
+
+#endif
+
+static apr_status_t free_result(void *data)
+{
+    mysql_free_result(data);
+    return APR_SUCCESS;
+}
+
+static int dbd_mysql_select(apr_pool_t *pool, apr_dbd_t *sql,
+                            apr_dbd_results_t **results,
+                            const char *query, int seek)
+{
+    int sz;
+    int ret;
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+    ret = mysql_query(sql->conn, query);
+    if (!ret) {
+        if (sz = mysql_field_count(sql->conn), sz > 0) {
+            if (!*results) {
+                *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
+            }
+            (*results)->random = seek;
+            (*results)->statement = NULL;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+            (*results)->pool = pool;
+#endif
+            if (seek) {
+                (*results)->res = mysql_store_result(sql->conn);
+            }
+            else {
+                (*results)->res = mysql_use_result(sql->conn);
+            }
+            apr_pool_cleanup_register(pool, (*results)->res,
+                                      free_result,apr_pool_cleanup_null);
+        }
+    } else {
+        ret = mysql_errno(sql->conn);
+    }
+    
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+#else
+    if (sql->trans) {
+#endif
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+static const char *dbd_mysql_get_name(const apr_dbd_results_t *res, int n)
+{
+    if ((n < 0) || (n >= mysql_num_fields(res->res))) {
+        return NULL;
+    }
+
+    return mysql_fetch_fields(res->res)[n].name;
+}
+#endif
+
+static int dbd_mysql_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
+                             apr_dbd_row_t **row, int rownum)
+{
+    MYSQL_ROW r = NULL;
+    int ret = 0;
+
+    if (res->statement) {
+        if (res->random) {
+            if (rownum >= 0) {
+                mysql_stmt_data_seek(res->statement, (my_ulonglong)rownum);
+            }
+        }
+        ret = mysql_stmt_fetch(res->statement);
+        switch (ret) {
+        case 1:
+            ret = mysql_stmt_errno(res->statement);
+            break;
+        case MYSQL_NO_DATA:
+            ret = -1;
+            break;
+        default:
+            ret = 0; /* bad luck - get_entry will deal with this */
+            break;
+        }
+    }
+    else {
+        if (res->random) {
+            if (rownum >= 0) {
+                mysql_data_seek(res->res, (my_ulonglong) rownum);
+            }
+        }
+        r = mysql_fetch_row(res->res);
+        if (r == NULL) {
+            ret = -1;
+        }
+    }
+    if (ret == 0) {
+        if (!*row) {
+            *row = apr_palloc(pool, sizeof(apr_dbd_row_t));
+        }
+        (*row)->row = r;
+        (*row)->res = res;
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+        (*row)->len = mysql_fetch_lengths(res->res);
+#endif
+    }
+    else {
+        apr_pool_cleanup_run(pool, res->res, free_result);
+    }
+    return ret;
+}
+#if 0
+/* An improved API that was proposed but not followed up */
+static int dbd_mysql_get_entry(const apr_dbd_row_t *row, int n,
+                               apr_dbd_datum_t *val)
+{
+    MYSQL_BIND *bind;
+    if (row->res->statement) {
+        bind = &row->res->bind[n];
+        if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) {
+            val->type = APR_DBD_VALUE_NULL;
+            return -1;
+        }
+        if (*bind->is_null) {
+            val->type = APR_DBD_VALUE_NULL;
+            return -1;
+        }
+        else {
+            val->type = APR_DBD_VALUE_STRING;
+            val->value.stringval = bind->buffer;
+        }
+    }
+    else {
+        val->type = APR_DBD_VALUE_STRING;
+        val->value.stringval = row->row[n];
+    }
+    return 0;
+}
+#else
+
+static const char *dbd_mysql_get_entry(const apr_dbd_row_t *row, int n)
+{
+    MYSQL_BIND *bind;
+    if (row->res->statement) {
+        bind = &row->res->bind[n];
+        if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) {
+            return NULL;
+        }
+        if (*bind->is_null) {
+            return NULL;
+        }
+        else {
+            return bind->buffer;
+        }
+    }
+    else {
+        return row->row[n];
+    }
+    return NULL;
+}
+#endif
+
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+static apr_status_t dbd_mysql_datum_get(const apr_dbd_row_t *row, int n,
+                                        apr_dbd_type_e type, void *data)
+{
+    if (row->res->statement) {
+        MYSQL_BIND *bind = &row->res->bind[n];
+        unsigned long len = *bind->length;
+
+        if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) {
+            return APR_EGENERAL;
+        }
+
+        if (*bind->is_null) {
+            return APR_ENOENT;
+        }
+
+        switch (type) {
+        case APR_DBD_TYPE_TINY:
+            *(char*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_UTINY:
+            *(unsigned char*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_SHORT:
+            *(short*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_USHORT:
+            *(unsigned short*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_INT:
+            *(int*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_UINT:
+            *(unsigned int*)data = atoi(bind->buffer);
+            break;
+        case APR_DBD_TYPE_LONG:
+            *(long*)data = atol(bind->buffer);
+            break;
+        case APR_DBD_TYPE_ULONG:
+            *(unsigned long*)data = atol(bind->buffer);
+            break;
+        case APR_DBD_TYPE_LONGLONG:
+            *(apr_int64_t*)data = apr_atoi64(bind->buffer);
+            break;
+        case APR_DBD_TYPE_ULONGLONG:
+            *(apr_uint64_t*)data = apr_atoi64(bind->buffer);
+            break;
+        case APR_DBD_TYPE_FLOAT:
+            *(float*)data = atof(bind->buffer);
+            break;
+        case APR_DBD_TYPE_DOUBLE:
+            *(double*)data = atof(bind->buffer);
+            break;
+        case APR_DBD_TYPE_STRING:
+        case APR_DBD_TYPE_TEXT:
+        case APR_DBD_TYPE_TIME:
+        case APR_DBD_TYPE_DATE:
+        case APR_DBD_TYPE_DATETIME:
+        case APR_DBD_TYPE_TIMESTAMP:
+        case APR_DBD_TYPE_ZTIMESTAMP:
+            *((char*)bind->buffer+bind->buffer_length-1) = '\0';
+            *(char**)data = bind->buffer;
+            break;
+        case APR_DBD_TYPE_BLOB:
+        case APR_DBD_TYPE_CLOB:
+            {
+            apr_bucket *e;
+            apr_bucket_brigade *b = (apr_bucket_brigade*)data;
+
+            e = apr_bucket_lob_create(row, n, 0, len,
+                                      row->res->pool, b->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(b, e);
+            }
+            break;
+        case APR_DBD_TYPE_NULL:
+            *(void**)data = NULL;
+            break;
+        default:
+            return APR_EGENERAL;
+        }
+    }
+    else {
+        if (row->row[n] == NULL) {
+            return APR_ENOENT;
+        }
+
+        switch (type) {
+        case APR_DBD_TYPE_TINY:
+            *(char*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_UTINY:
+            *(unsigned char*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_SHORT:
+            *(short*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_USHORT:
+            *(unsigned short*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_INT:
+            *(int*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_UINT:
+            *(unsigned int*)data = atoi(row->row[n]);
+            break;
+        case APR_DBD_TYPE_LONG:
+            *(long*)data = atol(row->row[n]);
+            break;
+        case APR_DBD_TYPE_ULONG:
+            *(unsigned long*)data = atol(row->row[n]);
+            break;
+        case APR_DBD_TYPE_LONGLONG:
+            *(apr_int64_t*)data = apr_atoi64(row->row[n]);
+            break;
+        case APR_DBD_TYPE_ULONGLONG:
+            *(apr_uint64_t*)data = apr_atoi64(row->row[n]);
+            break;
+        case APR_DBD_TYPE_FLOAT:
+            *(float*)data = atof(row->row[n]);
+            break;
+        case APR_DBD_TYPE_DOUBLE:
+            *(double*)data = atof(row->row[n]);
+            break;
+        case APR_DBD_TYPE_STRING:
+        case APR_DBD_TYPE_TEXT:
+        case APR_DBD_TYPE_TIME:
+        case APR_DBD_TYPE_DATE:
+        case APR_DBD_TYPE_DATETIME:
+        case APR_DBD_TYPE_TIMESTAMP:
+        case APR_DBD_TYPE_ZTIMESTAMP:
+            *(char**)data = row->row[n];
+            break;
+        case APR_DBD_TYPE_BLOB:
+        case APR_DBD_TYPE_CLOB:
+            {
+            apr_bucket *e;
+            apr_bucket_brigade *b = (apr_bucket_brigade*)data;
+
+            e = apr_bucket_pool_create(row->row[n], row->len[n],
+                                       row->res->pool, b->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(b, e);
+            }
+            break;
+        case APR_DBD_TYPE_NULL:
+            *(void**)data = NULL;
+            break;
+        default:
+            return APR_EGENERAL;
+        }
+    }
+    return 0;
+}
+#endif
+
+static const char *dbd_mysql_error(apr_dbd_t *sql, int n)
+{
+    return mysql_error(sql->conn);
+}
+
+static int dbd_mysql_query(apr_dbd_t *sql, int *nrows, const char *query)
+{
+    int ret;
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+    ret = mysql_query(sql->conn, query);
+    if (ret != 0) {
+        ret = mysql_errno(sql->conn);
+    }
+    *nrows = mysql_affected_rows(sql->conn);
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+#else
+    if (sql->trans) {
+#endif
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static const char *dbd_mysql_escape(apr_pool_t *pool, const char *arg,
+                                    apr_dbd_t *sql)
+{
+    unsigned long len = strlen(arg);
+    char *ret = apr_palloc(pool, 2*len + 1);
+    mysql_real_escape_string(sql->conn, ret, arg, len);
+    return ret;
+}
+
+static apr_status_t stmt_close(void *data)
+{
+    mysql_stmt_close(data);
+    return APR_SUCCESS;
+}
+
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+static int dbd_mysql_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)
+{
+    /* Translate from apr_dbd to native query format */
+    int ret;
+
+    if (!*statement) {
+        *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t));
+    }
+    (*statement)->stmt = mysql_stmt_init(sql->conn);
+
+    if ((*statement)->stmt) {
+        apr_pool_cleanup_register(pool, (*statement)->stmt,
+                                  stmt_close, apr_pool_cleanup_null);
+        ret = mysql_stmt_prepare((*statement)->stmt, query, strlen(query));
+
+        if (ret != 0) {
+            ret = mysql_stmt_errno((*statement)->stmt);
+        }
+
+        (*statement)->nargs = nargs;
+        (*statement)->nvals = nvals;
+        (*statement)->types = types;
+
+        return ret;
+    }
+
+    return CR_OUT_OF_MEMORY;
+}
+
+static void dbd_mysql_bind(apr_dbd_prepared_t *statement,
+                           const char **values, MYSQL_BIND *bind)
+{
+    int i, j;
+
+    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
+        bind[i].length = &bind[i].buffer_length;
+        bind[i].is_unsigned = 0;
+        bind[i].is_null = NULL;
+
+        if (values[j] == NULL) {
+            bind[i].buffer_type = MYSQL_TYPE_NULL;
+        }
+        else {
+            switch (statement->types[i]) {
+            case APR_DBD_TYPE_BLOB:
+            case APR_DBD_TYPE_CLOB:
+                bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB;
+                bind[i].buffer = (void*)values[j];
+                bind[i].buffer_length = atol(values[++j]);
+
+                /* skip table and column */
+                j += 2;
+                break;
+            default:
+                bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+                bind[i].buffer = (void*)values[j];
+                bind[i].buffer_length = strlen(values[j]);
+                break;
+            }
+        }
+    }
+
+    return;
+}
+
+static int dbd_mysql_pquery_internal(apr_pool_t *pool, apr_dbd_t *sql,
+                                     int *nrows, apr_dbd_prepared_t *statement,
+                                     MYSQL_BIND *bind)
+{
+    int ret;
+
+    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    if (ret != 0) {
+        *nrows = 0;
+        ret = mysql_stmt_errno(statement->stmt);
+    }
+    else {
+        ret = mysql_stmt_execute(statement->stmt);
+        if (ret != 0) {
+            ret = mysql_stmt_errno(statement->stmt);
+        }
+        *nrows = mysql_stmt_affected_rows(statement->stmt);
+    }
+
+    return ret;
+}
+
+static int dbd_mysql_pquery(apr_pool_t *pool, apr_dbd_t *sql,
+                            int *nrows, apr_dbd_prepared_t *statement,
+                            const char **values)
+{
+    MYSQL_BIND *bind;
+    int ret;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND));
+
+    dbd_mysql_bind(statement, values, bind);
+
+    ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind);
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_mysql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
+                             apr_dbd_prepared_t *statement, va_list args)
+{
+    const char **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
+
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const char*);
+    }
+
+    return dbd_mysql_pquery(pool, sql, nrows, statement, values);
+}
+
+static int dbd_mysql_pselect_internal(apr_pool_t *pool, apr_dbd_t *sql,
+                                      apr_dbd_results_t **res,
+                                      apr_dbd_prepared_t *statement,
+                                      int random, MYSQL_BIND *bind)
+{
+    int nfields, i;
+    my_bool *is_nullr;
+#if MYSQL_VERSION_ID >= 50000
+    my_bool *error;
+#endif
+    int ret;
+    unsigned long *length, maxlen;
+
+    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    if (ret == 0) {
+        ret = mysql_stmt_execute(statement->stmt);
+        if (!ret) {
+            if (!*res) {
+                *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
+            }
+            (*res)->random = random;
+            (*res)->statement = statement->stmt;
+            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
+            (*res)->pool = pool;
+            apr_pool_cleanup_register(pool, (*res)->res,
+                                      free_result, apr_pool_cleanup_null);
+            nfields = mysql_num_fields((*res)->res);
+            if (!(*res)->bind) {
+                (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND));
+                length = apr_pcalloc(pool, nfields*sizeof(unsigned long));
+#if MYSQL_VERSION_ID >= 50000
+                error = apr_palloc(pool, nfields*sizeof(my_bool));
+#endif
+                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
+                for ( i = 0; i < nfields; ++i ) {
+                    maxlen = ((*res)->res->fields[i].length < sql->fldsz ?
+                              (*res)->res->fields[i].length : sql->fldsz) + 1;
+                    if ((*res)->res->fields[i].type == MYSQL_TYPE_BLOB) {
+                        (*res)->bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB;
+                    }
+                    else {
+                        (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+                    }
+                    (*res)->bind[i].buffer_length = maxlen;
+                    (*res)->bind[i].length = &length[i];
+                    (*res)->bind[i].buffer = apr_palloc(pool, maxlen);
+                    (*res)->bind[i].is_null = is_nullr+i;
+#if MYSQL_VERSION_ID >= 50000
+                    (*res)->bind[i].error = error+i;
+#endif
+                }
+            }
+            ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
+            if (!ret) {
+                ret = mysql_stmt_store_result(statement->stmt);
+            }
+        }
+    }
+    if (ret != 0) {
+        ret = mysql_stmt_errno(statement->stmt);
+    }
+
+    return ret;
+}
+
+static int dbd_mysql_pselect(apr_pool_t *pool, apr_dbd_t *sql,
+                             apr_dbd_results_t **res,
+                             apr_dbd_prepared_t *statement, int random,
+                             const char **args)
+{
+    int ret;
+    MYSQL_BIND *bind;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND));
+
+    dbd_mysql_bind(statement, args, bind);
+
+    ret = dbd_mysql_pselect_internal(pool, sql,  res, statement, random, bind);
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
+                              apr_dbd_results_t **res,
+                              apr_dbd_prepared_t *statement, int random,
+                              va_list args)
+{
+    const char **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
+
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const char*);
+    }
+
+    return dbd_mysql_pselect(pool, sql, res, statement, random, values);
+}
+
+static void dbd_mysql_bbind(apr_pool_t *pool, apr_dbd_prepared_t *statement,
+                            const void **values, MYSQL_BIND *bind)
+{
+    void *arg;
+    int i, j;
+    apr_dbd_type_e type;
+
+    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
+        arg = (void *)values[j];
+
+        bind[i].length = &bind[i].buffer_length;
+        bind[i].is_null = NULL;
+
+        type = (arg == NULL ? APR_DBD_TYPE_NULL : statement->types[i]);
+        switch (type) {
+        case APR_DBD_TYPE_TINY:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_TINY;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_UTINY:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_TINY;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_SHORT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_SHORT;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_USHORT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_SHORT;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_INT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_LONG;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_UINT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_LONG;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_LONG:
+            if (sizeof(int) == sizeof(long)) {
+                bind[i].buffer = arg;
+            }
+            else {
+                bind[i].buffer = apr_palloc(pool, sizeof(int));
+                *(int*)bind[i].buffer = *(long*)arg;
+            }
+            bind[i].buffer_type = MYSQL_TYPE_LONG;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_ULONG:
+            if (sizeof(unsigned int) == sizeof(unsigned long)) {
+                bind[i].buffer = arg;
+            }
+            else {
+                bind[i].buffer = apr_palloc(pool, sizeof(unsigned int));
+                *(unsigned int*)bind[i].buffer = *(unsigned long*)arg;
+            }
+            bind[i].buffer_type = MYSQL_TYPE_LONG;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_LONGLONG:
+            if (sizeof(long long) == sizeof(apr_int64_t)) {
+                bind[i].buffer = arg;
+            }
+            else {
+                bind[i].buffer = apr_palloc(pool, sizeof(long long));
+                *(long long*)bind[i].buffer = *(apr_int64_t*)arg;
+            }
+            bind[i].buffer_type = MYSQL_TYPE_LONGLONG;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_ULONGLONG:
+            if (sizeof(unsigned long long) == sizeof(apr_uint64_t)) {
+                bind[i].buffer = arg;
+            }
+            else {
+                bind[i].buffer = apr_palloc(pool, sizeof(unsigned long long));
+                *(unsigned long long*)bind[i].buffer = *(apr_uint64_t*)arg;
+            }
+            bind[i].buffer_type = MYSQL_TYPE_LONGLONG;
+            bind[i].is_unsigned = 1;
+            break;
+        case APR_DBD_TYPE_FLOAT:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_FLOAT;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_DOUBLE:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_DOUBLE;
+            bind[i].is_unsigned = 0;
+            break;
+        case APR_DBD_TYPE_STRING:
+        case APR_DBD_TYPE_TEXT:
+        case APR_DBD_TYPE_TIME:
+        case APR_DBD_TYPE_DATE:
+        case APR_DBD_TYPE_DATETIME:
+        case APR_DBD_TYPE_TIMESTAMP:
+        case APR_DBD_TYPE_ZTIMESTAMP:
+            bind[i].buffer = arg;
+            bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+            bind[i].is_unsigned = 0;
+            bind[i].buffer_length = strlen((const char *)arg);
+            break;
+        case APR_DBD_TYPE_BLOB:
+        case APR_DBD_TYPE_CLOB:
+            bind[i].buffer = (void *)arg;
+            bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB;
+            bind[i].is_unsigned = 0;
+            bind[i].buffer_length = *(apr_size_t*)values[++j];
+
+            /* skip table and column */
+            j += 2;
+            break;
+        case APR_DBD_TYPE_NULL:
+        default:
+            bind[i].buffer_type = MYSQL_TYPE_NULL;
+            break;
+        }
+    }
+
+    return;
+}
+
+static int dbd_mysql_pbquery(apr_pool_t *pool, apr_dbd_t *sql,
+                             int *nrows, apr_dbd_prepared_t *statement,
+                             const void **values)
+{
+    MYSQL_BIND *bind;
+    int ret;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND));
+
+    dbd_mysql_bbind(pool, statement, values, bind);
+
+    ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind);
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_mysql_pvbquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
+                              apr_dbd_prepared_t *statement, va_list args)
+{
+    const void **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
+
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const void*);
+    }
+
+    return dbd_mysql_pbquery(pool, sql, nrows, statement, values);
+}
+
+static int dbd_mysql_pbselect(apr_pool_t *pool, apr_dbd_t *sql,
+                              apr_dbd_results_t **res,
+                              apr_dbd_prepared_t *statement, int random,
+                              const void **args)
+{
+    int ret;
+    MYSQL_BIND *bind;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND));
+
+    dbd_mysql_bbind(pool, statement, args, bind);
+
+    ret = dbd_mysql_pselect_internal(pool, sql,  res, statement, random, bind);
+
+    if (TXN_NOTICE_ERRORS(sql->trans)) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_mysql_pvbselect(apr_pool_t *pool, apr_dbd_t *sql,
+                               apr_dbd_results_t **res,
+                               apr_dbd_prepared_t *statement, int random,
+                               va_list args)
+{
+    const void **values;
+    int i;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
+
+    for (i = 0; i < statement->nvals; i++) {
+        values[i] = va_arg(args, const void*);
+    }
+
+    return dbd_mysql_pbselect(pool, sql, res, statement, random, values);
+}
+#else
+static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql,
+                             const char *query, const char *label,
+                             apr_dbd_prepared_t **statement)
+{
+    /* Translate from apr_dbd to native query format */
+    char *myquery = apr_pstrdup(pool, query);
+    char *p = myquery;
+    const char *q;
+    int ret;
+    for (q = query; *q; ++q) {
+        if (q[0] == '%') {
+            if (isalpha(q[1])) {
+                *p++ = '?';
+                ++q;
+            }
+            else if (q[1] == '%') {
+                /* reduce %% to % */
+                *p++ = *q++;
+            }
+            else {
+                *p++ = *q;
+            }
+        }
+        else {
+            *p++ = *q;
+        }
+    } 
+    *p = 0;
+    if (!*statement) {
+        *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t));
+    }
+    (*statement)->stmt = mysql_stmt_init(sql->conn);
+
+    if ((*statement)->stmt) {
+        apr_pool_cleanup_register(pool, (*statement)->stmt,
+                                  stmt_close, apr_pool_cleanup_null);
+        ret = mysql_stmt_prepare((*statement)->stmt, myquery, strlen(myquery));
+
+        if (ret != 0) {
+            ret = mysql_stmt_errno((*statement)->stmt);
+        }
+
+        return ret;
+    }
+
+    return CR_OUT_OF_MEMORY;
+}
+
+static int dbd_mysql_pquery(apr_pool_t *pool, apr_dbd_t *sql,
+                            int *nrows, apr_dbd_prepared_t *statement,
+                            int nargs, const char **values)
+{
+    MYSQL_BIND *bind;
+    char *arg;
+    int ret;
+    int i;
+    my_bool is_null = FALSE;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+    nargs = mysql_stmt_param_count(statement->stmt);
+
+    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
+    for (i=0; i < nargs; ++i) {
+        arg = (char*)values[i];
+        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+        bind[i].buffer = arg;
+        bind[i].buffer_length = strlen(arg);
+        bind[i].length = &bind[i].buffer_length;
+        bind[i].is_null = &is_null;
+        bind[i].is_unsigned = 0;
+    }
+
+    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    if (ret != 0) {
+        *nrows = 0;
+        ret = mysql_stmt_errno(statement->stmt);
+    }
+    else {
+        ret = mysql_stmt_execute(statement->stmt);
+        if (ret != 0) {
+            ret = mysql_stmt_errno(statement->stmt);
+        }
+        *nrows = mysql_stmt_affected_rows(statement->stmt);
+    }
+    if (sql->trans) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_mysql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
+                             apr_dbd_prepared_t *statement, va_list args)
+{
+    MYSQL_BIND *bind;
+    char *arg;
+    int ret;
+    int nargs = 0;
+    int i;
+    my_bool is_null = FALSE;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+    nargs = mysql_stmt_param_count(statement->stmt);
+
+    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
+    for (i=0; i < nargs; ++i) {
+        arg = va_arg(args, char*);
+        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+        bind[i].buffer = arg;
+        bind[i].buffer_length = strlen(arg);
+        bind[i].length = &bind[i].buffer_length;
+        bind[i].is_null = &is_null;
+        bind[i].is_unsigned = 0;
+    }
+
+    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    if (ret != 0) {
+        *nrows = 0;
+        ret = mysql_stmt_errno(statement->stmt);
+    }
+    else {
+        ret = mysql_stmt_execute(statement->stmt);
+        if (ret != 0) {
+            ret = mysql_stmt_errno(statement->stmt);
+        }
+        *nrows = mysql_stmt_affected_rows(statement->stmt);
+    }
+    if (sql->trans) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_mysql_pselect(apr_pool_t *pool, apr_dbd_t *sql,
+                             apr_dbd_results_t **res,
+                             apr_dbd_prepared_t *statement, int random,
+                             int nargs, const char **args)
+{
+    int i;
+    int nfields;
+    char *arg;
+    my_bool is_null = FALSE;
+    my_bool *is_nullr;
+#if MYSQL_VERSION_ID >= 50000
+    my_bool *error;
+#endif
+    int ret;
+    unsigned long *length, maxlen;
+    MYSQL_BIND *bind;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    nargs = mysql_stmt_param_count(statement->stmt);
+    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
+
+    for (i=0; i < nargs; ++i) {
+        arg = (char*)args[i];
+        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+        bind[i].buffer = arg;
+        bind[i].buffer_length = strlen(arg);
+        bind[i].length = &bind[i].buffer_length;
+        bind[i].is_null = &is_null;
+        bind[i].is_unsigned = 0;
+    }
+
+    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    if (ret == 0) {
+        ret = mysql_stmt_execute(statement->stmt);
+        if (!ret) {
+            if (!*res) {
+                *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
+            }
+            (*res)->random = random;
+            (*res)->statement = statement->stmt;
+            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
+            apr_pool_cleanup_register(pool, (*res)->res,
+                                      free_result, apr_pool_cleanup_null);
+            nfields = mysql_num_fields((*res)->res);
+            if (!(*res)->bind) {
+                (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND));
+                length = apr_pcalloc(pool, nfields*sizeof(unsigned long));
+#if MYSQL_VERSION_ID >= 50000
+                error = apr_palloc(pool, nfields*sizeof(my_bool));
+#endif
+                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
+                for ( i = 0; i < nfields; ++i ) {
+                    maxlen = ((*res)->res->fields[i].length < sql->fldsz ?
+                              (*res)->res->fields[i].length : sql->fldsz) + 1;
+                    (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+                    (*res)->bind[i].buffer_length = maxlen;
+                    (*res)->bind[i].length = &length[i];
+                    (*res)->bind[i].buffer = apr_palloc(pool, maxlen);
+                    (*res)->bind[i].is_null = is_nullr+i;
+#if MYSQL_VERSION_ID >= 50000
+                    (*res)->bind[i].error = error+i;
+#endif
+                }
+            }
+            ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
+            if (!ret) {
+                ret = mysql_stmt_store_result(statement->stmt);
+            }
+        }
+    }
+    if (ret != 0) {
+        ret = mysql_stmt_errno(statement->stmt);
+    }
+    if (sql->trans) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
+                              apr_dbd_results_t **res,
+                              apr_dbd_prepared_t *statement, int random,
+                              va_list args)
+{
+    int i;
+    int nfields;
+    char *arg;
+    my_bool is_null = FALSE;
+    my_bool *is_nullr;
+#if MYSQL_VERSION_ID >= 50000
+    my_bool *error;
+#endif
+    int ret;
+    unsigned long *length, maxlen;
+    int nargs;
+    MYSQL_BIND *bind;
+
+    if (sql->trans && sql->trans->errnum) {
+        return sql->trans->errnum;
+    }
+
+    nargs = mysql_stmt_param_count(statement->stmt);
+    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
+
+    for (i=0; i < nargs; ++i) {
+        arg = va_arg(args, char*);
+        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+        bind[i].buffer = arg;
+        bind[i].buffer_length = strlen(arg);
+        bind[i].length = &bind[i].buffer_length;
+        bind[i].is_null = &is_null;
+        bind[i].is_unsigned = 0;
+    }
+
+    ret = mysql_stmt_bind_param(statement->stmt, bind);
+    if (ret == 0) {
+        ret = mysql_stmt_execute(statement->stmt);
+        if (!ret) {
+            if (!*res) {
+                *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
+            }
+            (*res)->random = random;
+            (*res)->statement = statement->stmt;
+            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
+            apr_pool_cleanup_register(pool, (*res)->res,
+                                      free_result, apr_pool_cleanup_null);
+            nfields = mysql_num_fields((*res)->res);
+            if (!(*res)->bind) {
+                (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND));
+                length = apr_pcalloc(pool, nfields*sizeof(unsigned long));
+#if MYSQL_VERSION_ID >= 50000
+                error = apr_palloc(pool, nfields*sizeof(my_bool));
+#endif
+                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
+                for ( i = 0; i < nfields; ++i ) {
+                    maxlen = ((*res)->res->fields[i].length < sql->fldsz ?
+                              (*res)->res->fields[i].length : sql->fldsz) + 1;
+                    (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+                    (*res)->bind[i].buffer_length = maxlen;
+                    (*res)->bind[i].length = &length[i];
+                    (*res)->bind[i].buffer = apr_palloc(pool, maxlen);
+                    (*res)->bind[i].is_null = is_nullr+i;
+#if MYSQL_VERSION_ID >= 50000
+                    (*res)->bind[i].error = error+i;
+#endif
+                }
+            }
+            ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
+            if (!ret) {
+                ret = mysql_stmt_store_result(statement->stmt);
+            }
+        }
+    }
+    if (ret != 0) {
+        ret = mysql_stmt_errno(statement->stmt);
+    }
+    if (sql->trans) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+#endif
+
+static int dbd_mysql_end_transaction(apr_dbd_transaction_t *trans)
+{
+    int ret = -1;
+    if (trans) {
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+        /* rollback on error or explicit rollback request */
+        if (trans->errnum || TXN_DO_ROLLBACK(trans)) {
+#else
+        if (trans->errnum) {
+#endif
+            trans->errnum = 0;
+            ret = mysql_rollback(trans->handle->conn);
+        }
+        else {
+            ret = mysql_commit(trans->handle->conn);
+        }
+    }
+    ret |= mysql_autocommit(trans->handle->conn, 1);
+    trans->handle->trans = NULL;
+    return ret;
+}
+/* Whether or not transactions work depends on whether the
+ * underlying DB supports them within MySQL.  Unfortunately
+ * it fails silently with the default InnoDB.
+ */
+
+static int dbd_mysql_transaction(apr_pool_t *pool, apr_dbd_t *handle,
+                                 apr_dbd_transaction_t **trans)
+{
+    /* Don't try recursive transactions here */
+    if (handle->trans) {
+        dbd_mysql_end_transaction(handle->trans) ;
+    }
+    if (!*trans) {
+        *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
+    }
+    (*trans)->errnum = mysql_autocommit(handle->conn, 0);
+    (*trans)->handle = handle;
+    handle->trans = *trans;
+    return (*trans)->errnum;
+}
+
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+static int dbd_mysql_transaction_mode_get(apr_dbd_transaction_t *trans)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode;
+}
+
+static int dbd_mysql_transaction_mode_set(apr_dbd_transaction_t *trans,
+                                          int mode)
+{
+    if (!trans)
+        return APR_DBD_TRANSACTION_COMMIT;
+
+    return trans->mode = (mode & TXN_MODE_BITS);
+}
+#endif
+
+static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params)
+{
+    static const char *const delims = " \r\n\t;|,";
+    const char *ptr;
+    int i;
+    const char *key;
+    size_t klen;
+    const char *value;
+    size_t vlen;
+#if MYSQL_VERSION_ID >= 50013
+    my_bool do_reconnect = 1;
+#endif
+    MYSQL *real_conn;
+    unsigned long flags = 0;
+    
+    struct {
+        const char *field;
+        const char *value;
+    } fields[] = {
+        {"host", NULL},
+        {"user", NULL},
+        {"pass", NULL},
+        {"dbname", NULL},
+        {"port", NULL},
+        {"sock", NULL},
+        {"flags", NULL},
+        {"fldsz", NULL},
+        {NULL, NULL}
+    };
+    unsigned int port = 0;
+    apr_dbd_t *sql = apr_pcalloc(pool, sizeof(apr_dbd_t));
+    sql->fldsz = FIELDSIZE;
+    sql->conn = mysql_init(sql->conn);
+    if ( sql->conn == NULL ) {
+        return NULL;
+    }
+    for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {
+        for (key = ptr-1; isspace(*key); --key);
+        klen = 0;
+        while (isalpha(*key)) {
+            /* don't parse backwards off the start of the string */
+            if (key == params) {
+                --key;
+                ++klen;
+                break;
+            }
+            --key;
+            ++klen;
+        }
+        ++key;
+        for (value = ptr+1; isspace(*value); ++value);
+        vlen = strcspn(value, delims);
+        for (i = 0; fields[i].field != NULL; i++) {
+            if (!strncasecmp(fields[i].field, key, klen)) {
+                fields[i].value = apr_pstrndup(pool, value, vlen);
+                break;
+            }
+        }
+        ptr = value+vlen;
+    }
+    if (fields[4].value != NULL) {
+        port = atoi(fields[4].value);
+    }
+    if (fields[6].value != NULL &&
+        !strcmp(fields[6].value, "CLIENT_FOUND_ROWS")) {
+        flags |= CLIENT_FOUND_ROWS; /* only option we know */
+    }
+    if (fields[7].value != NULL) {
+        sql->fldsz = atol(fields[7].value);
+    }
+
+#if MYSQL_VERSION_ID >= 50013
+    /* the MySQL manual says this should be BEFORE mysql_real_connect */
+    mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect);
+#endif
+    
+    real_conn = mysql_real_connect(sql->conn, fields[0].value,
+                                   fields[1].value, fields[2].value,
+                                   fields[3].value, port,
+                                   fields[5].value, flags);
+
+    if(real_conn == NULL) {
+        mysql_close(sql->conn);
+        return NULL;
+    }
+
+#if MYSQL_VERSION_ID >= 50013
+    /* Some say this should be AFTER mysql_real_connect */
+    mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect);
+#endif
+
+    return sql;
+}
+
+static apr_status_t dbd_mysql_close(apr_dbd_t *handle)
+{
+    mysql_close(handle->conn);
+    return APR_SUCCESS;
+}
+
+static apr_status_t dbd_mysql_check_conn(apr_pool_t *pool,
+                                         apr_dbd_t *handle)
+{
+    return mysql_ping(handle->conn) ? APR_EGENERAL : APR_SUCCESS;
+}
+
+static int dbd_mysql_select_db(apr_pool_t *pool, apr_dbd_t* handle,
+                               const char* name)
+{
+    return mysql_select_db(handle->conn, name);
+}
+
+static void *dbd_mysql_native(apr_dbd_t *handle)
+{
+    return handle->conn;
+}
+
+static int dbd_mysql_num_cols(apr_dbd_results_t *res)
+{
+    if (res->statement) {
+        return mysql_stmt_field_count(res->statement);
+    }
+    else {
+        return mysql_num_fields(res->res);
+    }
+}
+
+static int dbd_mysql_num_tuples(apr_dbd_results_t *res)
+{
+    if (res->random) {
+        if (res->statement) {
+            return (int) mysql_stmt_num_rows(res->statement);
+        }
+        else {
+            return (int) mysql_num_rows(res->res);
+        }
+    }
+    else {
+        return -1;
+    }
+}
+
+static apr_status_t thread_end(void *data)
+{
+    mysql_thread_end();
+    return APR_SUCCESS;
+}
+
+static void dbd_mysql_init(apr_pool_t *pool)
+{
+    my_init();
+    /* FIXME: this is a guess; find out what it really does */ 
+    apr_pool_cleanup_register(pool, NULL, thread_end, apr_pool_cleanup_null);
+}
+APU_DECLARE_DATA const apr_dbd_driver_t apr_dbd_mysql_driver = {
+    "mysql",
+    dbd_mysql_init,
+    dbd_mysql_native,
+    dbd_mysql_open,
+    dbd_mysql_check_conn,
+    dbd_mysql_close,
+    dbd_mysql_select_db,
+    dbd_mysql_transaction,
+    dbd_mysql_end_transaction,
+    dbd_mysql_query,
+    dbd_mysql_select,
+    dbd_mysql_num_cols,
+    dbd_mysql_num_tuples,
+    dbd_mysql_get_row,
+    dbd_mysql_get_entry,
+    dbd_mysql_error,
+    dbd_mysql_escape,
+    dbd_mysql_prepare,
+    dbd_mysql_pvquery,
+    dbd_mysql_pvselect,
+    dbd_mysql_pquery,
+    dbd_mysql_pselect
+#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
+    ,
+    dbd_mysql_get_name,
+    dbd_mysql_transaction_mode_get,
+    dbd_mysql_transaction_mode_set,
+    "?",
+    dbd_mysql_pvbquery,
+    dbd_mysql_pvbselect,
+    dbd_mysql_pbquery,
+    dbd_mysql_pbselect,
+    dbd_mysql_datum_get
+#endif
+};
+
+#endif



Re: svn commit: r572642 - in /apr/apr-util/trunk: CHANGES INSTALL.MySQL build/dbd.m4 configure.in dbd/apr_dbd_freetds.c dbd/apr_dbd_mysql.c

Posted by Bojan Smojver <bo...@rexursive.com>.
On Sun, 2007-09-09 at 15:03 -0700, Sander Temme wrote:

> ./config.nice --with-mysql=/usr

Yeah, that's pretty much like the default, as long as /usr/bin is in
your path (which on most system it is).

> ./config.nice --with-mysql=/usr/bin/mysql_config

That won't work. You cannot point to the config script, only to
location.

Let me ask the question differently. What's the location of MySQL
libraries, include files and configuration script that you'd like to
pick up?

-- 
Bojan


Re: svn commit: r572642 - in /apr/apr-util/trunk: CHANGES INSTALL.MySQL build/dbd.m4 configure.in dbd/apr_dbd_freetds.c dbd/apr_dbd_mysql.c

Posted by Sander Temme <sc...@apache.org>.
On Sep 9, 2007, at 2:33 PM, Bojan Smojver wrote:

> On Fri, 2007-09-07 at 16:50 -0700, Sander Temme wrote:
>
>> Nope.
>
> So, have you tried pointing it to your own, by passing the location to
> --with-mysql? Does it still fail?

Re-ran configure from this morning by calling

./config.nice --with-mysql=/usr

and got:

<..>
checking for mysql_config... /usr/bin/mysql_config
   adding "-I/usr/include/mysql" to CPPFLAGS
   setting LDFLAGS to "-pipe -L/usr/lib/mysql -lmysqlclient_r -lz -lm"
configure: checking for mysql in /usr
checking mysql.h usability... yes
checking mysql.h presence... yes
checking for mysql.h... yes
checking for mysql_init in -lmysqlclient_r... yes
   setting APRUTIL_INCLUDES to "-I/usr/include/mysql"
<..>
make clean all
<..>
/bin/sh /Volumes/X1/home/sctemme/asf/gump/trunk/work/workspace/apr/ 
dest-09092007/build-1/libtool --silent --mode=link  gcc -g -O2   - 
DHAVE_CONFIG_H -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -no-cpp- 
precomp   -I/Volumes/X1/home/sctemme/work/workspace/apr-util/include - 
I/Volumes/X1/home/sctemme/work/workspace/apr-util/include/private -I/ 
Volumes/X1/home/sctemme/asf/gump/trunk/work/workspace/apr-util/ 
include/private -I/Volumes/X1/home/sctemme/asf/gump/trunk/work/ 
workspace/apr-util/include  -I/Volumes/X1/home/sctemme/asf/gump/trunk/ 
work/workspace/apr/dest-09092007/include/apr-1  -I/usr/include/mysql   
-version-info 3:0:3    -o libaprutil-1.la -rpath /Volumes/X1/home/ 
sctemme/asf/gump/trunk/work/workspace/apr-util/dest-09092007/lib  
buckets/apr_brigade.lo buckets/apr_buckets.lo buckets/ 
apr_buckets_alloc.lo buckets/apr_buckets_eos.lo buckets/ 
apr_buckets_file.lo buckets/apr_buckets_flush.lo buckets/ 
apr_buckets_heap.lo buckets/apr_buckets_mmap.lo buckets/ 
apr_buckets_pipe.lo buckets/apr_buckets_pool.lo buckets/ 
apr_buckets_refcount.lo buckets/apr_buckets_simple.lo buckets/ 
apr_buckets_socket.lo crypto/apr_md4.lo crypto/apr_md5.lo crypto/ 
apr_sha1.lo crypto/getuuid.lo crypto/uuid.lo dbm/apr_dbm.lo dbm/ 
apr_dbm_berkeleydb.lo dbm/apr_dbm_gdbm.lo dbm/apr_dbm_ndbm.lo dbm/ 
apr_dbm_sdbm.lo dbm/sdbm/sdbm.lo dbm/sdbm/sdbm_hash.lo dbm/sdbm/ 
sdbm_lock.lo dbm/sdbm/sdbm_pair.lo encoding/apr_base64.lo hooks/ 
apr_hooks.lo ldap/apr_ldap_init.lo ldap/apr_ldap_option.lo ldap/ 
apr_ldap_url.lo misc/apr_date.lo misc/apr_queue.lo misc/ 
apr_reslist.lo misc/apr_rmm.lo misc/apr_thread_pool.lo misc/ 
apu_version.lo memcache/apr_memcache.lo uri/apr_uri.lo xml/apr_xml.lo  
strmatch/apr_strmatch.lo xlate/xlate.lo dbd/apr_dbd.lo ssl/apr_ssl.lo  
ssl/apr_ssl_openssl.lo ssl/apr_ssl_socket.lo ssl/apr_ssl_winsock.lo  
dbd/apr_dbd_mysql.lo dbd/apr_dbd_sqlite3.lo   -lpthread  -lsqlite3  - 
pipe -L/usr/lib/mysql -lmysqlclient_r -lz -lm  -lexpat -liconv / 
Volumes/X1/home/sctemme/asf/gump/trunk/work/workspace/apr/ 
dest-09092007/lib/libapr-1.la -lpthread
ld: common symbols not allowed with MH_DYLIB output format with the - 
multi_module option
/usr/lib/mysql/libmysqlclient_r.a(my_error.o) definition of common  
_errbuff (size 512)
/usr/lib/mysql/libmysqlclient_r.a(my_static.o) definition of common  
_my_signals (size 4)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_THR_LOCK_open (size 44)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_THR_LOCK_malloc (size 44)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_LOCK_gethostbyname_r (size 44)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_THR_KEY_mysys (size 4)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_THR_LOCK_charset (size 44)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_THR_LOCK_heap (size 44)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_THR_LOCK_isam (size 44)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_THR_LOCK_lock (size 44)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_THR_LOCK_myisam (size 44)
/usr/lib/mysql/libmysqlclient_r.a(my_thr_init.o) definition of common  
_THR_LOCK_net (size 44)
/usr/lib/mysql/libmysqlclient_r.a(charset.o) definition of common  
_all_charsets (size 1024)
/usr/lib/mysql/libmysqlclient_r.a(dbug.o) definition of common  
_THR_LOCK_dbug (size 44)
/usr/bin/libtool: internal link edit command failed
make[1]: *** [libaprutil-1.la] Error 1
make: *** [all-recursive] Error 1

(same deal)

So, explicitly overriding the --with-mysql flag doesn't make it  
forget about the bundled driver.

Interestingly:

./config.nice --with-mysql=/usr/bin/mysql_config
<..>
checking for mysql_config... no
   adding "-I/usr/bin/mysql_config/include" to CPPFLAGS
   setting LDFLAGS to "-L/usr/bin/mysql_config/lib "
configure: checking for mysql in /usr/bin/mysql_config
checking mysql.h usability... no
checking mysql.h presence... no
checking for mysql.h... no
checking mysql/mysql.h usability... no
checking mysql/mysql.h presence... no
checking for mysql/mysql.h... no
<..>
make
<..>
/bin/sh /Volumes/X1/home/sctemme/asf/gump/trunk/work/workspace/apr/ 
dest-09092007/build-1/libtool --silent --mode=link  gcc -g -O2   - 
DHAVE_CONFIG_H -DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK -no-cpp- 
precomp   -I/Volumes/X1/home/sctemme/work/workspace/apr-util/include - 
I/Volumes/X1/home/sctemme/work/workspace/apr-util/include/private -I/ 
Volumes/X1/home/sctemme/asf/gump/trunk/work/workspace/apr-util/ 
include/private -I/Volumes/X1/home/sctemme/asf/gump/trunk/work/ 
workspace/apr-util/include  -I/Volumes/X1/home/sctemme/asf/gump/trunk/ 
work/workspace/apr/dest-09092007/include/apr-1    -version-info  
3:0:3    -o libaprutil-1.la -rpath /Volumes/X1/home/sctemme/asf/gump/ 
trunk/work/workspace/apr-util/dest-09092007/lib buckets/ 
apr_brigade.lo buckets/apr_buckets.lo buckets/apr_buckets_alloc.lo  
buckets/apr_buckets_eos.lo buckets/apr_buckets_file.lo buckets/ 
apr_buckets_flush.lo buckets/apr_buckets_heap.lo buckets/ 
apr_buckets_mmap.lo buckets/apr_buckets_pipe.lo buckets/ 
apr_buckets_pool.lo buckets/apr_buckets_refcount.lo buckets/ 
apr_buckets_simple.lo buckets/apr_buckets_socket.lo crypto/apr_md4.lo  
crypto/apr_md5.lo crypto/apr_sha1.lo crypto/getuuid.lo crypto/uuid.lo  
dbm/apr_dbm.lo dbm/apr_dbm_berkeleydb.lo dbm/apr_dbm_gdbm.lo dbm/ 
apr_dbm_ndbm.lo dbm/apr_dbm_sdbm.lo dbm/sdbm/sdbm.lo dbm/sdbm/ 
sdbm_hash.lo dbm/sdbm/sdbm_lock.lo dbm/sdbm/sdbm_pair.lo encoding/ 
apr_base64.lo hooks/apr_hooks.lo ldap/apr_ldap_init.lo ldap/ 
apr_ldap_option.lo ldap/apr_ldap_url.lo misc/apr_date.lo misc/ 
apr_queue.lo misc/apr_reslist.lo misc/apr_rmm.lo misc/ 
apr_thread_pool.lo misc/apu_version.lo memcache/apr_memcache.lo uri/ 
apr_uri.lo xml/apr_xml.lo strmatch/apr_strmatch.lo xlate/xlate.lo dbd/ 
apr_dbd.lo ssl/apr_ssl.lo ssl/apr_ssl_openssl.lo ssl/ 
apr_ssl_socket.lo ssl/apr_ssl_winsock.lo dbd/apr_dbd_sqlite3.lo   - 
lpthread  -lsqlite3    -lexpat -liconv /Volumes/X1/home/sctemme/asf/ 
gump/trunk/work/workspace/apr/dest-09092007/lib/libapr-1.la -lpthread
<..>
(completes without error but note mysql is not on the link line in  
any form)

So now mysql_config is not found (or searched for) on the path...  
it's still there in /usr/bin!  Then configure treats the with-mysql  
parameter as a directory (as advertised in ./configure --help), does  
*not* find mysql there, and proceeds to build without mysql support  
at all!

S.

-- 
Sander Temme
sctemme@apache.org
PGP FP: 51B4 8727 466A 0BC3 69F4  B7B8 B2BE BC40 1529 24AF




Re: svn commit: r572642 - in /apr/apr-util/trunk: CHANGES INSTALL.MySQL build/dbd.m4 configure.in dbd/apr_dbd_freetds.c dbd/apr_dbd_mysql.c

Posted by Bojan Smojver <bo...@rexursive.com>.
On Fri, 2007-09-07 at 16:50 -0700, Sander Temme wrote:

> Nope.

So, have you tried pointing it to your own, by passing the location to
--with-mysql? Does it still fail?

-- 
Bojan


Re: svn commit: r572642 - in /apr/apr-util/trunk: CHANGES INSTALL.MySQL build/dbd.m4 configure.in dbd/apr_dbd_freetds.c dbd/apr_dbd_mysql.c

Posted by Sander Temme <sc...@apache.org>.
On Sep 7, 2007, at 4:38 PM, Bojan Smojver wrote:

> On Fri, 2007-09-07 at 12:38 -0700, Sander Temme wrote:
>
>> If you look at the (long) link line at the bottom, you'll see that
>> it's picking up -L/usr/lib/mysql -lmysqlclient_r , and the root cause
>> of that is probably somewhere in configure where it decides to use
>> the system MySQL despite the fact that we have one of our own.
>
> Is that with --with-mysql=/your/own/location/of/mysql? Or without  
> that?

Nope.  Here's what Gump does:

http://clarus.apache.org/apr-util/apr-util-configure/gump_work/ 
buildscript_apr-util_apr-util-configure.html

Note:

checking for mysql_config... /usr/bin/mysql_config
   adding "-I/usr/include/mysql" to CPPFLAGS
   setting LDFLAGS to "-pipe -L/usr/lib/mysql -lmysqlclient_r -lz -lm"
checking mysql.h usability... yes
checking mysql.h presence... yes
checking for mysql.h... yes
checking for mysql_init in -lmysqlclient_r... yes
   setting APRUTIL_INCLUDES to "-I/usr/include/mysql"

This does not break on vmgump because it doesn't have the appropriate  
mysql development package installed.  On MacOS X Server, you get that  
automatically.  Or maybe with the Devtools, I don't know.  I don't  
think I have any Macs without the Devtools installed.

S.

-- 
Sander Temme
sctemme@apache.org
PGP FP: 51B4 8727 466A 0BC3 69F4  B7B8 B2BE BC40 1529 24AF




Re: svn commit: r572642 - in /apr/apr-util/trunk: CHANGES INSTALL.MySQL build/dbd.m4 configure.in dbd/apr_dbd_freetds.c dbd/apr_dbd_mysql.c

Posted by Bojan Smojver <bo...@rexursive.com>.
On Fri, 2007-09-07 at 12:38 -0700, Sander Temme wrote:

> If you look at the (long) link line at the bottom, you'll see that  
> it's picking up -L/usr/lib/mysql -lmysqlclient_r , and the root cause  
> of that is probably somewhere in configure where it decides to use  
> the system MySQL despite the fact that we have one of our own.

Is that with --with-mysql=/your/own/location/of/mysql? Or without that?

-- 
Bojan


Re: svn commit: r572642 - in /apr/apr-util/trunk: CHANGES INSTALL.MySQL build/dbd.m4 configure.in dbd/apr_dbd_freetds.c dbd/apr_dbd_mysql.c

Posted by Sander Temme <sc...@apache.org>.
On Sep 4, 2007, at 5:05 AM, niq@apache.org wrote:

> Author: niq
> Date: Tue Sep  4 05:05:35 2007
> New Revision: 572642
>
> URL: http://svn.apache.org/viewvc?rev=572642&view=rev
> Log:
> Commit DBD MySQL driver (relicensed) and FreeTDS driver (new)

Gump says that breaks the build if there is an existing mysql on the  
system:

http://clarus.apache.org/apr-util/apr-util-make/gump_work/build_apr- 
util_apr-util-make.html

If you look at the (long) link line at the bottom, you'll see that  
it's picking up -L/usr/lib/mysql -lmysqlclient_r , and the root cause  
of that is probably somewhere in configure where it decides to use  
the system MySQL despite the fact that we have one of our own.

Thoughts?

S.

-- 
Sander Temme
sctemme@apache.org
PGP FP: 51B4 8727 466A 0BC3 69F4  B7B8 B2BE BC40 1529 24AF