apr_dbd_oracle.c

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

C
1,920
字号
/* 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. *//* Developed initially by Nick Kew and Chris Darroch. * Contributed to the APR project by kind permission of * Pearson Education Core Technology Group (CTG), * formerly Central Media Group (CMG). *//* apr_dbd_oracle - a painful attempt * * Based first on the documentation at * http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/toc.htm * * Those docs have a lot of internal inconsistencies, contradictions, etc * So I've snarfed the demo programs (from Oracle 8, not included in * the current downloadable oracle), and used code from them. * * Why do cdemo81.c and cdemo82.c do the same thing in very different ways? * e.g. cdemo82 releases all its handle on shutdown; cdemo81 doesn't * * All the ORA* functions return a "sword".  Some of them are documented; * others aren't.  So I've adopted a policy of using switch statements * everywhere, even when we're not doing anything with the return values. * * This makes no attempt at performance tuning, such as setting * prefetch cache size.  We need some actual performance data * to make that meaningful.  Input from someone with experience * as a sysop using oracle would be a good start. *//* shut compiler up */#ifdef DEBUG#define int_errorcode int errorcode#else#define int_errorcode#endif#include "apu.h"#if APU_HAVE_ORACLE#include <ctype.h>#include <stdlib.h>#include <stdio.h>#include <oci.h>#include "apr_strings.h"#include "apr_time.h"#include "apr_hash.h"#include "apr_buckets.h"#define TRANS_TIMEOUT 30#define MAX_ARG_LEN 256 /* in line with other apr_dbd drivers.  We alloc this                         * lots of times, so a large value gets hungry.                         * Should really make it configurable                         */#define DEFAULT_LONG_SIZE 4096#define DBD_ORACLE_MAX_COLUMNS 256#define NUMERIC_FIELD_SIZE 32#define CHECK_CONN_QUERY "SELECT 1 FROM dual"#define ERR_BUF_SIZE 200#ifdef DEBUG#include <stdio.h>#endif#include "apr_dbd_internal.h"/* declarations */static const char *dbd_oracle_error(apr_dbd_t *sql, int n);static int dbd_oracle_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);static int outputParams(apr_dbd_t*, apr_dbd_prepared_t*);static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,                              apr_dbd_results_t **results,                              apr_dbd_prepared_t *statement,                              int seek, const char **values);static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,                             int *nrows, apr_dbd_prepared_t *statement,                             const char **values);static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,                                        apr_dbd_transaction_t **trans);static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans);struct apr_dbd_transaction_t {    int mode;    enum { TRANS_NONE, TRANS_ERROR, TRANS_1, TRANS_2 } status;    apr_dbd_t *handle;    OCITrans *trans;    OCISnapshot *snapshot1;    OCISnapshot *snapshot2;};struct apr_dbd_results_t {    apr_pool_t *pool;    apr_dbd_t* handle;    unsigned int rownum;    int seek;    int nrows;    apr_dbd_prepared_t *statement;};struct apr_dbd_t {    sword status;    OCIError *err;    OCIServer *svr;    OCISvcCtx *svc;    OCISession *auth;    apr_dbd_transaction_t* trans;    apr_pool_t *pool;    char buf[ERR_BUF_SIZE]; /* for error messages */    apr_size_t long_size;    apr_dbd_prepared_t *check_conn_stmt;};struct apr_dbd_row_t {    int n;    apr_dbd_results_t *res;    apr_pool_t *pool;};typedef struct {    apr_dbd_type_e type;    sb2 ind;    sb4 len;    OCIBind *bind;    union {        void *raw;        char *sval;        int ival;        unsigned int uval;        double fval;        OCILobLocator *lobval;    } value;} bind_arg;typedef struct {    int type;    sb2 ind;    ub2 len;         /* length of actual output */    OCIDefine *defn;    apr_size_t sz;   /* length of buf for output */    union {        void *raw;        char *sval;        OCILobLocator *lobval;    } buf;    const char *name;} define_arg;struct apr_dbd_prepared_t {    OCIStmt *stmt;    int nargs;    int nvals;    bind_arg *args;    int nout;    define_arg *out;    apr_dbd_t *handle;    apr_pool_t *pool;    int type;};/* AFAICT from the docs, the OCIEnv thingey can be used async * across threads, so lets have a global one. * * We'll need shorter-lived envs to deal with requests and connections * * Hmmm, that doesn't work: we don't have a usermem framework. * OK, forget about using APR pools here, until we figure out * the right way to do it (if such a thing exists). */static OCIEnv *dbd_oracle_env = NULL;/* Oracle specific bucket for BLOB/CLOB types */typedef struct apr_bucket_lob apr_bucket_lob;/** * A bucket referring to a Oracle BLOB/CLOB */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;    apr_size_t blength = e->length;  /* bytes remaining in file past offset */    apr_off_t boffset = e->start;    define_arg *val = &res->statement->out[col];    apr_dbd_t *sql = res->handle;/* Only with 10g, unfortunately    oraub8 length = APR_BUCKET_BUFF_SIZE;*/    ub4 length = APR_BUCKET_BUFF_SIZE;    char *buf = NULL;    *str = NULL;  /* in case we die prematurely */    /* fetch from offset if not at the beginning */    buf = apr_palloc(row->pool, APR_BUCKET_BUFF_SIZE);    sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,                             &length, 1 + boffset,                             (dvoid*) buf, APR_BUCKET_BUFF_SIZE,                             NULL, NULL, 0, SQLCS_IMPLICIT);/* Only with 10g, unfortunately    sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,                              &length, NULL, 1 + boffset,                              (dvoid*) buf, APR_BUCKET_BUFF_SIZE,                              OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);*/    if (sql->status != OCI_SUCCESS) {        return APR_EGENERAL;    }    blength -= length;    *len = length;    *str = buf;    /*     * 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 dbd_free_lobdesc(void *lob){    switch (OCIDescriptorFree(lob, OCI_DTYPE_LOB)) {    case OCI_SUCCESS:        return APR_SUCCESS;    default:        return APR_EGENERAL;    }}static apr_status_t dbd_free_snapshot(void *snap){    switch (OCIDescriptorFree(snap, OCI_DTYPE_SNAP)) {    case OCI_SUCCESS:        return APR_SUCCESS;    default:        return APR_EGENERAL;    }}static void dbd_oracle_init(apr_pool_t *pool){    if (dbd_oracle_env == NULL) {        /* Sadly, OCI_SHARED seems to be impossible to use, due to         * various Oracle bugs.  See, for example, Oracle MetaLink bug 2972890         * and PHP bug http://bugs.php.net/bug.php?id=23733         */#ifdef OCI_NEW_LENGTH_SEMANTICS        OCIEnvCreate(&dbd_oracle_env, OCI_THREADED|OCI_NEW_LENGTH_SEMANTICS,                     NULL, NULL, NULL, NULL, 0, NULL);#else        OCIEnvCreate(&dbd_oracle_env, OCI_THREADED,                     NULL, NULL, NULL, NULL, 0, NULL);#endif    }}static apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params,                                  const char **error){    apr_dbd_t *ret = apr_pcalloc(pool, sizeof(apr_dbd_t));    int errorcode;    char *BLANK = "";    struct {        const char *field;        char *value;

⌨️ 快捷键说明

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