diff --git a/README.md b/README.md index 5c5a0f7..5c0c83e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # libaprutil +The mission of the Apache Portable Runtime (APR) project is to create and maintain software libraries that provide a predictable and consistent interface to underlying platform-specific implementations. +The primary goal is to provide an API to which software developers may code and be assured of predictable if not identical behaviour regardless of the platform on which their software is built, relieving them of the need to code special-case conditions to work around or take advantage of platform-specific deficiencies or features. + diff --git a/apr_dbd_mysql.c b/apr_dbd_mysql.c new file mode 100644 index 0000000..6bfea91 --- /dev/null +++ b/apr_dbd_mysql.c @@ -0,0 +1,1632 @@ +/****************************** NOTICE *************************** + * + * This is no longer the recommended version of this driver. + * Please use the versions from the APR repositories at svn.apache.org + * + ****************************** NOTICE ***************************/ + +/* + Copyright (c) 2003-7, WebThing Ltd and other contributors + +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. Alternatively, where this program +is aggregated with the Apache APR-UTIL package version 1.2 or later, +you can distribute and/or modify it under the terms of the Apache +License 2.0 as published by the Apache Software Foundation. + +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 +applicable 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. +You may obtain a copy of the Apache License 2.0 at: +http://www.apache.org/licenses/LICENSE-2.0 + +*/ + +/* LICENSE NOTE + * + * The current GPL satisfies MySQL licensing terms without + * invoking any exceptions. ASF policy doesn't permit GPL + * software to be distributed by apache.org, but this should + * not be a problem for third-parties who wish to distribute + * it alongside the APR and other Apache software. + * + * It is updated to dual license after discussion with Debian + * and taking into account MySQL's FOSS exception. + * http://bahumbug.wordpress.com/2007/01/09/re-licensing-apr_dbd_mysql/ + * http://www.mysql.com/company/legal/licensing/foss-exception.html + * + * MAINTAINERS + * + * This code was originally written by Nick Kew for MySQL 4.1. + * and subsequently updated by others to support MySQL 5.0. + * The current lead maintainer is Bojan Smojver, with others + * contributing via the developer list at apr.apache.org. + * + */ + + +#include "apu.h" +#define HAVE_MYSQL_MYSQL_H + +#if APU_HAVE_MYSQL + +#include "apu_version.h" +#include "apu_config.h" + +#include +#include + +#ifdef HAVE_MYSQL_H +#include +#include +#elif defined(HAVE_MYSQL_MYSQL_H) +#include +#include +#endif + +#include "apr_strings.h" +#include "apr_buckets.h" + +#include "apr_dbd_internal.h" + +/* default maximum field size 1 MB */ +#define FIELDSIZE 1048575 + +struct apr_dbd_prepared_t { + MYSQL_STMT* stmt; +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + int nargs; + int nvals; + apr_dbd_type_e *types; +#endif +}; + +struct apr_dbd_transaction_t { +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + int mode; +#endif + int errnum; + apr_dbd_t *handle; +}; + +struct apr_dbd_t { + MYSQL* conn ; + apr_dbd_transaction_t* trans ; + unsigned long fldsz; +}; + +struct apr_dbd_results_t { + int random; + MYSQL_RES *res; + MYSQL_STMT *statement; + MYSQL_BIND *bind; +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + apr_pool_t *pool; +#endif +}; +struct apr_dbd_row_t { + MYSQL_ROW row; + apr_dbd_results_t *res; +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + unsigned long *len; +#endif +}; + +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) +/* MySQL specific bucket for BLOB types */ +typedef struct apr_bucket_lob apr_bucket_lob; +/** + * A bucket referring to a MySQL BLOB + */ +struct apr_bucket_lob { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The row this bucket refers to */ + const apr_dbd_row_t *row; + /** The column this bucket refers to */ + int col; + /** The pool into which any needed structures should + * be created while reading from this bucket */ + apr_pool_t *readpool; +}; + +static void lob_bucket_destroy(void *data); +static apr_status_t lob_bucket_read(apr_bucket *e, const char **str, + apr_size_t *len, apr_read_type_e block); +static apr_bucket *apr_bucket_lob_make(apr_bucket *b, + const apr_dbd_row_t *row, int col, + apr_off_t offset, apr_size_t len, + apr_pool_t *p); +static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col, + apr_off_t offset, + apr_size_t len, apr_pool_t *p, + apr_bucket_alloc_t *list); + +static const apr_bucket_type_t apr_bucket_type_lob = { + "LOB", 5, APR_BUCKET_DATA, + lob_bucket_destroy, + lob_bucket_read, + apr_bucket_setaside_notimpl, + apr_bucket_shared_split, + apr_bucket_shared_copy +}; + +static void lob_bucket_destroy(void *data) +{ + apr_bucket_lob *f = data; + + if (apr_bucket_shared_destroy(f)) { + /* no need to destroy database objects here; it will get + * done automatically when the pool gets cleaned up */ + apr_bucket_free(f); + } +} + +static apr_status_t lob_bucket_read(apr_bucket *e, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + apr_bucket_lob *a = e->data; + const apr_dbd_row_t *row = a->row; + apr_dbd_results_t *res = row->res; + int col = a->col; + apr_bucket *b = NULL; + int rv; + apr_size_t blength = e->length; /* bytes remaining in file past offset */ + apr_off_t boffset = e->start; + MYSQL_BIND *bind = &res->bind[col]; + + *str = NULL; /* in case we die prematurely */ + + /* fetch from offset if not at the beginning */ + if (boffset > 0) { + rv = mysql_stmt_fetch_column(res->statement, bind, col, boffset); + if (rv != 0) { + return APR_EGENERAL; + } + } + blength -= blength > bind->buffer_length ? bind->buffer_length : blength; + *len = e->length - blength; + *str = bind->buffer; + + /* allocate new buffer, since we used this one for the bucket */ + bind->buffer = apr_palloc(res->pool, bind->buffer_length); + + /* + * Change the current bucket to refer to what we read, + * even if we read nothing because we hit EOF. + */ + apr_bucket_pool_make(e, *str, *len, res->pool); + + /* If we have more to read from the field, then create another bucket */ + if (blength > 0) { + /* for efficiency, we can just build a new apr_bucket struct + * to wrap around the existing LOB bucket */ + b = apr_bucket_alloc(sizeof(*b), e->list); + b->start = boffset + *len; + b->length = blength; + b->data = a; + b->type = &apr_bucket_type_lob; + b->free = apr_bucket_free; + b->list = e->list; + APR_BUCKET_INSERT_AFTER(e, b); + } + else { + lob_bucket_destroy(a); + } + + return APR_SUCCESS; +} + +static apr_bucket *apr_bucket_lob_make(apr_bucket *b, + const apr_dbd_row_t *row, int col, + apr_off_t offset, apr_size_t len, + apr_pool_t *p) +{ + apr_bucket_lob *f; + + f = apr_bucket_alloc(sizeof(*f), b->list); + f->row = row; + f->col = col; + f->readpool = p; + + b = apr_bucket_shared_make(b, f, offset, len); + b->type = &apr_bucket_type_lob; + + return b; +} + +static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col, + apr_off_t offset, + apr_size_t len, apr_pool_t *p, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_lob_make(b, row, col, offset, len, p); +} + +#endif + +static apr_status_t free_result(void *data) +{ + mysql_free_result(data); + return APR_SUCCESS; +} + +static int dbd_mysql_select(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + const char *query, int seek) +{ + int sz; + int ret; + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + ret = mysql_query(sql->conn, query); + if (!ret) { + if (sz = mysql_field_count(sql->conn), sz > 0) { + if (!*results) { + *results = apr_palloc(pool, sizeof(apr_dbd_results_t)); + } + (*results)->random = seek; + (*results)->statement = NULL; +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + (*results)->pool = pool; +#endif + if (seek) { + (*results)->res = mysql_store_result(sql->conn); + } + else { + (*results)->res = mysql_use_result(sql->conn); + } + apr_pool_cleanup_register(pool, (*results)->res, + free_result,apr_pool_cleanup_null); + } + } else { + ret = mysql_errno(sql->conn); + } + +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + if (TXN_NOTICE_ERRORS(sql->trans)) { +#else + if (sql->trans) { +#endif + sql->trans->errnum = ret; + } + return ret; +} + +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) +static const char *dbd_mysql_get_name(const apr_dbd_results_t *res, int n) +{ + if ((n < 0) || (n >= mysql_num_fields(res->res))) { + return NULL; + } + + return mysql_fetch_fields(res->res)[n].name; +} +#endif + +static int dbd_mysql_get_row(apr_pool_t *pool, apr_dbd_results_t *res, + apr_dbd_row_t **row, int rownum) +{ + MYSQL_ROW r = NULL; + int ret = 0; + + if (res->statement) { + if (res->random) { + if (rownum >= 0) { + mysql_stmt_data_seek(res->statement, (my_ulonglong)rownum); + } + } + ret = mysql_stmt_fetch(res->statement); + switch (ret) { + case 1: + ret = mysql_stmt_errno(res->statement); + break; + case MYSQL_NO_DATA: + ret = -1; + break; + default: + ret = 0; /* bad luck - get_entry will deal with this */ + break; + } + } + else { + if (res->random) { + if (rownum >= 0) { + mysql_data_seek(res->res, (my_ulonglong) rownum); + } + } + r = mysql_fetch_row(res->res); + if (r == NULL) { + ret = -1; + } + } + if (ret == 0) { + if (!*row) { + *row = apr_palloc(pool, sizeof(apr_dbd_row_t)); + } + (*row)->row = r; + (*row)->res = res; +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + (*row)->len = mysql_fetch_lengths(res->res); +#endif + } + else { + apr_pool_cleanup_run(pool, res->res, free_result); + } + return ret; +} +#if 0 +/* An improved API that was proposed but not followed up */ +static int dbd_mysql_get_entry(const apr_dbd_row_t *row, int n, + apr_dbd_datum_t *val) +{ + MYSQL_BIND *bind; + if (row->res->statement) { + bind = &row->res->bind[n]; + if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) { + val->type = APR_DBD_VALUE_NULL; + return -1; + } + if (*bind->is_null) { + val->type = APR_DBD_VALUE_NULL; + return -1; + } + else { + val->type = APR_DBD_VALUE_STRING; + val->value.stringval = bind->buffer; + } + } + else { + val->type = APR_DBD_VALUE_STRING; + val->value.stringval = row->row[n]; + } + return 0; +} +#else + +static const char *dbd_mysql_get_entry(const apr_dbd_row_t *row, int n) +{ + MYSQL_BIND *bind; + if (row->res->statement) { + bind = &row->res->bind[n]; + if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) { + return NULL; + } + if (*bind->is_null) { + return NULL; + } + else { + return bind->buffer; + } + } + else { + return row->row[n]; + } + return NULL; +} +#endif + +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) +static apr_status_t dbd_mysql_datum_get(const apr_dbd_row_t *row, int n, + apr_dbd_type_e type, void *data) +{ + if (row->res->statement) { + MYSQL_BIND *bind = &row->res->bind[n]; + unsigned long len = *bind->length; + + if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) { + return APR_EGENERAL; + } + + if (*bind->is_null) { + return APR_ENOENT; + } + + switch (type) { + case APR_DBD_TYPE_TINY: + *(char*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_UTINY: + *(unsigned char*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_SHORT: + *(short*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_USHORT: + *(unsigned short*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_INT: + *(int*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_UINT: + *(unsigned int*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_LONG: + *(long*)data = atol(bind->buffer); + break; + case APR_DBD_TYPE_ULONG: + *(unsigned long*)data = atol(bind->buffer); + break; + case APR_DBD_TYPE_LONGLONG: + *(apr_int64_t*)data = apr_atoi64(bind->buffer); + break; + case APR_DBD_TYPE_ULONGLONG: + *(apr_uint64_t*)data = apr_atoi64(bind->buffer); + break; + case APR_DBD_TYPE_FLOAT: + *(float*)data = atof(bind->buffer); + break; + case APR_DBD_TYPE_DOUBLE: + *(double*)data = atof(bind->buffer); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + *((char*)bind->buffer+bind->buffer_length-1) = '\0'; + *(char**)data = bind->buffer; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + apr_bucket *e; + apr_bucket_brigade *b = (apr_bucket_brigade*)data; + + e = apr_bucket_lob_create(row, n, 0, len, + row->res->pool, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + break; + case APR_DBD_TYPE_NULL: + *(void**)data = NULL; + break; + default: + return APR_EGENERAL; + } + } + else { + if (row->row[n] == NULL) { + return APR_ENOENT; + } + + switch (type) { + case APR_DBD_TYPE_TINY: + *(char*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_UTINY: + *(unsigned char*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_SHORT: + *(short*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_USHORT: + *(unsigned short*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_INT: + *(int*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_UINT: + *(unsigned int*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_LONG: + *(long*)data = atol(row->row[n]); + break; + case APR_DBD_TYPE_ULONG: + *(unsigned long*)data = atol(row->row[n]); + break; + case APR_DBD_TYPE_LONGLONG: + *(apr_int64_t*)data = apr_atoi64(row->row[n]); + break; + case APR_DBD_TYPE_ULONGLONG: + *(apr_uint64_t*)data = apr_atoi64(row->row[n]); + break; + case APR_DBD_TYPE_FLOAT: + *(float*)data = atof(row->row[n]); + break; + case APR_DBD_TYPE_DOUBLE: + *(double*)data = atof(row->row[n]); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + *(char**)data = row->row[n]; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + apr_bucket *e; + apr_bucket_brigade *b = (apr_bucket_brigade*)data; + + e = apr_bucket_pool_create(row->row[n], row->len[n], + row->res->pool, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + break; + case APR_DBD_TYPE_NULL: + *(void**)data = NULL; + break; + default: + return APR_EGENERAL; + } + } + return 0; +} +#endif + +static const char *dbd_mysql_error(apr_dbd_t *sql, int n) +{ + return mysql_error(sql->conn); +} + +static int dbd_mysql_query(apr_dbd_t *sql, int *nrows, const char *query) +{ + int ret; + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + ret = mysql_query(sql->conn, query); + if (ret != 0) { + ret = mysql_errno(sql->conn); + } + *nrows = mysql_affected_rows(sql->conn); +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + if (TXN_NOTICE_ERRORS(sql->trans)) { +#else + if (sql->trans) { +#endif + sql->trans->errnum = ret; + } + return ret; +} + +static const char *dbd_mysql_escape(apr_pool_t *pool, const char *arg, + apr_dbd_t *sql) +{ + unsigned long len = strlen(arg); + char *ret = apr_palloc(pool, 2*len + 1); + mysql_real_escape_string(sql->conn, ret, arg, len); + return ret; +} + +static apr_status_t stmt_close(void *data) +{ + mysql_stmt_close(data); + return APR_SUCCESS; +} + +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) +static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql, + const char *query, const char *label, + int nargs, int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t **statement) +{ + /* Translate from apr_dbd to native query format */ + int ret; + + if (!*statement) { + *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t)); + } + (*statement)->stmt = mysql_stmt_init(sql->conn); + + if ((*statement)->stmt) { + apr_pool_cleanup_register(pool, (*statement)->stmt, + stmt_close, apr_pool_cleanup_null); + ret = mysql_stmt_prepare((*statement)->stmt, query, strlen(query)); + + if (ret != 0) { + ret = mysql_stmt_errno((*statement)->stmt); + } + + (*statement)->nargs = nargs; + (*statement)->nvals = nvals; + (*statement)->types = types; + + return ret; + } + + return CR_OUT_OF_MEMORY; +} + +static void dbd_mysql_bind(apr_dbd_prepared_t *statement, + const char **values, MYSQL_BIND *bind) +{ + int i, j; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + bind[i].length = &bind[i].buffer_length; + bind[i].is_unsigned = 0; + bind[i].is_null = NULL; + + if (values[j] == NULL) { + bind[i].buffer_type = MYSQL_TYPE_NULL; + } + else { + switch (statement->types[i]) { + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB; + bind[i].buffer = (void*)values[j]; + bind[i].buffer_length = atol(values[++j]); + + /* skip table and column */ + j += 2; + break; + default: + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].buffer = (void*)values[j]; + bind[i].buffer_length = strlen(values[j]); + break; + } + } + } + + return; +} + +static int dbd_mysql_pquery_internal(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + MYSQL_BIND *bind) +{ + int ret; + + ret = mysql_stmt_bind_param(statement->stmt, bind); + if (ret != 0) { + *nrows = 0; + ret = mysql_stmt_errno(statement->stmt); + } + else { + ret = mysql_stmt_execute(statement->stmt); + if (ret != 0) { + ret = mysql_stmt_errno(statement->stmt); + } + *nrows = mysql_stmt_affected_rows(statement->stmt); + } + + return ret; +} + +static int dbd_mysql_pquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const char **values) +{ + MYSQL_BIND *bind; + int ret; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND)); + + dbd_mysql_bind(statement, values, bind); + + ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_mysql_pquery(pool, sql, nrows, statement, values); +} + +static int dbd_mysql_pselect_internal(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, MYSQL_BIND *bind) +{ + int nfields, i; + my_bool *is_nullr; +#if MYSQL_VERSION_ID >= 50000 + my_bool *error; +#endif + int ret; + unsigned long *length, maxlen; + + ret = mysql_stmt_bind_param(statement->stmt, bind); + if (ret == 0) { + ret = mysql_stmt_execute(statement->stmt); + if (!ret) { + if (!*res) { + *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + (*res)->random = random; + (*res)->statement = statement->stmt; + (*res)->res = mysql_stmt_result_metadata(statement->stmt); + (*res)->pool = pool; + apr_pool_cleanup_register(pool, (*res)->res, + free_result, apr_pool_cleanup_null); + nfields = mysql_num_fields((*res)->res); + if (!(*res)->bind) { + (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND)); + length = apr_pcalloc(pool, nfields*sizeof(unsigned long)); +#if MYSQL_VERSION_ID >= 50000 + error = apr_palloc(pool, nfields*sizeof(my_bool)); +#endif + is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool)); + for ( i = 0; i < nfields; ++i ) { + maxlen = ((*res)->res->fields[i].length < sql->fldsz ? + (*res)->res->fields[i].length : sql->fldsz) + 1; + if ((*res)->res->fields[i].type == MYSQL_TYPE_BLOB) { + (*res)->bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB; + } + else { + (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + } + (*res)->bind[i].buffer_length = maxlen; + (*res)->bind[i].length = &length[i]; + (*res)->bind[i].buffer = apr_palloc(pool, maxlen); + (*res)->bind[i].is_null = is_nullr+i; +#if MYSQL_VERSION_ID >= 50000 + (*res)->bind[i].error = error+i; +#endif + } + } + ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind); + if (!ret) { + ret = mysql_stmt_store_result(statement->stmt); + } + } + } + if (ret != 0) { + ret = mysql_stmt_errno(statement->stmt); + } + + return ret; +} + +static int dbd_mysql_pselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + const char **args) +{ + int ret; + MYSQL_BIND *bind; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND)); + + dbd_mysql_bind(statement, args, bind); + + ret = dbd_mysql_pselect_internal(pool, sql, res, statement, random, bind); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_mysql_pselect(pool, sql, res, statement, random, values); +} + +static void dbd_mysql_bbind(apr_pool_t *pool, apr_dbd_prepared_t *statement, + const void **values, MYSQL_BIND *bind) +{ + void *arg; + int i, j; + apr_dbd_type_e type; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + arg = (void *)values[j]; + + bind[i].length = &bind[i].buffer_length; + bind[i].is_null = NULL; + + type = (arg == NULL ? APR_DBD_TYPE_NULL : statement->types[i]); + switch (type) { + case APR_DBD_TYPE_TINY: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_TINY; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_UTINY: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_TINY; + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_SHORT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_SHORT; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_USHORT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_SHORT; + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_INT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_UINT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_LONG: + if (sizeof(int) == sizeof(long)) { + bind[i].buffer = arg; + } + else { + bind[i].buffer = apr_palloc(pool, sizeof(int)); + *(int*)bind[i].buffer = *(long*)arg; + } + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_ULONG: + if (sizeof(unsigned int) == sizeof(unsigned long)) { + bind[i].buffer = arg; + } + else { + bind[i].buffer = apr_palloc(pool, sizeof(unsigned int)); + *(unsigned int*)bind[i].buffer = *(unsigned long*)arg; + } + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_LONGLONG: + if (sizeof(long long) == sizeof(apr_int64_t)) { + bind[i].buffer = arg; + } + else { + bind[i].buffer = apr_palloc(pool, sizeof(long long)); + *(long long*)bind[i].buffer = *(apr_int64_t*)arg; + } + bind[i].buffer_type = MYSQL_TYPE_LONGLONG; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_ULONGLONG: + if (sizeof(unsigned long long) == sizeof(apr_uint64_t)) { + bind[i].buffer = arg; + } + else { + bind[i].buffer = apr_palloc(pool, sizeof(unsigned long long)); + *(unsigned long long*)bind[i].buffer = *(apr_uint64_t*)arg; + } + bind[i].buffer_type = MYSQL_TYPE_LONGLONG; + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_FLOAT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_FLOAT; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_DOUBLE: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_DOUBLE; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].is_unsigned = 0; + bind[i].buffer_length = strlen((const char *)arg); + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + bind[i].buffer = (void *)arg; + bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB; + bind[i].is_unsigned = 0; + bind[i].buffer_length = *(apr_size_t*)values[++j]; + + /* skip table and column */ + j += 2; + break; + case APR_DBD_TYPE_NULL: + default: + bind[i].buffer_type = MYSQL_TYPE_NULL; + break; + } + } + + return; +} + +static int dbd_mysql_pbquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const void **values) +{ + MYSQL_BIND *bind; + int ret; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND)); + + dbd_mysql_bbind(pool, statement, values, bind); + + ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvbquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_mysql_pbquery(pool, sql, nrows, statement, values); +} + +static int dbd_mysql_pbselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + const void **args) +{ + int ret; + MYSQL_BIND *bind; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND)); + + dbd_mysql_bbind(pool, statement, args, bind); + + ret = dbd_mysql_pselect_internal(pool, sql, res, statement, random, bind); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvbselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_mysql_pbselect(pool, sql, res, statement, random, values); +} +#else +static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql, + const char *query, const char *label, + apr_dbd_prepared_t **statement) +{ + /* Translate from apr_dbd to native query format */ + char *myquery = apr_pstrdup(pool, query); + char *p = myquery; + const char *q; + int ret; + for (q = query; *q; ++q) { + if (q[0] == '%') { + if (isalpha(q[1])) { + *p++ = '?'; + ++q; + } + else if (q[1] == '%') { + /* reduce %% to % */ + *p++ = *q++; + } + else { + *p++ = *q; + } + } + else { + *p++ = *q; + } + } + *p = 0; + if (!*statement) { + *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t)); + } + (*statement)->stmt = mysql_stmt_init(sql->conn); + + if ((*statement)->stmt) { + apr_pool_cleanup_register(pool, (*statement)->stmt, + stmt_close, apr_pool_cleanup_null); + ret = mysql_stmt_prepare((*statement)->stmt, myquery, strlen(myquery)); + + if (ret != 0) { + ret = mysql_stmt_errno((*statement)->stmt); + } + + return ret; + } + + return CR_OUT_OF_MEMORY; +} + +static int dbd_mysql_pquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + int nargs, const char **values) +{ + MYSQL_BIND *bind; + char *arg; + int ret; + int i; + my_bool is_null = FALSE; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + nargs = mysql_stmt_param_count(statement->stmt); + + bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND)); + for (i=0; i < nargs; ++i) { + arg = (char*)values[i]; + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].buffer = arg; + bind[i].buffer_length = strlen(arg); + bind[i].length = &bind[i].buffer_length; + bind[i].is_null = &is_null; + bind[i].is_unsigned = 0; + } + + ret = mysql_stmt_bind_param(statement->stmt, bind); + if (ret != 0) { + *nrows = 0; + ret = mysql_stmt_errno(statement->stmt); + } + else { + ret = mysql_stmt_execute(statement->stmt); + if (ret != 0) { + ret = mysql_stmt_errno(statement->stmt); + } + *nrows = mysql_stmt_affected_rows(statement->stmt); + } + if (sql->trans) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + MYSQL_BIND *bind; + char *arg; + int ret; + int nargs = 0; + int i; + my_bool is_null = FALSE; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + nargs = mysql_stmt_param_count(statement->stmt); + + bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND)); + for (i=0; i < nargs; ++i) { + arg = va_arg(args, char*); + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].buffer = arg; + bind[i].buffer_length = strlen(arg); + bind[i].length = &bind[i].buffer_length; + bind[i].is_null = &is_null; + bind[i].is_unsigned = 0; + } + + ret = mysql_stmt_bind_param(statement->stmt, bind); + if (ret != 0) { + *nrows = 0; + ret = mysql_stmt_errno(statement->stmt); + } + else { + ret = mysql_stmt_execute(statement->stmt); + if (ret != 0) { + ret = mysql_stmt_errno(statement->stmt); + } + *nrows = mysql_stmt_affected_rows(statement->stmt); + } + if (sql->trans) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + int nargs, const char **args) +{ + int i; + int nfields; + char *arg; + my_bool is_null = FALSE; + my_bool *is_nullr; +#if MYSQL_VERSION_ID >= 50000 + my_bool *error; +#endif + int ret; + unsigned long *length, maxlen; + MYSQL_BIND *bind; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + nargs = mysql_stmt_param_count(statement->stmt); + bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND)); + + for (i=0; i < nargs; ++i) { + arg = (char*)args[i]; + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].buffer = arg; + bind[i].buffer_length = strlen(arg); + bind[i].length = &bind[i].buffer_length; + bind[i].is_null = &is_null; + bind[i].is_unsigned = 0; + } + + ret = mysql_stmt_bind_param(statement->stmt, bind); + if (ret == 0) { + ret = mysql_stmt_execute(statement->stmt); + if (!ret) { + if (!*res) { + *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + (*res)->random = random; + (*res)->statement = statement->stmt; + (*res)->res = mysql_stmt_result_metadata(statement->stmt); + apr_pool_cleanup_register(pool, (*res)->res, + free_result, apr_pool_cleanup_null); + nfields = mysql_num_fields((*res)->res); + if (!(*res)->bind) { + (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND)); + length = apr_pcalloc(pool, nfields*sizeof(unsigned long)); +#if MYSQL_VERSION_ID >= 50000 + error = apr_palloc(pool, nfields*sizeof(my_bool)); +#endif + is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool)); + for ( i = 0; i < nfields; ++i ) { + maxlen = ((*res)->res->fields[i].length < sql->fldsz ? + (*res)->res->fields[i].length : sql->fldsz) + 1; + (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + (*res)->bind[i].buffer_length = maxlen; + (*res)->bind[i].length = &length[i]; + (*res)->bind[i].buffer = apr_palloc(pool, maxlen); + (*res)->bind[i].is_null = is_nullr+i; +#if MYSQL_VERSION_ID >= 50000 + (*res)->bind[i].error = error+i; +#endif + } + } + ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind); + if (!ret) { + ret = mysql_stmt_store_result(statement->stmt); + } + } + } + if (ret != 0) { + ret = mysql_stmt_errno(statement->stmt); + } + if (sql->trans) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + va_list args) +{ + int i; + int nfields; + char *arg; + my_bool is_null = FALSE; + my_bool *is_nullr; +#if MYSQL_VERSION_ID >= 50000 + my_bool *error; +#endif + int ret; + unsigned long *length, maxlen; + int nargs; + MYSQL_BIND *bind; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + nargs = mysql_stmt_param_count(statement->stmt); + bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND)); + + for (i=0; i < nargs; ++i) { + arg = va_arg(args, char*); + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].buffer = arg; + bind[i].buffer_length = strlen(arg); + bind[i].length = &bind[i].buffer_length; + bind[i].is_null = &is_null; + bind[i].is_unsigned = 0; + } + + ret = mysql_stmt_bind_param(statement->stmt, bind); + if (ret == 0) { + ret = mysql_stmt_execute(statement->stmt); + if (!ret) { + if (!*res) { + *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + (*res)->random = random; + (*res)->statement = statement->stmt; + (*res)->res = mysql_stmt_result_metadata(statement->stmt); + apr_pool_cleanup_register(pool, (*res)->res, + free_result, apr_pool_cleanup_null); + nfields = mysql_num_fields((*res)->res); + if (!(*res)->bind) { + (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND)); + length = apr_pcalloc(pool, nfields*sizeof(unsigned long)); +#if MYSQL_VERSION_ID >= 50000 + error = apr_palloc(pool, nfields*sizeof(my_bool)); +#endif + is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool)); + for ( i = 0; i < nfields; ++i ) { + maxlen = ((*res)->res->fields[i].length < sql->fldsz ? + (*res)->res->fields[i].length : sql->fldsz) + 1; + (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + (*res)->bind[i].buffer_length = maxlen; + (*res)->bind[i].length = &length[i]; + (*res)->bind[i].buffer = apr_palloc(pool, maxlen); + (*res)->bind[i].is_null = is_nullr+i; +#if MYSQL_VERSION_ID >= 50000 + (*res)->bind[i].error = error+i; +#endif + } + } + ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind); + if (!ret) { + ret = mysql_stmt_store_result(statement->stmt); + } + } + } + if (ret != 0) { + ret = mysql_stmt_errno(statement->stmt); + } + if (sql->trans) { + sql->trans->errnum = ret; + } + return ret; +} +#endif + +static int dbd_mysql_end_transaction(apr_dbd_transaction_t *trans) +{ + int ret = -1; + if (trans) { +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + /* rollback on error or explicit rollback request */ + if (trans->errnum || TXN_DO_ROLLBACK(trans)) { +#else + if (trans->errnum) { +#endif + trans->errnum = 0; + ret = mysql_rollback(trans->handle->conn); + } + else { + ret = mysql_commit(trans->handle->conn); + } + } + ret |= mysql_autocommit(trans->handle->conn, 1); + trans->handle->trans = NULL; + return ret; +} +/* Whether or not transactions work depends on whether the + * underlying DB supports them within MySQL. Unfortunately + * it fails silently with the default InnoDB. + */ + +static int dbd_mysql_transaction(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_transaction_t **trans) +{ + /* Don't try recursive transactions here */ + if (handle->trans) { + dbd_mysql_end_transaction(handle->trans) ; + } + if (!*trans) { + *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); + } + (*trans)->errnum = mysql_autocommit(handle->conn, 0); + (*trans)->handle = handle; + handle->trans = *trans; + return (*trans)->errnum; +} + +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) +static int dbd_mysql_transaction_mode_get(apr_dbd_transaction_t *trans) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode; +} + +static int dbd_mysql_transaction_mode_set(apr_dbd_transaction_t *trans, + int mode) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode = (mode & TXN_MODE_BITS); +} +#endif + +static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params) +{ + static const char *const delims = " \r\n\t;|,"; + const char *ptr; + int i; + const char *key; + size_t klen; + const char *value; + size_t vlen; +#if MYSQL_VERSION_ID >= 50013 + my_bool do_reconnect = 1; +#endif + MYSQL *real_conn; + unsigned long flags = 0; + + struct { + const char *field; + const char *value; + } fields[] = { + {"host", NULL}, + {"user", NULL}, + {"pass", NULL}, + {"dbname", NULL}, + {"port", NULL}, + {"sock", NULL}, + {"flags", NULL}, + {"fldsz", NULL}, + {NULL, NULL} + }; + unsigned int port = 0; + apr_dbd_t *sql = apr_pcalloc(pool, sizeof(apr_dbd_t)); + sql->fldsz = FIELDSIZE; + sql->conn = mysql_init(sql->conn); + if ( sql->conn == NULL ) { + return NULL; + } + for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) { + for (key = ptr-1; isspace(*key); --key); + klen = 0; + while (isalpha(*key)) { + /* don't parse backwards off the start of the string */ + if (key == params) { + --key; + ++klen; + break; + } + --key; + ++klen; + } + ++key; + for (value = ptr+1; isspace(*value); ++value); + vlen = strcspn(value, delims); + for (i = 0; fields[i].field != NULL; i++) { + if (!strncasecmp(fields[i].field, key, klen)) { + fields[i].value = apr_pstrndup(pool, value, vlen); + break; + } + } + ptr = value+vlen; + } + if (fields[4].value != NULL) { + port = atoi(fields[4].value); + } + if (fields[6].value != NULL && + !strcmp(fields[6].value, "CLIENT_FOUND_ROWS")) { + flags |= CLIENT_FOUND_ROWS; /* only option we know */ + } + if (fields[7].value != NULL) { + sql->fldsz = atol(fields[7].value); + } + +#if MYSQL_VERSION_ID >= 50013 + /* the MySQL manual says this should be BEFORE mysql_real_connect */ + mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect); +#endif + + real_conn = mysql_real_connect(sql->conn, fields[0].value, + fields[1].value, fields[2].value, + fields[3].value, port, + fields[5].value, flags); + + if(real_conn == NULL) { + mysql_close(sql->conn); + return NULL; + } + +#if MYSQL_VERSION_ID >= 50013 + /* Some say this should be AFTER mysql_real_connect */ + mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect); +#endif + + return sql; +} + +static apr_status_t dbd_mysql_close(apr_dbd_t *handle) +{ + mysql_close(handle->conn); + return APR_SUCCESS; +} + +static apr_status_t dbd_mysql_check_conn(apr_pool_t *pool, + apr_dbd_t *handle) +{ + return mysql_ping(handle->conn) ? APR_EGENERAL : APR_SUCCESS; +} + +static int dbd_mysql_select_db(apr_pool_t *pool, apr_dbd_t* handle, + const char* name) +{ + return mysql_select_db(handle->conn, name); +} + +static void *dbd_mysql_native(apr_dbd_t *handle) +{ + return handle->conn; +} + +static int dbd_mysql_num_cols(apr_dbd_results_t *res) +{ + if (res->statement) { + return mysql_stmt_field_count(res->statement); + } + else { + return mysql_num_fields(res->res); + } +} + +static int dbd_mysql_num_tuples(apr_dbd_results_t *res) +{ + if (res->random) { + if (res->statement) { + return (int) mysql_stmt_num_rows(res->statement); + } + else { + return (int) mysql_num_rows(res->res); + } + } + else { + return -1; + } +} + +static apr_status_t thread_end(void *data) +{ + mysql_thread_end(); + return APR_SUCCESS; +} + +static void dbd_mysql_init(apr_pool_t *pool) +{ + my_init(); + /* FIXME: this is a guess; find out what it really does */ + apr_pool_cleanup_register(pool, NULL, thread_end, apr_pool_cleanup_null); +} +APU_DECLARE_DATA const apr_dbd_driver_t apr_dbd_mysql_driver = { + "mysql", + dbd_mysql_init, + dbd_mysql_native, + dbd_mysql_open, + dbd_mysql_check_conn, + dbd_mysql_close, + dbd_mysql_select_db, + dbd_mysql_transaction, + dbd_mysql_end_transaction, + dbd_mysql_query, + dbd_mysql_select, + dbd_mysql_num_cols, + dbd_mysql_num_tuples, + dbd_mysql_get_row, + dbd_mysql_get_entry, + dbd_mysql_error, + dbd_mysql_escape, + dbd_mysql_prepare, + dbd_mysql_pvquery, + dbd_mysql_pvselect, + dbd_mysql_pquery, + dbd_mysql_pselect +#if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) + , + dbd_mysql_get_name, + dbd_mysql_transaction_mode_get, + dbd_mysql_transaction_mode_set, + "?", + dbd_mysql_pvbquery, + dbd_mysql_pvbselect, + dbd_mysql_pbquery, + dbd_mysql_pbselect, + dbd_mysql_datum_get +#endif +}; + +#endif diff --git a/libaprutil.spec b/libaprutil.spec new file mode 100644 index 0000000..b33b706 --- /dev/null +++ b/libaprutil.spec @@ -0,0 +1,209 @@ +%define aprutilver %version +%define aprutilmajver %(echo %aprutilver | cut -d. -f 1) + +Name: libaprutil +Version: 1.5.3 +Release: 1mamba +Epoch: 1 +Summary: The Apache Portable Runtime (APR) +Group: System/Libraries +Vendor: openmamba +Distribution: openmamba +Packager: Silvan Calarco +URL: http://apr.apache.org/ +Source: http://mirror.nohup.it/apache//apr/apr-util-%{version}.tar.bz2 +Source2: http://apache.webthing.com/svn/apache/apr/apr_dbd_mysql.c +License: Apache License 2.0 +BuildRoot: %{_tmppath}/%{name}-%{version}-root +## AUTOBUILDREQ-BEGIN +BuildRequires: glibc-devel +BuildRequires: libapr-devel +BuildRequires: libdb47-devel +BuildRequires: libe2fs-devel +BuildRequires: libexpat-devel +BuildRequires: libgdbm-devel +BuildRequires: libmysql5-devel +BuildRequires: libodbc-devel +BuildRequires: libopenldap-devel +BuildRequires: libpostgresql-devel +%if "%{stage1}" != "1" +BuildRequires: libsqlite2-devel +%endif +BuildRequires: libsqlite-devel +## AUTOBUILDREQ-END +BuildRequires: libfreetds-devel +Provides: libaprutil1 +Obsoletes: libaprutil1 + +%description +The mission of the Apache Portable Runtime (APR) project is to create and maintain software libraries that provide a predictable and consistent interface to underlying platform-specific implementations. +The primary goal is to provide an API to which software developers may code and be assured of predictable if not identical behaviour regardless of the platform on which their software is built, relieving them of the need to code special-case conditions to work around or take advantage of platform-specific deficiencies or features. + +%package devel +Summary: Devel package for %{name} +Group: Development/Libraries +Requires: %{name} = %{?epoch:%epoch:}%{version}-%{release} +Provides: libaprutil1-devel = %{?epoch:%epoch:}%{version}-%{release} +Obsoletes: libaprutil1-devel + +%description devel +The mission of the Apache Portable Runtime (APR) project is to create and maintain software libraries that provide a predictable and consistent interface to underlying platform-specific implementations. +The primary goal is to provide an API to which software developers may code and be assured of predictable if not identical behaviour regardless of the platform on which their software is built, relieving them of the need to code special-case conditions to work around or take advantage of platform-specific deficiencies or features. + +This package contains static libraries and header files need for development. + +%prep +%setup -q -n apr-util-%{version} +# see file INSTALL.MySQL +install -m 0644 %{SOURCE2} dbd/ + +%build +#./buildconf --with-apr=.. +./configure \ + --prefix=%{_prefix} \ + --libdir=%{_libdir} \ + --with-apr=%{_prefix} \ + --with-ldap \ + --with-dbm=db47 \ + --with-berkeley-db=%{_includedir} \ + --with-gdbm \ + --with-mysql=%{_prefix} \ + --with-pgsql \ + --with-sqlite3 \ + --with-expat=%{_prefix} + +%make + +%install +[ "%{buildroot}" != / ] && rm -rf %{buildroot} +%makeinstall + +# unpackaged files +rm -f %{buildroot}%{_libdir}/aprutil.exp + +%clean +[ "%{buildroot}" != / ] && rm -rf %{buildroot} + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%{_bindir}/apu-%{aprutilmajver}-config +%{_libdir}/libaprutil-%{aprutilmajver}.so.* +%{_libdir}/apr-util-1/apr_dbd_mysql-1.so +%{_libdir}/apr-util-1/apr_dbd_mysql.a +%{_libdir}/apr-util-1/apr_dbd_mysql.la +%{_libdir}/apr-util-1/apr_dbd_mysql.so +%{_libdir}/apr-util-1/apr_dbd_odbc-1.so +%{_libdir}/apr-util-1/apr_dbd_odbc.a +%{_libdir}/apr-util-1/apr_dbd_odbc.la +%{_libdir}/apr-util-1/apr_dbd_odbc.so +%{_libdir}/apr-util-1/apr_dbd_pgsql-1.so +%{_libdir}/apr-util-1/apr_dbd_pgsql.a +%{_libdir}/apr-util-1/apr_dbd_pgsql.la +%{_libdir}/apr-util-1/apr_dbd_pgsql.so +%if "%{stage1}" != "1" +%{_libdir}/apr-util-1/apr_dbd_sqlite2-1.so +%{_libdir}/apr-util-1/apr_dbd_sqlite2.a +%{_libdir}/apr-util-1/apr_dbd_sqlite2.la +%{_libdir}/apr-util-1/apr_dbd_sqlite2.so +%endif +%{_libdir}/apr-util-1/apr_dbd_sqlite3-1.so +%{_libdir}/apr-util-1/apr_dbd_sqlite3.a +%{_libdir}/apr-util-1/apr_dbd_sqlite3.la +%{_libdir}/apr-util-1/apr_dbd_sqlite3.so +%{_libdir}/apr-util-1/apr_dbm_db-1.so +%{_libdir}/apr-util-1/apr_dbm_db.a +%{_libdir}/apr-util-1/apr_dbm_db.la +%{_libdir}/apr-util-1/apr_dbm_db.so +%{_libdir}/apr-util-1/apr_dbd_freetds-1.so +%{_libdir}/apr-util-1/apr_dbd_freetds.a +%{_libdir}/apr-util-1/apr_dbd_freetds.la +%{_libdir}/apr-util-1/apr_dbd_freetds.so +%{_libdir}/apr-util-1/apr_dbm_gdbm-1.so +%{_libdir}/apr-util-1/apr_dbm_gdbm.a +%{_libdir}/apr-util-1/apr_dbm_gdbm.la +%{_libdir}/apr-util-1/apr_dbm_gdbm.so +%{_libdir}/apr-util-1/apr_ldap-1.so +%{_libdir}/apr-util-1/apr_ldap.a +%{_libdir}/apr-util-1/apr_ldap.la +%{_libdir}/apr-util-1/apr_ldap.so +%doc CHANGES LICENSE + +%files devel +%defattr(-,root,root) +%{_includedir}/apr-1/*.h +%{_libdir}/pkgconfig/apr-util-1.pc +%{_libdir}/libaprutil-%{aprutilmajver}.a +%{_libdir}/libaprutil-%{aprutilmajver}.la +%{_libdir}/libaprutil-%{aprutilmajver}.so + +%changelog +* Tue Nov 19 2013 Automatic Build System 1.5.3-1mamba +- automatic update by autodist + +* Thu Apr 04 2013 Automatic Build System 1.5.2-1mamba +- automatic version update by autodist + +* Mon Oct 15 2012 Automatic Build System 1.5.1-1mamba +- automatic version update by autodist + +* Thu Apr 26 2012 Automatic Build System 1.4.1-1mamba +- automatic version update by autodist + +* Sun Jun 19 2011 Automatic Build System 1.3.12-1mamba +- automatic update by autodist + +* Thu May 12 2011 Automatic Build System 1.3.11-1mamba +- automatic update by autodist + +* Wed Nov 24 2010 Silvan Calarco 1.3.10-1mamba +- update to 1.3.10 + +* Tue Oct 20 2009 Silvan Calarco 1.3.9-1mamba +- update to 1.3.9 + +* Wed Jun 10 2009 Automatic Build System 1.3.7-1mamba +- automatic update by autodist + +* Thu Dec 18 2008 Silvan Calarco 1.3.4-1mamba +- update to 1.3.4 + +* Mon Dec 08 2008 Silvan Calarco 1.3.3-1mamba +- update to 1.3.3 + +* Sun Feb 10 2008 Silvan Calarco 1.2.12-1mamba +- update to 1.2.12 +- libapr-devel: obsolete libapr1-devel + +* Wed Nov 21 2007 Silvan Calarco 1.2.11-2mamba +- rename to libapr and obsolete libapr1 packages + +* Thu Sep 27 2007 Silvan Calarco 1.2.11-1mamba +- update to 1.2.11 + +* Thu May 24 2007 Silvan Calarco 1.2.8-4mamba +- libapr1-devel: obsolete and remove libaprutil1-devel + +* Tue May 08 2007 Silvan Calarco 1.2.8-3mamba +- set epoch to 1 as it was for libaprutil1 for updates to work + +* Mon May 07 2007 Silvan Calarco 1.2.8-2mamba +- but libaprutil1 from libapr1 source package + +* Fri Apr 27 2007 Silvan Calarco 1.2.8-1mamba +- update to 1.2.8 +- includes installed into %{_includedir}/apr-1 + +* Thu Apr 19 2007 Davide Madrisan 1.2.2-3mamba +- rebuilt with the openmamba compiler to fix the output of 'apr-1-config --cc' + +* Mon Mar 20 2006 Davide Madrisan 1.2.2-2qilnx +- moved apr-%{aprver}-config executable to main package + +* Wed Mar 01 2006 Silvan Calarco 1.2.2-1qilnx +- update to version 1.2.2 by autospec + +* Mon Feb 07 2005 Silvan Calarco 1.1.0-1qilnx +- package created by autospec