jorton 8721b3
/*
jorton 8721b3
         Copyright (c) 2003-7, WebThing Ltd and other contributors
jorton 8721b3
 
jorton 8721b3
This program is free software; you can redistribute it and/or modify
jorton 8721b3
it under the terms of the GNU General Public License as published by
jorton 8721b3
the Free Software Foundation; either version 2 of the License, or
jorton 8721b3
(at your option) any later version.  Alternatively, where this program
jorton 8721b3
is aggregated with the Apache APR-UTIL package version 1.2 or later,
jorton 8721b3
you can distribute and/or modify it under the terms of the Apache
jorton 8721b3
License 2.0 as published by the Apache Software Foundation.
jorton 8721b3
 
jorton 8721b3
This program is distributed in the hope that it will be useful,
jorton 8721b3
but WITHOUT ANY WARRANTY; without even the implied warranty of
jorton 8721b3
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jorton 8721b3
applicable License for more details.
jorton 8721b3
 
jorton 8721b3
You should have received a copy of the GNU General Public License
jorton 8721b3
along with this program; if not, write to the Free Software
jorton 8721b3
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
jorton 8721b3
You may obtain a copy of the Apache License 2.0 at:
jorton 8721b3
http://www.apache.org/licenses/LICENSE-2.0
jorton 8721b3
 
jorton 8721b3
*/
jorton 8721b3
jorton 8721b3
/* LICENSE NOTE
jorton 8721b3
 *
jorton 8721b3
 * The current GPL satisfies MySQL licensing terms without
jorton 8721b3
 * invoking any exceptions.  ASF policy doesn't permit GPL
jorton 8721b3
 * software to be distributed by apache.org, but this should
jorton 8721b3
 * not be a problem for third-parties who wish to distribute
jorton 8721b3
 * it alongside the APR and other Apache software.
jorton 8721b3
 * 
jorton 8721b3
 * It is updated to dual license after discussion with Debian
jorton 8721b3
 * and taking into account MySQL's FOSS exception.
jorton 8721b3
 * http://bahumbug.wordpress.com/2007/01/09/re-licensing-apr_dbd_mysql/
jorton 8721b3
 * http://www.mysql.com/company/legal/licensing/foss-exception.html
jorton 8721b3
 *
jorton 8721b3
 * MAINTAINERS
jorton 8721b3
 *
jorton 8721b3
 * This code was originally written by Nick Kew for MySQL 4.1.
jorton 8721b3
 * and subsequently updated by others to support MySQL 5.0.
jorton 8721b3
 * The current lead maintainer is Bojan Smojver, with others
jorton 8721b3
 * contributing via the developer list at apr.apache.org.
jorton 8721b3
 *
jorton 8721b3
 */
jorton 8721b3
jorton 8721b3
jorton 8721b3
#include "apu.h"
jorton 8721b3
#define HAVE_MYSQL_MYSQL_H
jorton 8721b3
jorton 8721b3
#if APU_HAVE_MYSQL
jorton 8721b3
jorton 8721b3
#include "apu_version.h"
jorton 8721b3
#include "apu_config.h"
jorton 8721b3
jorton 8721b3
#include <ctype.h>
jorton 8721b3
#include <stdlib.h>
jorton 8721b3
jorton 8721b3
#ifdef HAVE_MYSQL_H
jorton 8721b3
#include <mysql.h>
jorton 8721b3
#include <errmsg.h>
jorton 8721b3
#elif defined(HAVE_MYSQL_MYSQL_H)
jorton 8721b3
#include <mysql/mysql.h>
jorton 8721b3
#include <mysql/errmsg.h>
jorton 8721b3
#endif
jorton 8721b3
jorton 8721b3
#include "apr_strings.h"
jorton 8721b3
#include "apr_buckets.h"
jorton 8721b3
jorton 8721b3
#include "apr_dbd_internal.h"
jorton 8721b3
jorton 8721b3
/* default maximum field size 1 MB */
jorton 8721b3
#define FIELDSIZE 1048575
jorton 8721b3
jorton 8721b3
struct apr_dbd_prepared_t {
jorton 8721b3
    MYSQL_STMT* stmt;
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
    int nargs;
jorton 8721b3
    int nvals;
jorton 8721b3
    apr_dbd_type_e *types;
jorton 8721b3
#endif
jorton 8721b3
};
jorton 8721b3
jorton 8721b3
struct apr_dbd_transaction_t {
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
    int mode;
jorton 8721b3
#endif
jorton 8721b3
    int errnum;
jorton 8721b3
    apr_dbd_t *handle;
jorton 8721b3
};
jorton 8721b3
jorton 8721b3
struct apr_dbd_t {
jorton 8721b3
    MYSQL* conn ;
jorton 8721b3
    apr_dbd_transaction_t* trans ;
jorton 8721b3
    unsigned long fldsz;
jorton 8721b3
};
jorton 8721b3
jorton 8721b3
struct apr_dbd_results_t {
jorton 8721b3
    int random;
jorton 8721b3
    MYSQL_RES *res;
jorton 8721b3
    MYSQL_STMT *statement;
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
    apr_pool_t *pool;
jorton 8721b3
#endif
jorton 8721b3
};
jorton 8721b3
struct apr_dbd_row_t {
jorton 8721b3
    MYSQL_ROW row;
jorton 8721b3
    apr_dbd_results_t *res;
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
    unsigned long *len;
jorton 8721b3
#endif
jorton 8721b3
};
jorton 8721b3
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
/* MySQL specific bucket for BLOB types */
jorton 8721b3
typedef struct apr_bucket_lob apr_bucket_lob;
jorton 8721b3
/**
jorton 8721b3
 * A bucket referring to a MySQL BLOB
jorton 8721b3
 */
jorton 8721b3
struct apr_bucket_lob {
jorton 8721b3
    /** Number of buckets using this memory */
jorton 8721b3
    apr_bucket_refcount  refcount;
jorton 8721b3
    /** The row this bucket refers to */
jorton 8721b3
    const apr_dbd_row_t *row;
jorton 8721b3
    /** The column this bucket refers to */
jorton 8721b3
    int col;
jorton 8721b3
    /** The pool into which any needed structures should
jorton 8721b3
     *  be created while reading from this bucket */
jorton 8721b3
    apr_pool_t *readpool;
jorton 8721b3
};
jorton 8721b3
jorton 8721b3
static void lob_bucket_destroy(void *data);
jorton 8721b3
static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
jorton 8721b3
                                    apr_size_t *len, apr_read_type_e block);
jorton 8721b3
static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
jorton 8721b3
                                       const apr_dbd_row_t *row, int col,
jorton 8721b3
                                       apr_off_t offset, apr_size_t len,
jorton 8721b3
                                       apr_pool_t *p);
jorton 8721b3
static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
jorton 8721b3
                                         apr_off_t offset,
jorton 8721b3
                                         apr_size_t len, apr_pool_t *p,
jorton 8721b3
                                         apr_bucket_alloc_t *list);
jorton 8721b3
jorton 8721b3
static const apr_bucket_type_t apr_bucket_type_lob = {
jorton 8721b3
    "LOB", 5, APR_BUCKET_DATA,
jorton 8721b3
    lob_bucket_destroy,
jorton 8721b3
    lob_bucket_read,
jorton 8721b3
    apr_bucket_setaside_notimpl,
jorton 8721b3
    apr_bucket_shared_split,
jorton 8721b3
    apr_bucket_shared_copy
jorton 8721b3
};
jorton 8721b3
jorton 8721b3
static void lob_bucket_destroy(void *data)
jorton 8721b3
{
jorton 8721b3
    apr_bucket_lob *f = data;
jorton 8721b3
jorton 8721b3
    if (apr_bucket_shared_destroy(f)) {
jorton 8721b3
        /* no need to destroy database objects here; it will get
jorton 8721b3
         * done automatically when the pool gets cleaned up */
jorton 8721b3
        apr_bucket_free(f);
jorton 8721b3
    }
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
jorton 8721b3
                                    apr_size_t *len, apr_read_type_e block)
