]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr-util/dbd/apr_dbd_oracle.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / apr-util / dbd / apr_dbd_oracle.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* Developed initially by Nick Kew and Chris Darroch.
18  * Contributed to the APR project by kind permission of
19  * Pearson Education Core Technology Group (CTG),
20  * formerly Central Media Group (CMG).
21  */
22
23 /* apr_dbd_oracle - a painful attempt
24  *
25  * Based first on the documentation at
26  * http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/toc.htm
27  *
28  * Those docs have a lot of internal inconsistencies, contradictions, etc
29  * So I've snarfed the demo programs (from Oracle 8, not included in
30  * the current downloadable oracle), and used code from them.
31  *
32  * Why do cdemo81.c and cdemo82.c do the same thing in very different ways?
33  * e.g. cdemo82 releases all its handle on shutdown; cdemo81 doesn't
34  *
35  * All the ORA* functions return a "sword".  Some of them are documented;
36  * others aren't.  So I've adopted a policy of using switch statements
37  * everywhere, even when we're not doing anything with the return values.
38  *
39  * This makes no attempt at performance tuning, such as setting
40  * prefetch cache size.  We need some actual performance data
41  * to make that meaningful.  Input from someone with experience
42  * as a sysop using oracle would be a good start.
43  */
44
45 /* shut compiler up */
46 #ifdef DEBUG
47 #define int_errorcode int errorcode
48 #else
49 #define int_errorcode
50 #endif
51
52 #include "apu.h"
53
54 #if APU_HAVE_ORACLE
55
56 #include <ctype.h>
57 #include <stdlib.h>
58 #include <stdio.h>
59
60 #include <oci.h>
61
62 #include "apr_strings.h"
63 #include "apr_lib.h"
64 #include "apr_time.h"
65 #include "apr_hash.h"
66 #include "apr_buckets.h"
67
68 #define TRANS_TIMEOUT 30
69 #define MAX_ARG_LEN 256 /* in line with other apr_dbd drivers.  We alloc this
70                          * lots of times, so a large value gets hungry.
71                          * Should really make it configurable
72                          */
73 #define DEFAULT_LONG_SIZE 4096
74 #define DBD_ORACLE_MAX_COLUMNS 256
75 #define NUMERIC_FIELD_SIZE 32
76
77 #define CHECK_CONN_QUERY "SELECT 1 FROM dual"
78
79 #define ERR_BUF_SIZE 200
80
81 #ifdef DEBUG
82 #include <stdio.h>
83 #endif
84
85 #include "apr_dbd_internal.h"
86
87 /* declarations */
88 static const char *dbd_oracle_error(apr_dbd_t *sql, int n);
89 static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
90                               const char *query, const char *label,
91                               int nargs, int nvals, apr_dbd_type_e *types,
92                               apr_dbd_prepared_t **statement);
93 static int outputParams(apr_dbd_t*, apr_dbd_prepared_t*);
94 static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
95                               apr_dbd_results_t **results,
96                               apr_dbd_prepared_t *statement,
97                               int seek, const char **values);
98 static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
99                              int *nrows, apr_dbd_prepared_t *statement,
100                              const char **values);
101 static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
102                                         apr_dbd_transaction_t **trans);
103 static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans);
104
105 struct apr_dbd_transaction_t {
106     int mode;
107     enum { TRANS_NONE, TRANS_ERROR, TRANS_1, TRANS_2 } status;
108     apr_dbd_t *handle;
109     OCITrans *trans;
110     OCISnapshot *snapshot1;
111     OCISnapshot *snapshot2;
112 };
113
114 struct apr_dbd_results_t {
115     apr_pool_t *pool;
116     apr_dbd_t* handle;
117     unsigned int rownum;
118     int seek;
119     int nrows;
120     apr_dbd_prepared_t *statement;
121 };
122
123 struct apr_dbd_t {
124     sword status;
125     OCIError *err;
126     OCIServer *svr;
127     OCISvcCtx *svc;
128     OCISession *auth;
129     apr_dbd_transaction_t* trans;
130     apr_pool_t *pool;
131     char buf[ERR_BUF_SIZE]; /* for error messages */
132     apr_size_t long_size;
133     apr_dbd_prepared_t *check_conn_stmt;
134 };
135
136 struct apr_dbd_row_t {
137     int n;
138     apr_dbd_results_t *res;
139     apr_pool_t *pool;
140 };
141
142 typedef struct {
143     apr_dbd_type_e type;
144     sb2 ind;
145     sb4 len;
146     OCIBind *bind;
147     union {
148         void *raw;
149         char *sval;
150         int ival;
151         unsigned int uval;
152         double fval;
153         OCILobLocator *lobval;
154     } value;
155 } bind_arg;
156
157 typedef struct {
158     int type;
159     sb2 ind;
160     ub2 len;         /* length of actual output */
161     OCIDefine *defn;
162     apr_size_t sz;   /* length of buf for output */
163     union {
164         void *raw;
165         char *sval;
166         OCILobLocator *lobval;
167     } buf;
168     const char *name;
169 } define_arg;
170
171 struct apr_dbd_prepared_t {
172     OCIStmt *stmt;
173     int nargs;
174     int nvals;
175     bind_arg *args;
176     int nout;
177     define_arg *out;
178     apr_dbd_t *handle;
179     apr_pool_t *pool;
180     ub2 type;
181 };
182
183 /* AFAICT from the docs, the OCIEnv thingey can be used async
184  * across threads, so lets have a global one.
185  *
186  * We'll need shorter-lived envs to deal with requests and connections
187  *
188  * Hmmm, that doesn't work: we don't have a usermem framework.
189  * OK, forget about using APR pools here, until we figure out
190  * the right way to do it (if such a thing exists).
191  */
192 static OCIEnv *dbd_oracle_env = NULL;
193
194 /* Oracle specific bucket for BLOB/CLOB types */
195 typedef struct apr_bucket_lob apr_bucket_lob;
196 /**
197  * A bucket referring to a Oracle BLOB/CLOB
198  */
199 struct apr_bucket_lob {
200     /** Number of buckets using this memory */
201     apr_bucket_refcount  refcount;
202     /** The row this bucket refers to */
203     const apr_dbd_row_t *row;
204     /** The column this bucket refers to */
205     int col;
206     /** The pool into which any needed structures should
207      *  be created while reading from this bucket */
208     apr_pool_t *readpool;
209 };
210
211 static void lob_bucket_destroy(void *data);
212 static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
213                                     apr_size_t *len, apr_read_type_e block);
214 static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
215                                        const apr_dbd_row_t *row, int col,
216                                        apr_off_t offset, apr_size_t len,
217                                        apr_pool_t *p);
218 static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
219                                          apr_off_t offset,
220                                          apr_size_t len, apr_pool_t *p,
221                                          apr_bucket_alloc_t *list);
222
223 static const apr_bucket_type_t apr_bucket_type_lob = {
224     "LOB", 5, APR_BUCKET_DATA,
225     lob_bucket_destroy,
226     lob_bucket_read,
227     apr_bucket_setaside_notimpl,
228     apr_bucket_shared_split,
229     apr_bucket_shared_copy
230 };
231
232 static void lob_bucket_destroy(void *data)
233 {
234     apr_bucket_lob *f = data;
235
236     if (apr_bucket_shared_destroy(f)) {
237         /* no need to destroy database objects here; it will get
238          * done automatically when the pool gets cleaned up */
239         apr_bucket_free(f);
240     }
241 }
242
243 static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
244                                     apr_size_t *len, apr_read_type_e block)
245 {
246     apr_bucket_lob *a = e->data;
247     const apr_dbd_row_t *row = a->row;
248     apr_dbd_results_t *res = row->res;
249     int col = a->col;
250     apr_bucket *b = NULL;
251     apr_size_t blength = e->length;  /* bytes remaining in file past offset */
252     apr_off_t boffset = e->start;
253     define_arg *val = &res->statement->out[col];
254     apr_dbd_t *sql = res->handle;
255 /* Only with 10g, unfortunately
256     oraub8 length = APR_BUCKET_BUFF_SIZE;
257 */
258     ub4 length = APR_BUCKET_BUFF_SIZE;
259     char *buf = NULL;
260
261     *str = NULL;  /* in case we die prematurely */
262
263     /* fetch from offset if not at the beginning */
264     buf = apr_palloc(row->pool, APR_BUCKET_BUFF_SIZE);
265     sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
266                              &length, 1 + (size_t)boffset,
267                              (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
268                              NULL, NULL, 0, SQLCS_IMPLICIT);
269 /* Only with 10g, unfortunately
270     sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,
271                               &length, NULL, 1 + boffset,
272                               (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
273                               OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
274 */
275     if (sql->status != OCI_SUCCESS) {
276         return APR_EGENERAL;
277     }
278     blength -= length;
279     *len = length;
280     *str = buf;
281
282     /*
283      * Change the current bucket to refer to what we read,
284      * even if we read nothing because we hit EOF.
285      */
286     apr_bucket_pool_make(e, *str, *len, res->pool);
287
288     /* If we have more to read from the field, then create another bucket */
289     if (blength > 0) {
290         /* for efficiency, we can just build a new apr_bucket struct
291          * to wrap around the existing LOB bucket */
292         b = apr_bucket_alloc(sizeof(*b), e->list);
293         b->start  = boffset + *len;
294         b->length = blength;
295         b->data   = a;
296         b->type   = &apr_bucket_type_lob;
297         b->free   = apr_bucket_free;
298         b->list   = e->list;
299         APR_BUCKET_INSERT_AFTER(e, b);
300     }
301     else {
302         lob_bucket_destroy(a);
303     }
304
305     return APR_SUCCESS;
306 }
307
308 static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
309                                        const apr_dbd_row_t *row, int col,
310                                        apr_off_t offset, apr_size_t len,
311                                        apr_pool_t *p)
312 {
313     apr_bucket_lob *f;
314
315     f = apr_bucket_alloc(sizeof(*f), b->list);
316     f->row = row;
317     f->col = col;
318     f->readpool = p;
319
320     b = apr_bucket_shared_make(b, f, offset, len);
321     b->type = &apr_bucket_type_lob;
322
323     return b;
324 }
325
326 static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
327                                          apr_off_t offset,
328                                          apr_size_t len, apr_pool_t *p,
329                                          apr_bucket_alloc_t *list)
330 {
331     apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
332
333     APR_BUCKET_INIT(b);
334     b->free = apr_bucket_free;
335     b->list = list;
336     return apr_bucket_lob_make(b, row, col, offset, len, p);
337 }
338
339 static apr_status_t dbd_free_lobdesc(void *lob)
340 {
341     switch (OCIDescriptorFree(lob, OCI_DTYPE_LOB)) {
342     case OCI_SUCCESS:
343         return APR_SUCCESS;
344     default:
345         return APR_EGENERAL;
346     }
347 }
348
349 static apr_status_t dbd_free_snapshot(void *snap)
350 {
351     switch (OCIDescriptorFree(snap, OCI_DTYPE_SNAP)) {
352     case OCI_SUCCESS:
353         return APR_SUCCESS;
354     default:
355         return APR_EGENERAL;
356     }
357 }
358
359 static void dbd_oracle_init(apr_pool_t *pool)
360 {
361     if (dbd_oracle_env == NULL) {
362         /* Sadly, OCI_SHARED seems to be impossible to use, due to
363          * various Oracle bugs.  See, for example, Oracle MetaLink bug 2972890
364          * and PHP bug http://bugs.php.net/bug.php?id=23733
365          */
366 #ifdef OCI_NEW_LENGTH_SEMANTICS
367         OCIEnvCreate(&dbd_oracle_env, OCI_THREADED|OCI_NEW_LENGTH_SEMANTICS,
368                      NULL, NULL, NULL, NULL, 0, NULL);
369 #else
370         OCIEnvCreate(&dbd_oracle_env, OCI_THREADED,
371                      NULL, NULL, NULL, NULL, 0, NULL);
372 #endif
373     }
374 }
375
376 static apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params,
377                                   const char **error)
378 {
379     apr_dbd_t *ret = apr_pcalloc(pool, sizeof(apr_dbd_t));
380     int errorcode;
381
382     char *BLANK = "";
383     struct {
384         const char *field;
385         char *value;
386     } fields[] = {
387         {"user", BLANK},
388         {"pass", BLANK},
389         {"dbname", BLANK},
390         {"server", BLANK},
391         {NULL, NULL}
392     };
393     int i;
394     const char *ptr;
395     const char *key;
396     size_t klen;
397     const char *value;
398     size_t vlen;
399     static const char *const delims = " \r\n\t;|,";
400
401     ret->pool = pool;
402     ret->long_size = DEFAULT_LONG_SIZE;
403
404     /* snitch parsing from the MySQL driver */
405     for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {
406         /* don't dereference memory that may not belong to us */
407         if (ptr == params) {
408             ++ptr;
409             continue;
410         }
411         for (key = ptr-1; apr_isspace(*key); --key);
412         klen = 0;
413         while (apr_isalpha(*key)) {
414             if (key == params) {
415                 /* Don't parse off the front of the params */
416                 --key;
417                 ++klen;
418                 break;
419             }
420             --key;
421             ++klen;
422         }
423         ++key;
424         for (value = ptr+1; apr_isspace(*value); ++value);
425         vlen = strcspn(value, delims);
426         for (i=0; fields[i].field != NULL; ++i) {
427             if (!strncasecmp(fields[i].field, key, klen)) {
428                 fields[i].value = apr_pstrndup(pool, value, vlen);
429                 break;
430             }
431         }
432         ptr = value+vlen;
433     }
434
435     ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->err,
436                                  OCI_HTYPE_ERROR, 0, NULL);
437     switch (ret->status) {
438     default:
439 #ifdef DEBUG
440         printf("ret->status is %d\n", ret->status);
441         break;
442 #else
443         return NULL;
444 #endif
445     case OCI_SUCCESS:
446         break;
447     }
448
449     ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svr,
450                                  OCI_HTYPE_SERVER, 0, NULL);
451     switch (ret->status) {
452     default:
453 #ifdef DEBUG
454         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
455                     sizeof(ret->buf), OCI_HTYPE_ERROR);
456         printf("OPEN ERROR %d (alloc svr): %s\n", ret->status, ret->buf);
457         break;
458 #else
459         if (error) {
460             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
461             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
462                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
463         }
464         return NULL;
465 #endif
466     case OCI_SUCCESS:
467         break;
468     }
469
470     ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svc,
471                                  OCI_HTYPE_SVCCTX, 0, NULL);
472     switch (ret->status) {
473     default:
474 #ifdef DEBUG
475         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
476                     sizeof(ret->buf), OCI_HTYPE_ERROR);
477         printf("OPEN ERROR %d (alloc svc): %s\n", ret->status, ret->buf);
478         break;
479 #else
480         if (error) {
481             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
482             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
483                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
484         }
485         return NULL;
486 #endif
487     case OCI_SUCCESS:
488         break;
489     }
490
491 /* All the examples use the #else */
492 #if CAN_DO_LOGIN
493     ret->status = OCILogon(dbd_oracle_env, ret->err, &ret->svc, fields[0].value,
494                      strlen(fields[0].value), fields[1].value,
495                      strlen(fields[1].value), fields[2].value,
496                      strlen(fields[2].value));
497     switch (ret->status) {
498     default:
499 #ifdef DEBUG
500         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
501                     sizeof(ret->buf), OCI_HTYPE_ERROR);
502         printf("OPEN ERROR: %s\n", ret->buf);
503         break;
504 #else
505         if (error) {
506             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
507             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
508                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
509         }
510         return NULL;
511 #endif
512     case OCI_SUCCESS:
513         break;
514     }
515 #else
516     ret->status = OCIServerAttach(ret->svr, ret->err, (text*) fields[3].value,
517                                   strlen(fields[3].value), OCI_DEFAULT);
518     switch (ret->status) {
519     default:
520 #ifdef DEBUG
521         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
522                     sizeof(ret->buf), OCI_HTYPE_ERROR);
523         printf("OPEN ERROR %d (server attach): %s\n", ret->status, ret->buf);
524         break;
525 #else
526         if (error) {
527             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
528             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
529                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
530         }
531         return NULL;
532 #endif
533     case OCI_SUCCESS:
534         break;
535     }
536     ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->svr, 0,
537                         OCI_ATTR_SERVER, ret->err);
538     switch (ret->status) {
539     default:
540 #ifdef DEBUG
541         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
542                     sizeof(ret->buf), OCI_HTYPE_ERROR);
543         printf("OPEN ERROR %d (attr set): %s\n", ret->status, ret->buf);
544         break;
545 #else
546         if (error) {
547             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
548             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
549                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
550         }
551         return NULL;
552 #endif
553     case OCI_SUCCESS:
554         break;
555     }
556     ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->auth,
557                             OCI_HTYPE_SESSION, 0, NULL);
558     switch (ret->status) {
559     default:
560 #ifdef DEBUG
561         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
562                     sizeof(ret->buf), OCI_HTYPE_ERROR);
563         printf("OPEN ERROR %d (alloc auth): %s\n", ret->status, ret->buf);
564         break;
565 #else
566         if (error) {
567             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
568             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
569                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
570         }
571         return NULL;
572 #endif
573     case OCI_SUCCESS:
574         break;
575     }
576     ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[0].value,
577                         strlen(fields[0].value), OCI_ATTR_USERNAME, ret->err);
578     switch (ret->status) {
579     default:
580 #ifdef DEBUG
581         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
582                     sizeof(ret->buf), OCI_HTYPE_ERROR);
583         printf("OPEN ERROR %d (attr username): %s\n", ret->status, ret->buf);
584         break;
585 #else
586         if (error) {
587             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
588             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
589                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
590         }
591         return NULL;
592 #endif
593     case OCI_SUCCESS:
594         break;
595     }
596     ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[1].value,
597                         strlen(fields[1].value), OCI_ATTR_PASSWORD, ret->err);
598     switch (ret->status) {
599     default:
600 #ifdef DEBUG
601         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
602                     sizeof(ret->buf), OCI_HTYPE_ERROR);
603         printf("OPEN ERROR %d (attr password): %s\n", ret->status, ret->buf);
604         break;
605 #else
606         if (error) {
607             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
608             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
609                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
610         }
611         return NULL;
612 #endif
613     case OCI_SUCCESS:
614         break;
615     }
616     ret->status = OCISessionBegin(ret->svc, ret->err, ret->auth,
617                              OCI_CRED_RDBMS, OCI_DEFAULT);
618     switch (ret->status) {
619     default:
620 #ifdef DEBUG
621         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
622                     sizeof(ret->buf), OCI_HTYPE_ERROR);
623         printf("OPEN ERROR %d (session begin): %s\n", ret->status, ret->buf);
624         break;
625 #else
626         if (error) {
627             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
628             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
629                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
630         }
631         return NULL;
632 #endif
633     case OCI_SUCCESS:
634         break;
635     }
636     ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->auth, 0,
637                         OCI_ATTR_SESSION, ret->err);
638     switch (ret->status) {
639     default:
640 #ifdef DEBUG
641         OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
642                     sizeof(ret->buf), OCI_HTYPE_ERROR);
643         printf("OPEN ERROR %d (attr session): %s\n", ret->status, ret->buf);
644 #else
645         if (error) {
646             *error = apr_pcalloc(pool, ERR_BUF_SIZE);
647             OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
648                         ERR_BUF_SIZE, OCI_HTYPE_ERROR);
649         }
650         return NULL;
651 #endif
652         break;
653     case OCI_SUCCESS:
654         break;
655     }
656 #endif
657
658     if(dbd_oracle_prepare(pool, ret, CHECK_CONN_QUERY, NULL, 0, 0, NULL,
659                           &ret->check_conn_stmt) != 0) {
660         return NULL;
661     }
662
663     return ret;
664 }
665
666 #ifdef EXPORT_NATIVE_FUNCS
667 static apr_size_t dbd_oracle_long_size_set(apr_dbd_t *sql,
668                                            apr_size_t long_size)
669 {
670     apr_size_t old_size = sql->long_size;
671     sql->long_size = long_size;
672     return old_size;
673 }
674 #endif
675
676 static const char *dbd_oracle_get_name(const apr_dbd_results_t *res, int n)
677 {
678     define_arg *val = &res->statement->out[n];
679
680     if ((n < 0) || (n >= res->statement->nout)) {
681         return NULL;
682     }
683     return val->name;
684 }
685
686 static int dbd_oracle_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
687                               apr_dbd_row_t **rowp, int rownum)
688 {
689     apr_dbd_row_t *row = *rowp;
690     apr_dbd_t *sql = res->handle;
691     int_errorcode;
692
693     if (row == NULL) {
694         row = apr_palloc(pool, sizeof(apr_dbd_row_t));
695         *rowp = row;
696         row->res = res;
697         /* Oracle starts counting at 1 according to the docs */
698         row->n = res->seek ? rownum : 1;
699         row->pool = pool;
700     }
701     else {
702         if (res->seek) {
703             row->n = rownum;
704         }
705         else {
706             ++row->n;
707         }
708     }
709
710     if (res->seek) {
711         sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
712                                     OCI_FETCH_ABSOLUTE, row->n, OCI_DEFAULT);
713     }
714     else {
715         sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
716                                     OCI_FETCH_NEXT, 0, OCI_DEFAULT);
717     }
718     switch (sql->status) {
719     case OCI_SUCCESS:
720         (*rowp)->res = res;
721         return 0;
722     case OCI_NO_DATA:
723         return -1;
724     case OCI_ERROR:
725 #ifdef DEBUG
726         OCIErrorGet(sql->err, 1, NULL, &errorcode,
727                     sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
728         printf("Execute error %d: %s\n", sql->status, sql->buf);
729 #endif
730         /* fallthrough */
731     default:
732         return 1;
733     }
734     return 0;
735 }
736
737 static const char *dbd_oracle_error(apr_dbd_t *sql, int n)
738 {
739     /* This is ugly.  Needs us to pass in a buffer of unknown size.
740      * Either we put it on the handle, or we have to keep allocing/copying
741      */
742     sb4 errorcode;
743
744     switch (sql->status) {
745     case OCI_SUCCESS:
746         return "OCI_SUCCESS";
747     case OCI_SUCCESS_WITH_INFO:
748         return "OCI_SUCCESS_WITH_INFO";
749     case OCI_NEED_DATA:
750         return "OCI_NEED_DATA";
751     case OCI_NO_DATA:
752         return "OCI_NO_DATA";
753     case OCI_INVALID_HANDLE:
754         return "OCI_INVALID_HANDLE";
755     case OCI_STILL_EXECUTING:
756         return "OCI_STILL_EXECUTING";
757     case OCI_CONTINUE:
758         return "OCI_CONTINUE";
759     }
760
761     switch (OCIErrorGet(sql->err, 1, NULL, &errorcode,
762                         (text*) sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR)) {
763     case OCI_SUCCESS:
764         return sql->buf; 
765     default:
766         return "internal error: OCIErrorGet failed";
767     }
768 }
769
770 static apr_status_t freeStatement(void *statement)
771 {
772     int rv = APR_SUCCESS;
773     OCIStmt *stmt = ((apr_dbd_prepared_t*)statement)->stmt;
774
775 #ifdef PREPARE2
776     OCIError *err;
777
778     if (OCIHandleAlloc(dbd_oracle_env, (dvoid**)&err, OCI_HTYPE_ERROR,
779                        0, NULL) != OCI_SUCCESS) {
780         return APR_EGENERAL;
781     }
782     if (OCIStmtRelease(stmt, err, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS) {
783         rv = APR_EGENERAL;
784     }
785     if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) {
786         rv = APR_EGENERAL;
787     }
788 #else
789     if (OCIHandleFree(stmt, OCI_HTYPE_STMT) != OCI_SUCCESS) {
790         rv = APR_EGENERAL;
791     }
792 #endif
793
794     return rv;
795 }
796
797 static int dbd_oracle_select(apr_pool_t *pool, apr_dbd_t *sql,
798                              apr_dbd_results_t **results,
799                              const char *query, int seek)
800 {
801     int ret = 0;
802     apr_dbd_prepared_t *statement = NULL;
803
804     ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
805     if (ret != 0) {
806         return ret;
807     }
808
809     ret = dbd_oracle_pselect(pool, sql, results, statement, seek, NULL);
810     if (ret != 0) {
811         return ret;
812     }
813
814     return ret;
815 }
816
817 static int dbd_oracle_query(apr_dbd_t *sql, int *nrows, const char *query)
818 {
819     int ret = 0;
820     apr_pool_t *pool;
821     apr_dbd_prepared_t *statement = NULL;
822
823     if (sql->trans && sql->trans->status == TRANS_ERROR) {
824         return 1;
825     }
826
827     /* make our own pool so that APR allocations don't linger and so that
828      * both Stmt and LOB handles are cleaned up (LOB handles may be
829      * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs)
830      */
831     apr_pool_create(&pool, sql->pool);
832
833     ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
834     if (ret == 0) {
835         ret = dbd_oracle_pquery(pool, sql, nrows, statement, NULL);
836         if (ret == 0) {
837             sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT,
838                                      nrows, 0, OCI_ATTR_ROW_COUNT,
839                                      sql->err);
840         }
841     }
842
843     apr_pool_destroy(pool);
844
845     return ret;
846 }
847
848 static const char *dbd_oracle_escape(apr_pool_t *pool, const char *arg,
849                                      apr_dbd_t *sql)
850 {
851     return arg;        /* OCI has no concept of string escape */
852 }
853
854 static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
855                               const char *query, const char *label,
856                               int nargs, int nvals, apr_dbd_type_e *types,
857                               apr_dbd_prepared_t **statement)
858 {
859     int ret = 0;
860     int i;
861     apr_dbd_prepared_t *stmt ;
862
863     if (*statement == NULL) {
864         *statement = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t));
865     }
866     stmt = *statement;
867     stmt->handle = sql;
868     stmt->pool = pool;
869     stmt->nargs = nargs;
870     stmt->nvals = nvals;
871
872     /* populate our own args, if any */
873     if (nargs > 0) {
874         stmt->args = apr_pcalloc(pool, nargs*sizeof(bind_arg));
875         for (i = 0; i < nargs; i++) {
876             stmt->args[i].type = types[i];
877         }
878     }
879
880     sql->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**) &stmt->stmt,
881                                  OCI_HTYPE_STMT, 0, NULL);
882     if (sql->status != OCI_SUCCESS) {
883         return 1;
884     }
885
886     sql->status = OCIStmtPrepare(stmt->stmt, sql->err, (text*) query,
887                                  strlen(query), OCI_NTV_SYNTAX, OCI_DEFAULT);
888     if (sql->status != OCI_SUCCESS) {
889         OCIHandleFree(stmt->stmt, OCI_HTYPE_STMT);
890         return 1;
891     }
892
893     apr_pool_cleanup_register(pool, stmt, freeStatement,
894                               apr_pool_cleanup_null);
895
896     /* Perl gets statement type here */
897     sql->status = OCIAttrGet(stmt->stmt, OCI_HTYPE_STMT, &stmt->type, 0,
898                              OCI_ATTR_STMT_TYPE, sql->err);
899     if (sql->status != OCI_SUCCESS) {
900         return 1;
901     }
902
903 /* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
904 #if 0
905     sql->status = OCIAttrSet(stmt->stmt, OCI_HTYPE_STMT, &prefetch_size,
906                              sizeof(prefetch_size), OCI_ATTR_PREFETCH_MEMORY,
907                              sql->err);
908     if (sql->status != OCI_SUCCESS) {
909         return 1;
910     }
911 #endif
912
913     if (stmt->type == OCI_STMT_SELECT) {
914         ret = outputParams(sql, stmt);
915     }
916     return ret;
917 }
918
919 static void dbd_oracle_bind(apr_dbd_prepared_t *statement, const char **values)
920 {
921     OCIStmt *stmt = statement->stmt;
922     apr_dbd_t *sql = statement->handle;
923     int i, j;
924     sb2 null_ind = -1;
925
926     for (i = 0, j = 0; i < statement->nargs; i++, j++) {
927         if (values[j] == NULL) {
928             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
929                                        sql->err, i + 1,
930                                        NULL, 0, SQLT_STR,
931                                        &null_ind, NULL,
932                                        (ub2) 0, (ub4) 0,
933                                        (ub4 *) 0, OCI_DEFAULT);
934         }
935         else {
936             switch (statement->args[i].type) {
937             case APR_DBD_TYPE_BLOB:
938                 {
939                 char *data = (char *)values[j];
940                 int size = atoi((char*)values[++j]);
941
942                 /* skip table and column for now */
943                 j += 2;
944
945                 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
946                                            sql->err, i + 1,
947                                            data, size, SQLT_LBI,
948                                            &statement->args[i].ind,
949                                            NULL,
950                                            (ub2) 0, (ub4) 0,
951                                            (ub4 *) 0, OCI_DEFAULT);
952                 }
953                 break;
954             case APR_DBD_TYPE_CLOB:
955                 {
956                 char *data = (char *)values[j];
957                 int size = atoi((char*)values[++j]);
958
959                 /* skip table and column for now */
960                 j += 2;
961
962                 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
963                                            sql->err, i + 1,
964                                            data, size, SQLT_LNG,
965                                            &statement->args[i].ind,
966                                            NULL,
967                                            (ub2) 0, (ub4) 0,
968                                            (ub4 *) 0, OCI_DEFAULT);
969                 }
970                 break;
971             default:
972                 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
973                                            sql->err, i + 1,
974                                            (dvoid*) values[j],
975                                            strlen(values[j]) + 1,
976                                            SQLT_STR,
977                                            &statement->args[i].ind,
978                                            NULL,
979                                            (ub2) 0, (ub4) 0,
980                                            (ub4 *) 0, OCI_DEFAULT);
981                 break;
982             }
983         }
984
985         if (sql->status != OCI_SUCCESS) {
986             return;
987         }
988     }
989
990     return;
991 }
992
993 static int outputParams(apr_dbd_t *sql, apr_dbd_prepared_t *stmt)
994 {
995     OCIParam *parms;
996     int i;
997     ub2 paramtype[DBD_ORACLE_MAX_COLUMNS];
998     ub2 paramsize[DBD_ORACLE_MAX_COLUMNS];
999     char *paramname[DBD_ORACLE_MAX_COLUMNS];
1000     ub4 paramnamelen[DBD_ORACLE_MAX_COLUMNS];
1001     int_errorcode;
1002
1003     /* Perl uses 0 where we used 1 */
1004     sql->status = OCIStmtExecute(sql->svc, stmt->stmt, sql->err, 0, 0,
1005                                  NULL, NULL, OCI_DESCRIBE_ONLY);
1006     switch (sql->status) {
1007     case OCI_SUCCESS:
1008     case OCI_SUCCESS_WITH_INFO:
1009         break;
1010     case OCI_ERROR:
1011 #ifdef DEBUG
1012         OCIErrorGet(sql->err, 1, NULL, &errorcode,
1013                     sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1014         printf("Describing prepared statement: %s\n", sql->buf);
1015 #endif
1016     default:
1017         return 1;
1018     }
1019     while (sql->status == OCI_SUCCESS) {
1020         sql->status = OCIParamGet(stmt->stmt, OCI_HTYPE_STMT,
1021                                   sql->err, (dvoid**)&parms, stmt->nout+1);
1022         switch (sql->status) {
1023         case OCI_SUCCESS:
1024             sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1025                                      &paramtype[stmt->nout],
1026                                      0, OCI_ATTR_DATA_TYPE, sql->err);
1027             sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1028                                      &paramsize[stmt->nout],
1029                                      0, OCI_ATTR_DATA_SIZE, sql->err);
1030             sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1031                                      &paramname[stmt->nout],
1032                                      &paramnamelen[stmt->nout],
1033                                      OCI_ATTR_NAME, sql->err);
1034             ++stmt->nout;
1035         }
1036     }
1037     switch (sql->status) {
1038     case OCI_SUCCESS:
1039         break;
1040     case OCI_ERROR:
1041         break;        /* this is what we expect at end-of-loop */
1042     default:
1043         return 1;
1044     }
1045
1046     /* OK, the above works.  We have the params; now OCIDefine them */
1047     stmt->out = apr_palloc(stmt->pool, stmt->nout*sizeof(define_arg));
1048     for (i=0; i<stmt->nout; ++i) {
1049         stmt->out[i].type = paramtype[i];
1050         stmt->out[i].len = stmt->out[i].sz = paramsize[i];
1051         stmt->out[i].name = apr_pstrmemdup(stmt->pool,
1052                                            paramname[i], paramnamelen[i]);
1053         switch (stmt->out[i].type) {
1054         default:
1055             switch (stmt->out[i].type) {
1056             case SQLT_NUM:           /* 2: numeric, Perl worst case=130+38+3 */
1057                 stmt->out[i].sz = 171;
1058                 break;
1059             case SQLT_CHR:           /* 1: char */
1060             case SQLT_AFC:           /* 96: ANSI fixed char */
1061                 stmt->out[i].sz *= 4; /* ugh, wasteful UCS-4 handling */
1062                 break;
1063             case SQLT_DAT:           /* 12: date, depends on NLS date format */
1064                 stmt->out[i].sz = 75;
1065                 break;
1066             case SQLT_BIN:           /* 23: raw binary, perhaps UTF-16? */
1067                 stmt->out[i].sz *= 2;
1068                 break;
1069             case SQLT_RID:           /* 11: rowid */
1070             case SQLT_RDD:           /* 104: rowid descriptor */
1071                 stmt->out[i].sz = 20;
1072                 break;
1073             case SQLT_TIMESTAMP:     /* 187: timestamp */
1074             case SQLT_TIMESTAMP_TZ:  /* 188: timestamp with time zone */
1075             case SQLT_INTERVAL_YM:   /* 189: interval year-to-month */
1076             case SQLT_INTERVAL_DS:   /* 190: interval day-to-second */
1077             case SQLT_TIMESTAMP_LTZ: /* 232: timestamp with local time zone */
1078                 stmt->out[i].sz = 75;
1079                 break;
1080             default:
1081 #ifdef DEBUG
1082                 printf("Unsupported data type: %d\n", stmt->out[i].type);
1083 #endif
1084                 break;
1085             }
1086             ++stmt->out[i].sz;
1087             stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1088             sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1089                                          sql->err, i+1,
1090                                          stmt->out[i].buf.sval,
1091                                          stmt->out[i].sz, SQLT_STR,
1092                                          &stmt->out[i].ind, &stmt->out[i].len,
1093                                          0, OCI_DEFAULT);
1094             break;
1095         case SQLT_LNG: /* 8: long */
1096             stmt->out[i].sz = sql->long_size * 4 + 4; /* ugh, UCS-4 handling */
1097             stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1098             sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1099                                          sql->err, i+1,
1100                                          stmt->out[i].buf.raw,
1101                                          stmt->out[i].sz, SQLT_LVC,
1102                                          &stmt->out[i].ind, NULL,
1103                                          0, OCI_DEFAULT);
1104             break;
1105         case SQLT_LBI: /* 24: long binary, perhaps UTF-16? */
1106             stmt->out[i].sz = sql->long_size * 2 + 4; /* room for int prefix */
1107             stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1108             sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1109                                          sql->err, i+1,
1110                                          stmt->out[i].buf.raw,
1111                                          stmt->out[i].sz, SQLT_LVB,
1112                                          &stmt->out[i].ind, NULL,
1113                                          0, OCI_DEFAULT);
1114             break;
1115         case SQLT_BLOB: /* 113 */
1116         case SQLT_CLOB: /* 112 */
1117 /*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1118             sql->status = OCIDescriptorAlloc(dbd_oracle_env,
1119                                              (dvoid**)&stmt->out[i].buf.lobval,
1120                                              OCI_DTYPE_LOB, 0, NULL);
1121             apr_pool_cleanup_register(stmt->pool, stmt->out[i].buf.lobval,
1122                                       dbd_free_lobdesc,
1123                                       apr_pool_cleanup_null);
1124             sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1125                                          sql->err, i+1,
1126                                          (dvoid*) &stmt->out[i].buf.lobval,
1127                                          -1, stmt->out[i].type,
1128                                          &stmt->out[i].ind, &stmt->out[i].len,
1129                                          0, OCI_DEFAULT);
1130             break;
1131         }
1132         switch (sql->status) {
1133         case OCI_SUCCESS:
1134             break;
1135         default:
1136             return 1;
1137         }
1138     }
1139     return 0;
1140 }
1141
1142 static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
1143                              int *nrows, apr_dbd_prepared_t *statement,
1144                              const char **values)
1145 {
1146     OCISnapshot *oldsnapshot = NULL;
1147     OCISnapshot *newsnapshot = NULL;
1148     apr_dbd_transaction_t* trans = sql->trans;
1149     int exec_mode;
1150     int_errorcode;
1151
1152     if (trans) {
1153         switch (trans->status) {
1154         case TRANS_ERROR:
1155             return -1;
1156         case TRANS_NONE:
1157             trans = NULL;
1158             break;
1159         case TRANS_1:
1160             oldsnapshot = trans->snapshot1;
1161             newsnapshot = trans->snapshot2;
1162             trans->status = TRANS_2;
1163             break;
1164         case TRANS_2:
1165             oldsnapshot = trans->snapshot2;
1166             newsnapshot = trans->snapshot1;
1167             trans->status = TRANS_1;
1168             break;
1169         }
1170         exec_mode = OCI_DEFAULT;
1171     }
1172     else {
1173         exec_mode = OCI_COMMIT_ON_SUCCESS;
1174     }
1175
1176     dbd_oracle_bind(statement, values);
1177
1178     sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1179                                  oldsnapshot, newsnapshot, exec_mode);
1180     switch (sql->status) {
1181     case OCI_SUCCESS:
1182         break;
1183     case OCI_ERROR:
1184 #ifdef DEBUG
1185         OCIErrorGet(sql->err, 1, NULL, &errorcode,
1186                     sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1187         printf("Execute error %d: %s\n", sql->status, sql->buf);
1188 #endif
1189         /* fallthrough */
1190     default:
1191         if (TXN_NOTICE_ERRORS(trans)) {
1192             trans->status = TRANS_ERROR;
1193         }
1194         return 1;
1195     }
1196
1197     sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1198                              OCI_ATTR_ROW_COUNT, sql->err);
1199     return 0;
1200 }
1201
1202 static int dbd_oracle_pvquery(apr_pool_t *pool, apr_dbd_t *sql,
1203                               int *nrows, apr_dbd_prepared_t *statement,
1204                               va_list args)
1205 {
1206     const char **values;
1207     int i;
1208
1209     if (sql->trans && sql->trans->status == TRANS_ERROR) {
1210         return -1;
1211     }
1212
1213     values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1214
1215     for (i = 0; i < statement->nvals; i++) {
1216         values[i] = va_arg(args, const char*);
1217     }
1218
1219     return dbd_oracle_pquery(pool, sql, nrows, statement, values);
1220 }
1221
1222 static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
1223                               apr_dbd_results_t **results,
1224                               apr_dbd_prepared_t *statement,
1225                               int seek, const char **values)
1226 {
1227     int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1228     OCISnapshot *oldsnapshot = NULL;
1229     OCISnapshot *newsnapshot = NULL;
1230     apr_dbd_transaction_t* trans = sql->trans;
1231     int_errorcode;
1232
1233     if (trans) {
1234         switch (trans->status) {
1235         case TRANS_ERROR:
1236             return 1;
1237         case TRANS_NONE:
1238             trans = NULL;
1239             break;
1240         case TRANS_1:
1241             oldsnapshot = trans->snapshot1;
1242             newsnapshot = trans->snapshot2;
1243             trans->status = TRANS_2;
1244             break;
1245         case TRANS_2:
1246             oldsnapshot = trans->snapshot2;
1247             newsnapshot = trans->snapshot1;
1248             trans->status = TRANS_1;
1249             break;
1250         }
1251     }
1252
1253     dbd_oracle_bind(statement, values);
1254
1255     sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1256                                  oldsnapshot, newsnapshot, exec_mode);
1257     switch (sql->status) {
1258     case OCI_SUCCESS:
1259         break;
1260     case OCI_ERROR:
1261 #ifdef DEBUG
1262         OCIErrorGet(sql->err, 1, NULL, &errorcode,
1263                     sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1264         printf("Executing prepared statement: %s\n", sql->buf);
1265 #endif
1266         /* fallthrough */
1267     default:
1268         if (TXN_NOTICE_ERRORS(trans)) {
1269             trans->status = TRANS_ERROR;
1270         }
1271         return 1;
1272     }
1273
1274     if (!*results) {
1275         *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1276     }
1277     (*results)->handle = sql;
1278     (*results)->statement = statement;
1279     (*results)->seek = seek;
1280     (*results)->rownum = seek ? 0 : -1;
1281     (*results)->pool = pool;
1282
1283     return 0;
1284 }
1285
1286 static int dbd_oracle_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
1287                                apr_dbd_results_t **results,
1288                                apr_dbd_prepared_t *statement,
1289                                int seek, va_list args)
1290 {
1291     const char **values;
1292     int i;
1293
1294     if (sql->trans && sql->trans->status == TRANS_ERROR) {
1295         return -1;
1296     }
1297
1298     values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1299
1300     for (i = 0; i < statement->nvals; i++) {
1301         values[i] = va_arg(args, const char*);
1302     }
1303
1304     return dbd_oracle_pselect(pool, sql, results, statement, seek, values);
1305 }
1306
1307 static void dbd_oracle_bbind(apr_dbd_prepared_t * statement,
1308                              const void **values)
1309 {
1310     OCIStmt *stmt = statement->stmt;
1311     apr_dbd_t *sql = statement->handle;
1312     int i, j;
1313     sb2 null_ind = -1;
1314     apr_dbd_type_e type;
1315
1316     for (i = 0, j = 0; i < statement->nargs; i++, j++) {
1317         type = (values[j] == NULL ? APR_DBD_TYPE_NULL
1318                                   : statement->args[i].type);
1319
1320         switch (type) {
1321         case APR_DBD_TYPE_TINY:
1322             statement->args[i].value.ival = *(char*)values[j];
1323             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1324                                        sql->err, i + 1,
1325                                        &statement->args[i].value.ival,
1326                                        sizeof(statement->args[i].value.ival),
1327                                        SQLT_INT,
1328                                        &statement->args[i].ind, NULL,
1329                                        (ub2) 0, (ub4) 0,
1330                                        (ub4 *) 0, OCI_DEFAULT);
1331             break;
1332         case APR_DBD_TYPE_UTINY:
1333             statement->args[i].value.uval = *(unsigned char*)values[j];
1334             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1335                                        sql->err, i + 1,
1336                                        &statement->args[i].value.uval,
1337                                        sizeof(statement->args[i].value.uval),
1338                                        SQLT_UIN,
1339                                        &statement->args[i].ind, NULL,
1340                                        (ub2) 0, (ub4) 0,
1341                                        (ub4 *) 0, OCI_DEFAULT);
1342             break;
1343         case APR_DBD_TYPE_SHORT:
1344             statement->args[i].value.ival = *(short*)values[j];
1345             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1346                                        sql->err, i + 1,
1347                                        &statement->args[i].value.ival,
1348                                        sizeof(statement->args[i].value.ival),
1349                                        SQLT_INT,
1350                                        &statement->args[i].ind, NULL,
1351                                        (ub2) 0, (ub4) 0,
1352                                        (ub4 *) 0, OCI_DEFAULT);
1353             break;
1354         case APR_DBD_TYPE_USHORT:
1355             statement->args[i].value.uval = *(unsigned short*)values[j];
1356             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1357                                        sql->err, i + 1,
1358                                        &statement->args[i].value.uval,
1359                                        sizeof(statement->args[i].value.uval),
1360                                        SQLT_UIN,
1361                                        &statement->args[i].ind, NULL,
1362                                        (ub2) 0, (ub4) 0,
1363                                        (ub4 *) 0, OCI_DEFAULT);
1364             break;
1365         case APR_DBD_TYPE_INT:
1366             statement->args[i].value.ival = *(int*)values[j];
1367             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1368                                        sql->err, i + 1,
1369                                        &statement->args[i].value.ival,
1370                                        sizeof(statement->args[i].value.ival),
1371                                        SQLT_INT,
1372                                        &statement->args[i].ind, NULL,
1373                                        (ub2) 0, (ub4) 0,
1374                                        (ub4 *) 0, OCI_DEFAULT);
1375             break;
1376         case APR_DBD_TYPE_UINT:
1377             statement->args[i].value.uval = *(unsigned int*)values[j];
1378             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1379                                        sql->err, i + 1,
1380                                        &statement->args[i].value.uval,
1381                                        sizeof(statement->args[i].value.uval),
1382                                        SQLT_UIN,
1383                                        &statement->args[i].ind, NULL,
1384                                        (ub2) 0, (ub4) 0,
1385                                        (ub4 *) 0, OCI_DEFAULT);
1386             break;
1387         case APR_DBD_TYPE_LONG:
1388             statement->args[i].value.sval =
1389                 apr_psprintf(statement->pool, "%ld", *(long*)values[j]);
1390             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1391                                        sql->err, i + 1,
1392                                        statement->args[i].value.sval,
1393                                        strlen(statement->args[i].value.sval)+1,
1394                                        SQLT_STR,
1395                                        &statement->args[i].ind, NULL,
1396                                        (ub2) 0, (ub4) 0,
1397                                        (ub4 *) 0, OCI_DEFAULT);
1398             break;
1399         case APR_DBD_TYPE_ULONG:
1400             statement->args[i].value.sval =
1401                 apr_psprintf(statement->pool, "%lu",
1402                                               *(unsigned long*)values[j]);
1403             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1404                                        sql->err, i + 1,
1405                                        statement->args[i].value.sval,
1406                                        strlen(statement->args[i].value.sval)+1,
1407                                        SQLT_STR,
1408                                        &statement->args[i].ind, NULL,
1409                                        (ub2) 0, (ub4) 0,
1410                                        (ub4 *) 0, OCI_DEFAULT);
1411             break;
1412         case APR_DBD_TYPE_LONGLONG:
1413             statement->args[i].value.sval =
1414                 apr_psprintf(statement->pool, "%" APR_INT64_T_FMT,
1415                                               *(apr_int64_t*)values[j]);
1416             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1417                                        sql->err, i + 1,
1418                                        statement->args[i].value.sval,
1419                                        strlen(statement->args[i].value.sval)+1,
1420                                        SQLT_STR,
1421                                        &statement->args[i].ind, NULL,
1422                                        (ub2) 0, (ub4) 0,
1423                                        (ub4 *) 0, OCI_DEFAULT);
1424             break;
1425         case APR_DBD_TYPE_ULONGLONG:
1426             statement->args[i].value.sval =
1427                 apr_psprintf(statement->pool, "%" APR_UINT64_T_FMT,
1428                                               *(apr_uint64_t*)values[j]);
1429             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1430                                        sql->err, i + 1,
1431                                        statement->args[i].value.sval,
1432                                        strlen(statement->args[i].value.sval)+1,
1433                                        SQLT_UIN,
1434                                        &statement->args[i].ind, NULL,
1435                                        (ub2) 0, (ub4) 0,
1436                                        (ub4 *) 0, OCI_DEFAULT);
1437             break;
1438         case APR_DBD_TYPE_FLOAT:
1439             statement->args[i].value.fval = *(float*)values[j];
1440             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1441                                        sql->err, i + 1,
1442                                        &statement->args[i].value.fval,
1443                                        sizeof(statement->args[i].value.fval),
1444                                        SQLT_FLT,
1445                                        &statement->args[i].ind, NULL,
1446                                        (ub2) 0, (ub4) 0,
1447                                        (ub4 *) 0, OCI_DEFAULT);
1448             break;
1449         case APR_DBD_TYPE_DOUBLE:
1450             statement->args[i].value.fval = *(double*)values[j];
1451             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1452                                        sql->err, i + 1,
1453                                        &statement->args[i].value.fval,
1454                                        sizeof(statement->args[i].value.fval),
1455                                        SQLT_FLT,
1456                                        &statement->args[i].ind, NULL,
1457                                        (ub2) 0, (ub4) 0,
1458                                        (ub4 *) 0, OCI_DEFAULT);
1459             break;
1460         case APR_DBD_TYPE_STRING:
1461         case APR_DBD_TYPE_TEXT:
1462         case APR_DBD_TYPE_TIME:
1463         case APR_DBD_TYPE_DATE:
1464         case APR_DBD_TYPE_DATETIME:
1465         case APR_DBD_TYPE_TIMESTAMP:
1466         case APR_DBD_TYPE_ZTIMESTAMP:
1467             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1468                                        sql->err, i + 1,
1469                                        (dvoid*) values[j],
1470                                        strlen(values[j]) + 1,
1471                                        SQLT_STR,
1472                                        &statement->args[i].ind, NULL,
1473                                        (ub2) 0, (ub4) 0,
1474                                        (ub4 *) 0, OCI_DEFAULT);
1475             break;
1476         case APR_DBD_TYPE_BLOB:
1477             {
1478             char *data = (char *)values[j];
1479             apr_size_t size = *(apr_size_t*)values[++j];
1480
1481             /* skip table and column for now */
1482             j += 2;
1483
1484             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1485                                        sql->err, i + 1,
1486                                        data, size, SQLT_LBI,
1487                                        &statement->args[i].ind,
1488                                        NULL,
1489                                        (ub2) 0, (ub4) 0,
1490                                        (ub4 *) 0, OCI_DEFAULT);
1491             }
1492             break;
1493         case APR_DBD_TYPE_CLOB:
1494             {
1495             char *data = (char *)values[j];
1496             apr_size_t size = *(apr_size_t*)values[++j];
1497
1498             /* skip table and column for now */
1499             j += 2;
1500
1501             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1502                                        sql->err, i + 1,
1503                                        data, size, SQLT_LNG,
1504                                        &statement->args[i].ind,
1505                                        NULL,
1506                                        (ub2) 0, (ub4) 0,
1507                                        (ub4 *) 0, OCI_DEFAULT);
1508             }
1509             break;
1510         case APR_DBD_TYPE_NULL:
1511         default:
1512             sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1513                                        sql->err, i + 1,
1514                                        NULL, 0, SQLT_STR,
1515                                        &null_ind, NULL,
1516                                        (ub2) 0, (ub4) 0,
1517                                        (ub4 *) 0, OCI_DEFAULT);
1518             break;
1519         }
1520
1521         if (sql->status != OCI_SUCCESS) {
1522             return;
1523         }
1524     }
1525
1526     return;
1527 }
1528
1529 static int dbd_oracle_pbquery(apr_pool_t * pool, apr_dbd_t * sql,
1530                               int *nrows, apr_dbd_prepared_t * statement,
1531                               const void **values)
1532 {
1533     OCISnapshot *oldsnapshot = NULL;
1534     OCISnapshot *newsnapshot = NULL;
1535     apr_dbd_transaction_t* trans = sql->trans;
1536     int exec_mode;
1537     int_errorcode;
1538
1539     if (trans) {
1540         switch (trans->status) {
1541         case TRANS_ERROR:
1542             return -1;
1543         case TRANS_NONE:
1544             trans = NULL;
1545             break;
1546         case TRANS_1:
1547             oldsnapshot = trans->snapshot1;
1548             newsnapshot = trans->snapshot2;
1549             trans->status = TRANS_2;
1550             break;
1551         case TRANS_2:
1552             oldsnapshot = trans->snapshot2;
1553             newsnapshot = trans->snapshot1;
1554             trans->status = TRANS_1;
1555             break;
1556         }
1557         exec_mode = OCI_DEFAULT;
1558     }
1559     else {
1560         exec_mode = OCI_COMMIT_ON_SUCCESS;
1561     }
1562
1563     dbd_oracle_bbind(statement, values);
1564
1565     sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1566                                  oldsnapshot, newsnapshot, exec_mode);
1567     switch (sql->status) {
1568     case OCI_SUCCESS:
1569         break;
1570     case OCI_ERROR:
1571 #ifdef DEBUG
1572         OCIErrorGet(sql->err, 1, NULL, &errorcode,
1573                     sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1574         printf("Execute error %d: %s\n", sql->status, sql->buf);
1575 #endif
1576         /* fallthrough */
1577     default:
1578         if (TXN_NOTICE_ERRORS(trans)) {
1579             trans->status = TRANS_ERROR;
1580         }
1581         return 1;
1582     }
1583
1584     sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1585                              OCI_ATTR_ROW_COUNT, sql->err);
1586     return 0;
1587 }
1588
1589 static int dbd_oracle_pvbquery(apr_pool_t * pool, apr_dbd_t * sql,
1590                                int *nrows, apr_dbd_prepared_t * statement,
1591                                va_list args)
1592 {
1593     const void **values;
1594     int i;
1595
1596     if (sql->trans && sql->trans->status == TRANS_ERROR) {
1597         return -1;
1598     }
1599
1600     values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1601
1602     for (i = 0; i < statement->nvals; i++) {
1603         values[i] = va_arg(args, const void*);
1604     }
1605
1606     return dbd_oracle_pbquery(pool, sql, nrows, statement, values);
1607 }
1608
1609 static int dbd_oracle_pbselect(apr_pool_t * pool, apr_dbd_t * sql,
1610                                apr_dbd_results_t ** results,
1611                                apr_dbd_prepared_t * statement,
1612                                int seek, const void **values)
1613 {
1614     int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1615     OCISnapshot *oldsnapshot = NULL;
1616     OCISnapshot *newsnapshot = NULL;
1617     apr_dbd_transaction_t* trans = sql->trans;
1618     int_errorcode;
1619
1620     if (trans) {
1621         switch (trans->status) {
1622         case TRANS_ERROR:
1623             return 1;
1624         case TRANS_NONE:
1625             trans = NULL;
1626             break;
1627         case TRANS_1:
1628             oldsnapshot = trans->snapshot1;
1629             newsnapshot = trans->snapshot2;
1630             trans->status = TRANS_2;
1631             break;
1632         case TRANS_2:
1633             oldsnapshot = trans->snapshot2;
1634             newsnapshot = trans->snapshot1;
1635             trans->status = TRANS_1;
1636             break;
1637         }
1638     }
1639
1640     dbd_oracle_bbind(statement, values);
1641
1642     sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1643                                  oldsnapshot, newsnapshot, exec_mode);
1644     switch (sql->status) {
1645     case OCI_SUCCESS:
1646         break;
1647     case OCI_ERROR:
1648 #ifdef DEBUG
1649         OCIErrorGet(sql->err, 1, NULL, &errorcode,
1650                     sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1651         printf("Executing prepared statement: %s\n", sql->buf);
1652 #endif
1653         /* fallthrough */
1654     default:
1655         if (TXN_NOTICE_ERRORS(trans)) {
1656             trans->status = TRANS_ERROR;
1657         }
1658         return 1;
1659     }
1660
1661     if (!*results) {
1662         *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1663     }
1664     (*results)->handle = sql;
1665     (*results)->statement = statement;
1666     (*results)->seek = seek;
1667     (*results)->rownum = seek ? 0 : -1;
1668     (*results)->pool = pool;
1669
1670     return 0;
1671 }
1672
1673 static int dbd_oracle_pvbselect(apr_pool_t * pool, apr_dbd_t * sql,
1674                                 apr_dbd_results_t ** results,
1675                                 apr_dbd_prepared_t * statement, int seek,
1676                                 va_list args)
1677 {
1678     const void **values;
1679     int i;
1680
1681     if (sql->trans && sql->trans->status == TRANS_ERROR) {
1682         return -1;
1683     }
1684
1685     values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1686
1687     for (i = 0; i < statement->nvals; i++) {
1688         values[i] = va_arg(args, const void*);
1689     }
1690
1691     return dbd_oracle_pbselect(pool, sql, results, statement, seek, values);
1692 }
1693
1694 static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
1695                                         apr_dbd_transaction_t **trans)
1696 {
1697     int ret = 0;
1698     int_errorcode;
1699     if (*trans) {
1700         dbd_oracle_end_transaction(*trans);
1701     }
1702     else {
1703         *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
1704         OCIHandleAlloc(dbd_oracle_env, (dvoid**)&(*trans)->trans,
1705                        OCI_HTYPE_TRANS, 0, 0);
1706         OCIAttrSet(sql->svc, OCI_HTYPE_SVCCTX, (*trans)->trans, 0,
1707                    OCI_ATTR_TRANS, sql->err);
1708     }
1709
1710
1711     sql->status = OCITransStart(sql->svc, sql->err, TRANS_TIMEOUT,
1712                                 OCI_TRANS_NEW);
1713     switch (sql->status) {
1714     case OCI_ERROR:
1715 #ifdef DEBUG
1716         OCIErrorGet(sql->err, 1, NULL, &errorcode, sql->buf,
1717                     sizeof(sql->buf), OCI_HTYPE_ERROR);
1718         printf("Transaction: %s\n", sql->buf);
1719 #endif
1720         ret = 1;
1721         break;
1722     case OCI_SUCCESS:
1723         (*trans)->handle = sql;
1724         (*trans)->status = TRANS_1;
1725         sql->trans = *trans;
1726         switch (OCIDescriptorAlloc(dbd_oracle_env,
1727                                    (dvoid**)&(*trans)->snapshot1,
1728                                    OCI_DTYPE_SNAP, 0, NULL)) {
1729         case OCI_SUCCESS:
1730             apr_pool_cleanup_register(pool, (*trans)->snapshot1,
1731                                       dbd_free_snapshot, apr_pool_cleanup_null);
1732             break;
1733         case OCI_INVALID_HANDLE:
1734             ret = 1;
1735             break;
1736         }
1737         switch (OCIDescriptorAlloc(dbd_oracle_env,
1738                                    (dvoid**)&(*trans)->snapshot2,
1739                                    OCI_DTYPE_SNAP, 0, NULL)) {
1740         case OCI_SUCCESS:
1741             apr_pool_cleanup_register(pool, (*trans)->snapshot2,
1742                                       dbd_free_snapshot, apr_pool_cleanup_null);
1743             break;
1744         case OCI_INVALID_HANDLE:
1745             ret = 1;
1746             break;
1747         }
1748         break;
1749     default:
1750         ret = 1;
1751         break;
1752     }
1753     return ret;
1754 }
1755
1756 static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans)
1757 {
1758     int ret = 1;             /* no transaction is an error cond */
1759     sword status;
1760     apr_dbd_t *handle = trans->handle;
1761     if (trans) {
1762         switch (trans->status) {
1763         case TRANS_NONE:     /* No trans is an error here */
1764             status = OCI_ERROR;
1765             break;
1766         case TRANS_ERROR:
1767             status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1768             break;
1769         default:
1770             /* rollback on explicit rollback request */
1771             if (TXN_DO_ROLLBACK(trans)) {
1772                 status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1773             } else {
1774                 status = OCITransCommit(handle->svc, handle->err, OCI_DEFAULT);
1775             }
1776             break;
1777         }
1778
1779         handle->trans = NULL;
1780
1781         switch (status) {
1782         case OCI_SUCCESS:
1783             ret = 0;
1784             break;
1785         default:
1786             ret = 3;
1787             break;
1788         }
1789     }
1790     return ret;
1791 }
1792
1793 static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t *trans)
1794 {
1795     if (!trans)
1796         return APR_DBD_TRANSACTION_COMMIT;
1797
1798     return trans->mode;
1799 }
1800
1801 static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t *trans,
1802                                            int mode)
1803 {
1804     if (!trans)
1805         return APR_DBD_TRANSACTION_COMMIT;
1806
1807     return trans->mode = (mode & TXN_MODE_BITS);
1808 }
1809
1810 /* This doesn't work for BLOB because of NULLs, but it can fake it
1811  * if the BLOB is really a string
1812  */
1813 static const char *dbd_oracle_get_entry(const apr_dbd_row_t *row, int n)
1814 {
1815     ub4 len = 0;
1816     ub1 csform = 0;
1817     ub2 csid = 0;
1818     apr_size_t buflen = 0;
1819     char *buf = NULL;
1820     define_arg *val = &row->res->statement->out[n];
1821     apr_dbd_t *sql = row->res->handle;
1822     int_errorcode;
1823
1824     if ((n < 0) || (n >= row->res->statement->nout) || (val->ind == -1)) {
1825         return NULL;
1826     }
1827
1828     switch (val->type) {
1829     case SQLT_BLOB:
1830     case SQLT_CLOB:
1831         sql->status = OCILobGetLength(sql->svc, sql->err, val->buf.lobval,
1832                                       &len);
1833         switch (sql->status) {
1834         case OCI_SUCCESS:
1835         case OCI_SUCCESS_WITH_INFO:
1836             if (len == 0) {
1837                 buf = "";
1838             }
1839             break;
1840         case OCI_ERROR:
1841 #ifdef DEBUG
1842             OCIErrorGet(sql->err, 1, NULL, &errorcode,
1843                         sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1844             printf("Finding LOB length: %s\n", sql->buf);
1845             break;
1846 #endif
1847         default:
1848             break;
1849         }
1850
1851         if (len == 0) {
1852             break;
1853         }
1854
1855         if (val->type == APR_DBD_TYPE_CLOB) {
1856 #if 1
1857             /* Is this necessary, or can it be defaulted? */
1858             sql->status = OCILobCharSetForm(dbd_oracle_env, sql->err,
1859                                             val->buf.lobval, &csform);
1860             if (sql->status == OCI_SUCCESS) {
1861                 sql->status = OCILobCharSetId(dbd_oracle_env, sql->err,
1862                                               val->buf.lobval, &csid);
1863             }
1864             switch (sql->status) {
1865             case OCI_SUCCESS:
1866             case OCI_SUCCESS_WITH_INFO:
1867                 buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1868                 /* zeroise all - where the string ends depends on charset */
1869                 buf = apr_pcalloc(row->pool, buflen);
1870                 break;
1871 #ifdef DEBUG
1872             case OCI_ERROR:
1873                 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1874                             sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1875                 printf("Reading LOB character set: %s\n", sql->buf);
1876                 break; /*** XXX?? ***/
1877 #endif
1878             default:
1879                 break; /*** XXX?? ***/
1880             }
1881 #else   /* ignore charset */
1882             buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1883             /* zeroise all - where the string ends depends on charset */
1884             buf = apr_pcalloc(row->pool, buflen);
1885 #endif
1886         } else {
1887             /* BUG: this'll only work if the BLOB looks like a string */
1888             buflen = len;
1889             buf = apr_palloc(row->pool, buflen+1);
1890             buf[buflen] = 0;
1891         }
1892
1893         if (!buf) {
1894             break;
1895         }
1896
1897         sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
1898                                  &len, 1, (dvoid*) buf, buflen,
1899                                  NULL, NULL, csid, csform);
1900         switch (sql->status) {
1901         case OCI_SUCCESS:
1902         case OCI_SUCCESS_WITH_INFO:
1903             break;
1904 #ifdef DEBUG
1905         case OCI_ERROR:
1906             OCIErrorGet(sql->err, 1, NULL, &errorcode,
1907                         sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1908             printf("Reading LOB: %s\n", sql->buf);
1909             buf = NULL; /*** XXX?? ***/
1910             break;
1911 #endif
1912         default:
1913             buf = NULL; /*** XXX?? ***/
1914             break;
1915         }
1916
1917         break;
1918     case SQLT_LNG:
1919     case SQLT_LBI:
1920         /* raw is struct { ub4 len; char *buf; } */
1921         len = *(ub4*) val->buf.raw;
1922         buf = apr_pstrndup(row->pool, val->buf.sval + sizeof(ub4), len);
1923         break;
1924     default:
1925         buf = apr_pstrndup(row->pool, val->buf.sval, val->len);
1926         break;
1927     }
1928     return (const char*) buf;
1929 }
1930
1931 /* XXX Should this use Oracle proper API instead of calling get_entry()? */
1932 static apr_status_t dbd_oracle_datum_get(const apr_dbd_row_t *row, int n,
1933                                          apr_dbd_type_e type, void *data)
1934 {
1935     define_arg *val = &row->res->statement->out[n];
1936     const char *entry;
1937
1938     if ((n < 0) || (n >= row->res->statement->nout)) {
1939         return APR_EGENERAL;
1940     }
1941
1942     if(val->ind == -1) {
1943         return APR_ENOENT;
1944     }
1945
1946     switch (type) {
1947     case APR_DBD_TYPE_TINY:
1948         entry = dbd_oracle_get_entry(row, n);
1949         if (entry == NULL) {
1950             return APR_ENOENT;
1951         }
1952         *(char*)data = atoi(entry);
1953         break;
1954     case APR_DBD_TYPE_UTINY:
1955         entry = dbd_oracle_get_entry(row, n);
1956         if (entry == NULL) {
1957             return APR_ENOENT;
1958         }
1959         *(unsigned char*)data = atoi(entry);
1960         break;
1961     case APR_DBD_TYPE_SHORT:
1962         entry = dbd_oracle_get_entry(row, n);
1963         if (entry == NULL) {
1964             return APR_ENOENT;
1965         }
1966         *(short*)data = atoi(entry);
1967         break;
1968     case APR_DBD_TYPE_USHORT:
1969         entry = dbd_oracle_get_entry(row, n);
1970         if (entry == NULL) {
1971             return APR_ENOENT;
1972         }
1973         *(unsigned short*)data = atoi(entry);
1974         break;
1975     case APR_DBD_TYPE_INT:
1976         entry = dbd_oracle_get_entry(row, n);
1977         if (entry == NULL) {
1978             return APR_ENOENT;
1979         }
1980         *(int*)data = atoi(entry);
1981         break;
1982     case APR_DBD_TYPE_UINT:
1983         entry = dbd_oracle_get_entry(row, n);
1984         if (entry == NULL) {
1985             return APR_ENOENT;
1986         }
1987         *(unsigned int*)data = atoi(entry);
1988         break;
1989     case APR_DBD_TYPE_LONG:
1990         entry = dbd_oracle_get_entry(row, n);
1991         if (entry == NULL) {
1992             return APR_ENOENT;
1993         }
1994         *(long*)data = atol(entry);
1995         break;
1996     case APR_DBD_TYPE_ULONG:
1997         entry = dbd_oracle_get_entry(row, n);
1998         if (entry == NULL) {
1999             return APR_ENOENT;
2000         }
2001         *(unsigned long*)data = atol(entry);
2002         break;
2003     case APR_DBD_TYPE_LONGLONG:
2004         entry = dbd_oracle_get_entry(row, n);
2005         if (entry == NULL) {
2006             return APR_ENOENT;
2007         }
2008         *(apr_int64_t*)data = apr_atoi64(entry);
2009         break;
2010     case APR_DBD_TYPE_ULONGLONG:
2011         entry = dbd_oracle_get_entry(row, n);
2012         if (entry == NULL) {
2013             return APR_ENOENT;
2014         }
2015         *(apr_uint64_t*)data = apr_atoi64(entry);
2016         break;
2017     case APR_DBD_TYPE_FLOAT:
2018         entry = dbd_oracle_get_entry(row, n);
2019         if (entry == NULL) {
2020             return APR_ENOENT;
2021         }
2022         *(float*)data = (float)atof(entry);
2023         break;
2024     case APR_DBD_TYPE_DOUBLE:
2025         entry = dbd_oracle_get_entry(row, n);
2026         if (entry == NULL) {
2027             return APR_ENOENT;
2028         }
2029         *(double*)data = atof(entry);
2030         break;
2031     case APR_DBD_TYPE_STRING:
2032     case APR_DBD_TYPE_TEXT:
2033     case APR_DBD_TYPE_TIME:
2034     case APR_DBD_TYPE_DATE:
2035     case APR_DBD_TYPE_DATETIME:
2036     case APR_DBD_TYPE_TIMESTAMP:
2037     case APR_DBD_TYPE_ZTIMESTAMP:
2038         entry = dbd_oracle_get_entry(row, n);
2039         if (entry == NULL) {
2040             return APR_ENOENT;
2041         }
2042         *(char**)data = (char*)entry;
2043         break;
2044     case APR_DBD_TYPE_BLOB:
2045     case APR_DBD_TYPE_CLOB:
2046         {
2047         apr_bucket *e;
2048         apr_bucket_brigade *b = (apr_bucket_brigade*)data;
2049         apr_dbd_t *sql = row->res->handle;
2050         ub4 len = 0;
2051
2052         switch (val->type) {
2053         case SQLT_BLOB:
2054         case SQLT_CLOB:
2055             sql->status = OCILobGetLength(sql->svc, sql->err,
2056                                           val->buf.lobval, &len);
2057             switch(sql->status) {
2058             case OCI_SUCCESS:
2059             case OCI_SUCCESS_WITH_INFO:
2060                 if (len == 0) {
2061                     e = apr_bucket_eos_create(b->bucket_alloc);
2062                 }
2063                 else {
2064                     e = apr_bucket_lob_create(row, n, 0, len,
2065                                               row->pool, b->bucket_alloc);
2066                 }
2067                 break;
2068             default:
2069                 return APR_ENOENT;
2070             }
2071             break;
2072         default:
2073             entry = dbd_oracle_get_entry(row, n);
2074             if (entry == NULL) {
2075                 return APR_ENOENT;
2076             }
2077             e = apr_bucket_pool_create(entry, strlen(entry),
2078                                        row->pool, b->bucket_alloc);
2079             break;
2080         }
2081         APR_BRIGADE_INSERT_TAIL(b, e);
2082         }
2083         break;
2084     case APR_DBD_TYPE_NULL:
2085         *(void**)data = NULL;
2086         break;
2087     default:
2088         return APR_EGENERAL;
2089     }
2090
2091     return APR_SUCCESS;
2092 }
2093
2094 static apr_status_t dbd_oracle_close(apr_dbd_t *handle)
2095 {
2096     /* FIXME: none of the oracle docs/examples say anything about
2097      * closing/releasing handles.  Which seems unlikely ...
2098      */
2099
2100     /* OK, let's grab from cdemo again.
2101      * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
2102      */
2103     switch (OCISessionEnd(handle->svc, handle->err, handle->auth,
2104             (ub4)OCI_DEFAULT)) {
2105     default:
2106         break;
2107     }
2108     switch (OCIServerDetach(handle->svr, handle->err, (ub4) OCI_DEFAULT )) {
2109     default:
2110         break;
2111     }
2112     /* does OCISessionEnd imply this? */
2113     switch (OCIHandleFree((dvoid *) handle->auth, (ub4) OCI_HTYPE_SESSION)) {
2114     default:
2115         break;
2116     }
2117     switch (OCIHandleFree((dvoid *) handle->svr, (ub4) OCI_HTYPE_SERVER)) {
2118     default:
2119         break;
2120     }
2121     switch (OCIHandleFree((dvoid *) handle->svc, (ub4) OCI_HTYPE_SVCCTX)) {
2122     default:
2123         break;
2124     }
2125     switch (OCIHandleFree((dvoid *) handle->err, (ub4) OCI_HTYPE_ERROR)) {
2126     default:
2127         break;
2128     }
2129     return APR_SUCCESS;
2130 }
2131
2132 static apr_status_t dbd_oracle_check_conn(apr_pool_t *pool, apr_dbd_t *sql)
2133 {
2134     apr_dbd_results_t *res = NULL;
2135     apr_dbd_row_t *row = NULL;
2136     
2137     if(dbd_oracle_pselect(pool, sql, &res, sql->check_conn_stmt,
2138                           0, NULL) != 0) {
2139         return APR_EGENERAL;
2140     }
2141     
2142     if(dbd_oracle_get_row(pool, res, &row, -1) != 0) {
2143         return APR_EGENERAL;
2144     }
2145     
2146     if(dbd_oracle_get_row(pool, res, &row, -1) != -1) {
2147         return APR_EGENERAL;
2148     }
2149
2150     return APR_SUCCESS;
2151 }
2152
2153 static int dbd_oracle_select_db(apr_pool_t *pool, apr_dbd_t *handle,
2154                                 const char *name)
2155 {
2156     /* FIXME: need to find this in the docs */
2157     return APR_ENOTIMPL;
2158 }
2159
2160 static void *dbd_oracle_native(apr_dbd_t *handle)
2161 {
2162     /* FIXME: can we do anything better?  Oracle doesn't seem to have
2163      * a concept of a handle in the sense we use it.
2164      */
2165     return dbd_oracle_env;
2166 }
2167
2168 static int dbd_oracle_num_cols(apr_dbd_results_t* res)
2169 {
2170     return res->statement->nout;
2171 }
2172
2173 static int dbd_oracle_num_tuples(apr_dbd_results_t* res)
2174 {
2175     if (!res->seek) {
2176         return -1;
2177     }
2178     if (res->nrows >= 0) {
2179         return res->nrows;
2180     }
2181     res->handle->status = OCIAttrGet(res->statement->stmt, OCI_HTYPE_STMT,
2182                                      &res->nrows, 0, OCI_ATTR_ROW_COUNT,
2183                                      res->handle->err);
2184     return res->nrows;
2185 }
2186
2187 APU_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_oracle_driver = {
2188     "oracle",
2189     dbd_oracle_init,
2190     dbd_oracle_native,
2191     dbd_oracle_open,
2192     dbd_oracle_check_conn,
2193     dbd_oracle_close,
2194     dbd_oracle_select_db,
2195     dbd_oracle_start_transaction,
2196     dbd_oracle_end_transaction,
2197     dbd_oracle_query,
2198     dbd_oracle_select,
2199     dbd_oracle_num_cols,
2200     dbd_oracle_num_tuples,
2201     dbd_oracle_get_row,
2202     dbd_oracle_get_entry,
2203     dbd_oracle_error,
2204     dbd_oracle_escape,
2205     dbd_oracle_prepare,
2206     dbd_oracle_pvquery,
2207     dbd_oracle_pvselect,
2208     dbd_oracle_pquery,
2209     dbd_oracle_pselect,
2210     dbd_oracle_get_name,
2211     dbd_oracle_transaction_mode_get,
2212     dbd_oracle_transaction_mode_set,
2213     ":apr%d",
2214     dbd_oracle_pvbquery,
2215     dbd_oracle_pvbselect,
2216     dbd_oracle_pbquery,
2217     dbd_oracle_pbselect,
2218     dbd_oracle_datum_get
2219 };
2220 #endif