SOURCES: apr_dbd_mysql.c (NEW) - add here

arekm arekm at pld-linux.org
Wed Dec 21 23:06:34 CET 2005


Author: arekm                        Date: Wed Dec 21 22:06:34 2005 GMT
Module: SOURCES                       Tag: HEAD
---- Log message:
- add here

---- Files affected:
SOURCES:
   apr_dbd_mysql.c (NONE -> 1.1)  (NEW)

---- Diffs:

================================================================
Index: SOURCES/apr_dbd_mysql.c
diff -u /dev/null SOURCES/apr_dbd_mysql.c:1.1
--- /dev/null	Wed Dec 21 23:06:34 2005
+++ SOURCES/apr_dbd_mysql.c	Wed Dec 21 23:06:29 2005
@@ -0,0 +1,642 @@
+/*
+         Copyright (c) 2003-4, WebThing Ltd
+         Author: Nick Kew <nick at webthing.com>
+ 
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+ 
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+ 
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ 
+*/
+
+/*
+        The current GPL satisfies MySQL licensing terms without
+        invoking any exceptions.
+
+        This code is untested, and probably mostly won't work.
+        It's a demo of concept.
+*/
+
+#include "apu.h"
+
+#if APU_HAVE_MYSQL
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include <mysql/mysql.h>
+#include <mysql/errmsg.h>
+
+#include "apr_strings.h"
+
+#include "apr_dbd_internal.h"
+
+
+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 ;
+};
+
+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 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,
+                                      (void*)mysql_free_result,
+                                      apr_pool_cleanup_null);
+        }
+    }
+    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;
+    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);
+    }
+    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 {
+        mysql_free_result(res->res);
+        apr_pool_cleanup_kill(pool, res->res, (void*)mysql_free_result);
+        ret = -1;
+    }
+    return ret;
+}
+#if 0
+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 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);
+    *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 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;
+    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);
+    apr_pool_cleanup_register(pool, *statement, (void*)mysql_stmt_close,
+                              apr_pool_cleanup_null);
+    return mysql_stmt_prepare((*statement)->stmt, myquery, strlen(myquery));
+}
+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;
+    }
+    else {
+        ret = mysql_stmt_execute(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;
+    }
+    else {
+        ret = mysql_stmt_execute(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;
+    int ret;
+    const int FIELDSIZE = 255;
+    unsigned long *length;
+    char **data;
+    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));
+                if (!*res) {
+                    while (!mysql_stmt_fetch(statement->stmt));
+                    return -1;
+                }
+            }
+            (*res)->random = random;
+            (*res)->statement = statement->stmt;
+            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
+            apr_pool_cleanup_register(pool, (*res)->res,
+                (void*)mysql_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));
+                data = apr_palloc(pool, nfields*sizeof(char*));
+                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
+                length = apr_pcalloc(pool, nfields);
+                for ( i = 0; i < nfields; ++i ) {
+                    (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+                    (*res)->bind[i].buffer_length = FIELDSIZE;
+                    (*res)->bind[i].length = &length[i];
+                    data[i] = apr_palloc(pool, FIELDSIZE*sizeof(char));
+                    (*res)->bind[i].buffer = data[i];
+                    (*res)->bind[i].is_null = is_nullr+i;
+                }
+            }
+            ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
+            if (!ret) {
+                ret = mysql_stmt_store_result(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;
+    int ret;
+    const int FIELDSIZE = 255;
+    unsigned long *length;
+    char **data;
+    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));
+                if (!*res) {
+                    while (!mysql_stmt_fetch(statement->stmt));
+                    return -1;
+                }
+            }
+            (*res)->random = random;
+            (*res)->statement = statement->stmt;
+            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
+            apr_pool_cleanup_register(pool, (*res)->res,
+                (void*)mysql_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));
+                data = apr_palloc(pool, nfields*sizeof(char*));
+                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
+                length = apr_pcalloc(pool, nfields);
+                for ( i = 0; i < nfields; ++i ) {
+                    (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+                    (*res)->bind[i].buffer_length = FIELDSIZE;
+                    (*res)->bind[i].length = &length[i];
+                    data[i] = apr_palloc(pool, FIELDSIZE*sizeof(char));
+                    (*res)->bind[i].buffer = data[i];
+                    (*res)->bind[i].is_null = is_nullr+i;
+                }
+            }
+            ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
+            if (!ret) {
+                ret = mysql_stmt_store_result(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);
+    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;
+    struct {
+        const char *field;
+        const char *value;
+    } fields[] = {
+        {"host", NULL},
+        {"user", NULL},
+        {"pass", NULL},
+        {"dbname", NULL},
+        {"port", NULL},
+        {"sock", NULL},
+        {NULL, NULL}
+    };
+    unsigned int port = 0;
+    apr_dbd_t *sql = apr_pcalloc(pool, sizeof(apr_dbd_t));
+    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)) {
+            --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);
+    }
+    sql->conn = mysql_real_connect(sql->conn, fields[0].value,
+                                   fields[1].value, fields[2].value,
+                                   fields[3].value, port,
+                                   fields[5].value, 0);
+    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);
+    }
<<Diff was trimmed, longer than 597 lines>>


More information about the pld-cvs-commit mailing list