apr_dbd_freetds.c

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

C
796
字号
/* 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"#include "apu_config.h"/* COMPILE_STUBS: compile stubs for unimplemented functions. * * This is required to compile in /trunk/, but can be * undefined to compile a driver for httpd-2.2 and other * APR-1.2 applications */#define COMPILE_STUBS#if APU_HAVE_FREETDS#include <ctype.h>#include <stdlib.h>#include "apr_strings.h"#include "apr_lib.h"#include "apr_pools.h"#include "apr_dbd_internal.h"#include <sybdb.h>#include <stdio.h>#include <sys/types.h>#include <regex.h>/* This probably needs to change for different applications */#define MAX_COL_LEN 256typedef struct freetds_cell_t {    int type;    DBINT len;    BYTE *data;} freetds_cell_t;struct apr_dbd_transaction_t {    int mode;    int errnum;    apr_dbd_t *handle;};struct apr_dbd_t {    DBPROCESS *proc;    apr_dbd_transaction_t *trans;    apr_pool_t *pool;    const char *params;    RETCODE err;};struct apr_dbd_results_t {    int random;    size_t ntuples;    size_t sz;    apr_pool_t *pool;    DBPROCESS *proc;};struct apr_dbd_row_t {    apr_dbd_results_t *res;    BYTE buf[MAX_COL_LEN];};struct apr_dbd_prepared_t {    int nargs;    regex_t **taint;    int *sz;    char *fmt;};#define dbd_freetds_is_success(x) (x == SUCCEED)static int labelnum = 0; /* FIXME */static regex_t dbd_freetds_find_arg;/* execute a query that doesn't return a result set, mop up, * and return and APR-flavoured status */static RETCODE freetds_exec(DBPROCESS *proc, const char *query,                            int want_results, int *nrows){    /* TBD */    RETCODE rv = dbcmd(proc, query);    if (rv != SUCCEED) {        return rv;    }    rv = dbsqlexec(proc);    if (rv != SUCCEED) {        return rv;    }    if (!want_results) {        while (dbresults(proc) != NO_MORE_RESULTS) {            ++*nrows;        }    }    return SUCCEED;}static apr_status_t clear_result(void *data){    /* clear cursor */    return (dbcanquery((DBPROCESS*)data) == SUCCEED)            ? APR_SUCCESS            : APR_EGENERAL;}static int dbd_freetds_select(apr_pool_t *pool, apr_dbd_t *sql,                              apr_dbd_results_t **results,                              const char *query, int seek){    apr_dbd_results_t *res;    int i;    if (sql->trans && (sql->trans->errnum != SUCCEED)) {        return 1;    }    /* the core of this is     * dbcmd(proc, query);     * dbsqlexec(proc);     * while (dbnextrow(dbproc) != NO_MORE_ROWS) {     *     do things     * }     *     * Ignore seek     */    sql->err = freetds_exec(sql->proc, query, 1, NULL);    if (!dbd_freetds_is_success(sql->err)) {        if (sql->trans) {            sql->trans->errnum = sql->err;        }        return 1;    }    sql->err = dbresults(sql->proc);    if (sql->err != SUCCEED) {        if (sql->trans) {            sql->trans->errnum = sql->err;        }        return 1;    }    if (!*results) {        *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t));    }    res = *results;    res->proc = sql->proc;    res->random = seek;    res->pool = pool;    res->ntuples = dblastrow(sql->proc);    res->sz = dbnumcols(sql->proc);    apr_pool_cleanup_register(pool, sql->proc, clear_result,                              apr_pool_cleanup_null);#if 0    /* Now we have a result set.  We need to bind to its vars */    res->vars = apr_palloc(pool, res->sz * sizeof(freetds_cell_t*));    for (i=1; i <= res->sz; ++i) {        freetds_cell_t *cell = &res->vars[i-1];        cell->type = dbcoltype(sql->proc, i);        cell->len = dbcollen(sql->proc, i);        cell->data = apr_palloc(pool, cell->len);        sql->err = dbbind(sql->proc, i, /*cell->type */ STRINGBIND, cell->len, cell->data);        if (sql->err != SUCCEED) {            fprintf(stderr, "dbbind error: %d, %d, %d", i, cell->type, cell->len);        }        if ((sql->err != SUCCEED) && (sql->trans != NULL)) {            sql->trans->errnum = sql->err;        }    }#endif    return (sql->err == SUCCEED) ? 0 : 1;}static const char *dbd_untaint(apr_pool_t *pool, regex_t *rx, const char *val){    regmatch_t match[1];    if (rx == NULL) {        /* no untaint expression */        return val;    }    if (regexec(rx, val, 1, match, 0) == 0) {        return apr_pstrndup(pool, val+match[0].rm_so,                            match[0].rm_eo - match[0].rm_so);    }    return "";}static const char *dbd_statement(apr_pool_t *pool,                                 apr_dbd_prepared_t *stmt,                                 int nargs, const char **args){    int i;    int len;    const char *var;    char *ret;    const char *p_in;    char *p_out;    char *q;       /* compute upper bound on length (since untaint shrinks) */    len  = strlen(stmt->fmt) +1;    for (i=0; i<nargs; ++i) {        len += strlen(args[i]) - 2;    }    i = 0;    p_in = stmt->fmt;    p_out = ret = apr_palloc(pool, len);    /* FIXME silly bug - this'll catch %%s */    while (q = strstr(p_in, "%s"), q != NULL) {        len = q-p_in;        strncpy(p_out, p_in, len);        p_in += len;        p_out += len;        var = dbd_untaint(pool, stmt->taint[i], args[i]);        len = strlen(var);        strncpy(p_out, var, len);        p_in += 2;        p_out += len;        ++i;    }    strcpy(p_out, p_in);    return ret;}static int dbd_freetds_pselect(apr_pool_t *pool, apr_dbd_t *sql,                               apr_dbd_results_t **results,                               apr_dbd_prepared_t *statement,                               int seek, int nargs, const char **values){    const char *query = dbd_statement(pool, statement, nargs, values);    return dbd_freetds_select(pool, sql, results, query, seek);}static int dbd_freetds_pvselect(apr_pool_t *pool, apr_dbd_t *sql,                                apr_dbd_results_t **results,                                apr_dbd_prepared_t *statement,                                int seek, 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->nargs);    for (i = 0; i < statement->nargs; i++) {        values[i] = va_arg(args, const char*);    }    return dbd_freetds_pselect(pool, sql, results, statement, seek,                               statement->nargs, values);}static int dbd_freetds_query(apr_dbd_t *sql, int *nrows, const char *query);static int dbd_freetds_pquery(apr_pool_t *pool, apr_dbd_t *sql,                              int *nrows, apr_dbd_prepared_t *statement,                              int nargs, const char **values){    const char *query = dbd_statement(pool, statement, nargs, values);    return dbd_freetds_query(sql, nrows, query);}static int dbd_freetds_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->nargs);    for (i = 0; i < statement->nargs; i++) {        values[i] = va_arg(args, const char*);    }    return dbd_freetds_pquery(pool, sql, nrows, statement,                              statement->nargs, values);}static int dbd_freetds_get_row(apr_pool_t *pool, apr_dbd_results_t *res,                               apr_dbd_row_t **rowp, int rownum){    RETCODE rv = 0;    apr_dbd_row_t *row = *rowp;    int sequential = ((rownum >= 0) && res->random) ? 0 : 1;    if (row == NULL) {        row = apr_palloc(pool, sizeof(apr_dbd_row_t));        *rowp = row;        row->res = res;    }    /*    else {        if ( sequential ) {            ++row->n;        }        else {            row->n = rownum;        }    }    */    if (sequential) {        rv = dbnextrow(res->proc);    }    else {        rv = (rownum >= 0) ? dbgetrow(res->proc, rownum) : NO_MORE_ROWS;    }    switch (rv) {    case SUCCEED: return 0;    case REG_ROW: return 0;    case NO_MORE_ROWS:        apr_pool_cleanup_run(pool, res->proc, clear_result);        *rowp = NULL;        return -1;    case FAIL: return 1;    case BUF_FULL: return 2; /* FIXME */    default: return 3;    }    return 0;}static const char *dbd_freetds_get_entry(const apr_dbd_row_t *row, int n){    /* FIXME: support different data types */    /* this fails - bind gets some vars but not others    return (const char*)row->res->vars[n].data;     */    DBPROCESS* proc = row->res->proc;    BYTE *ptr = dbdata(proc, n+1);    int t = dbcoltype(proc, n+1);    int l = dbcollen(proc, n+1);    if (dbwillconvert(t, SYBCHAR)) {      dbconvert(proc, t, ptr, l, SYBCHAR, row->buf, -1);      return (const char*)row->buf;    }    return ptr;}static const char *dbd_freetds_error(apr_dbd_t *sql, int n){    /* XXX this doesn't seem to exist in the API ??? */    return apr_psprintf(sql->pool, "Error %d", sql->err);}static int dbd_freetds_query(apr_dbd_t *sql, int *nrows, const char *query){    if (sql->trans && sql->trans->errnum) {        return sql->trans->errnum;    }    *nrows = 0;    sql->err = freetds_exec(sql->proc, query, 0, nrows);    if (sql->err != SUCCEED) {        if (sql->trans) {            sql->trans->errnum = sql->err;        }        return 1;    }    return 0;}static const char *dbd_freetds_escape(apr_pool_t *pool, const char *arg,                                      apr_dbd_t *sql){    return arg;}static apr_status_t freetds_regfree(void *rx){    regfree((regex_t*)rx);    return APR_SUCCESS;}static int recurse_args(apr_pool_t *pool, int n, const char *query,                        apr_dbd_prepared_t *stmt, int offs){    /* we only support %s arguments for now */    int ret;    char arg[256];    regmatch_t matches[3];    if (regexec(&dbd_freetds_find_arg, query, 3, matches, 0) != 0) {        /* No more args */        stmt->nargs = n;        stmt->taint = apr_palloc(pool, n*sizeof(regex_t*));

⌨️ 快捷键说明

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