apr_dbd_mysql.c

来自「linux网络服务器工具」· C语言 代码 · 共 1,277 行 · 第 1/3 页

C
1,277
字号
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License.  You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include "apu.h"#define HAVE_MYSQL_MYSQL_H#if APU_HAVE_MYSQL#include "apu_version.h"#include "apu_config.h"#include <ctype.h>#include <stdlib.h>#ifdef HAVE_MYSQL_H#include <mysql.h>#include <errmsg.h>#elif defined(HAVE_MYSQL_MYSQL_H)#include <mysql/mysql.h>#include <mysql/errmsg.h>#endif#include "apr_strings.h"#include "apr_buckets.h"#include "apr_dbd_internal.h"/* default maximum field size 1 MB */#define FIELDSIZE 1048575struct apr_dbd_prepared_t {    MYSQL_STMT* stmt;    int nargs;    int nvals;    apr_dbd_type_e *types;};struct apr_dbd_transaction_t {    int mode;    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;    apr_pool_t *pool;};struct apr_dbd_row_t {    MYSQL_ROW row;    apr_dbd_results_t *res;    unsigned long *len;};/* 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);}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;            (*results)->pool = pool;            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 (TXN_NOTICE_ERRORS(sql->trans)) {        sql->trans->errnum = ret;    }    return ret;}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;}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);            }            else {                return -1; /* invalid row */            }        }        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);            }            else {                return -1; /* invalid row */            }        }        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;        (*row)->len = mysql_fetch_lengths(res->res);    }    else {        apr_pool_cleanup_run(pool, res->res, free_result);    }    return ret;}#if 0/* An improved API that was proposed but not followed up */static int dbd_mysql_get_entry(const apr_dbd_row_t *row, int n,                               apr_dbd_datum_t *val){    MYSQL_BIND *bind;    if (row->res->statement) {        bind = &row->res->bind[n];        if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) {            val->type = APR_DBD_VALUE_NULL;            return -1;        }        if (*bind->is_null) {            val->type = APR_DBD_VALUE_NULL;            return -1;        }        else {            val->type = APR_DBD_VALUE_STRING;            val->value.stringval = bind->buffer;        }    }    else {        val->type = APR_DBD_VALUE_STRING;        val->value.stringval = row->row[n];    }    return 0;}#elsestatic 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;}#endifstatic 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:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?