jorton 8721b3
{
jorton 8721b3
    apr_bucket_lob *a = e->data;
jorton 8721b3
    const apr_dbd_row_t *row = a->row;
jorton 8721b3
    apr_dbd_results_t *res = row->res;
jorton 8721b3
    int col = a->col;
jorton 8721b3
    apr_bucket *b = NULL;
jorton 8721b3
    int rv;
jorton 8721b3
    apr_size_t blength = e->length;  /* bytes remaining in file past offset */
jorton 8721b3
    apr_off_t boffset = e->start;
jorton 8721b3
    MYSQL_BIND *bind = &res->bind[col];
jorton 8721b3
jorton 8721b3
    *str = NULL;  /* in case we die prematurely */
jorton 8721b3
jorton 8721b3
    /* fetch from offset if not at the beginning */
jorton 8721b3
    if (boffset > 0) {
jorton 8721b3
        rv = mysql_stmt_fetch_column(res->statement, bind, col, boffset);
jorton 8721b3
        if (rv != 0) {
jorton 8721b3
            return APR_EGENERAL;
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    blength -= blength > bind->buffer_length ? bind->buffer_length : blength;
jorton 8721b3
    *len = e->length - blength;
jorton 8721b3
    *str = bind->buffer;
jorton 8721b3
jorton 8721b3
    /* allocate new buffer, since we used this one for the bucket */
jorton 8721b3
    bind->buffer = apr_palloc(res->pool, bind->buffer_length);
jorton 8721b3
jorton 8721b3
    /*
jorton 8721b3
     * Change the current bucket to refer to what we read,
jorton 8721b3
     * even if we read nothing because we hit EOF.
jorton 8721b3
     */
jorton 8721b3
    apr_bucket_pool_make(e, *str, *len, res->pool);
jorton 8721b3
jorton 8721b3
    /* If we have more to read from the field, then create another bucket */
jorton 8721b3
    if (blength > 0) {
jorton 8721b3
        /* for efficiency, we can just build a new apr_bucket struct
jorton 8721b3
         * to wrap around the existing LOB bucket */
jorton 8721b3
        b = apr_bucket_alloc(sizeof(*b), e->list);
jorton 8721b3
        b->start  = boffset + *len;
jorton 8721b3
        b->length = blength;
jorton 8721b3
        b->data   = a;
jorton 8721b3
        b->type   = &apr_bucket_type_lob;
jorton 8721b3
        b->free   = apr_bucket_free;
jorton 8721b3
        b->list   = e->list;
jorton 8721b3
        APR_BUCKET_INSERT_AFTER(e, b);
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        lob_bucket_destroy(a);
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return APR_SUCCESS;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
jorton 8721b3
                                       const apr_dbd_row_t *row, int col,
jorton 8721b3
                                       apr_off_t offset, apr_size_t len,
jorton 8721b3
                                       apr_pool_t *p)
jorton 8721b3
{
jorton 8721b3
    apr_bucket_lob *f;
jorton 8721b3
jorton 8721b3
    f = apr_bucket_alloc(sizeof(*f), b->list);
jorton 8721b3
    f->row = row;
jorton 8721b3
    f->col = col;
jorton 8721b3
    f->readpool = p;
jorton 8721b3
jorton 8721b3
    b = apr_bucket_shared_make(b, f, offset, len);
jorton 8721b3
    b->type = &apr_bucket_type_lob;
jorton 8721b3
jorton 8721b3
    return b;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
jorton 8721b3
                                         apr_off_t offset,
jorton 8721b3
                                         apr_size_t len, apr_pool_t *p,
jorton 8721b3
                                         apr_bucket_alloc_t *list)
jorton 8721b3
{
jorton 8721b3
    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
jorton 8721b3
jorton 8721b3
    APR_BUCKET_INIT(b);
jorton 8721b3
    b->free = apr_bucket_free;
jorton 8721b3
    b->list = list;
jorton 8721b3
    return apr_bucket_lob_make(b, row, col, offset, len, p);
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
#endif
jorton 8721b3
jorton 8721b3
static apr_status_t free_result(void *data)
jorton 8721b3
{
jorton 8721b3
    mysql_free_result(data);
jorton 8721b3
    return APR_SUCCESS;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_select(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                            apr_dbd_results_t **results,
jorton 8721b3
                            const char *query, int seek)
jorton 8721b3
{
jorton 8721b3
    int sz;
jorton 8721b3
    int ret;
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
    ret = mysql_query(sql->conn, query);
jorton 8721b3
    if (!ret) {
jorton 8721b3
        if (sz = mysql_field_count(sql->conn), sz > 0) {
jorton 8721b3
            if (!*results) {
jorton 8721b3
                *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
jorton 8721b3
            }
jorton 8721b3
            (*results)->random = seek;
jorton 8721b3
            (*results)->statement = NULL;
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
            (*results)->pool = pool;
jorton 8721b3
#endif
jorton 8721b3
            if (seek) {
jorton 8721b3
                (*results)->res = mysql_store_result(sql->conn);
jorton 8721b3
            }
jorton 8721b3
            else {
jorton 8721b3
                (*results)->res = mysql_use_result(sql->conn);
jorton 8721b3
            }
jorton 8721b3
            apr_pool_cleanup_register(pool, (*results)->res,
jorton 8721b3
                                      free_result,apr_pool_cleanup_null);
jorton 8721b3
        }
jorton 8721b3
    } else {
jorton 8721b3
        ret = mysql_errno(sql->conn);
jorton 8721b3
    }
jorton 8721b3
    
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
    if (TXN_NOTICE_ERRORS(sql->trans)) {
jorton 8721b3
#else
jorton 8721b3
    if (sql->trans) {
jorton 8721b3
#endif
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
static const char *dbd_mysql_get_name(const apr_dbd_results_t *res, int n)
jorton 8721b3
{
jorton 8721b3
    if ((n < 0) || (n >= mysql_num_fields(res->res))) {
jorton 8721b3
        return NULL;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return mysql_fetch_fields(res->res)[n].name;
jorton 8721b3
}
jorton 8721b3
#endif
jorton 8721b3
jorton 8721b3
static int dbd_mysql_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
jorton 8721b3
                             apr_dbd_row_t **row, int rownum)
jorton 8721b3
{
jorton 8721b3
    MYSQL_ROW r = NULL;
jorton 8721b3
    int ret = 0;
jorton 8721b3
jorton 8721b3
    if (res->statement) {
jorton 8721b3
        if (res->random) {
jorton 8721b3
            if (rownum >= 0) {
jorton 8721b3
                mysql_stmt_data_seek(res->statement, (my_ulonglong)rownum);
jorton 8721b3
            }
jorton 8721b3
        }
jorton 8721b3
        ret = mysql_stmt_fetch(res->statement);
jorton 8721b3
        switch (ret) {
jorton 8721b3
        case 1:
jorton 8721b3
            ret = mysql_stmt_errno(res->statement);
jorton 8721b3
            break;
jorton 8721b3
        case MYSQL_NO_DATA:
jorton 8721b3
            ret = -1;
jorton 8721b3
            break;
jorton 8721b3
        default:
jorton 8721b3
            ret = 0; /* bad luck - get_entry will deal with this */
jorton 8721b3
            break;
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        if (res->random) {
jorton 8721b3
            if (rownum >= 0) {
jorton 8721b3
                mysql_data_seek(res->res, (my_ulonglong) rownum);
jorton 8721b3
            }
jorton 8721b3
        }
jorton 8721b3
        r = mysql_fetch_row(res->res);
jorton 8721b3
        if (r == NULL) {
jorton 8721b3
            ret = -1;
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    if (ret == 0) {
jorton 8721b3
        if (!*row) {
jorton 8721b3
            *row = apr_palloc(pool, sizeof(apr_dbd_row_t));
jorton 8721b3
        }
jorton 8721b3
        (*row)->row = r;
jorton 8721b3
        (*row)->res = res;
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
        (*row)->len = mysql_fetch_lengths(res->res);
jorton 8721b3
#endif
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        apr_pool_cleanup_run(pool, res->res, free_result);
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
#if 0
jorton 8721b3
/* An improved API that was proposed but not followed up */
jorton 8721b3
static int dbd_mysql_get_entry(const apr_dbd_row_t *row, int n,
jorton 8721b3
                               apr_dbd_datum_t *val)
jorton 8721b3
{
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
    if (row->res->statement) {
jorton 8721b3
        bind = &row->res->bind[n];
jorton 8721b3
        if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) {
jorton 8721b3
            val->type = APR_DBD_VALUE_NULL;
jorton 8721b3
            return -1;
jorton 8721b3
        }
jorton 8721b3
        if (*bind->is_null) {
jorton 8721b3
            val->type = APR_DBD_VALUE_NULL;
jorton 8721b3
            return -1;
jorton 8721b3
        }
jorton 8721b3
        else {
jorton 8721b3
            val->type = APR_DBD_VALUE_STRING;
jorton 8721b3
            val->value.stringval = bind->buffer;
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        val->type = APR_DBD_VALUE_STRING;
jorton 8721b3
        val->value.stringval = row->row[n];
jorton 8721b3
    }
jorton 8721b3
    return 0;
jorton 8721b3
}
jorton 8721b3
#else
jorton 8721b3
jorton 8721b3
static const char *dbd_mysql_get_entry(const apr_dbd_row_t *row, int n)
jorton 8721b3
{
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
    if (row->res->statement) {
jorton 8721b3
        bind = &row->res->bind[n];
jorton 8721b3
        if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) {
jorton 8721b3
            return NULL;
jorton 8721b3
        }
jorton 8721b3
        if (*bind->is_null) {
jorton 8721b3
            return NULL;
jorton 8721b3
        }
jorton 8721b3
        else {
jorton 8721b3
            return bind->buffer;
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        return row->row[n];
jorton 8721b3
    }
jorton 8721b3
    return NULL;
jorton 8721b3
}
jorton 8721b3
#endif
jorton 8721b3
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
static apr_status_t dbd_mysql_datum_get(const apr_dbd_row_t *row, int n,
jorton 8721b3
                                        apr_dbd_type_e type, void *data)
jorton 8721b3
{
jorton 8721b3
    if (row->res->statement) {
jorton 8721b3
        MYSQL_BIND *bind = &row->res->bind[n];
jorton 8721b3
        unsigned long len = *bind->length;
jorton 8721b3
jorton 8721b3
        if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) {
jorton 8721b3
            return APR_EGENERAL;
jorton 8721b3
        }
jorton 8721b3
jorton 8721b3
        if (*bind->is_null) {
jorton 8721b3
            return APR_ENOENT;
jorton 8721b3
        }
jorton 8721b3
jorton 8721b3
        switch (type) {
jorton 8721b3
        case APR_DBD_TYPE_TINY:
jorton 8721b3
            *(char*)data = atoi(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_UTINY:
jorton 8721b3
            *(unsigned char*)data = atoi(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_SHORT:
jorton 8721b3
            *(short*)data = atoi(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_USHORT:
jorton 8721b3
            *(unsigned short*)data = atoi(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_INT:
jorton 8721b3
            *(int*)data = atoi(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_UINT:
jorton 8721b3
            *(unsigned int*)data = atoi(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_LONG:
jorton 8721b3
            *(long*)data = atol(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_ULONG:
jorton 8721b3
            *(unsigned long*)data = atol(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_LONGLONG:
jorton 8721b3
            *(apr_int64_t*)data = apr_atoi64(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_ULONGLONG:
jorton 8721b3
            *(apr_uint64_t*)data = apr_atoi64(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_FLOAT:
jorton 8721b3
            *(float*)data = atof(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_DOUBLE:
jorton 8721b3
            *(double*)data = atof(bind->buffer);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_STRING:
jorton 8721b3
        case APR_DBD_TYPE_TEXT:
jorton 8721b3
        case APR_DBD_TYPE_TIME:
jorton 8721b3
        case APR_DBD_TYPE_DATE:
jorton 8721b3
        case APR_DBD_TYPE_DATETIME:
jorton 8721b3
        case APR_DBD_TYPE_TIMESTAMP:
jorton 8721b3
        case APR_DBD_TYPE_ZTIMESTAMP:
jorton 8721b3
            *((char*)bind->buffer+bind->buffer_length-1) = '\0';
jorton 8721b3
            *(char**)data = bind->buffer;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_BLOB:
jorton 8721b3
        case APR_DBD_TYPE_CLOB:
jorton 8721b3
            {
jorton 8721b3
            apr_bucket *e;
jorton 8721b3
            apr_bucket_brigade *b = (apr_bucket_brigade*)data;
jorton 8721b3
jorton 8721b3
            e = apr_bucket_lob_create(row, n, 0, len,
jorton 8721b3
                                      row->res->pool, b->bucket_alloc);
jorton 8721b3
            APR_BRIGADE_INSERT_TAIL(b, e);
jorton 8721b3
            }
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_NULL:
jorton 8721b3
            *(void**)data = NULL;
jorton 8721b3
            break;
jorton 8721b3
        default:
jorton 8721b3
            return APR_EGENERAL;
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        if (row->row[n] == NULL) {
jorton 8721b3
            return APR_ENOENT;
jorton 8721b3
        }
jorton 8721b3
jorton 8721b3
        switch (type) {
jorton 8721b3
        case APR_DBD_TYPE_TINY:
jorton 8721b3
            *(char*)data = atoi(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_UTINY:
jorton 8721b3
            *(unsigned char*)data = atoi(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_SHORT:
jorton 8721b3
            *(short*)data = atoi(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_USHORT:
jorton 8721b3
            *(unsigned short*)data = atoi(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_INT:
jorton 8721b3
            *(int*)data = atoi(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_UINT:
jorton 8721b3
            *(unsigned int*)data = atoi(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_LONG:
jorton 8721b3
            *(long*)data = atol(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_ULONG:
jorton 8721b3
            *(unsigned long*)data = atol(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_LONGLONG:
jorton 8721b3
            *(apr_int64_t*)data = apr_atoi64(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_ULONGLONG:
jorton 8721b3
            *(apr_uint64_t*)data = apr_atoi64(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_FLOAT:
jorton 8721b3
            *(float*)data = atof(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_DOUBLE:
jorton 8721b3
            *(double*)data = atof(row->row[n]);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_STRING:
jorton 8721b3
        case APR_DBD_TYPE_TEXT:
jorton 8721b3
        case APR_DBD_TYPE_TIME:
jorton 8721b3
        case APR_DBD_TYPE_DATE:
jorton 8721b3
        case APR_DBD_TYPE_DATETIME:
jorton 8721b3
        case APR_DBD_TYPE_TIMESTAMP:
jorton 8721b3
        case APR_DBD_TYPE_ZTIMESTAMP:
jorton 8721b3
            *(char**)data = row->row[n];
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_BLOB:
jorton 8721b3
        case APR_DBD_TYPE_CLOB:
jorton 8721b3
            {
jorton 8721b3
            apr_bucket *e;
jorton 8721b3
            apr_bucket_brigade *b = (apr_bucket_brigade*)data;
jorton 8721b3
jorton 8721b3
            e = apr_bucket_pool_create(row->row[n], row->len[n],
jorton 8721b3
                                       row->res->pool, b->bucket_alloc);
jorton 8721b3
            APR_BRIGADE_INSERT_TAIL(b, e);
jorton 8721b3
            }
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_NULL:
jorton 8721b3
            *(void**)data = NULL;
jorton 8721b3
            break;
jorton 8721b3
        default:
jorton 8721b3
            return APR_EGENERAL;
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    return 0;
jorton 8721b3
}
jorton 8721b3
#endif
jorton 8721b3
jorton 8721b3
static const char *dbd_mysql_error(apr_dbd_t *sql, int n)
jorton 8721b3
{
jorton 8721b3
    return mysql_error(sql->conn);
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_query(apr_dbd_t *sql, int *nrows, const char *query)
jorton 8721b3
{
jorton 8721b3
    int ret;
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
    ret = mysql_query(sql->conn, query);
jorton 8721b3
    if (ret != 0) {
jorton 8721b3
        ret = mysql_errno(sql->conn);
jorton 8721b3
    }
jorton 8721b3
    *nrows = mysql_affected_rows(sql->conn);
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
    if (TXN_NOTICE_ERRORS(sql->trans)) {
jorton 8721b3
#else
jorton 8721b3
    if (sql->trans) {
jorton 8721b3
#endif
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static const char *dbd_mysql_escape(apr_pool_t *pool, const char *arg,
jorton 8721b3
                                    apr_dbd_t *sql)
jorton 8721b3
{
jorton 8721b3
    unsigned long len = strlen(arg);
jorton 8721b3
    char *ret = apr_palloc(pool, 2*len + 1);
jorton 8721b3
    mysql_real_escape_string(sql->conn, ret, arg, len);
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static apr_status_t stmt_close(void *data)
jorton 8721b3
{
jorton 8721b3
    mysql_stmt_close(data);
jorton 8721b3
    return APR_SUCCESS;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                             const char *query, const char *label,
jorton 8721b3
                             int nargs, int nvals, apr_dbd_type_e *types,
jorton 8721b3
                             apr_dbd_prepared_t **statement)
jorton 8721b3
{
jorton 8721b3
    /* Translate from apr_dbd to native query format */
jorton 8721b3
    int ret;
jorton 8721b3
jorton 8721b3
    if (!*statement) {
jorton 8721b3
        *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t));
jorton 8721b3
    }
jorton 8721b3
    (*statement)->stmt = mysql_stmt_init(sql->conn);
jorton 8721b3
jorton 8721b3
    if ((*statement)->stmt) {
jorton 8721b3
        apr_pool_cleanup_register(pool, (*statement)->stmt,
jorton 8721b3
                                  stmt_close, apr_pool_cleanup_null);
jorton 8721b3
        ret = mysql_stmt_prepare((*statement)->stmt, query, strlen(query));
jorton 8721b3
jorton 8721b3
        if (ret != 0) {
jorton 8721b3
            ret = mysql_stmt_errno((*statement)->stmt);
jorton 8721b3
        }
jorton 8721b3
jorton 8721b3
        (*statement)->nargs = nargs;
jorton 8721b3
        (*statement)->nvals = nvals;
jorton 8721b3
        (*statement)->types = types;
jorton 8721b3
jorton 8721b3
        return ret;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return CR_OUT_OF_MEMORY;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static void dbd_mysql_bind(apr_dbd_prepared_t *statement,
jorton 8721b3
                           const char **values, MYSQL_BIND *bind)
jorton 8721b3
{
jorton 8721b3
    int i, j;
jorton 8721b3
jorton 8721b3
    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
jorton 8721b3
        bind[i].length = &bind[i].buffer_length;
jorton 8721b3
        bind[i].is_unsigned = 0;
jorton 8721b3
        bind[i].is_null = NULL;
jorton 8721b3
jorton 8721b3
        if (values[j] == NULL) {
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_NULL;
jorton 8721b3
        }
jorton 8721b3
        else {
jorton 8721b3
            switch (statement->types[i]) {
jorton 8721b3
            case APR_DBD_TYPE_BLOB:
jorton 8721b3
            case APR_DBD_TYPE_CLOB:
jorton 8721b3
                bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB;
jorton 8721b3
                bind[i].buffer = (void*)values[j];
jorton 8721b3
                bind[i].buffer_length = atol(values[++j]);
jorton 8721b3
jorton 8721b3
                /* skip table and column */
jorton 8721b3
                j += 2;
jorton 8721b3
                break;
jorton 8721b3
            default:
jorton 8721b3
                bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
jorton 8721b3
                bind[i].buffer = (void*)values[j];
jorton 8721b3
                bind[i].buffer_length = strlen(values[j]);
jorton 8721b3
                break;
jorton 8721b3
            }
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pquery_internal(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                                     int *nrows, apr_dbd_prepared_t *statement,
jorton 8721b3
                                     MYSQL_BIND *bind)
jorton 8721b3
{
jorton 8721b3
    int ret;
jorton 8721b3
jorton 8721b3
    ret = mysql_stmt_bind_param(statement->stmt, bind);
jorton 8721b3
    if (ret != 0) {
jorton 8721b3
        *nrows = 0;
jorton 8721b3
        ret = mysql_stmt_errno(statement->stmt);
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        ret = mysql_stmt_execute(statement->stmt);
jorton 8721b3
        if (ret != 0) {
jorton 8721b3
            ret = mysql_stmt_errno(statement->stmt);
jorton 8721b3
        }
jorton 8721b3
        *nrows = mysql_stmt_affected_rows(statement->stmt);
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pquery(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                            int *nrows, apr_dbd_prepared_t *statement,
jorton 8721b3
                            const char **values)
jorton 8721b3
{
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
    int ret;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND));
jorton 8721b3
jorton 8721b3
    dbd_mysql_bind(statement, values, bind);
jorton 8721b3
jorton 8721b3
    ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind);
jorton 8721b3
jorton 8721b3
    if (TXN_NOTICE_ERRORS(sql->trans)) {
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
jorton 8721b3
                             apr_dbd_prepared_t *statement, va_list args)
jorton 8721b3
{
jorton 8721b3
    const char **values;
jorton 8721b3
    int i;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
jorton 8721b3
jorton 8721b3
    for (i = 0; i < statement->nvals; i++) {
jorton 8721b3
        values[i] = va_arg(args, const char*);
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return dbd_mysql_pquery(pool, sql, nrows, statement, values);
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pselect_internal(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                                      apr_dbd_results_t **res,
jorton 8721b3
                                      apr_dbd_prepared_t *statement,
jorton 8721b3
                                      int random, MYSQL_BIND *bind)
jorton 8721b3
{
jorton 8721b3
    int nfields, i;
jorton 8721b3
    my_bool *is_nullr;
jorton 8721b3
#if MYSQL_VERSION_ID >= 50000
jorton 8721b3
    my_bool *error;
jorton 8721b3
#endif
jorton 8721b3
    int ret;
jorton 8721b3
    unsigned long *length, maxlen;
jorton 8721b3
jorton 8721b3
    ret = mysql_stmt_bind_param(statement->stmt, bind);
jorton 8721b3
    if (ret == 0) {
jorton 8721b3
        ret = mysql_stmt_execute(statement->stmt);
jorton 8721b3
        if (!ret) {
jorton 8721b3
            if (!*res) {
jorton 8721b3
                *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
jorton 8721b3
            }
jorton 8721b3
            (*res)->random = random;
jorton 8721b3
            (*res)->statement = statement->stmt;
jorton 8721b3
            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
jorton 8721b3
            (*res)->pool = pool;
jorton 8721b3
            apr_pool_cleanup_register(pool, (*res)->res,
jorton 8721b3
                                      free_result, apr_pool_cleanup_null);
jorton 8721b3
            nfields = mysql_num_fields((*res)->res);
jorton 8721b3
            if (!(*res)->bind) {
jorton 8721b3
                (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND));
jorton 8721b3
                length = apr_pcalloc(pool, nfields*sizeof(unsigned long));
jorton 8721b3
#if MYSQL_VERSION_ID >= 50000
jorton 8721b3
                error = apr_palloc(pool, nfields*sizeof(my_bool));
jorton 8721b3
#endif
jorton 8721b3
                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
jorton 8721b3
                for ( i = 0; i < nfields; ++i ) {
jorton 8721b3
                    maxlen = ((*res)->res->fields[i].length < sql->fldsz ?
jorton 8721b3
                              (*res)->res->fields[i].length : sql->fldsz) + 1;
jorton 8721b3
                    if ((*res)->res->fields[i].type == MYSQL_TYPE_BLOB) {
jorton 8721b3
                        (*res)->bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB;
jorton 8721b3
                    }
jorton 8721b3
                    else {
jorton 8721b3
                        (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
jorton 8721b3
                    }
jorton 8721b3
                    (*res)->bind[i].buffer_length = maxlen;
jorton 8721b3
                    (*res)->bind[i].length = &length[i];
jorton 8721b3
                    (*res)->bind[i].buffer = apr_palloc(pool, maxlen);
jorton 8721b3
                    (*res)->bind[i].is_null = is_nullr+i;
jorton 8721b3
#if MYSQL_VERSION_ID >= 50000
jorton 8721b3
                    (*res)->bind[i].error = error+i;
jorton 8721b3
#endif
jorton 8721b3
                }
jorton 8721b3
            }
jorton 8721b3
            ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
jorton 8721b3
            if (!ret) {
jorton 8721b3
                ret = mysql_stmt_store_result(statement->stmt);
jorton 8721b3
            }
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    if (ret != 0) {
jorton 8721b3
        ret = mysql_stmt_errno(statement->stmt);
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pselect(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                             apr_dbd_results_t **res,
jorton 8721b3
                             apr_dbd_prepared_t *statement, int random,
jorton 8721b3
                             const char **args)
jorton 8721b3
{
jorton 8721b3
    int ret;
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND));
jorton 8721b3
jorton 8721b3
    dbd_mysql_bind(statement, args, bind);
jorton 8721b3
jorton 8721b3
    ret = dbd_mysql_pselect_internal(pool, sql,  res, statement, random, bind);
jorton 8721b3
jorton 8721b3
    if (TXN_NOTICE_ERRORS(sql->trans)) {
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                              apr_dbd_results_t **res,
jorton 8721b3
                              apr_dbd_prepared_t *statement, int random,
jorton 8721b3
                              va_list args)
jorton 8721b3
{
jorton 8721b3
    const char **values;
jorton 8721b3
    int i;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
jorton 8721b3
jorton 8721b3
    for (i = 0; i < statement->nvals; i++) {
jorton 8721b3
        values[i] = va_arg(args, const char*);
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return dbd_mysql_pselect(pool, sql, res, statement, random, values);
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static void dbd_mysql_bbind(apr_pool_t *pool, apr_dbd_prepared_t *statement,
jorton 8721b3
                            const void **values, MYSQL_BIND *bind)
jorton 8721b3
{
jorton 8721b3
    void *arg;
jorton 8721b3
    int i, j;
jorton 8721b3
    apr_dbd_type_e type;
jorton 8721b3
jorton 8721b3
    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
jorton 8721b3
        arg = (void *)values[j];
jorton 8721b3
jorton 8721b3
        bind[i].length = &bind[i].buffer_length;
jorton 8721b3
        bind[i].is_null = NULL;
jorton 8721b3
jorton 8721b3
        type = (arg == NULL ? APR_DBD_TYPE_NULL : statement->types[i]);
jorton 8721b3
        switch (type) {
jorton 8721b3
        case APR_DBD_TYPE_TINY:
jorton 8721b3
            bind[i].buffer = arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_TINY;
jorton 8721b3
            bind[i].is_unsigned = 0;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_UTINY:
jorton 8721b3
            bind[i].buffer = arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_TINY;
jorton 8721b3
            bind[i].is_unsigned = 1;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_SHORT:
jorton 8721b3
            bind[i].buffer = arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_SHORT;
jorton 8721b3
            bind[i].is_unsigned = 0;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_USHORT:
jorton 8721b3
            bind[i].buffer = arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_SHORT;
jorton 8721b3
            bind[i].is_unsigned = 1;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_INT:
jorton 8721b3
            bind[i].buffer = arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_LONG;
jorton 8721b3
            bind[i].is_unsigned = 0;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_UINT:
jorton 8721b3
            bind[i].buffer = arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_LONG;
jorton 8721b3
            bind[i].is_unsigned = 1;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_LONG:
jorton 8721b3
            if (sizeof(int) == sizeof(long)) {
jorton 8721b3
                bind[i].buffer = arg;
jorton 8721b3
            }
jorton 8721b3
            else {
jorton 8721b3
                bind[i].buffer = apr_palloc(pool, sizeof(int));
jorton 8721b3
                *(int*)bind[i].buffer = *(long*)arg;
jorton 8721b3
            }
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_LONG;
jorton 8721b3
            bind[i].is_unsigned = 0;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_ULONG:
jorton 8721b3
            if (sizeof(unsigned int) == sizeof(unsigned long)) {
jorton 8721b3
                bind[i].buffer = arg;
jorton 8721b3
            }
jorton 8721b3
            else {
jorton 8721b3
                bind[i].buffer = apr_palloc(pool, sizeof(unsigned int));
jorton 8721b3
                *(unsigned int*)bind[i].buffer = *(unsigned long*)arg;
jorton 8721b3
            }
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_LONG;
jorton 8721b3
            bind[i].is_unsigned = 1;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_LONGLONG:
jorton 8721b3
            if (sizeof(long long) == sizeof(apr_int64_t)) {
jorton 8721b3
                bind[i].buffer = arg;
jorton 8721b3
            }
jorton 8721b3
            else {
jorton 8721b3
                bind[i].buffer = apr_palloc(pool, sizeof(long long));
jorton 8721b3
                *(long long*)bind[i].buffer = *(apr_int64_t*)arg;
jorton 8721b3
            }
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_LONGLONG;
jorton 8721b3
            bind[i].is_unsigned = 0;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_ULONGLONG:
jorton 8721b3
            if (sizeof(unsigned long long) == sizeof(apr_uint64_t)) {
jorton 8721b3
                bind[i].buffer = arg;
jorton 8721b3
            }
jorton 8721b3
            else {
jorton 8721b3
                bind[i].buffer = apr_palloc(pool, sizeof(unsigned long long));
jorton 8721b3
                *(unsigned long long*)bind[i].buffer = *(apr_uint64_t*)arg;
jorton 8721b3
            }
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_LONGLONG;
jorton 8721b3
            bind[i].is_unsigned = 1;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_FLOAT:
jorton 8721b3
            bind[i].buffer = arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_FLOAT;
jorton 8721b3
            bind[i].is_unsigned = 0;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_DOUBLE:
jorton 8721b3
            bind[i].buffer = arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_DOUBLE;
jorton 8721b3
            bind[i].is_unsigned = 0;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_STRING:
jorton 8721b3
        case APR_DBD_TYPE_TEXT:
jorton 8721b3
        case APR_DBD_TYPE_TIME:
jorton 8721b3
        case APR_DBD_TYPE_DATE:
jorton 8721b3
        case APR_DBD_TYPE_DATETIME:
jorton 8721b3
        case APR_DBD_TYPE_TIMESTAMP:
jorton 8721b3
        case APR_DBD_TYPE_ZTIMESTAMP:
jorton 8721b3
            bind[i].buffer = arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
jorton 8721b3
            bind[i].is_unsigned = 0;
jorton 8721b3
            bind[i].buffer_length = strlen((const char *)arg);
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_BLOB:
jorton 8721b3
        case APR_DBD_TYPE_CLOB:
jorton 8721b3
            bind[i].buffer = (void *)arg;
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB;
jorton 8721b3
            bind[i].is_unsigned = 0;
jorton 8721b3
            bind[i].buffer_length = *(apr_size_t*)values[++j];
jorton 8721b3
jorton 8721b3
            /* skip table and column */
jorton 8721b3
            j += 2;
jorton 8721b3
            break;
jorton 8721b3
        case APR_DBD_TYPE_NULL:
jorton 8721b3
        default:
jorton 8721b3
            bind[i].buffer_type = MYSQL_TYPE_NULL;
jorton 8721b3
            break;
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pbquery(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                             int *nrows, apr_dbd_prepared_t *statement,
jorton 8721b3
                             const void **values)
jorton 8721b3
{
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
    int ret;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND));
jorton 8721b3
jorton 8721b3
    dbd_mysql_bbind(pool, statement, values, bind);
jorton 8721b3
jorton 8721b3
    ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind);
jorton 8721b3
jorton 8721b3
    if (TXN_NOTICE_ERRORS(sql->trans)) {
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pvbquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
jorton 8721b3
                              apr_dbd_prepared_t *statement, va_list args)
jorton 8721b3
{
jorton 8721b3
    const void **values;
jorton 8721b3
    int i;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
jorton 8721b3
jorton 8721b3
    for (i = 0; i < statement->nvals; i++) {
jorton 8721b3
        values[i] = va_arg(args, const void*);
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return dbd_mysql_pbquery(pool, sql, nrows, statement, values);
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pbselect(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                              apr_dbd_results_t **res,
jorton 8721b3
                              apr_dbd_prepared_t *statement, int random,
jorton 8721b3
                              const void **args)
jorton 8721b3
{
jorton 8721b3
    int ret;
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND));
jorton 8721b3
jorton 8721b3
    dbd_mysql_bbind(pool, statement, args, bind);
jorton 8721b3
jorton 8721b3
    ret = dbd_mysql_pselect_internal(pool, sql,  res, statement, random, bind);
jorton 8721b3
jorton 8721b3
    if (TXN_NOTICE_ERRORS(sql->trans)) {
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pvbselect(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                               apr_dbd_results_t **res,
jorton 8721b3
                               apr_dbd_prepared_t *statement, int random,
jorton 8721b3
                               va_list args)
jorton 8721b3
{
jorton 8721b3
    const void **values;
jorton 8721b3
    int i;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
jorton 8721b3
jorton 8721b3
    for (i = 0; i < statement->nvals; i++) {
jorton 8721b3
        values[i] = va_arg(args, const void*);
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return dbd_mysql_pbselect(pool, sql, res, statement, random, values);
jorton 8721b3
}
jorton 8721b3
#else
jorton 8721b3
static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                             const char *query, const char *label,
jorton 8721b3
                             apr_dbd_prepared_t **statement)
jorton 8721b3
{
jorton 8721b3
    /* Translate from apr_dbd to native query format */
jorton 8721b3
    char *myquery = apr_pstrdup(pool, query);
jorton 8721b3
    char *p = myquery;
jorton 8721b3
    const char *q;
jorton 8721b3
    int ret;
jorton 8721b3
    for (q = query; *q; ++q) {
jorton 8721b3
        if (q[0] == '%') {
jorton 8721b3
            if (isalpha(q[1])) {
jorton 8721b3
                *p++ = '?';
jorton 8721b3
                ++q;
jorton 8721b3
            }
jorton 8721b3
            else if (q[1] == '%') {
jorton 8721b3
                /* reduce %% to % */
jorton 8721b3
                *p++ = *q++;
jorton 8721b3
            }
jorton 8721b3
            else {
jorton 8721b3
                *p++ = *q;
jorton 8721b3
            }
jorton 8721b3
        }
jorton 8721b3
        else {
jorton 8721b3
            *p++ = *q;
jorton 8721b3
        }
jorton 8721b3
    } 
jorton 8721b3
    *p = 0;
jorton 8721b3
    if (!*statement) {
jorton 8721b3
        *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t));
jorton 8721b3
    }
jorton 8721b3
    (*statement)->stmt = mysql_stmt_init(sql->conn);
jorton 8721b3
jorton 8721b3
    if ((*statement)->stmt) {
jorton 8721b3
        apr_pool_cleanup_register(pool, (*statement)->stmt,
jorton 8721b3
                                  stmt_close, apr_pool_cleanup_null);
jorton 8721b3
        ret = mysql_stmt_prepare((*statement)->stmt, myquery, strlen(myquery));
jorton 8721b3
jorton 8721b3
        if (ret != 0) {
jorton 8721b3
            ret = mysql_stmt_errno((*statement)->stmt);
jorton 8721b3
        }
jorton 8721b3
jorton 8721b3
        return ret;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    return CR_OUT_OF_MEMORY;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pquery(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                            int *nrows, apr_dbd_prepared_t *statement,
jorton 8721b3
                            int nargs, const char **values)
jorton 8721b3
{
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
    char *arg;
jorton 8721b3
    int ret;
jorton 8721b3
    int i;
jorton 8721b3
    my_bool is_null = FALSE;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
    nargs = mysql_stmt_param_count(statement->stmt);
jorton 8721b3
jorton 8721b3
    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
jorton 8721b3
    for (i=0; i < nargs; ++i) {
jorton 8721b3
        arg = (char*)values[i];
jorton 8721b3
        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
jorton 8721b3
        bind[i].buffer = arg;
jorton 8721b3
        bind[i].buffer_length = strlen(arg);
jorton 8721b3
        bind[i].length = &bind[i].buffer_length;
jorton 8721b3
        bind[i].is_null = &is_null;
jorton 8721b3
        bind[i].is_unsigned = 0;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    ret = mysql_stmt_bind_param(statement->stmt, bind);
jorton 8721b3
    if (ret != 0) {
jorton 8721b3
        *nrows = 0;
jorton 8721b3
        ret = mysql_stmt_errno(statement->stmt);
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        ret = mysql_stmt_execute(statement->stmt);
jorton 8721b3
        if (ret != 0) {
jorton 8721b3
            ret = mysql_stmt_errno(statement->stmt);
jorton 8721b3
        }
jorton 8721b3
        *nrows = mysql_stmt_affected_rows(statement->stmt);
jorton 8721b3
    }
jorton 8721b3
    if (sql->trans) {
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows,
jorton 8721b3
                             apr_dbd_prepared_t *statement, va_list args)
jorton 8721b3
{
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
    char *arg;
jorton 8721b3
    int ret;
jorton 8721b3
    int nargs = 0;
jorton 8721b3
    int i;
jorton 8721b3
    my_bool is_null = FALSE;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
    nargs = mysql_stmt_param_count(statement->stmt);
jorton 8721b3
jorton 8721b3
    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
jorton 8721b3
    for (i=0; i < nargs; ++i) {
jorton 8721b3
        arg = va_arg(args, char*);
jorton 8721b3
        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
jorton 8721b3
        bind[i].buffer = arg;
jorton 8721b3
        bind[i].buffer_length = strlen(arg);
jorton 8721b3
        bind[i].length = &bind[i].buffer_length;
jorton 8721b3
        bind[i].is_null = &is_null;
jorton 8721b3
        bind[i].is_unsigned = 0;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    ret = mysql_stmt_bind_param(statement->stmt, bind);
jorton 8721b3
    if (ret != 0) {
jorton 8721b3
        *nrows = 0;
jorton 8721b3
        ret = mysql_stmt_errno(statement->stmt);
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        ret = mysql_stmt_execute(statement->stmt);
jorton 8721b3
        if (ret != 0) {
jorton 8721b3
            ret = mysql_stmt_errno(statement->stmt);
jorton 8721b3
        }
jorton 8721b3
        *nrows = mysql_stmt_affected_rows(statement->stmt);
jorton 8721b3
    }
jorton 8721b3
    if (sql->trans) {
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pselect(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                             apr_dbd_results_t **res,
jorton 8721b3
                             apr_dbd_prepared_t *statement, int random,
jorton 8721b3
                             int nargs, const char **args)
jorton 8721b3
{
jorton 8721b3
    int i;
jorton 8721b3
    int nfields;
jorton 8721b3
    char *arg;
jorton 8721b3
    my_bool is_null = FALSE;
jorton 8721b3
    my_bool *is_nullr;
jorton 8721b3
#if MYSQL_VERSION_ID >= 50000
jorton 8721b3
    my_bool *error;
jorton 8721b3
#endif
jorton 8721b3
    int ret;
jorton 8721b3
    unsigned long *length, maxlen;
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    nargs = mysql_stmt_param_count(statement->stmt);
jorton 8721b3
    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
jorton 8721b3
jorton 8721b3
    for (i=0; i < nargs; ++i) {
jorton 8721b3
        arg = (char*)args[i];
jorton 8721b3
        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
jorton 8721b3
        bind[i].buffer = arg;
jorton 8721b3
        bind[i].buffer_length = strlen(arg);
jorton 8721b3
        bind[i].length = &bind[i].buffer_length;
jorton 8721b3
        bind[i].is_null = &is_null;
jorton 8721b3
        bind[i].is_unsigned = 0;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    ret = mysql_stmt_bind_param(statement->stmt, bind);
jorton 8721b3
    if (ret == 0) {
jorton 8721b3
        ret = mysql_stmt_execute(statement->stmt);
jorton 8721b3
        if (!ret) {
jorton 8721b3
            if (!*res) {
jorton 8721b3
                *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
jorton 8721b3
            }
jorton 8721b3
            (*res)->random = random;
jorton 8721b3
            (*res)->statement = statement->stmt;
jorton 8721b3
            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
jorton 8721b3
            apr_pool_cleanup_register(pool, (*res)->res,
jorton 8721b3
                                      free_result, apr_pool_cleanup_null);
jorton 8721b3
            nfields = mysql_num_fields((*res)->res);
jorton 8721b3
            if (!(*res)->bind) {
jorton 8721b3
                (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND));
jorton 8721b3
                length = apr_pcalloc(pool, nfields*sizeof(unsigned long));
jorton 8721b3
#if MYSQL_VERSION_ID >= 50000
jorton 8721b3
                error = apr_palloc(pool, nfields*sizeof(my_bool));
jorton 8721b3
#endif
jorton 8721b3
                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
jorton 8721b3
                for ( i = 0; i < nfields; ++i ) {
jorton 8721b3
                    maxlen = ((*res)->res->fields[i].length < sql->fldsz ?
jorton 8721b3
                              (*res)->res->fields[i].length : sql->fldsz) + 1;
jorton 8721b3
                    (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
jorton 8721b3
                    (*res)->bind[i].buffer_length = maxlen;
jorton 8721b3
                    (*res)->bind[i].length = &length[i];
jorton 8721b3
                    (*res)->bind[i].buffer = apr_palloc(pool, maxlen);
jorton 8721b3
                    (*res)->bind[i].is_null = is_nullr+i;
jorton 8721b3
#if MYSQL_VERSION_ID >= 50000
jorton 8721b3
                    (*res)->bind[i].error = error+i;
jorton 8721b3
#endif
jorton 8721b3
                }
jorton 8721b3
            }
jorton 8721b3
            ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
jorton 8721b3
            if (!ret) {
jorton 8721b3
                ret = mysql_stmt_store_result(statement->stmt);
jorton 8721b3
            }
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    if (ret != 0) {
jorton 8721b3
        ret = mysql_stmt_errno(statement->stmt);
jorton 8721b3
    }
jorton 8721b3
    if (sql->trans) {
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
jorton 8721b3
                              apr_dbd_results_t **res,
jorton 8721b3
                              apr_dbd_prepared_t *statement, int random,
jorton 8721b3
                              va_list args)
jorton 8721b3
{
jorton 8721b3
    int i;
jorton 8721b3
    int nfields;
jorton 8721b3
    char *arg;
jorton 8721b3
    my_bool is_null = FALSE;
jorton 8721b3
    my_bool *is_nullr;
jorton 8721b3
#if MYSQL_VERSION_ID >= 50000
jorton 8721b3
    my_bool *error;
jorton 8721b3
#endif
jorton 8721b3
    int ret;
jorton 8721b3
    unsigned long *length, maxlen;
jorton 8721b3
    int nargs;
jorton 8721b3
    MYSQL_BIND *bind;
jorton 8721b3
jorton 8721b3
    if (sql->trans && sql->trans->errnum) {
jorton 8721b3
        return sql->trans->errnum;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    nargs = mysql_stmt_param_count(statement->stmt);
jorton 8721b3
    bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND));
jorton 8721b3
jorton 8721b3
    for (i=0; i < nargs; ++i) {
jorton 8721b3
        arg = va_arg(args, char*);
jorton 8721b3
        bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
jorton 8721b3
        bind[i].buffer = arg;
jorton 8721b3
        bind[i].buffer_length = strlen(arg);
jorton 8721b3
        bind[i].length = &bind[i].buffer_length;
jorton 8721b3
        bind[i].is_null = &is_null;
jorton 8721b3
        bind[i].is_unsigned = 0;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
    ret = mysql_stmt_bind_param(statement->stmt, bind);
jorton 8721b3
    if (ret == 0) {
jorton 8721b3
        ret = mysql_stmt_execute(statement->stmt);
jorton 8721b3
        if (!ret) {
jorton 8721b3
            if (!*res) {
jorton 8721b3
                *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t));
jorton 8721b3
            }
jorton 8721b3
            (*res)->random = random;
jorton 8721b3
            (*res)->statement = statement->stmt;
jorton 8721b3
            (*res)->res = mysql_stmt_result_metadata(statement->stmt);
jorton 8721b3
            apr_pool_cleanup_register(pool, (*res)->res,
jorton 8721b3
                                      free_result, apr_pool_cleanup_null);
jorton 8721b3
            nfields = mysql_num_fields((*res)->res);
jorton 8721b3
            if (!(*res)->bind) {
jorton 8721b3
                (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND));
jorton 8721b3
                length = apr_pcalloc(pool, nfields*sizeof(unsigned long));
jorton 8721b3
#if MYSQL_VERSION_ID >= 50000
jorton 8721b3
                error = apr_palloc(pool, nfields*sizeof(my_bool));
jorton 8721b3
#endif
jorton 8721b3
                is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool));
jorton 8721b3
                for ( i = 0; i < nfields; ++i ) {
jorton 8721b3
                    maxlen = ((*res)->res->fields[i].length < sql->fldsz ?
jorton 8721b3
                              (*res)->res->fields[i].length : sql->fldsz) + 1;
jorton 8721b3
                    (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
jorton 8721b3
                    (*res)->bind[i].buffer_length = maxlen;
jorton 8721b3
                    (*res)->bind[i].length = &length[i];
jorton 8721b3
                    (*res)->bind[i].buffer = apr_palloc(pool, maxlen);
jorton 8721b3
                    (*res)->bind[i].is_null = is_nullr+i;
jorton 8721b3
#if MYSQL_VERSION_ID >= 50000
jorton 8721b3
                    (*res)->bind[i].error = error+i;
jorton 8721b3
#endif
jorton 8721b3
                }
jorton 8721b3
            }
jorton 8721b3
            ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind);
jorton 8721b3
            if (!ret) {
jorton 8721b3
                ret = mysql_stmt_store_result(statement->stmt);
jorton 8721b3
            }
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    if (ret != 0) {
jorton 8721b3
        ret = mysql_stmt_errno(statement->stmt);
jorton 8721b3
    }
jorton 8721b3
    if (sql->trans) {
jorton 8721b3
        sql->trans->errnum = ret;
jorton 8721b3
    }
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
#endif
jorton 8721b3
jorton 8721b3
static int dbd_mysql_end_transaction(apr_dbd_transaction_t *trans)
jorton 8721b3
{
jorton 8721b3
    int ret = -1;
jorton 8721b3
    if (trans) {
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
        /* rollback on error or explicit rollback request */
jorton 8721b3
        if (trans->errnum || TXN_DO_ROLLBACK(trans)) {
jorton 8721b3
#else
jorton 8721b3
        if (trans->errnum) {
jorton 8721b3
#endif
jorton 8721b3
            trans->errnum = 0;
jorton 8721b3
            ret = mysql_rollback(trans->handle->conn);
jorton 8721b3
        }
jorton 8721b3
        else {
jorton 8721b3
            ret = mysql_commit(trans->handle->conn);
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    ret |= mysql_autocommit(trans->handle->conn, 1);
jorton 8721b3
    trans->handle->trans = NULL;
jorton 8721b3
    return ret;
jorton 8721b3
}
jorton 8721b3
/* Whether or not transactions work depends on whether the
jorton 8721b3
 * underlying DB supports them within MySQL.  Unfortunately
jorton 8721b3
 * it fails silently with the default InnoDB.
jorton 8721b3
 */
jorton 8721b3
jorton 8721b3
static int dbd_mysql_transaction(apr_pool_t *pool, apr_dbd_t *handle,
jorton 8721b3
                                 apr_dbd_transaction_t **trans)
jorton 8721b3
{
jorton 8721b3
    /* Don't try recursive transactions here */
jorton 8721b3
    if (handle->trans) {
jorton 8721b3
        dbd_mysql_end_transaction(handle->trans) ;
jorton 8721b3
    }
jorton 8721b3
    if (!*trans) {
jorton 8721b3
        *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
jorton 8721b3
    }
jorton 8721b3
    (*trans)->errnum = mysql_autocommit(handle->conn, 0);
jorton 8721b3
    (*trans)->handle = handle;
jorton 8721b3
    handle->trans = *trans;
jorton 8721b3
    return (*trans)->errnum;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
static int dbd_mysql_transaction_mode_get(apr_dbd_transaction_t *trans)
jorton 8721b3
{
jorton 8721b3
    if (!trans)
jorton 8721b3
        return APR_DBD_TRANSACTION_COMMIT;
jorton 8721b3
jorton 8721b3
    return trans->mode;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_transaction_mode_set(apr_dbd_transaction_t *trans,
jorton 8721b3
                                          int mode)
jorton 8721b3
{
jorton 8721b3
    if (!trans)
jorton 8721b3
        return APR_DBD_TRANSACTION_COMMIT;
jorton 8721b3
jorton 8721b3
    return trans->mode = (mode & TXN_MODE_BITS);
jorton 8721b3
}
jorton 8721b3
#endif
jorton 8721b3
jorton 8721b3
static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params)
jorton 8721b3
{
jorton 8721b3
    static const char *const delims = " \r\n\t;|,";
jorton 8721b3
    const char *ptr;
jorton 8721b3
    int i;
jorton 8721b3
    const char *key;
jorton 8721b3
    size_t klen;
jorton 8721b3
    const char *value;
jorton 8721b3
    size_t vlen;
jorton 8721b3
#if MYSQL_VERSION_ID >= 50013
jorton 8721b3
    my_bool do_reconnect = 1;
jorton 8721b3
#endif
jorton 8721b3
    MYSQL *real_conn;
jorton 8721b3
    unsigned long flags = 0;
jorton 8721b3
    
jorton 8721b3
    struct {
jorton 8721b3
        const char *field;
jorton 8721b3
        const char *value;
jorton 8721b3
    } fields[] = {
jorton 8721b3
        {"host", NULL},
jorton 8721b3
        {"user", NULL},
jorton 8721b3
        {"pass", NULL},
jorton 8721b3
        {"dbname", NULL},
jorton 8721b3
        {"port", NULL},
jorton 8721b3
        {"sock", NULL},
jorton 8721b3
        {"flags", NULL},
jorton 8721b3
        {"fldsz", NULL},
jorton 8721b3
        {NULL, NULL}
jorton 8721b3
    };
jorton 8721b3
    unsigned int port = 0;
jorton 8721b3
    apr_dbd_t *sql = apr_pcalloc(pool, sizeof(apr_dbd_t));
jorton 8721b3
    sql->fldsz = FIELDSIZE;
jorton 8721b3
    sql->conn = mysql_init(sql->conn);
jorton 8721b3
    if ( sql->conn == NULL ) {
jorton 8721b3
        return NULL;
jorton 8721b3
    }
jorton 8721b3
    for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {
jorton 8721b3
        for (key = ptr-1; isspace(*key); --key);
jorton 8721b3
        klen = 0;
jorton 8721b3
        while (isalpha(*key)) {
jorton 8721b3
            /* don't parse backwards off the start of the string */
jorton 8721b3
            if (key == params) {
jorton 8721b3
                --key;
jorton 8721b3
                ++klen;
jorton 8721b3
                break;
jorton 8721b3
            }
jorton 8721b3
            --key;
jorton 8721b3
            ++klen;
jorton 8721b3
        }
jorton 8721b3
        ++key;
jorton 8721b3
        for (value = ptr+1; isspace(*value); ++value);
jorton 8721b3
        vlen = strcspn(value, delims);
jorton 8721b3
        for (i = 0; fields[i].field != NULL; i++) {
jorton 8721b3
            if (!strncasecmp(fields[i].field, key, klen)) {
jorton 8721b3
                fields[i].value = apr_pstrndup(pool, value, vlen);
jorton 8721b3
                break;
jorton 8721b3
            }
jorton 8721b3
        }
jorton 8721b3
        ptr = value+vlen;
jorton 8721b3
    }
jorton 8721b3
    if (fields[4].value != NULL) {
jorton 8721b3
        port = atoi(fields[4].value);
jorton 8721b3
    }
jorton 8721b3
    if (fields[6].value != NULL &&
jorton 8721b3
        !strcmp(fields[6].value, "CLIENT_FOUND_ROWS")) {
jorton 8721b3
        flags |= CLIENT_FOUND_ROWS; /* only option we know */
jorton 8721b3
    }
jorton 8721b3
    if (fields[7].value != NULL) {
jorton 8721b3
        sql->fldsz = atol(fields[7].value);
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
#if MYSQL_VERSION_ID >= 50013
jorton 8721b3
    /* the MySQL manual says this should be BEFORE mysql_real_connect */
jorton 8721b3
    mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect);
jorton 8721b3
#endif
jorton 8721b3
    
jorton 8721b3
    real_conn = mysql_real_connect(sql->conn, fields[0].value,
jorton 8721b3
                                   fields[1].value, fields[2].value,
jorton 8721b3
                                   fields[3].value, port,
jorton 8721b3
                                   fields[5].value, flags);
jorton 8721b3
jorton 8721b3
    if(real_conn == NULL) {
jorton 8721b3
        mysql_close(sql->conn);
jorton 8721b3
        return NULL;
jorton 8721b3
    }
jorton 8721b3
jorton 8721b3
#if MYSQL_VERSION_ID >= 50013
jorton 8721b3
    /* Some say this should be AFTER mysql_real_connect */
jorton 8721b3
    mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect);
jorton 8721b3
#endif
jorton 8721b3
jorton 8721b3
    return sql;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static apr_status_t dbd_mysql_close(apr_dbd_t *handle)
jorton 8721b3
{
jorton 8721b3
    mysql_close(handle->conn);
jorton 8721b3
    return APR_SUCCESS;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static apr_status_t dbd_mysql_check_conn(apr_pool_t *pool,
jorton 8721b3
                                         apr_dbd_t *handle)
jorton 8721b3
{
jorton 8721b3
    return mysql_ping(handle->conn) ? APR_EGENERAL : APR_SUCCESS;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_select_db(apr_pool_t *pool, apr_dbd_t* handle,
jorton 8721b3
                               const char* name)
jorton 8721b3
{
jorton 8721b3
    return mysql_select_db(handle->conn, name);
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static void *dbd_mysql_native(apr_dbd_t *handle)
jorton 8721b3
{
jorton 8721b3
    return handle->conn;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_num_cols(apr_dbd_results_t *res)
jorton 8721b3
{
jorton 8721b3
    if (res->statement) {
jorton 8721b3
        return mysql_stmt_field_count(res->statement);
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        return mysql_num_fields(res->res);
jorton 8721b3
    }
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static int dbd_mysql_num_tuples(apr_dbd_results_t *res)
jorton 8721b3
{
jorton 8721b3
    if (res->random) {
jorton 8721b3
        if (res->statement) {
jorton 8721b3
            return (int) mysql_stmt_num_rows(res->statement);
jorton 8721b3
        }
jorton 8721b3
        else {
jorton 8721b3
            return (int) mysql_num_rows(res->res);
jorton 8721b3
        }
jorton 8721b3
    }
jorton 8721b3
    else {
jorton 8721b3
        return -1;
jorton 8721b3
    }
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static apr_status_t thread_end(void *data)
jorton 8721b3
{
jorton 8721b3
    mysql_thread_end();
jorton 8721b3
    return APR_SUCCESS;
jorton 8721b3
}
jorton 8721b3
jorton 8721b3
static void dbd_mysql_init(apr_pool_t *pool)
jorton 8721b3
{
jorton 8721b3
    my_init();
jorton 8721b3
    /* FIXME: this is a guess; find out what it really does */ 
jorton 8721b3
    apr_pool_cleanup_register(pool, NULL, thread_end, apr_pool_cleanup_null);
jorton 8721b3
}
jorton 8721b3
APU_DECLARE_DATA const apr_dbd_driver_t apr_dbd_mysql_driver = {
jorton 8721b3
    "mysql",
jorton 8721b3
    dbd_mysql_init,
jorton 8721b3
    dbd_mysql_native,
jorton 8721b3
    dbd_mysql_open,
jorton 8721b3
    dbd_mysql_check_conn,
jorton 8721b3
    dbd_mysql_close,
jorton 8721b3
    dbd_mysql_select_db,
jorton 8721b3
    dbd_mysql_transaction,
jorton 8721b3
    dbd_mysql_end_transaction,
jorton 8721b3
    dbd_mysql_query,
jorton 8721b3
    dbd_mysql_select,
jorton 8721b3
    dbd_mysql_num_cols,
jorton 8721b3
    dbd_mysql_num_tuples,
jorton 8721b3
    dbd_mysql_get_row,
jorton 8721b3
    dbd_mysql_get_entry,
jorton 8721b3
    dbd_mysql_error,
jorton 8721b3
    dbd_mysql_escape,
jorton 8721b3
    dbd_mysql_prepare,
jorton 8721b3
    dbd_mysql_pvquery,
jorton 8721b3
    dbd_mysql_pvselect,
jorton 8721b3
    dbd_mysql_pquery,
jorton 8721b3
    dbd_mysql_pselect
jorton 8721b3
#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3)
jorton 8721b3
    ,
jorton 8721b3
    dbd_mysql_get_name,
jorton 8721b3
    dbd_mysql_transaction_mode_get,
jorton 8721b3
    dbd_mysql_transaction_mode_set,
jorton 8721b3
    "?",
jorton 8721b3
    dbd_mysql_pvbquery,
jorton 8721b3
    dbd_mysql_pvbselect,
jorton 8721b3
    dbd_mysql_pbquery,
jorton 8721b3
    dbd_mysql_pbselect,
jorton 8721b3
    dbd_mysql_datum_get
jorton 8721b3
#endif
jorton 8721b3
};
jorton 8721b3
jorton 8721b3
#endif