1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter/* Developed initially by Nick Kew and Chris Darroch.
18251876Speter * Contributed to the APR project by kind permission of
19251876Speter * Pearson Education Core Technology Group (CTG),
20251876Speter * formerly Central Media Group (CMG).
21251876Speter */
22251876Speter
23251876Speter/* apr_dbd_oracle - a painful attempt
24251876Speter *
25251876Speter * Based first on the documentation at
26251876Speter * http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/toc.htm
27251876Speter *
28251876Speter * Those docs have a lot of internal inconsistencies, contradictions, etc
29251876Speter * So I've snarfed the demo programs (from Oracle 8, not included in
30251876Speter * the current downloadable oracle), and used code from them.
31251876Speter *
32251876Speter * Why do cdemo81.c and cdemo82.c do the same thing in very different ways?
33251876Speter * e.g. cdemo82 releases all its handle on shutdown; cdemo81 doesn't
34251876Speter *
35251876Speter * All the ORA* functions return a "sword".  Some of them are documented;
36251876Speter * others aren't.  So I've adopted a policy of using switch statements
37251876Speter * everywhere, even when we're not doing anything with the return values.
38251876Speter *
39251876Speter * This makes no attempt at performance tuning, such as setting
40251876Speter * prefetch cache size.  We need some actual performance data
41251876Speter * to make that meaningful.  Input from someone with experience
42251876Speter * as a sysop using oracle would be a good start.
43251876Speter */
44251876Speter
45251876Speter/* shut compiler up */
46251876Speter#ifdef DEBUG
47251876Speter#define int_errorcode int errorcode
48251876Speter#else
49251876Speter#define int_errorcode
50251876Speter#endif
51251876Speter
52251876Speter#include "apu.h"
53251876Speter
54251876Speter#if APU_HAVE_ORACLE
55251876Speter
56251876Speter#include <ctype.h>
57251876Speter#include <stdlib.h>
58251876Speter#include <stdio.h>
59251876Speter
60251876Speter#include <oci.h>
61251876Speter
62251876Speter#include "apr_strings.h"
63251876Speter#include "apr_lib.h"
64251876Speter#include "apr_time.h"
65251876Speter#include "apr_hash.h"
66251876Speter#include "apr_buckets.h"
67251876Speter
68251876Speter#define TRANS_TIMEOUT 30
69251876Speter#define MAX_ARG_LEN 256 /* in line with other apr_dbd drivers.  We alloc this
70251876Speter                         * lots of times, so a large value gets hungry.
71251876Speter                         * Should really make it configurable
72251876Speter                         */
73251876Speter#define DEFAULT_LONG_SIZE 4096
74251876Speter#define DBD_ORACLE_MAX_COLUMNS 256
75251876Speter#define NUMERIC_FIELD_SIZE 32
76251876Speter
77251876Speter#define CHECK_CONN_QUERY "SELECT 1 FROM dual"
78251876Speter
79251876Speter#define ERR_BUF_SIZE 200
80251876Speter
81251876Speter#ifdef DEBUG
82251876Speter#include <stdio.h>
83251876Speter#endif
84251876Speter
85251876Speter#include "apr_dbd_internal.h"
86251876Speter
87251876Speter/* declarations */
88251876Speterstatic const char *dbd_oracle_error(apr_dbd_t *sql, int n);
89251876Speterstatic int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
90251876Speter                              const char *query, const char *label,
91251876Speter                              int nargs, int nvals, apr_dbd_type_e *types,
92251876Speter                              apr_dbd_prepared_t **statement);
93251876Speterstatic int outputParams(apr_dbd_t*, apr_dbd_prepared_t*);
94251876Speterstatic int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
95251876Speter                              apr_dbd_results_t **results,
96251876Speter                              apr_dbd_prepared_t *statement,
97251876Speter                              int seek, const char **values);
98251876Speterstatic int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
99251876Speter                             int *nrows, apr_dbd_prepared_t *statement,
100251876Speter                             const char **values);
101251876Speterstatic int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
102251876Speter                                        apr_dbd_transaction_t **trans);
103251876Speterstatic int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans);
104251876Speter
105251876Speterstruct apr_dbd_transaction_t {
106251876Speter    int mode;
107251876Speter    enum { TRANS_NONE, TRANS_ERROR, TRANS_1, TRANS_2 } status;
108251876Speter    apr_dbd_t *handle;
109251876Speter    OCITrans *trans;
110251876Speter    OCISnapshot *snapshot1;
111251876Speter    OCISnapshot *snapshot2;
112251876Speter};
113251876Speter
114251876Speterstruct apr_dbd_results_t {
115251876Speter    apr_pool_t *pool;
116251876Speter    apr_dbd_t* handle;
117251876Speter    unsigned int rownum;
118251876Speter    int seek;
119251876Speter    int nrows;
120251876Speter    apr_dbd_prepared_t *statement;
121251876Speter};
122251876Speter
123251876Speterstruct apr_dbd_t {
124251876Speter    sword status;
125251876Speter    OCIError *err;
126251876Speter    OCIServer *svr;
127251876Speter    OCISvcCtx *svc;
128251876Speter    OCISession *auth;
129251876Speter    apr_dbd_transaction_t* trans;
130251876Speter    apr_pool_t *pool;
131251876Speter    char buf[ERR_BUF_SIZE]; /* for error messages */
132251876Speter    apr_size_t long_size;
133251876Speter    apr_dbd_prepared_t *check_conn_stmt;
134251876Speter};
135251876Speter
136251876Speterstruct apr_dbd_row_t {
137251876Speter    int n;
138251876Speter    apr_dbd_results_t *res;
139251876Speter    apr_pool_t *pool;
140251876Speter};
141251876Speter
142251876Spetertypedef struct {
143251876Speter    apr_dbd_type_e type;
144251876Speter    sb2 ind;
145251876Speter    sb4 len;
146251876Speter    OCIBind *bind;
147251876Speter    union {
148251876Speter        void *raw;
149251876Speter        char *sval;
150251876Speter        int ival;
151251876Speter        unsigned int uval;
152251876Speter        double fval;
153251876Speter        OCILobLocator *lobval;
154251876Speter    } value;
155251876Speter} bind_arg;
156251876Speter
157251876Spetertypedef struct {
158251876Speter    int type;
159251876Speter    sb2 ind;
160251876Speter    ub2 len;         /* length of actual output */
161251876Speter    OCIDefine *defn;
162251876Speter    apr_size_t sz;   /* length of buf for output */
163251876Speter    union {
164251876Speter        void *raw;
165251876Speter        char *sval;
166251876Speter        OCILobLocator *lobval;
167251876Speter    } buf;
168251876Speter    const char *name;
169251876Speter} define_arg;
170251876Speter
171251876Speterstruct apr_dbd_prepared_t {
172251876Speter    OCIStmt *stmt;
173251876Speter    int nargs;
174251876Speter    int nvals;
175251876Speter    bind_arg *args;
176251876Speter    int nout;
177251876Speter    define_arg *out;
178251876Speter    apr_dbd_t *handle;
179251876Speter    apr_pool_t *pool;
180251876Speter    ub2 type;
181251876Speter};
182251876Speter
183251876Speter/* AFAICT from the docs, the OCIEnv thingey can be used async
184251876Speter * across threads, so lets have a global one.
185251876Speter *
186251876Speter * We'll need shorter-lived envs to deal with requests and connections
187251876Speter *
188251876Speter * Hmmm, that doesn't work: we don't have a usermem framework.
189251876Speter * OK, forget about using APR pools here, until we figure out
190251876Speter * the right way to do it (if such a thing exists).
191251876Speter */
192251876Speterstatic OCIEnv *dbd_oracle_env = NULL;
193251876Speter
194251876Speter/* Oracle specific bucket for BLOB/CLOB types */
195251876Spetertypedef struct apr_bucket_lob apr_bucket_lob;
196251876Speter/**
197251876Speter * A bucket referring to a Oracle BLOB/CLOB
198251876Speter */
199251876Speterstruct apr_bucket_lob {
200251876Speter    /** Number of buckets using this memory */
201251876Speter    apr_bucket_refcount  refcount;
202251876Speter    /** The row this bucket refers to */
203251876Speter    const apr_dbd_row_t *row;
204251876Speter    /** The column this bucket refers to */
205251876Speter    int col;
206251876Speter    /** The pool into which any needed structures should
207251876Speter     *  be created while reading from this bucket */
208251876Speter    apr_pool_t *readpool;
209251876Speter};
210251876Speter
211251876Speterstatic void lob_bucket_destroy(void *data);
212251876Speterstatic apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
213251876Speter                                    apr_size_t *len, apr_read_type_e block);
214251876Speterstatic apr_bucket *apr_bucket_lob_make(apr_bucket *b,
215251876Speter                                       const apr_dbd_row_t *row, int col,
216251876Speter                                       apr_off_t offset, apr_size_t len,
217251876Speter                                       apr_pool_t *p);
218251876Speterstatic apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
219251876Speter                                         apr_off_t offset,
220251876Speter                                         apr_size_t len, apr_pool_t *p,
221251876Speter                                         apr_bucket_alloc_t *list);
222251876Speter
223251876Speterstatic const apr_bucket_type_t apr_bucket_type_lob = {
224251876Speter    "LOB", 5, APR_BUCKET_DATA,
225251876Speter    lob_bucket_destroy,
226251876Speter    lob_bucket_read,
227251876Speter    apr_bucket_setaside_notimpl,
228251876Speter    apr_bucket_shared_split,
229251876Speter    apr_bucket_shared_copy
230251876Speter};
231251876Speter
232251876Speterstatic void lob_bucket_destroy(void *data)
233251876Speter{
234251876Speter    apr_bucket_lob *f = data;
235251876Speter
236251876Speter    if (apr_bucket_shared_destroy(f)) {
237251876Speter        /* no need to destroy database objects here; it will get
238251876Speter         * done automatically when the pool gets cleaned up */
239251876Speter        apr_bucket_free(f);
240251876Speter    }
241251876Speter}
242251876Speter
243251876Speterstatic apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
244251876Speter                                    apr_size_t *len, apr_read_type_e block)
245251876Speter{
246251876Speter    apr_bucket_lob *a = e->data;
247251876Speter    const apr_dbd_row_t *row = a->row;
248251876Speter    apr_dbd_results_t *res = row->res;
249251876Speter    int col = a->col;
250251876Speter    apr_bucket *b = NULL;
251251876Speter    apr_size_t blength = e->length;  /* bytes remaining in file past offset */
252251876Speter    apr_off_t boffset = e->start;
253251876Speter    define_arg *val = &res->statement->out[col];
254251876Speter    apr_dbd_t *sql = res->handle;
255251876Speter/* Only with 10g, unfortunately
256251876Speter    oraub8 length = APR_BUCKET_BUFF_SIZE;
257251876Speter*/
258251876Speter    ub4 length = APR_BUCKET_BUFF_SIZE;
259251876Speter    char *buf = NULL;
260251876Speter
261251876Speter    *str = NULL;  /* in case we die prematurely */
262251876Speter
263251876Speter    /* fetch from offset if not at the beginning */
264251876Speter    buf = apr_palloc(row->pool, APR_BUCKET_BUFF_SIZE);
265251876Speter    sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
266251876Speter                             &length, 1 + (size_t)boffset,
267251876Speter                             (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
268251876Speter                             NULL, NULL, 0, SQLCS_IMPLICIT);
269251876Speter/* Only with 10g, unfortunately
270251876Speter    sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,
271251876Speter                              &length, NULL, 1 + boffset,
272251876Speter                              (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
273251876Speter                              OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
274251876Speter*/
275251876Speter    if (sql->status != OCI_SUCCESS) {
276251876Speter        return APR_EGENERAL;
277251876Speter    }
278251876Speter    blength -= length;
279251876Speter    *len = length;
280251876Speter    *str = buf;
281251876Speter
282251876Speter    /*
283251876Speter     * Change the current bucket to refer to what we read,
284251876Speter     * even if we read nothing because we hit EOF.
285251876Speter     */
286251876Speter    apr_bucket_pool_make(e, *str, *len, res->pool);
287251876Speter
288251876Speter    /* If we have more to read from the field, then create another bucket */
289251876Speter    if (blength > 0) {
290251876Speter        /* for efficiency, we can just build a new apr_bucket struct
291251876Speter         * to wrap around the existing LOB bucket */
292251876Speter        b = apr_bucket_alloc(sizeof(*b), e->list);
293251876Speter        b->start  = boffset + *len;
294251876Speter        b->length = blength;
295251876Speter        b->data   = a;
296251876Speter        b->type   = &apr_bucket_type_lob;
297251876Speter        b->free   = apr_bucket_free;
298251876Speter        b->list   = e->list;
299251876Speter        APR_BUCKET_INSERT_AFTER(e, b);
300251876Speter    }
301251876Speter    else {
302251876Speter        lob_bucket_destroy(a);
303251876Speter    }
304251876Speter
305251876Speter    return APR_SUCCESS;
306251876Speter}
307251876Speter
308251876Speterstatic apr_bucket *apr_bucket_lob_make(apr_bucket *b,
309251876Speter                                       const apr_dbd_row_t *row, int col,
310251876Speter                                       apr_off_t offset, apr_size_t len,
311251876Speter                                       apr_pool_t *p)
312251876Speter{
313251876Speter    apr_bucket_lob *f;
314251876Speter
315251876Speter    f = apr_bucket_alloc(sizeof(*f), b->list);
316251876Speter    f->row = row;
317251876Speter    f->col = col;
318251876Speter    f->readpool = p;
319251876Speter
320251876Speter    b = apr_bucket_shared_make(b, f, offset, len);
321251876Speter    b->type = &apr_bucket_type_lob;
322251876Speter
323251876Speter    return b;
324251876Speter}
325251876Speter
326251876Speterstatic apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
327251876Speter                                         apr_off_t offset,
328251876Speter                                         apr_size_t len, apr_pool_t *p,
329251876Speter                                         apr_bucket_alloc_t *list)
330251876Speter{
331251876Speter    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
332251876Speter
333251876Speter    APR_BUCKET_INIT(b);
334251876Speter    b->free = apr_bucket_free;
335251876Speter    b->list = list;
336251876Speter    return apr_bucket_lob_make(b, row, col, offset, len, p);
337251876Speter}
338251876Speter
339251876Speterstatic apr_status_t dbd_free_lobdesc(void *lob)
340251876Speter{
341251876Speter    switch (OCIDescriptorFree(lob, OCI_DTYPE_LOB)) {
342251876Speter    case OCI_SUCCESS:
343251876Speter        return APR_SUCCESS;
344251876Speter    default:
345251876Speter        return APR_EGENERAL;
346251876Speter    }
347251876Speter}
348251876Speter
349251876Speterstatic apr_status_t dbd_free_snapshot(void *snap)
350251876Speter{
351251876Speter    switch (OCIDescriptorFree(snap, OCI_DTYPE_SNAP)) {
352251876Speter    case OCI_SUCCESS:
353251876Speter        return APR_SUCCESS;
354251876Speter    default:
355251876Speter        return APR_EGENERAL;
356251876Speter    }
357251876Speter}
358251876Speter
359251876Speterstatic void dbd_oracle_init(apr_pool_t *pool)
360251876Speter{
361251876Speter    if (dbd_oracle_env == NULL) {
362251876Speter        /* Sadly, OCI_SHARED seems to be impossible to use, due to
363251876Speter         * various Oracle bugs.  See, for example, Oracle MetaLink bug 2972890
364251876Speter         * and PHP bug http://bugs.php.net/bug.php?id=23733
365251876Speter         */
366251876Speter#ifdef OCI_NEW_LENGTH_SEMANTICS
367251876Speter        OCIEnvCreate(&dbd_oracle_env, OCI_THREADED|OCI_NEW_LENGTH_SEMANTICS,
368251876Speter                     NULL, NULL, NULL, NULL, 0, NULL);
369251876Speter#else
370251876Speter        OCIEnvCreate(&dbd_oracle_env, OCI_THREADED,
371251876Speter                     NULL, NULL, NULL, NULL, 0, NULL);
372251876Speter#endif
373251876Speter    }
374251876Speter}
375251876Speter
376251876Speterstatic apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params,
377251876Speter                                  const char **error)
378251876Speter{
379251876Speter    apr_dbd_t *ret = apr_pcalloc(pool, sizeof(apr_dbd_t));
380251876Speter    int errorcode;
381251876Speter
382251876Speter    char *BLANK = "";
383251876Speter    struct {
384251876Speter        const char *field;
385251876Speter        char *value;
386251876Speter    } fields[] = {
387251876Speter        {"user", BLANK},
388251876Speter        {"pass", BLANK},
389251876Speter        {"dbname", BLANK},
390251876Speter        {"server", BLANK},
391251876Speter        {NULL, NULL}
392251876Speter    };
393251876Speter    int i;
394251876Speter    const char *ptr;
395251876Speter    const char *key;
396251876Speter    size_t klen;
397251876Speter    const char *value;
398251876Speter    size_t vlen;
399251876Speter    static const char *const delims = " \r\n\t;|,";
400251876Speter
401251876Speter    ret->pool = pool;
402251876Speter    ret->long_size = DEFAULT_LONG_SIZE;
403251876Speter
404251876Speter    /* snitch parsing from the MySQL driver */
405251876Speter    for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {
406251876Speter        /* don't dereference memory that may not belong to us */
407251876Speter        if (ptr == params) {
408251876Speter            ++ptr;
409251876Speter            continue;
410251876Speter        }
411251876Speter        for (key = ptr-1; apr_isspace(*key); --key);
412251876Speter        klen = 0;
413251876Speter        while (apr_isalpha(*key)) {
414251876Speter            if (key == params) {
415251876Speter                /* Don't parse off the front of the params */
416251876Speter                --key;
417251876Speter                ++klen;
418251876Speter                break;
419251876Speter            }
420251876Speter            --key;
421251876Speter            ++klen;
422251876Speter        }
423251876Speter        ++key;
424251876Speter        for (value = ptr+1; apr_isspace(*value); ++value);
425251876Speter        vlen = strcspn(value, delims);
426251876Speter        for (i=0; fields[i].field != NULL; ++i) {
427251876Speter            if (!strncasecmp(fields[i].field, key, klen)) {
428251876Speter                fields[i].value = apr_pstrndup(pool, value, vlen);
429251876Speter                break;
430251876Speter            }
431251876Speter        }
432251876Speter        ptr = value+vlen;
433251876Speter    }
434251876Speter
435251876Speter    ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->err,
436251876Speter                                 OCI_HTYPE_ERROR, 0, NULL);
437251876Speter    switch (ret->status) {
438251876Speter    default:
439251876Speter#ifdef DEBUG
440251876Speter        printf("ret->status is %d\n", ret->status);
441251876Speter        break;
442251876Speter#else
443251876Speter        return NULL;
444251876Speter#endif
445251876Speter    case OCI_SUCCESS:
446251876Speter        break;
447251876Speter    }
448251876Speter
449251876Speter    ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svr,
450251876Speter                                 OCI_HTYPE_SERVER, 0, NULL);
451251876Speter    switch (ret->status) {
452251876Speter    default:
453251876Speter#ifdef DEBUG
454251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
455251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
456251876Speter        printf("OPEN ERROR %d (alloc svr): %s\n", ret->status, ret->buf);
457251876Speter        break;
458251876Speter#else
459251876Speter        if (error) {
460251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
461251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
462251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
463251876Speter        }
464251876Speter        return NULL;
465251876Speter#endif
466251876Speter    case OCI_SUCCESS:
467251876Speter        break;
468251876Speter    }
469251876Speter
470251876Speter    ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svc,
471251876Speter                                 OCI_HTYPE_SVCCTX, 0, NULL);
472251876Speter    switch (ret->status) {
473251876Speter    default:
474251876Speter#ifdef DEBUG
475251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
476251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
477251876Speter        printf("OPEN ERROR %d (alloc svc): %s\n", ret->status, ret->buf);
478251876Speter        break;
479251876Speter#else
480251876Speter        if (error) {
481251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
482251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
483251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
484251876Speter        }
485251876Speter        return NULL;
486251876Speter#endif
487251876Speter    case OCI_SUCCESS:
488251876Speter        break;
489251876Speter    }
490251876Speter
491251876Speter/* All the examples use the #else */
492251876Speter#if CAN_DO_LOGIN
493251876Speter    ret->status = OCILogon(dbd_oracle_env, ret->err, &ret->svc, fields[0].value,
494251876Speter                     strlen(fields[0].value), fields[1].value,
495251876Speter                     strlen(fields[1].value), fields[2].value,
496251876Speter                     strlen(fields[2].value));
497251876Speter    switch (ret->status) {
498251876Speter    default:
499251876Speter#ifdef DEBUG
500251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
501251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
502251876Speter        printf("OPEN ERROR: %s\n", ret->buf);
503251876Speter        break;
504251876Speter#else
505251876Speter        if (error) {
506251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
507251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
508251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
509251876Speter        }
510251876Speter        return NULL;
511251876Speter#endif
512251876Speter    case OCI_SUCCESS:
513251876Speter        break;
514251876Speter    }
515251876Speter#else
516251876Speter    ret->status = OCIServerAttach(ret->svr, ret->err, (text*) fields[3].value,
517251876Speter                                  strlen(fields[3].value), OCI_DEFAULT);
518251876Speter    switch (ret->status) {
519251876Speter    default:
520251876Speter#ifdef DEBUG
521251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
522251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
523251876Speter        printf("OPEN ERROR %d (server attach): %s\n", ret->status, ret->buf);
524251876Speter        break;
525251876Speter#else
526251876Speter        if (error) {
527251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
528251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
529251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
530251876Speter        }
531251876Speter        return NULL;
532251876Speter#endif
533251876Speter    case OCI_SUCCESS:
534251876Speter        break;
535251876Speter    }
536251876Speter    ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->svr, 0,
537251876Speter                        OCI_ATTR_SERVER, ret->err);
538251876Speter    switch (ret->status) {
539251876Speter    default:
540251876Speter#ifdef DEBUG
541251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
542251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
543251876Speter        printf("OPEN ERROR %d (attr set): %s\n", ret->status, ret->buf);
544251876Speter        break;
545251876Speter#else
546251876Speter        if (error) {
547251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
548251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
549251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
550251876Speter        }
551251876Speter        return NULL;
552251876Speter#endif
553251876Speter    case OCI_SUCCESS:
554251876Speter        break;
555251876Speter    }
556251876Speter    ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->auth,
557251876Speter                            OCI_HTYPE_SESSION, 0, NULL);
558251876Speter    switch (ret->status) {
559251876Speter    default:
560251876Speter#ifdef DEBUG
561251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
562251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
563251876Speter        printf("OPEN ERROR %d (alloc auth): %s\n", ret->status, ret->buf);
564251876Speter        break;
565251876Speter#else
566251876Speter        if (error) {
567251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
568251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
569251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
570251876Speter        }
571251876Speter        return NULL;
572251876Speter#endif
573251876Speter    case OCI_SUCCESS:
574251876Speter        break;
575251876Speter    }
576251876Speter    ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[0].value,
577251876Speter                        strlen(fields[0].value), OCI_ATTR_USERNAME, ret->err);
578251876Speter    switch (ret->status) {
579251876Speter    default:
580251876Speter#ifdef DEBUG
581251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
582251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
583251876Speter        printf("OPEN ERROR %d (attr username): %s\n", ret->status, ret->buf);
584251876Speter        break;
585251876Speter#else
586251876Speter        if (error) {
587251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
588251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
589251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
590251876Speter        }
591251876Speter        return NULL;
592251876Speter#endif
593251876Speter    case OCI_SUCCESS:
594251876Speter        break;
595251876Speter    }
596251876Speter    ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[1].value,
597251876Speter                        strlen(fields[1].value), OCI_ATTR_PASSWORD, ret->err);
598251876Speter    switch (ret->status) {
599251876Speter    default:
600251876Speter#ifdef DEBUG
601251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
602251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
603251876Speter        printf("OPEN ERROR %d (attr password): %s\n", ret->status, ret->buf);
604251876Speter        break;
605251876Speter#else
606251876Speter        if (error) {
607251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
608251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
609251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
610251876Speter        }
611251876Speter        return NULL;
612251876Speter#endif
613251876Speter    case OCI_SUCCESS:
614251876Speter        break;
615251876Speter    }
616251876Speter    ret->status = OCISessionBegin(ret->svc, ret->err, ret->auth,
617251876Speter                             OCI_CRED_RDBMS, OCI_DEFAULT);
618251876Speter    switch (ret->status) {
619251876Speter    default:
620251876Speter#ifdef DEBUG
621251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
622251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
623251876Speter        printf("OPEN ERROR %d (session begin): %s\n", ret->status, ret->buf);
624251876Speter        break;
625251876Speter#else
626251876Speter        if (error) {
627251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
628251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
629251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
630251876Speter        }
631251876Speter        return NULL;
632251876Speter#endif
633251876Speter    case OCI_SUCCESS:
634251876Speter        break;
635251876Speter    }
636251876Speter    ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->auth, 0,
637251876Speter                        OCI_ATTR_SESSION, ret->err);
638251876Speter    switch (ret->status) {
639251876Speter    default:
640251876Speter#ifdef DEBUG
641251876Speter        OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
642251876Speter                    sizeof(ret->buf), OCI_HTYPE_ERROR);
643251876Speter        printf("OPEN ERROR %d (attr session): %s\n", ret->status, ret->buf);
644251876Speter#else
645251876Speter        if (error) {
646251876Speter            *error = apr_pcalloc(pool, ERR_BUF_SIZE);
647251876Speter            OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
648251876Speter                        ERR_BUF_SIZE, OCI_HTYPE_ERROR);
649251876Speter        }
650251876Speter        return NULL;
651251876Speter#endif
652251876Speter        break;
653251876Speter    case OCI_SUCCESS:
654251876Speter        break;
655251876Speter    }
656251876Speter#endif
657251876Speter
658251876Speter    if(dbd_oracle_prepare(pool, ret, CHECK_CONN_QUERY, NULL, 0, 0, NULL,
659251876Speter                          &ret->check_conn_stmt) != 0) {
660251876Speter        return NULL;
661251876Speter    }
662251876Speter
663251876Speter    return ret;
664251876Speter}
665251876Speter
666251876Speter#ifdef EXPORT_NATIVE_FUNCS
667251876Speterstatic apr_size_t dbd_oracle_long_size_set(apr_dbd_t *sql,
668251876Speter                                           apr_size_t long_size)
669251876Speter{
670251876Speter    apr_size_t old_size = sql->long_size;
671251876Speter    sql->long_size = long_size;
672251876Speter    return old_size;
673251876Speter}
674251876Speter#endif
675251876Speter
676251876Speterstatic const char *dbd_oracle_get_name(const apr_dbd_results_t *res, int n)
677251876Speter{
678251876Speter    define_arg *val = &res->statement->out[n];
679251876Speter
680251876Speter    if ((n < 0) || (n >= res->statement->nout)) {
681251876Speter        return NULL;
682251876Speter    }
683251876Speter    return val->name;
684251876Speter}
685251876Speter
686251876Speterstatic int dbd_oracle_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
687251876Speter                              apr_dbd_row_t **rowp, int rownum)
688251876Speter{
689251876Speter    apr_dbd_row_t *row = *rowp;
690251876Speter    apr_dbd_t *sql = res->handle;
691251876Speter    int_errorcode;
692251876Speter
693251876Speter    if (row == NULL) {
694251876Speter        row = apr_palloc(pool, sizeof(apr_dbd_row_t));
695251876Speter        *rowp = row;
696251876Speter        row->res = res;
697251876Speter        /* Oracle starts counting at 1 according to the docs */
698251876Speter        row->n = res->seek ? rownum : 1;
699251876Speter        row->pool = pool;
700251876Speter    }
701251876Speter    else {
702251876Speter        if (res->seek) {
703251876Speter            row->n = rownum;
704251876Speter        }
705251876Speter        else {
706251876Speter            ++row->n;
707251876Speter        }
708251876Speter    }
709251876Speter
710251876Speter    if (res->seek) {
711251876Speter        sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
712251876Speter                                    OCI_FETCH_ABSOLUTE, row->n, OCI_DEFAULT);
713251876Speter    }
714251876Speter    else {
715251876Speter        sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
716251876Speter                                    OCI_FETCH_NEXT, 0, OCI_DEFAULT);
717251876Speter    }
718251876Speter    switch (sql->status) {
719251876Speter    case OCI_SUCCESS:
720251876Speter        (*rowp)->res = res;
721251876Speter        return 0;
722251876Speter    case OCI_NO_DATA:
723251876Speter        return -1;
724251876Speter    case OCI_ERROR:
725251876Speter#ifdef DEBUG
726251876Speter        OCIErrorGet(sql->err, 1, NULL, &errorcode,
727251876Speter                    sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
728251876Speter        printf("Execute error %d: %s\n", sql->status, sql->buf);
729251876Speter#endif
730251876Speter        /* fallthrough */
731251876Speter    default:
732251876Speter        return 1;
733251876Speter    }
734251876Speter    return 0;
735251876Speter}
736251876Speter
737251876Speterstatic const char *dbd_oracle_error(apr_dbd_t *sql, int n)
738251876Speter{
739251876Speter    /* This is ugly.  Needs us to pass in a buffer of unknown size.
740251876Speter     * Either we put it on the handle, or we have to keep allocing/copying
741251876Speter     */
742251876Speter    sb4 errorcode;
743251876Speter
744251876Speter    switch (sql->status) {
745251876Speter    case OCI_SUCCESS:
746251876Speter        return "OCI_SUCCESS";
747251876Speter    case OCI_SUCCESS_WITH_INFO:
748251876Speter        return "OCI_SUCCESS_WITH_INFO";
749251876Speter    case OCI_NEED_DATA:
750251876Speter        return "OCI_NEED_DATA";
751251876Speter    case OCI_NO_DATA:
752251876Speter        return "OCI_NO_DATA";
753251876Speter    case OCI_INVALID_HANDLE:
754251876Speter        return "OCI_INVALID_HANDLE";
755251876Speter    case OCI_STILL_EXECUTING:
756251876Speter        return "OCI_STILL_EXECUTING";
757251876Speter    case OCI_CONTINUE:
758251876Speter        return "OCI_CONTINUE";
759251876Speter    }
760251876Speter
761251876Speter    switch (OCIErrorGet(sql->err, 1, NULL, &errorcode,
762251876Speter                        (text*) sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR)) {
763251876Speter    case OCI_SUCCESS:
764251876Speter        return sql->buf;
765251876Speter    default:
766251876Speter        return "internal error: OCIErrorGet failed";
767251876Speter    }
768251876Speter}
769251876Speter
770251876Speterstatic apr_status_t freeStatement(void *statement)
771251876Speter{
772251876Speter    int rv = APR_SUCCESS;
773251876Speter    OCIStmt *stmt = ((apr_dbd_prepared_t*)statement)->stmt;
774251876Speter
775251876Speter#ifdef PREPARE2
776251876Speter    OCIError *err;
777251876Speter
778251876Speter    if (OCIHandleAlloc(dbd_oracle_env, (dvoid**)&err, OCI_HTYPE_ERROR,
779251876Speter                       0, NULL) != OCI_SUCCESS) {
780251876Speter        return APR_EGENERAL;
781251876Speter    }
782251876Speter    if (OCIStmtRelease(stmt, err, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS) {
783251876Speter        rv = APR_EGENERAL;
784251876Speter    }
785251876Speter    if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) {
786251876Speter        rv = APR_EGENERAL;
787251876Speter    }
788251876Speter#else
789251876Speter    if (OCIHandleFree(stmt, OCI_HTYPE_STMT) != OCI_SUCCESS) {
790251876Speter        rv = APR_EGENERAL;
791251876Speter    }
792251876Speter#endif
793251876Speter
794251876Speter    return rv;
795251876Speter}
796251876Speter
797251876Speterstatic int dbd_oracle_select(apr_pool_t *pool, apr_dbd_t *sql,
798251876Speter                             apr_dbd_results_t **results,
799251876Speter                             const char *query, int seek)
800251876Speter{
801251876Speter    int ret = 0;
802251876Speter    apr_dbd_prepared_t *statement = NULL;
803251876Speter
804251876Speter    ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
805251876Speter    if (ret != 0) {
806251876Speter        return ret;
807251876Speter    }
808251876Speter
809251876Speter    ret = dbd_oracle_pselect(pool, sql, results, statement, seek, NULL);
810251876Speter    if (ret != 0) {
811251876Speter        return ret;
812251876Speter    }
813251876Speter
814251876Speter    return ret;
815251876Speter}
816251876Speter
817251876Speterstatic int dbd_oracle_query(apr_dbd_t *sql, int *nrows, const char *query)
818251876Speter{
819251876Speter    int ret = 0;
820251876Speter    apr_pool_t *pool;
821251876Speter    apr_dbd_prepared_t *statement = NULL;
822251876Speter
823251876Speter    if (sql->trans && sql->trans->status == TRANS_ERROR) {
824251876Speter        return 1;
825251876Speter    }
826251876Speter
827251876Speter    /* make our own pool so that APR allocations don't linger and so that
828251876Speter     * both Stmt and LOB handles are cleaned up (LOB handles may be
829251876Speter     * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs)
830251876Speter     */
831251876Speter    apr_pool_create(&pool, sql->pool);
832251876Speter
833251876Speter    ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
834251876Speter    if (ret == 0) {
835251876Speter        ret = dbd_oracle_pquery(pool, sql, nrows, statement, NULL);
836251876Speter        if (ret == 0) {
837251876Speter            sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT,
838251876Speter                                     nrows, 0, OCI_ATTR_ROW_COUNT,
839251876Speter                                     sql->err);
840251876Speter        }
841251876Speter    }
842251876Speter
843251876Speter    apr_pool_destroy(pool);
844251876Speter
845251876Speter    return ret;
846251876Speter}
847251876Speter
848251876Speterstatic const char *dbd_oracle_escape(apr_pool_t *pool, const char *arg,
849251876Speter                                     apr_dbd_t *sql)
850251876Speter{
851251876Speter    return arg;        /* OCI has no concept of string escape */
852251876Speter}
853251876Speter
854251876Speterstatic int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
855251876Speter                              const char *query, const char *label,
856251876Speter                              int nargs, int nvals, apr_dbd_type_e *types,
857251876Speter                              apr_dbd_prepared_t **statement)
858251876Speter{
859251876Speter    int ret = 0;
860251876Speter    int i;
861251876Speter    apr_dbd_prepared_t *stmt ;
862251876Speter
863251876Speter    if (*statement == NULL) {
864251876Speter        *statement = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t));
865251876Speter    }
866251876Speter    stmt = *statement;
867251876Speter    stmt->handle = sql;
868251876Speter    stmt->pool = pool;
869251876Speter    stmt->nargs = nargs;
870251876Speter    stmt->nvals = nvals;
871251876Speter
872251876Speter    /* populate our own args, if any */
873251876Speter    if (nargs > 0) {
874251876Speter        stmt->args = apr_pcalloc(pool, nargs*sizeof(bind_arg));
875251876Speter        for (i = 0; i < nargs; i++) {
876251876Speter            stmt->args[i].type = types[i];
877251876Speter        }
878251876Speter    }
879251876Speter
880251876Speter    sql->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**) &stmt->stmt,
881251876Speter                                 OCI_HTYPE_STMT, 0, NULL);
882251876Speter    if (sql->status != OCI_SUCCESS) {
883251876Speter        return 1;
884251876Speter    }
885251876Speter
886251876Speter    sql->status = OCIStmtPrepare(stmt->stmt, sql->err, (text*) query,
887251876Speter                                 strlen(query), OCI_NTV_SYNTAX, OCI_DEFAULT);
888251876Speter    if (sql->status != OCI_SUCCESS) {
889251876Speter        OCIHandleFree(stmt->stmt, OCI_HTYPE_STMT);
890251876Speter        return 1;
891251876Speter    }
892251876Speter
893251876Speter    apr_pool_cleanup_register(pool, stmt, freeStatement,
894251876Speter                              apr_pool_cleanup_null);
895251876Speter
896251876Speter    /* Perl gets statement type here */
897251876Speter    sql->status = OCIAttrGet(stmt->stmt, OCI_HTYPE_STMT, &stmt->type, 0,
898251876Speter                             OCI_ATTR_STMT_TYPE, sql->err);
899251876Speter    if (sql->status != OCI_SUCCESS) {
900251876Speter        return 1;
901251876Speter    }
902251876Speter
903251876Speter/* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
904251876Speter#if 0
905251876Speter    sql->status = OCIAttrSet(stmt->stmt, OCI_HTYPE_STMT, &prefetch_size,
906251876Speter                             sizeof(prefetch_size), OCI_ATTR_PREFETCH_MEMORY,
907251876Speter                             sql->err);
908251876Speter    if (sql->status != OCI_SUCCESS) {
909251876Speter        return 1;
910251876Speter    }
911251876Speter#endif
912251876Speter
913251876Speter    if (stmt->type == OCI_STMT_SELECT) {
914251876Speter        ret = outputParams(sql, stmt);
915251876Speter    }
916251876Speter    return ret;
917251876Speter}
918251876Speter
919251876Speterstatic void dbd_oracle_bind(apr_dbd_prepared_t *statement, const char **values)
920251876Speter{
921251876Speter    OCIStmt *stmt = statement->stmt;
922251876Speter    apr_dbd_t *sql = statement->handle;
923251876Speter    int i, j;
924251876Speter    sb2 null_ind = -1;
925251876Speter
926251876Speter    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
927251876Speter        if (values[j] == NULL) {
928251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
929251876Speter                                       sql->err, i + 1,
930251876Speter                                       NULL, 0, SQLT_STR,
931251876Speter                                       &null_ind, NULL,
932251876Speter                                       (ub2) 0, (ub4) 0,
933251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
934251876Speter        }
935251876Speter        else {
936251876Speter            switch (statement->args[i].type) {
937251876Speter            case APR_DBD_TYPE_BLOB:
938251876Speter                {
939251876Speter                char *data = (char *)values[j];
940251876Speter                int size = atoi((char*)values[++j]);
941251876Speter
942251876Speter                /* skip table and column for now */
943251876Speter                j += 2;
944251876Speter
945251876Speter                sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
946251876Speter                                           sql->err, i + 1,
947251876Speter                                           data, size, SQLT_LBI,
948251876Speter                                           &statement->args[i].ind,
949251876Speter                                           NULL,
950251876Speter                                           (ub2) 0, (ub4) 0,
951251876Speter                                           (ub4 *) 0, OCI_DEFAULT);
952251876Speter                }
953251876Speter                break;
954251876Speter            case APR_DBD_TYPE_CLOB:
955251876Speter                {
956251876Speter                char *data = (char *)values[j];
957251876Speter                int size = atoi((char*)values[++j]);
958251876Speter
959251876Speter                /* skip table and column for now */
960251876Speter                j += 2;
961251876Speter
962251876Speter                sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
963251876Speter                                           sql->err, i + 1,
964251876Speter                                           data, size, SQLT_LNG,
965251876Speter                                           &statement->args[i].ind,
966251876Speter                                           NULL,
967251876Speter                                           (ub2) 0, (ub4) 0,
968251876Speter                                           (ub4 *) 0, OCI_DEFAULT);
969251876Speter                }
970251876Speter                break;
971251876Speter            default:
972251876Speter                sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
973251876Speter                                           sql->err, i + 1,
974251876Speter                                           (dvoid*) values[j],
975251876Speter                                           strlen(values[j]) + 1,
976251876Speter                                           SQLT_STR,
977251876Speter                                           &statement->args[i].ind,
978251876Speter                                           NULL,
979251876Speter                                           (ub2) 0, (ub4) 0,
980251876Speter                                           (ub4 *) 0, OCI_DEFAULT);
981251876Speter                break;
982251876Speter            }
983251876Speter        }
984251876Speter
985251876Speter        if (sql->status != OCI_SUCCESS) {
986251876Speter            return;
987251876Speter        }
988251876Speter    }
989251876Speter
990251876Speter    return;
991251876Speter}
992251876Speter
993251876Speterstatic int outputParams(apr_dbd_t *sql, apr_dbd_prepared_t *stmt)
994251876Speter{
995251876Speter    OCIParam *parms;
996251876Speter    int i;
997251876Speter    ub2 paramtype[DBD_ORACLE_MAX_COLUMNS];
998251876Speter    ub2 paramsize[DBD_ORACLE_MAX_COLUMNS];
999251876Speter    char *paramname[DBD_ORACLE_MAX_COLUMNS];
1000251876Speter    ub4 paramnamelen[DBD_ORACLE_MAX_COLUMNS];
1001251876Speter    int_errorcode;
1002251876Speter
1003251876Speter    /* Perl uses 0 where we used 1 */
1004251876Speter    sql->status = OCIStmtExecute(sql->svc, stmt->stmt, sql->err, 0, 0,
1005251876Speter                                 NULL, NULL, OCI_DESCRIBE_ONLY);
1006251876Speter    switch (sql->status) {
1007251876Speter    case OCI_SUCCESS:
1008251876Speter    case OCI_SUCCESS_WITH_INFO:
1009251876Speter        break;
1010251876Speter    case OCI_ERROR:
1011251876Speter#ifdef DEBUG
1012251876Speter        OCIErrorGet(sql->err, 1, NULL, &errorcode,
1013251876Speter                    sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1014251876Speter        printf("Describing prepared statement: %s\n", sql->buf);
1015251876Speter#endif
1016251876Speter    default:
1017251876Speter        return 1;
1018251876Speter    }
1019251876Speter    while (sql->status == OCI_SUCCESS) {
1020251876Speter        sql->status = OCIParamGet(stmt->stmt, OCI_HTYPE_STMT,
1021251876Speter                                  sql->err, (dvoid**)&parms, stmt->nout+1);
1022251876Speter        switch (sql->status) {
1023251876Speter        case OCI_SUCCESS:
1024251876Speter            sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1025251876Speter                                     &paramtype[stmt->nout],
1026251876Speter                                     0, OCI_ATTR_DATA_TYPE, sql->err);
1027251876Speter            sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1028251876Speter                                     &paramsize[stmt->nout],
1029251876Speter                                     0, OCI_ATTR_DATA_SIZE, sql->err);
1030251876Speter            sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1031251876Speter                                     &paramname[stmt->nout],
1032251876Speter                                     &paramnamelen[stmt->nout],
1033251876Speter                                     OCI_ATTR_NAME, sql->err);
1034251876Speter            ++stmt->nout;
1035251876Speter        }
1036251876Speter    }
1037251876Speter    switch (sql->status) {
1038251876Speter    case OCI_SUCCESS:
1039251876Speter        break;
1040251876Speter    case OCI_ERROR:
1041251876Speter        break;        /* this is what we expect at end-of-loop */
1042251876Speter    default:
1043251876Speter        return 1;
1044251876Speter    }
1045251876Speter
1046251876Speter    /* OK, the above works.  We have the params; now OCIDefine them */
1047251876Speter    stmt->out = apr_palloc(stmt->pool, stmt->nout*sizeof(define_arg));
1048251876Speter    for (i=0; i<stmt->nout; ++i) {
1049251876Speter        stmt->out[i].type = paramtype[i];
1050251876Speter        stmt->out[i].len = stmt->out[i].sz = paramsize[i];
1051251876Speter        stmt->out[i].name = apr_pstrmemdup(stmt->pool,
1052251876Speter                                           paramname[i], paramnamelen[i]);
1053251876Speter        switch (stmt->out[i].type) {
1054251876Speter        default:
1055251876Speter            switch (stmt->out[i].type) {
1056251876Speter            case SQLT_NUM:           /* 2: numeric, Perl worst case=130+38+3 */
1057251876Speter                stmt->out[i].sz = 171;
1058251876Speter                break;
1059251876Speter            case SQLT_CHR:           /* 1: char */
1060251876Speter            case SQLT_AFC:           /* 96: ANSI fixed char */
1061251876Speter                stmt->out[i].sz *= 4; /* ugh, wasteful UCS-4 handling */
1062251876Speter                break;
1063251876Speter            case SQLT_DAT:           /* 12: date, depends on NLS date format */
1064251876Speter                stmt->out[i].sz = 75;
1065251876Speter                break;
1066251876Speter            case SQLT_BIN:           /* 23: raw binary, perhaps UTF-16? */
1067251876Speter                stmt->out[i].sz *= 2;
1068251876Speter                break;
1069251876Speter            case SQLT_RID:           /* 11: rowid */
1070251876Speter            case SQLT_RDD:           /* 104: rowid descriptor */
1071251876Speter                stmt->out[i].sz = 20;
1072251876Speter                break;
1073251876Speter            case SQLT_TIMESTAMP:     /* 187: timestamp */
1074251876Speter            case SQLT_TIMESTAMP_TZ:  /* 188: timestamp with time zone */
1075251876Speter            case SQLT_INTERVAL_YM:   /* 189: interval year-to-month */
1076251876Speter            case SQLT_INTERVAL_DS:   /* 190: interval day-to-second */
1077251876Speter            case SQLT_TIMESTAMP_LTZ: /* 232: timestamp with local time zone */
1078251876Speter                stmt->out[i].sz = 75;
1079251876Speter                break;
1080251876Speter            default:
1081251876Speter#ifdef DEBUG
1082251876Speter                printf("Unsupported data type: %d\n", stmt->out[i].type);
1083251876Speter#endif
1084251876Speter                break;
1085251876Speter            }
1086251876Speter            ++stmt->out[i].sz;
1087251876Speter            stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1088251876Speter            sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1089251876Speter                                         sql->err, i+1,
1090251876Speter                                         stmt->out[i].buf.sval,
1091251876Speter                                         stmt->out[i].sz, SQLT_STR,
1092251876Speter                                         &stmt->out[i].ind, &stmt->out[i].len,
1093251876Speter                                         0, OCI_DEFAULT);
1094251876Speter            break;
1095251876Speter        case SQLT_LNG: /* 8: long */
1096251876Speter            stmt->out[i].sz = sql->long_size * 4 + 4; /* ugh, UCS-4 handling */
1097251876Speter            stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1098251876Speter            sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1099251876Speter                                         sql->err, i+1,
1100251876Speter                                         stmt->out[i].buf.raw,
1101251876Speter                                         stmt->out[i].sz, SQLT_LVC,
1102251876Speter                                         &stmt->out[i].ind, NULL,
1103251876Speter                                         0, OCI_DEFAULT);
1104251876Speter            break;
1105251876Speter        case SQLT_LBI: /* 24: long binary, perhaps UTF-16? */
1106251876Speter            stmt->out[i].sz = sql->long_size * 2 + 4; /* room for int prefix */
1107251876Speter            stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1108251876Speter            sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1109251876Speter                                         sql->err, i+1,
1110251876Speter                                         stmt->out[i].buf.raw,
1111251876Speter                                         stmt->out[i].sz, SQLT_LVB,
1112251876Speter                                         &stmt->out[i].ind, NULL,
1113251876Speter                                         0, OCI_DEFAULT);
1114251876Speter            break;
1115251876Speter        case SQLT_BLOB: /* 113 */
1116251876Speter        case SQLT_CLOB: /* 112 */
1117251876Speter/*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1118251876Speter            sql->status = OCIDescriptorAlloc(dbd_oracle_env,
1119251876Speter                                             (dvoid**)&stmt->out[i].buf.lobval,
1120251876Speter                                             OCI_DTYPE_LOB, 0, NULL);
1121251876Speter            apr_pool_cleanup_register(stmt->pool, stmt->out[i].buf.lobval,
1122251876Speter                                      dbd_free_lobdesc,
1123251876Speter                                      apr_pool_cleanup_null);
1124251876Speter            sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1125251876Speter                                         sql->err, i+1,
1126251876Speter                                         (dvoid*) &stmt->out[i].buf.lobval,
1127251876Speter                                         -1, stmt->out[i].type,
1128251876Speter                                         &stmt->out[i].ind, &stmt->out[i].len,
1129251876Speter                                         0, OCI_DEFAULT);
1130251876Speter            break;
1131251876Speter        }
1132251876Speter        switch (sql->status) {
1133251876Speter        case OCI_SUCCESS:
1134251876Speter            break;
1135251876Speter        default:
1136251876Speter            return 1;
1137251876Speter        }
1138251876Speter    }
1139251876Speter    return 0;
1140251876Speter}
1141251876Speter
1142251876Speterstatic int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
1143251876Speter                             int *nrows, apr_dbd_prepared_t *statement,
1144251876Speter                             const char **values)
1145251876Speter{
1146251876Speter    OCISnapshot *oldsnapshot = NULL;
1147251876Speter    OCISnapshot *newsnapshot = NULL;
1148251876Speter    apr_dbd_transaction_t* trans = sql->trans;
1149251876Speter    int exec_mode;
1150251876Speter    int_errorcode;
1151251876Speter
1152251876Speter    if (trans) {
1153251876Speter        switch (trans->status) {
1154251876Speter        case TRANS_ERROR:
1155251876Speter            return -1;
1156251876Speter        case TRANS_NONE:
1157251876Speter            trans = NULL;
1158251876Speter            break;
1159251876Speter        case TRANS_1:
1160251876Speter            oldsnapshot = trans->snapshot1;
1161251876Speter            newsnapshot = trans->snapshot2;
1162251876Speter            trans->status = TRANS_2;
1163251876Speter            break;
1164251876Speter        case TRANS_2:
1165251876Speter            oldsnapshot = trans->snapshot2;
1166251876Speter            newsnapshot = trans->snapshot1;
1167251876Speter            trans->status = TRANS_1;
1168251876Speter            break;
1169251876Speter        }
1170251876Speter        exec_mode = OCI_DEFAULT;
1171251876Speter    }
1172251876Speter    else {
1173251876Speter        exec_mode = OCI_COMMIT_ON_SUCCESS;
1174251876Speter    }
1175251876Speter
1176251876Speter    dbd_oracle_bind(statement, values);
1177251876Speter
1178251876Speter    sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1179251876Speter                                 oldsnapshot, newsnapshot, exec_mode);
1180251876Speter    switch (sql->status) {
1181251876Speter    case OCI_SUCCESS:
1182251876Speter        break;
1183251876Speter    case OCI_ERROR:
1184251876Speter#ifdef DEBUG
1185251876Speter        OCIErrorGet(sql->err, 1, NULL, &errorcode,
1186251876Speter                    sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1187251876Speter        printf("Execute error %d: %s\n", sql->status, sql->buf);
1188251876Speter#endif
1189251876Speter        /* fallthrough */
1190251876Speter    default:
1191251876Speter        if (TXN_NOTICE_ERRORS(trans)) {
1192251876Speter            trans->status = TRANS_ERROR;
1193251876Speter        }
1194251876Speter        return 1;
1195251876Speter    }
1196251876Speter
1197251876Speter    sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1198251876Speter                             OCI_ATTR_ROW_COUNT, sql->err);
1199251876Speter    return 0;
1200251876Speter}
1201251876Speter
1202251876Speterstatic int dbd_oracle_pvquery(apr_pool_t *pool, apr_dbd_t *sql,
1203251876Speter                              int *nrows, apr_dbd_prepared_t *statement,
1204251876Speter                              va_list args)
1205251876Speter{
1206251876Speter    const char **values;
1207251876Speter    int i;
1208251876Speter
1209251876Speter    if (sql->trans && sql->trans->status == TRANS_ERROR) {
1210251876Speter        return -1;
1211251876Speter    }
1212251876Speter
1213251876Speter    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1214251876Speter
1215251876Speter    for (i = 0; i < statement->nvals; i++) {
1216251876Speter        values[i] = va_arg(args, const char*);
1217251876Speter    }
1218251876Speter
1219251876Speter    return dbd_oracle_pquery(pool, sql, nrows, statement, values);
1220251876Speter}
1221251876Speter
1222251876Speterstatic int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
1223251876Speter                              apr_dbd_results_t **results,
1224251876Speter                              apr_dbd_prepared_t *statement,
1225251876Speter                              int seek, const char **values)
1226251876Speter{
1227251876Speter    int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1228251876Speter    OCISnapshot *oldsnapshot = NULL;
1229251876Speter    OCISnapshot *newsnapshot = NULL;
1230251876Speter    apr_dbd_transaction_t* trans = sql->trans;
1231251876Speter    int_errorcode;
1232251876Speter
1233251876Speter    if (trans) {
1234251876Speter        switch (trans->status) {
1235251876Speter        case TRANS_ERROR:
1236251876Speter            return 1;
1237251876Speter        case TRANS_NONE:
1238251876Speter            trans = NULL;
1239251876Speter            break;
1240251876Speter        case TRANS_1:
1241251876Speter            oldsnapshot = trans->snapshot1;
1242251876Speter            newsnapshot = trans->snapshot2;
1243251876Speter            trans->status = TRANS_2;
1244251876Speter            break;
1245251876Speter        case TRANS_2:
1246251876Speter            oldsnapshot = trans->snapshot2;
1247251876Speter            newsnapshot = trans->snapshot1;
1248251876Speter            trans->status = TRANS_1;
1249251876Speter            break;
1250251876Speter        }
1251251876Speter    }
1252251876Speter
1253251876Speter    dbd_oracle_bind(statement, values);
1254251876Speter
1255251876Speter    sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1256251876Speter                                 oldsnapshot, newsnapshot, exec_mode);
1257251876Speter    switch (sql->status) {
1258251876Speter    case OCI_SUCCESS:
1259251876Speter        break;
1260251876Speter    case OCI_ERROR:
1261251876Speter#ifdef DEBUG
1262251876Speter        OCIErrorGet(sql->err, 1, NULL, &errorcode,
1263251876Speter                    sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1264251876Speter        printf("Executing prepared statement: %s\n", sql->buf);
1265251876Speter#endif
1266251876Speter        /* fallthrough */
1267251876Speter    default:
1268251876Speter        if (TXN_NOTICE_ERRORS(trans)) {
1269251876Speter            trans->status = TRANS_ERROR;
1270251876Speter        }
1271251876Speter        return 1;
1272251876Speter    }
1273251876Speter
1274251876Speter    if (!*results) {
1275251876Speter        *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1276251876Speter    }
1277251876Speter    (*results)->handle = sql;
1278251876Speter    (*results)->statement = statement;
1279251876Speter    (*results)->seek = seek;
1280251876Speter    (*results)->rownum = seek ? 0 : -1;
1281251876Speter    (*results)->pool = pool;
1282251876Speter
1283251876Speter    return 0;
1284251876Speter}
1285251876Speter
1286251876Speterstatic int dbd_oracle_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
1287251876Speter                               apr_dbd_results_t **results,
1288251876Speter                               apr_dbd_prepared_t *statement,
1289251876Speter                               int seek, va_list args)
1290251876Speter{
1291251876Speter    const char **values;
1292251876Speter    int i;
1293251876Speter
1294251876Speter    if (sql->trans && sql->trans->status == TRANS_ERROR) {
1295251876Speter        return -1;
1296251876Speter    }
1297251876Speter
1298251876Speter    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1299251876Speter
1300251876Speter    for (i = 0; i < statement->nvals; i++) {
1301251876Speter        values[i] = va_arg(args, const char*);
1302251876Speter    }
1303251876Speter
1304251876Speter    return dbd_oracle_pselect(pool, sql, results, statement, seek, values);
1305251876Speter}
1306251876Speter
1307251876Speterstatic void dbd_oracle_bbind(apr_dbd_prepared_t * statement,
1308251876Speter                             const void **values)
1309251876Speter{
1310251876Speter    OCIStmt *stmt = statement->stmt;
1311251876Speter    apr_dbd_t *sql = statement->handle;
1312251876Speter    int i, j;
1313251876Speter    sb2 null_ind = -1;
1314251876Speter    apr_dbd_type_e type;
1315251876Speter
1316251876Speter    for (i = 0, j = 0; i < statement->nargs; i++, j++) {
1317251876Speter        type = (values[j] == NULL ? APR_DBD_TYPE_NULL
1318251876Speter                                  : statement->args[i].type);
1319251876Speter
1320251876Speter        switch (type) {
1321251876Speter        case APR_DBD_TYPE_TINY:
1322251876Speter            statement->args[i].value.ival = *(char*)values[j];
1323251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1324251876Speter                                       sql->err, i + 1,
1325251876Speter                                       &statement->args[i].value.ival,
1326251876Speter                                       sizeof(statement->args[i].value.ival),
1327251876Speter                                       SQLT_INT,
1328251876Speter                                       &statement->args[i].ind, NULL,
1329251876Speter                                       (ub2) 0, (ub4) 0,
1330251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1331251876Speter            break;
1332251876Speter        case APR_DBD_TYPE_UTINY:
1333251876Speter            statement->args[i].value.uval = *(unsigned char*)values[j];
1334251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1335251876Speter                                       sql->err, i + 1,
1336251876Speter                                       &statement->args[i].value.uval,
1337251876Speter                                       sizeof(statement->args[i].value.uval),
1338251876Speter                                       SQLT_UIN,
1339251876Speter                                       &statement->args[i].ind, NULL,
1340251876Speter                                       (ub2) 0, (ub4) 0,
1341251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1342251876Speter            break;
1343251876Speter        case APR_DBD_TYPE_SHORT:
1344251876Speter            statement->args[i].value.ival = *(short*)values[j];
1345251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1346251876Speter                                       sql->err, i + 1,
1347251876Speter                                       &statement->args[i].value.ival,
1348251876Speter                                       sizeof(statement->args[i].value.ival),
1349251876Speter                                       SQLT_INT,
1350251876Speter                                       &statement->args[i].ind, NULL,
1351251876Speter                                       (ub2) 0, (ub4) 0,
1352251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1353251876Speter            break;
1354251876Speter        case APR_DBD_TYPE_USHORT:
1355251876Speter            statement->args[i].value.uval = *(unsigned short*)values[j];
1356251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1357251876Speter                                       sql->err, i + 1,
1358251876Speter                                       &statement->args[i].value.uval,
1359251876Speter                                       sizeof(statement->args[i].value.uval),
1360251876Speter                                       SQLT_UIN,
1361251876Speter                                       &statement->args[i].ind, NULL,
1362251876Speter                                       (ub2) 0, (ub4) 0,
1363251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1364251876Speter            break;
1365251876Speter        case APR_DBD_TYPE_INT:
1366251876Speter            statement->args[i].value.ival = *(int*)values[j];
1367251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1368251876Speter                                       sql->err, i + 1,
1369251876Speter                                       &statement->args[i].value.ival,
1370251876Speter                                       sizeof(statement->args[i].value.ival),
1371251876Speter                                       SQLT_INT,
1372251876Speter                                       &statement->args[i].ind, NULL,
1373251876Speter                                       (ub2) 0, (ub4) 0,
1374251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1375251876Speter            break;
1376251876Speter        case APR_DBD_TYPE_UINT:
1377251876Speter            statement->args[i].value.uval = *(unsigned int*)values[j];
1378251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1379251876Speter                                       sql->err, i + 1,
1380251876Speter                                       &statement->args[i].value.uval,
1381251876Speter                                       sizeof(statement->args[i].value.uval),
1382251876Speter                                       SQLT_UIN,
1383251876Speter                                       &statement->args[i].ind, NULL,
1384251876Speter                                       (ub2) 0, (ub4) 0,
1385251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1386251876Speter            break;
1387251876Speter        case APR_DBD_TYPE_LONG:
1388251876Speter            statement->args[i].value.sval =
1389251876Speter                apr_psprintf(statement->pool, "%ld", *(long*)values[j]);
1390251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1391251876Speter                                       sql->err, i + 1,
1392251876Speter                                       statement->args[i].value.sval,
1393251876Speter                                       strlen(statement->args[i].value.sval)+1,
1394251876Speter                                       SQLT_STR,
1395251876Speter                                       &statement->args[i].ind, NULL,
1396251876Speter                                       (ub2) 0, (ub4) 0,
1397251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1398251876Speter            break;
1399251876Speter        case APR_DBD_TYPE_ULONG:
1400251876Speter            statement->args[i].value.sval =
1401251876Speter                apr_psprintf(statement->pool, "%lu",
1402251876Speter                                              *(unsigned long*)values[j]);
1403251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1404251876Speter                                       sql->err, i + 1,
1405251876Speter                                       statement->args[i].value.sval,
1406251876Speter                                       strlen(statement->args[i].value.sval)+1,
1407251876Speter                                       SQLT_STR,
1408251876Speter                                       &statement->args[i].ind, NULL,
1409251876Speter                                       (ub2) 0, (ub4) 0,
1410251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1411251876Speter            break;
1412251876Speter        case APR_DBD_TYPE_LONGLONG:
1413251876Speter            statement->args[i].value.sval =
1414251876Speter                apr_psprintf(statement->pool, "%" APR_INT64_T_FMT,
1415251876Speter                                              *(apr_int64_t*)values[j]);
1416251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1417251876Speter                                       sql->err, i + 1,
1418251876Speter                                       statement->args[i].value.sval,
1419251876Speter                                       strlen(statement->args[i].value.sval)+1,
1420251876Speter                                       SQLT_STR,
1421251876Speter                                       &statement->args[i].ind, NULL,
1422251876Speter                                       (ub2) 0, (ub4) 0,
1423251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1424251876Speter            break;
1425251876Speter        case APR_DBD_TYPE_ULONGLONG:
1426251876Speter            statement->args[i].value.sval =
1427251876Speter                apr_psprintf(statement->pool, "%" APR_UINT64_T_FMT,
1428251876Speter                                              *(apr_uint64_t*)values[j]);
1429251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1430251876Speter                                       sql->err, i + 1,
1431251876Speter                                       statement->args[i].value.sval,
1432251876Speter                                       strlen(statement->args[i].value.sval)+1,
1433251876Speter                                       SQLT_UIN,
1434251876Speter                                       &statement->args[i].ind, NULL,
1435251876Speter                                       (ub2) 0, (ub4) 0,
1436251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1437251876Speter            break;
1438251876Speter        case APR_DBD_TYPE_FLOAT:
1439251876Speter            statement->args[i].value.fval = *(float*)values[j];
1440251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1441251876Speter                                       sql->err, i + 1,
1442251876Speter                                       &statement->args[i].value.fval,
1443251876Speter                                       sizeof(statement->args[i].value.fval),
1444251876Speter                                       SQLT_FLT,
1445251876Speter                                       &statement->args[i].ind, NULL,
1446251876Speter                                       (ub2) 0, (ub4) 0,
1447251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1448251876Speter            break;
1449251876Speter        case APR_DBD_TYPE_DOUBLE:
1450251876Speter            statement->args[i].value.fval = *(double*)values[j];
1451251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1452251876Speter                                       sql->err, i + 1,
1453251876Speter                                       &statement->args[i].value.fval,
1454251876Speter                                       sizeof(statement->args[i].value.fval),
1455251876Speter                                       SQLT_FLT,
1456251876Speter                                       &statement->args[i].ind, NULL,
1457251876Speter                                       (ub2) 0, (ub4) 0,
1458251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1459251876Speter            break;
1460251876Speter        case APR_DBD_TYPE_STRING:
1461251876Speter        case APR_DBD_TYPE_TEXT:
1462251876Speter        case APR_DBD_TYPE_TIME:
1463251876Speter        case APR_DBD_TYPE_DATE:
1464251876Speter        case APR_DBD_TYPE_DATETIME:
1465251876Speter        case APR_DBD_TYPE_TIMESTAMP:
1466251876Speter        case APR_DBD_TYPE_ZTIMESTAMP:
1467251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1468251876Speter                                       sql->err, i + 1,
1469251876Speter                                       (dvoid*) values[j],
1470251876Speter                                       strlen(values[j]) + 1,
1471251876Speter                                       SQLT_STR,
1472251876Speter                                       &statement->args[i].ind, NULL,
1473251876Speter                                       (ub2) 0, (ub4) 0,
1474251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1475251876Speter            break;
1476251876Speter        case APR_DBD_TYPE_BLOB:
1477251876Speter            {
1478251876Speter            char *data = (char *)values[j];
1479251876Speter            apr_size_t size = *(apr_size_t*)values[++j];
1480251876Speter
1481251876Speter            /* skip table and column for now */
1482251876Speter            j += 2;
1483251876Speter
1484251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1485251876Speter                                       sql->err, i + 1,
1486251876Speter                                       data, size, SQLT_LBI,
1487251876Speter                                       &statement->args[i].ind,
1488251876Speter                                       NULL,
1489251876Speter                                       (ub2) 0, (ub4) 0,
1490251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1491251876Speter            }
1492251876Speter            break;
1493251876Speter        case APR_DBD_TYPE_CLOB:
1494251876Speter            {
1495251876Speter            char *data = (char *)values[j];
1496251876Speter            apr_size_t size = *(apr_size_t*)values[++j];
1497251876Speter
1498251876Speter            /* skip table and column for now */
1499251876Speter            j += 2;
1500251876Speter
1501251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1502251876Speter                                       sql->err, i + 1,
1503251876Speter                                       data, size, SQLT_LNG,
1504251876Speter                                       &statement->args[i].ind,
1505251876Speter                                       NULL,
1506251876Speter                                       (ub2) 0, (ub4) 0,
1507251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1508251876Speter            }
1509251876Speter            break;
1510251876Speter        case APR_DBD_TYPE_NULL:
1511251876Speter        default:
1512251876Speter            sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1513251876Speter                                       sql->err, i + 1,
1514251876Speter                                       NULL, 0, SQLT_STR,
1515251876Speter                                       &null_ind, NULL,
1516251876Speter                                       (ub2) 0, (ub4) 0,
1517251876Speter                                       (ub4 *) 0, OCI_DEFAULT);
1518251876Speter            break;
1519251876Speter        }
1520251876Speter
1521251876Speter        if (sql->status != OCI_SUCCESS) {
1522251876Speter            return;
1523251876Speter        }
1524251876Speter    }
1525251876Speter
1526251876Speter    return;
1527251876Speter}
1528251876Speter
1529251876Speterstatic int dbd_oracle_pbquery(apr_pool_t * pool, apr_dbd_t * sql,
1530251876Speter                              int *nrows, apr_dbd_prepared_t * statement,
1531251876Speter                              const void **values)
1532251876Speter{
1533251876Speter    OCISnapshot *oldsnapshot = NULL;
1534251876Speter    OCISnapshot *newsnapshot = NULL;
1535251876Speter    apr_dbd_transaction_t* trans = sql->trans;
1536251876Speter    int exec_mode;
1537251876Speter    int_errorcode;
1538251876Speter
1539251876Speter    if (trans) {
1540251876Speter        switch (trans->status) {
1541251876Speter        case TRANS_ERROR:
1542251876Speter            return -1;
1543251876Speter        case TRANS_NONE:
1544251876Speter            trans = NULL;
1545251876Speter            break;
1546251876Speter        case TRANS_1:
1547251876Speter            oldsnapshot = trans->snapshot1;
1548251876Speter            newsnapshot = trans->snapshot2;
1549251876Speter            trans->status = TRANS_2;
1550251876Speter            break;
1551251876Speter        case TRANS_2:
1552251876Speter            oldsnapshot = trans->snapshot2;
1553251876Speter            newsnapshot = trans->snapshot1;
1554251876Speter            trans->status = TRANS_1;
1555251876Speter            break;
1556251876Speter        }
1557251876Speter        exec_mode = OCI_DEFAULT;
1558251876Speter    }
1559251876Speter    else {
1560251876Speter        exec_mode = OCI_COMMIT_ON_SUCCESS;
1561251876Speter    }
1562251876Speter
1563251876Speter    dbd_oracle_bbind(statement, values);
1564251876Speter
1565251876Speter    sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1566251876Speter                                 oldsnapshot, newsnapshot, exec_mode);
1567251876Speter    switch (sql->status) {
1568251876Speter    case OCI_SUCCESS:
1569251876Speter        break;
1570251876Speter    case OCI_ERROR:
1571251876Speter#ifdef DEBUG
1572251876Speter        OCIErrorGet(sql->err, 1, NULL, &errorcode,
1573251876Speter                    sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1574251876Speter        printf("Execute error %d: %s\n", sql->status, sql->buf);
1575251876Speter#endif
1576251876Speter        /* fallthrough */
1577251876Speter    default:
1578251876Speter        if (TXN_NOTICE_ERRORS(trans)) {
1579251876Speter            trans->status = TRANS_ERROR;
1580251876Speter        }
1581251876Speter        return 1;
1582251876Speter    }
1583251876Speter
1584251876Speter    sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1585251876Speter                             OCI_ATTR_ROW_COUNT, sql->err);
1586251876Speter    return 0;
1587251876Speter}
1588251876Speter
1589251876Speterstatic int dbd_oracle_pvbquery(apr_pool_t * pool, apr_dbd_t * sql,
1590251876Speter                               int *nrows, apr_dbd_prepared_t * statement,
1591251876Speter                               va_list args)
1592251876Speter{
1593251876Speter    const void **values;
1594251876Speter    int i;
1595251876Speter
1596251876Speter    if (sql->trans && sql->trans->status == TRANS_ERROR) {
1597251876Speter        return -1;
1598251876Speter    }
1599251876Speter
1600251876Speter    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1601251876Speter
1602251876Speter    for (i = 0; i < statement->nvals; i++) {
1603251876Speter        values[i] = va_arg(args, const void*);
1604251876Speter    }
1605251876Speter
1606251876Speter    return dbd_oracle_pbquery(pool, sql, nrows, statement, values);
1607251876Speter}
1608251876Speter
1609251876Speterstatic int dbd_oracle_pbselect(apr_pool_t * pool, apr_dbd_t * sql,
1610251876Speter                               apr_dbd_results_t ** results,
1611251876Speter                               apr_dbd_prepared_t * statement,
1612251876Speter                               int seek, const void **values)
1613251876Speter{
1614251876Speter    int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1615251876Speter    OCISnapshot *oldsnapshot = NULL;
1616251876Speter    OCISnapshot *newsnapshot = NULL;
1617251876Speter    apr_dbd_transaction_t* trans = sql->trans;
1618251876Speter    int_errorcode;
1619251876Speter
1620251876Speter    if (trans) {
1621251876Speter        switch (trans->status) {
1622251876Speter        case TRANS_ERROR:
1623251876Speter            return 1;
1624251876Speter        case TRANS_NONE:
1625251876Speter            trans = NULL;
1626251876Speter            break;
1627251876Speter        case TRANS_1:
1628251876Speter            oldsnapshot = trans->snapshot1;
1629251876Speter            newsnapshot = trans->snapshot2;
1630251876Speter            trans->status = TRANS_2;
1631251876Speter            break;
1632251876Speter        case TRANS_2:
1633251876Speter            oldsnapshot = trans->snapshot2;
1634251876Speter            newsnapshot = trans->snapshot1;
1635251876Speter            trans->status = TRANS_1;
1636251876Speter            break;
1637251876Speter        }
1638251876Speter    }
1639251876Speter
1640251876Speter    dbd_oracle_bbind(statement, values);
1641251876Speter
1642251876Speter    sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1643251876Speter                                 oldsnapshot, newsnapshot, exec_mode);
1644251876Speter    switch (sql->status) {
1645251876Speter    case OCI_SUCCESS:
1646251876Speter        break;
1647251876Speter    case OCI_ERROR:
1648251876Speter#ifdef DEBUG
1649251876Speter        OCIErrorGet(sql->err, 1, NULL, &errorcode,
1650251876Speter                    sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1651251876Speter        printf("Executing prepared statement: %s\n", sql->buf);
1652251876Speter#endif
1653251876Speter        /* fallthrough */
1654251876Speter    default:
1655251876Speter        if (TXN_NOTICE_ERRORS(trans)) {
1656251876Speter            trans->status = TRANS_ERROR;
1657251876Speter        }
1658251876Speter        return 1;
1659251876Speter    }
1660251876Speter
1661251876Speter    if (!*results) {
1662251876Speter        *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1663251876Speter    }
1664251876Speter    (*results)->handle = sql;
1665251876Speter    (*results)->statement = statement;
1666251876Speter    (*results)->seek = seek;
1667251876Speter    (*results)->rownum = seek ? 0 : -1;
1668251876Speter    (*results)->pool = pool;
1669251876Speter
1670251876Speter    return 0;
1671251876Speter}
1672251876Speter
1673251876Speterstatic int dbd_oracle_pvbselect(apr_pool_t * pool, apr_dbd_t * sql,
1674251876Speter                                apr_dbd_results_t ** results,
1675251876Speter                                apr_dbd_prepared_t * statement, int seek,
1676251876Speter                                va_list args)
1677251876Speter{
1678251876Speter    const void **values;
1679251876Speter    int i;
1680251876Speter
1681251876Speter    if (sql->trans && sql->trans->status == TRANS_ERROR) {
1682251876Speter        return -1;
1683251876Speter    }
1684251876Speter
1685251876Speter    values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1686251876Speter
1687251876Speter    for (i = 0; i < statement->nvals; i++) {
1688251876Speter        values[i] = va_arg(args, const void*);
1689251876Speter    }
1690251876Speter
1691251876Speter    return dbd_oracle_pbselect(pool, sql, results, statement, seek, values);
1692251876Speter}
1693251876Speter
1694251876Speterstatic int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
1695251876Speter                                        apr_dbd_transaction_t **trans)
1696251876Speter{
1697251876Speter    int ret = 0;
1698251876Speter    int_errorcode;
1699251876Speter    if (*trans) {
1700251876Speter        dbd_oracle_end_transaction(*trans);
1701251876Speter    }
1702251876Speter    else {
1703251876Speter        *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
1704251876Speter        OCIHandleAlloc(dbd_oracle_env, (dvoid**)&(*trans)->trans,
1705251876Speter                       OCI_HTYPE_TRANS, 0, 0);
1706251876Speter        OCIAttrSet(sql->svc, OCI_HTYPE_SVCCTX, (*trans)->trans, 0,
1707251876Speter                   OCI_ATTR_TRANS, sql->err);
1708251876Speter    }
1709251876Speter
1710251876Speter
1711251876Speter    sql->status = OCITransStart(sql->svc, sql->err, TRANS_TIMEOUT,
1712251876Speter                                OCI_TRANS_NEW);
1713251876Speter    switch (sql->status) {
1714251876Speter    case OCI_ERROR:
1715251876Speter#ifdef DEBUG
1716251876Speter        OCIErrorGet(sql->err, 1, NULL, &errorcode, sql->buf,
1717251876Speter                    sizeof(sql->buf), OCI_HTYPE_ERROR);
1718251876Speter        printf("Transaction: %s\n", sql->buf);
1719251876Speter#endif
1720251876Speter        ret = 1;
1721251876Speter        break;
1722251876Speter    case OCI_SUCCESS:
1723251876Speter        (*trans)->handle = sql;
1724251876Speter        (*trans)->status = TRANS_1;
1725251876Speter        sql->trans = *trans;
1726251876Speter        switch (OCIDescriptorAlloc(dbd_oracle_env,
1727251876Speter                                   (dvoid**)&(*trans)->snapshot1,
1728251876Speter                                   OCI_DTYPE_SNAP, 0, NULL)) {
1729251876Speter        case OCI_SUCCESS:
1730251876Speter            apr_pool_cleanup_register(pool, (*trans)->snapshot1,
1731251876Speter                                      dbd_free_snapshot, apr_pool_cleanup_null);
1732251876Speter            break;
1733251876Speter        case OCI_INVALID_HANDLE:
1734251876Speter            ret = 1;
1735251876Speter            break;
1736251876Speter        }
1737251876Speter        switch (OCIDescriptorAlloc(dbd_oracle_env,
1738251876Speter                                   (dvoid**)&(*trans)->snapshot2,
1739251876Speter                                   OCI_DTYPE_SNAP, 0, NULL)) {
1740251876Speter        case OCI_SUCCESS:
1741251876Speter            apr_pool_cleanup_register(pool, (*trans)->snapshot2,
1742251876Speter                                      dbd_free_snapshot, apr_pool_cleanup_null);
1743251876Speter            break;
1744251876Speter        case OCI_INVALID_HANDLE:
1745251876Speter            ret = 1;
1746251876Speter            break;
1747251876Speter        }
1748251876Speter        break;
1749251876Speter    default:
1750251876Speter        ret = 1;
1751251876Speter        break;
1752251876Speter    }
1753251876Speter    return ret;
1754251876Speter}
1755251876Speter
1756251876Speterstatic int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans)
1757251876Speter{
1758251876Speter    int ret = 1;             /* no transaction is an error cond */
1759251876Speter    sword status;
1760251876Speter    apr_dbd_t *handle = trans->handle;
1761251876Speter    if (trans) {
1762251876Speter        switch (trans->status) {
1763251876Speter        case TRANS_NONE:     /* No trans is an error here */
1764251876Speter            status = OCI_ERROR;
1765251876Speter            break;
1766251876Speter        case TRANS_ERROR:
1767251876Speter            status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1768251876Speter            break;
1769251876Speter        default:
1770251876Speter            /* rollback on explicit rollback request */
1771251876Speter            if (TXN_DO_ROLLBACK(trans)) {
1772251876Speter                status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1773251876Speter            } else {
1774251876Speter                status = OCITransCommit(handle->svc, handle->err, OCI_DEFAULT);
1775251876Speter            }
1776251876Speter            break;
1777251876Speter        }
1778251876Speter
1779251876Speter        handle->trans = NULL;
1780251876Speter
1781251876Speter        switch (status) {
1782251876Speter        case OCI_SUCCESS:
1783251876Speter            ret = 0;
1784251876Speter            break;
1785251876Speter        default:
1786251876Speter            ret = 3;
1787251876Speter            break;
1788251876Speter        }
1789251876Speter    }
1790251876Speter    return ret;
1791251876Speter}
1792251876Speter
1793251876Speterstatic int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t *trans)
1794251876Speter{
1795251876Speter    if (!trans)
1796251876Speter        return APR_DBD_TRANSACTION_COMMIT;
1797251876Speter
1798251876Speter    return trans->mode;
1799251876Speter}
1800251876Speter
1801251876Speterstatic int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t *trans,
1802251876Speter                                           int mode)
1803251876Speter{
1804251876Speter    if (!trans)
1805251876Speter        return APR_DBD_TRANSACTION_COMMIT;
1806251876Speter
1807251876Speter    return trans->mode = (mode & TXN_MODE_BITS);
1808251876Speter}
1809251876Speter
1810251876Speter/* This doesn't work for BLOB because of NULLs, but it can fake it
1811251876Speter * if the BLOB is really a string
1812251876Speter */
1813251876Speterstatic const char *dbd_oracle_get_entry(const apr_dbd_row_t *row, int n)
1814251876Speter{
1815251876Speter    ub4 len = 0;
1816251876Speter    ub1 csform = 0;
1817251876Speter    ub2 csid = 0;
1818251876Speter    apr_size_t buflen = 0;
1819251876Speter    char *buf = NULL;
1820251876Speter    define_arg *val = &row->res->statement->out[n];
1821251876Speter    apr_dbd_t *sql = row->res->handle;
1822251876Speter    int_errorcode;
1823251876Speter
1824251876Speter    if ((n < 0) || (n >= row->res->statement->nout) || (val->ind == -1)) {
1825251876Speter        return NULL;
1826251876Speter    }
1827251876Speter
1828251876Speter    switch (val->type) {
1829251876Speter    case SQLT_BLOB:
1830251876Speter    case SQLT_CLOB:
1831251876Speter        sql->status = OCILobGetLength(sql->svc, sql->err, val->buf.lobval,
1832251876Speter                                      &len);
1833251876Speter        switch (sql->status) {
1834251876Speter        case OCI_SUCCESS:
1835251876Speter        case OCI_SUCCESS_WITH_INFO:
1836251876Speter            if (len == 0) {
1837251876Speter                buf = "";
1838251876Speter            }
1839251876Speter            break;
1840251876Speter        case OCI_ERROR:
1841251876Speter#ifdef DEBUG
1842251876Speter            OCIErrorGet(sql->err, 1, NULL, &errorcode,
1843251876Speter                        sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1844251876Speter            printf("Finding LOB length: %s\n", sql->buf);
1845251876Speter            break;
1846251876Speter#endif
1847251876Speter        default:
1848251876Speter            break;
1849251876Speter        }
1850251876Speter
1851251876Speter        if (len == 0) {
1852251876Speter            break;
1853251876Speter        }
1854251876Speter
1855251876Speter        if (val->type == APR_DBD_TYPE_CLOB) {
1856251876Speter#if 1
1857251876Speter            /* Is this necessary, or can it be defaulted? */
1858251876Speter            sql->status = OCILobCharSetForm(dbd_oracle_env, sql->err,
1859251876Speter                                            val->buf.lobval, &csform);
1860251876Speter            if (sql->status == OCI_SUCCESS) {
1861251876Speter                sql->status = OCILobCharSetId(dbd_oracle_env, sql->err,
1862251876Speter                                              val->buf.lobval, &csid);
1863251876Speter            }
1864251876Speter            switch (sql->status) {
1865251876Speter            case OCI_SUCCESS:
1866251876Speter            case OCI_SUCCESS_WITH_INFO:
1867251876Speter                buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1868251876Speter                /* zeroise all - where the string ends depends on charset */
1869251876Speter                buf = apr_pcalloc(row->pool, buflen);
1870251876Speter                break;
1871251876Speter#ifdef DEBUG
1872251876Speter            case OCI_ERROR:
1873251876Speter                OCIErrorGet(sql->err, 1, NULL, &errorcode,
1874251876Speter                            sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1875251876Speter                printf("Reading LOB character set: %s\n", sql->buf);
1876251876Speter                break; /*** XXX?? ***/
1877251876Speter#endif
1878251876Speter            default:
1879251876Speter                break; /*** XXX?? ***/
1880251876Speter            }
1881251876Speter#else   /* ignore charset */
1882251876Speter            buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1883251876Speter            /* zeroise all - where the string ends depends on charset */
1884251876Speter            buf = apr_pcalloc(row->pool, buflen);
1885251876Speter#endif
1886251876Speter        } else {
1887251876Speter            /* BUG: this'll only work if the BLOB looks like a string */
1888251876Speter            buflen = len;
1889251876Speter            buf = apr_palloc(row->pool, buflen+1);
1890251876Speter            buf[buflen] = 0;
1891251876Speter        }
1892251876Speter
1893251876Speter        if (!buf) {
1894251876Speter            break;
1895251876Speter        }
1896251876Speter
1897251876Speter        sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
1898251876Speter                                 &len, 1, (dvoid*) buf, buflen,
1899251876Speter                                 NULL, NULL, csid, csform);
1900251876Speter        switch (sql->status) {
1901251876Speter        case OCI_SUCCESS:
1902251876Speter        case OCI_SUCCESS_WITH_INFO:
1903251876Speter            break;
1904251876Speter#ifdef DEBUG
1905251876Speter        case OCI_ERROR:
1906251876Speter            OCIErrorGet(sql->err, 1, NULL, &errorcode,
1907251876Speter                        sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1908251876Speter            printf("Reading LOB: %s\n", sql->buf);
1909251876Speter            buf = NULL; /*** XXX?? ***/
1910251876Speter            break;
1911251876Speter#endif
1912251876Speter        default:
1913251876Speter            buf = NULL; /*** XXX?? ***/
1914251876Speter            break;
1915251876Speter        }
1916251876Speter
1917251876Speter        break;
1918251876Speter    case SQLT_LNG:
1919251876Speter    case SQLT_LBI:
1920251876Speter        /* raw is struct { ub4 len; char *buf; } */
1921251876Speter        len = *(ub4*) val->buf.raw;
1922251876Speter        buf = apr_pstrndup(row->pool, val->buf.sval + sizeof(ub4), len);
1923251876Speter        break;
1924251876Speter    default:
1925251876Speter        buf = apr_pstrndup(row->pool, val->buf.sval, val->len);
1926251876Speter        break;
1927251876Speter    }
1928251876Speter    return (const char*) buf;
1929251876Speter}
1930251876Speter
1931251876Speter/* XXX Should this use Oracle proper API instead of calling get_entry()? */
1932251876Speterstatic apr_status_t dbd_oracle_datum_get(const apr_dbd_row_t *row, int n,
1933251876Speter                                         apr_dbd_type_e type, void *data)
1934251876Speter{
1935251876Speter    define_arg *val = &row->res->statement->out[n];
1936251876Speter    const char *entry;
1937251876Speter
1938251876Speter    if ((n < 0) || (n >= row->res->statement->nout)) {
1939251876Speter        return APR_EGENERAL;
1940251876Speter    }
1941251876Speter
1942251876Speter    if(val->ind == -1) {
1943251876Speter        return APR_ENOENT;
1944251876Speter    }
1945251876Speter
1946251876Speter    switch (type) {
1947251876Speter    case APR_DBD_TYPE_TINY:
1948251876Speter        entry = dbd_oracle_get_entry(row, n);
1949251876Speter        if (entry == NULL) {
1950251876Speter            return APR_ENOENT;
1951251876Speter        }
1952251876Speter        *(char*)data = atoi(entry);
1953251876Speter        break;
1954251876Speter    case APR_DBD_TYPE_UTINY:
1955251876Speter        entry = dbd_oracle_get_entry(row, n);
1956251876Speter        if (entry == NULL) {
1957251876Speter            return APR_ENOENT;
1958251876Speter        }
1959251876Speter        *(unsigned char*)data = atoi(entry);
1960251876Speter        break;
1961251876Speter    case APR_DBD_TYPE_SHORT:
1962251876Speter        entry = dbd_oracle_get_entry(row, n);
1963251876Speter        if (entry == NULL) {
1964251876Speter            return APR_ENOENT;
1965251876Speter        }
1966251876Speter        *(short*)data = atoi(entry);
1967251876Speter        break;
1968251876Speter    case APR_DBD_TYPE_USHORT:
1969251876Speter        entry = dbd_oracle_get_entry(row, n);
1970251876Speter        if (entry == NULL) {
1971251876Speter            return APR_ENOENT;
1972251876Speter        }
1973251876Speter        *(unsigned short*)data = atoi(entry);
1974251876Speter        break;
1975251876Speter    case APR_DBD_TYPE_INT:
1976251876Speter        entry = dbd_oracle_get_entry(row, n);
1977251876Speter        if (entry == NULL) {
1978251876Speter            return APR_ENOENT;
1979251876Speter        }
1980251876Speter        *(int*)data = atoi(entry);
1981251876Speter        break;
1982251876Speter    case APR_DBD_TYPE_UINT:
1983251876Speter        entry = dbd_oracle_get_entry(row, n);
1984251876Speter        if (entry == NULL) {
1985251876Speter            return APR_ENOENT;
1986251876Speter        }
1987251876Speter        *(unsigned int*)data = atoi(entry);
1988251876Speter        break;
1989251876Speter    case APR_DBD_TYPE_LONG:
1990251876Speter        entry = dbd_oracle_get_entry(row, n);
1991251876Speter        if (entry == NULL) {
1992251876Speter            return APR_ENOENT;
1993251876Speter        }
1994251876Speter        *(long*)data = atol(entry);
1995251876Speter        break;
1996251876Speter    case APR_DBD_TYPE_ULONG:
1997251876Speter        entry = dbd_oracle_get_entry(row, n);
1998251876Speter        if (entry == NULL) {
1999251876Speter            return APR_ENOENT;
2000251876Speter        }
2001251876Speter        *(unsigned long*)data = atol(entry);
2002251876Speter        break;
2003251876Speter    case APR_DBD_TYPE_LONGLONG:
2004251876Speter        entry = dbd_oracle_get_entry(row, n);
2005251876Speter        if (entry == NULL) {
2006251876Speter            return APR_ENOENT;
2007251876Speter        }
2008251876Speter        *(apr_int64_t*)data = apr_atoi64(entry);
2009251876Speter        break;
2010251876Speter    case APR_DBD_TYPE_ULONGLONG:
2011251876Speter        entry = dbd_oracle_get_entry(row, n);
2012251876Speter        if (entry == NULL) {
2013251876Speter            return APR_ENOENT;
2014251876Speter        }
2015251876Speter        *(apr_uint64_t*)data = apr_atoi64(entry);
2016251876Speter        break;
2017251876Speter    case APR_DBD_TYPE_FLOAT:
2018251876Speter        entry = dbd_oracle_get_entry(row, n);
2019251876Speter        if (entry == NULL) {
2020251876Speter            return APR_ENOENT;
2021251876Speter        }
2022251876Speter        *(float*)data = (float)atof(entry);
2023251876Speter        break;
2024251876Speter    case APR_DBD_TYPE_DOUBLE:
2025251876Speter        entry = dbd_oracle_get_entry(row, n);
2026251876Speter        if (entry == NULL) {
2027251876Speter            return APR_ENOENT;
2028251876Speter        }
2029251876Speter        *(double*)data = atof(entry);
2030251876Speter        break;
2031251876Speter    case APR_DBD_TYPE_STRING:
2032251876Speter    case APR_DBD_TYPE_TEXT:
2033251876Speter    case APR_DBD_TYPE_TIME:
2034251876Speter    case APR_DBD_TYPE_DATE:
2035251876Speter    case APR_DBD_TYPE_DATETIME:
2036251876Speter    case APR_DBD_TYPE_TIMESTAMP:
2037251876Speter    case APR_DBD_TYPE_ZTIMESTAMP:
2038251876Speter        entry = dbd_oracle_get_entry(row, n);
2039251876Speter        if (entry == NULL) {
2040251876Speter            return APR_ENOENT;
2041251876Speter        }
2042251876Speter        *(char**)data = (char*)entry;
2043251876Speter        break;
2044251876Speter    case APR_DBD_TYPE_BLOB:
2045251876Speter    case APR_DBD_TYPE_CLOB:
2046251876Speter        {
2047251876Speter        apr_bucket *e;
2048251876Speter        apr_bucket_brigade *b = (apr_bucket_brigade*)data;
2049251876Speter        apr_dbd_t *sql = row->res->handle;
2050251876Speter        ub4 len = 0;
2051251876Speter
2052251876Speter        switch (val->type) {
2053251876Speter        case SQLT_BLOB:
2054251876Speter        case SQLT_CLOB:
2055251876Speter            sql->status = OCILobGetLength(sql->svc, sql->err,
2056251876Speter                                          val->buf.lobval, &len);
2057251876Speter            switch(sql->status) {
2058251876Speter            case OCI_SUCCESS:
2059251876Speter            case OCI_SUCCESS_WITH_INFO:
2060251876Speter                if (len == 0) {
2061251876Speter                    e = apr_bucket_eos_create(b->bucket_alloc);
2062251876Speter                }
2063251876Speter                else {
2064251876Speter                    e = apr_bucket_lob_create(row, n, 0, len,
2065251876Speter                                              row->pool, b->bucket_alloc);
2066251876Speter                }
2067251876Speter                break;
2068251876Speter            default:
2069251876Speter                return APR_ENOENT;
2070251876Speter            }
2071251876Speter            break;
2072251876Speter        default:
2073251876Speter            entry = dbd_oracle_get_entry(row, n);
2074251876Speter            if (entry == NULL) {
2075251876Speter                return APR_ENOENT;
2076251876Speter            }
2077251876Speter            e = apr_bucket_pool_create(entry, strlen(entry),
2078251876Speter                                       row->pool, b->bucket_alloc);
2079251876Speter            break;
2080251876Speter        }
2081251876Speter        APR_BRIGADE_INSERT_TAIL(b, e);
2082251876Speter        }
2083251876Speter        break;
2084251876Speter    case APR_DBD_TYPE_NULL:
2085251876Speter        *(void**)data = NULL;
2086251876Speter        break;
2087251876Speter    default:
2088251876Speter        return APR_EGENERAL;
2089251876Speter    }
2090251876Speter
2091251876Speter    return APR_SUCCESS;
2092251876Speter}
2093251876Speter
2094251876Speterstatic apr_status_t dbd_oracle_close(apr_dbd_t *handle)
2095251876Speter{
2096251876Speter    /* FIXME: none of the oracle docs/examples say anything about
2097251876Speter     * closing/releasing handles.  Which seems unlikely ...
2098251876Speter     */
2099251876Speter
2100251876Speter    /* OK, let's grab from cdemo again.
2101251876Speter     * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
2102251876Speter     */
2103251876Speter    switch (OCISessionEnd(handle->svc, handle->err, handle->auth,
2104251876Speter            (ub4)OCI_DEFAULT)) {
2105251876Speter    default:
2106251876Speter        break;
2107251876Speter    }
2108251876Speter    switch (OCIServerDetach(handle->svr, handle->err, (ub4) OCI_DEFAULT )) {
2109251876Speter    default:
2110251876Speter        break;
2111251876Speter    }
2112251876Speter    /* does OCISessionEnd imply this? */
2113251876Speter    switch (OCIHandleFree((dvoid *) handle->auth, (ub4) OCI_HTYPE_SESSION)) {
2114251876Speter    default:
2115251876Speter        break;
2116251876Speter    }
2117251876Speter    switch (OCIHandleFree((dvoid *) handle->svr, (ub4) OCI_HTYPE_SERVER)) {
2118251876Speter    default:
2119251876Speter        break;
2120251876Speter    }
2121251876Speter    switch (OCIHandleFree((dvoid *) handle->svc, (ub4) OCI_HTYPE_SVCCTX)) {
2122251876Speter    default:
2123251876Speter        break;
2124251876Speter    }
2125251876Speter    switch (OCIHandleFree((dvoid *) handle->err, (ub4) OCI_HTYPE_ERROR)) {
2126251876Speter    default:
2127251876Speter        break;
2128251876Speter    }
2129251876Speter    return APR_SUCCESS;
2130251876Speter}
2131251876Speter
2132251876Speterstatic apr_status_t dbd_oracle_check_conn(apr_pool_t *pool, apr_dbd_t *sql)
2133251876Speter{
2134251876Speter    apr_dbd_results_t *res = NULL;
2135251876Speter    apr_dbd_row_t *row = NULL;
2136251876Speter
2137251876Speter    if(dbd_oracle_pselect(pool, sql, &res, sql->check_conn_stmt,
2138251876Speter                          0, NULL) != 0) {
2139251876Speter        return APR_EGENERAL;
2140251876Speter    }
2141251876Speter
2142251876Speter    if(dbd_oracle_get_row(pool, res, &row, -1) != 0) {
2143251876Speter        return APR_EGENERAL;
2144251876Speter    }
2145251876Speter
2146251876Speter    if(dbd_oracle_get_row(pool, res, &row, -1) != -1) {
2147251876Speter        return APR_EGENERAL;
2148251876Speter    }
2149251876Speter
2150251876Speter    return APR_SUCCESS;
2151251876Speter}
2152251876Speter
2153251876Speterstatic int dbd_oracle_select_db(apr_pool_t *pool, apr_dbd_t *handle,
2154251876Speter                                const char *name)
2155251876Speter{
2156251876Speter    /* FIXME: need to find this in the docs */
2157251876Speter    return APR_ENOTIMPL;
2158251876Speter}
2159251876Speter
2160251876Speterstatic void *dbd_oracle_native(apr_dbd_t *handle)
2161251876Speter{
2162251876Speter    /* FIXME: can we do anything better?  Oracle doesn't seem to have
2163251876Speter     * a concept of a handle in the sense we use it.
2164251876Speter     */
2165251876Speter    return dbd_oracle_env;
2166251876Speter}
2167251876Speter
2168251876Speterstatic int dbd_oracle_num_cols(apr_dbd_results_t* res)
2169251876Speter{
2170251876Speter    return res->statement->nout;
2171251876Speter}
2172251876Speter
2173251876Speterstatic int dbd_oracle_num_tuples(apr_dbd_results_t* res)
2174251876Speter{
2175251876Speter    if (!res->seek) {
2176251876Speter        return -1;
2177251876Speter    }
2178251876Speter    if (res->nrows >= 0) {
2179251876Speter        return res->nrows;
2180251876Speter    }
2181251876Speter    res->handle->status = OCIAttrGet(res->statement->stmt, OCI_HTYPE_STMT,
2182251876Speter                                     &res->nrows, 0, OCI_ATTR_ROW_COUNT,
2183251876Speter                                     res->handle->err);
2184251876Speter    return res->nrows;
2185251876Speter}
2186251876Speter
2187251876SpeterAPU_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_oracle_driver = {
2188251876Speter    "oracle",
2189251876Speter    dbd_oracle_init,
2190251876Speter    dbd_oracle_native,
2191251876Speter    dbd_oracle_open,
2192251876Speter    dbd_oracle_check_conn,
2193251876Speter    dbd_oracle_close,
2194251876Speter    dbd_oracle_select_db,
2195251876Speter    dbd_oracle_start_transaction,
2196251876Speter    dbd_oracle_end_transaction,
2197251876Speter    dbd_oracle_query,
2198251876Speter    dbd_oracle_select,
2199251876Speter    dbd_oracle_num_cols,
2200251876Speter    dbd_oracle_num_tuples,
2201251876Speter    dbd_oracle_get_row,
2202251876Speter    dbd_oracle_get_entry,
2203251876Speter    dbd_oracle_error,
2204251876Speter    dbd_oracle_escape,
2205251876Speter    dbd_oracle_prepare,
2206251876Speter    dbd_oracle_pvquery,
2207251876Speter    dbd_oracle_pvselect,
2208251876Speter    dbd_oracle_pquery,
2209251876Speter    dbd_oracle_pselect,
2210251876Speter    dbd_oracle_get_name,
2211251876Speter    dbd_oracle_transaction_mode_get,
2212251876Speter    dbd_oracle_transaction_mode_set,
2213251876Speter    ":apr%d",
2214251876Speter    dbd_oracle_pvbquery,
2215251876Speter    dbd_oracle_pvbselect,
2216251876Speter    dbd_oracle_pbquery,
2217251876Speter    dbd_oracle_pbselect,
2218251876Speter    dbd_oracle_datum_get
2219251876Speter};
2220251876Speter#endif
2221