apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bo...@apache.org
Subject svn commit: r573063 - in /apr/apr-util/branches/1.2.x: CHANGES INSTALL.MySQL build/dbd.m4 dbd/apr_dbd_mysql.c
Date Wed, 05 Sep 2007 21:20:23 GMT
Author: bojan
Date: Wed Sep  5 14:20:22 2007
New Revision: 573063

URL: http://svn.apache.org/viewvc?rev=573063&view=rev
Log:
Backport r572642 (partially, MySQL only)
Remove unnecessary APU version checks from MySQL DBD driver
Remove checks for dbd/apr_dbd_mysql.c
Other small cleanups to DBD M4 file

Added:
    apr/apr-util/branches/1.2.x/dbd/apr_dbd_mysql.c
Removed:
    apr/apr-util/branches/1.2.x/INSTALL.MySQL
Modified:
    apr/apr-util/branches/1.2.x/CHANGES
    apr/apr-util/branches/1.2.x/build/dbd.m4

Modified: apr/apr-util/branches/1.2.x/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.2.x/CHANGES?rev=573063&r1=573062&r2=573063&view=diff
==============================================================================
--- apr/apr-util/branches/1.2.x/CHANGES [utf-8] (original)
+++ apr/apr-util/branches/1.2.x/CHANGES [utf-8] Wed Sep  5 14:20:22 2007
@@ -1,7 +1,7 @@
                                                      -*- coding: utf-8 -*-
 Changes with APR-util 1.2.11
 
-
+  *) Add MySQL DBD driver [Nick Kew, Bojan Smojver]
 
 Changes with APR-util 1.2.10
 

