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 + -
显示快捷键?