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