Modified: apr/apr-util/branches/1.2.x/build/dbd.m4
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.2.x/build/dbd.m4?rev=573063&r1=573062&r2=573063&view=diff
==============================================================================
--- apr/apr-util/branches/1.2.x/build/dbd.m4 (original)
+++ apr/apr-util/branches/1.2.x/build/dbd.m4 Wed Sep  5 14:20:22 2007
@@ -24,9 +24,9 @@
 AC_DEFUN([APU_CHECK_DBD], [
   apu_have_pgsql=0
 
-  AC_ARG_WITH([pgsql], [
-  --with-pgsql=DIR          specify PostgreSQL location
-  ], [
+  AC_ARG_WITH([pgsql],
+    APR_HELP_STRING([--with-pgsql=DIR], [specify PostgreSQL location]),
+  [
     apu_have_pgsql=0
     if test "$withval" = "yes"; then
       AC_CHECK_HEADERS(libpq-fe.h, AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1]))
@@ -78,99 +78,97 @@
 AC_DEFUN([APU_CHECK_DBD_MYSQL], [
   apu_have_mysql=0
 
-  AC_CHECK_FILES([dbd/apr_dbd_mysql.c],[
-    AC_ARG_WITH([mysql], [
-    --with-mysql=DIR          **** SEE INSTALL.MySQL ****
-    ], [
-      apu_have_mysql=0
-      if test "$withval" = "yes"; then
-        old_cppflags="$CPPFLAGS"
-        old_ldflags="$LDFLAGS"
-
-        AC_PATH_PROG([MYSQL_CONFIG],[mysql_config])
-        if test "x$MYSQL_CONFIG" != 'x'; then
-          mysql_CPPFLAGS="`$MYSQL_CONFIG --include`"
-          mysql_LDFLAGS="`$MYSQL_CONFIG --libs_r`"
-
-          APR_ADDTO(CPPFLAGS, [$mysql_CPPFLAGS])
-          APR_ADDTO(LDFLAGS, [$mysql_LDFLAGS])
-        fi
-
-        AC_CHECK_HEADERS(mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
-        if test "$apu_have_mysql" = "0"; then
-          AC_CHECK_HEADERS(mysql/mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
-        else
-          if test "x$MYSQL_CONFIG" != 'x'; then
-            APR_ADDTO(APRUTIL_INCLUDES, [$mysql_CPPFLAGS])
-            APR_ADDTO(APRUTIL_LDFLAGS, [$mysql_LDFLAGS])
-          fi
-        fi
-
-        CPPFLAGS="$old_cppflags"
-        LDFLAGS="$old_ldflags"
-      elif test "$withval" = "no"; then
-        apu_have_mysql=0
-      else
-        old_cppflags="$CPPFLAGS"
-        old_ldflags="$LDFLAGS"
+  AC_ARG_WITH([mysql],
+    APR_HELP_STRING([--with-mysql=DIR], [specify MySQL location]),
+  [
+    apu_have_mysql=0
+    if test "$withval" = "yes"; then
+      old_cppflags="$CPPFLAGS"
+      old_ldflags="$LDFLAGS"
 
-        AC_PATH_PROG([MYSQL_CONFIG],[mysql_config],,[$withval/bin])
-        if test "x$MYSQL_CONFIG" != 'x'; then
-          mysql_CPPFLAGS="`$MYSQL_CONFIG --include`"
-          mysql_LDFLAGS="`$MYSQL_CONFIG --libs_r`"
-        else
-          mysql_CPPFLAGS="-I$withval/include"
-          mysql_LDFLAGS="-L$withval/lib "
-        fi
+      AC_PATH_PROG([MYSQL_CONFIG],[mysql_config])
+      if test "x$MYSQL_CONFIG" != 'x'; then
+        mysql_CPPFLAGS="`$MYSQL_CONFIG --include`"
+        mysql_LDFLAGS="`$MYSQL_CONFIG --libs_r`"
 
         APR_ADDTO(CPPFLAGS, [$mysql_CPPFLAGS])
         APR_ADDTO(LDFLAGS, [$mysql_LDFLAGS])
+      fi
 
-        AC_MSG_NOTICE(checking for mysql in $withval)
-        AC_CHECK_HEADERS(mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
-        if test "$apu_have_mysql" != "0"; then
+      AC_CHECK_HEADERS(mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
+      if test "$apu_have_mysql" = "0"; then
+        AC_CHECK_HEADERS(mysql/mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
+      else
+        if test "x$MYSQL_CONFIG" != 'x'; then
           APR_ADDTO(APRUTIL_INCLUDES, [$mysql_CPPFLAGS])
           APR_ADDTO(APRUTIL_LDFLAGS, [$mysql_LDFLAGS])
         fi
-
-        if test "$apu_have_mysql" != "1"; then
-          AC_CHECK_HEADERS(mysql/mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
-          if test "$apu_have_mysql" != "0"; then
-            APR_ADDTO(APRUTIL_INCLUDES, [-I$withval/include/mysql])
-            APR_ADDTO(APRUTIL_LDFLAGS, [-L$withval/lib])
-          fi
-        fi
-
-        CPPFLAGS="$old_cppflags"
-        LDFLAGS="$old_ldflags"
       fi
-    ], [
-      apu_have_mysql=0
 
+      CPPFLAGS="$old_cppflags"
+      LDFLAGS="$old_ldflags"
+    elif test "$withval" = "no"; then
+      apu_have_mysql=0
+    else
       old_cppflags="$CPPFLAGS"
       old_ldflags="$LDFLAGS"
 
-      AC_PATH_PROG([MYSQL_CONFIG],[mysql_config])
+      AC_PATH_PROG([MYSQL_CONFIG],[mysql_config],,[$withval/bin])
       if test "x$MYSQL_CONFIG" != 'x'; then
         mysql_CPPFLAGS="`$MYSQL_CONFIG --include`"
         mysql_LDFLAGS="`$MYSQL_CONFIG --libs_r`"
-
-        APR_ADDTO(CPPFLAGS, [$mysql_CPPFLAGS])
-        APR_ADDTO(LDFLAGS, [$mysql_LDFLAGS])
+      else
+        mysql_CPPFLAGS="-I$withval/include"
+        mysql_LDFLAGS="-L$withval/lib "
       fi
 
-      AC_CHECK_HEADERS(mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
+      APR_ADDTO(CPPFLAGS, [$mysql_CPPFLAGS])
+      APR_ADDTO(LDFLAGS, [$mysql_LDFLAGS])
 
+      AC_MSG_NOTICE(checking for mysql in $withval)
+      AC_CHECK_HEADERS(mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
       if test "$apu_have_mysql" != "0"; then
-        if test "x$MYSQL_CONFIG" != 'x'; then
-          APR_ADDTO(APRUTIL_INCLUDES, [$mysql_CPPFLAGS])
-          APR_ADDTO(APRUTIL_LDFLAGS, [$mysql_LDFLAGS])
+        APR_ADDTO(APRUTIL_INCLUDES, [$mysql_CPPFLAGS])
+        APR_ADDTO(APRUTIL_LDFLAGS, [$mysql_LDFLAGS])
+      fi
+
+      if test "$apu_have_mysql" != "1"; then
+        AC_CHECK_HEADERS(mysql/mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
+        if test "$apu_have_mysql" != "0"; then
+          APR_ADDTO(APRUTIL_INCLUDES, [-I$withval/include/mysql])
+          APR_ADDTO(APRUTIL_LDFLAGS, [-L$withval/lib])
         fi
       fi
 
       CPPFLAGS="$old_cppflags"
       LDFLAGS="$old_ldflags"
-    ])
+    fi
+  ], [
+    apu_have_mysql=0
+
+    old_cppflags="$CPPFLAGS"
+    old_ldflags="$LDFLAGS"
+
+    AC_PATH_PROG([MYSQL_CONFIG],[mysql_config])
+    if test "x$MYSQL_CONFIG" != 'x'; then
+      mysql_CPPFLAGS="`$MYSQL_CONFIG --include`"
+      mysql_LDFLAGS="`$MYSQL_CONFIG --libs_r`"
+
+      APR_ADDTO(CPPFLAGS, [$mysql_CPPFLAGS])
+      APR_ADDTO(LDFLAGS, [$mysql_LDFLAGS])
+    fi
+
+    AC_CHECK_HEADERS(mysql.h, AC_CHECK_LIB(mysqlclient_r, mysql_init, [apu_have_mysql=1]))
+
+    if test "$apu_have_mysql" != "0"; then
+      if test "x$MYSQL_CONFIG" != 'x'; then
+        APR_ADDTO(APRUTIL_INCLUDES, [$mysql_CPPFLAGS])
+        APR_ADDTO(APRUTIL_LDFLAGS, [$mysql_LDFLAGS])
+      fi
+    fi
+
+    CPPFLAGS="$old_cppflags"
+    LDFLAGS="$old_ldflags"
   ])
 
   AC_SUBST(apu_have_mysql)
@@ -186,9 +184,9 @@
 AC_DEFUN([APU_CHECK_DBD_SQLITE3], [
   apu_have_sqlite3=0
 
-  AC_ARG_WITH([sqlite3], [
-  --with-sqlite3=DIR         
-  ], [
+  AC_ARG_WITH([sqlite3],
+    APR_HELP_STRING([--with-sqlite3=DIR], [enable sqlite3 DBD driver]),
+  [
     apu_have_sqlite3=0
     if test "$withval" = "yes"; then
       AC_CHECK_HEADERS(sqlite3.h, AC_CHECK_LIB(sqlite3, sqlite3_open, [apu_have_sqlite3=1]))
@@ -232,9 +230,9 @@
 AC_DEFUN([APU_CHECK_DBD_SQLITE2], [
   apu_have_sqlite2=0
 
-  AC_ARG_WITH([sqlite2], [
-  --with-sqlite2=DIR         
-  ], [
+  AC_ARG_WITH([sqlite2],
+    APR_HELP_STRING([--with-sqlite2=DIR], [enable sqlite2 DBD driver]),        
+  [
     apu_have_sqlite2=0
     if test "$withval" = "yes"; then
       AC_CHECK_HEADERS(sqlite.h, AC_CHECK_LIB(sqlite, sqlite_open, [apu_have_sqlite2=1]))

Added: apr/apr-util/branches/1.2.x/dbd/apr_dbd_mysql.c
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.2.x/dbd/apr_dbd_mysql.c?rev=573063&view=auto
==============================================================================
--- apr/apr-util/branches/1.2.x/dbd/apr_dbd_mysql.c (added)
+++ apr/apr-util/branches/1.2.x/dbd/apr_dbd_mysql.c Wed Sep  5 14:20:22 2007
@@ -0,0 +1,765 @@
+/* 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;
+};
+
+struct apr_dbd_transaction_t {
+    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;
+};
+struct apr_dbd_row_t {
+    MYSQL_ROW row;
+    apr_dbd_results_t *res;
+};
+
+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 (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 (sql->trans) {
+        sql->trans->errnum = ret;
+    }
+    return ret;
+}
+
+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;
+    }
+    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
+
+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 (sql->trans) {
+        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;
+}
+
+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;
+}
+
+static int dbd_mysql_end_transaction(apr_dbd_transaction_t *trans)
+{
+    int ret = -1;
+    if (trans) {
+        if (trans->errnum) {
+            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;
+}
+
+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
+};
+
+#endif



Mime
View raw message