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