Unify parsing of prepared statements in DBD
[apr-util.git] / dbd / apr_dbd_oracle.c
blobdf7ecdb97585ee61138e6b8fe0099d11a40934b6
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 /*******************************************************************/
47 /* GLOBAL_PREPARED_STATEMENTS
49 * This probably needs bindings taken away from prepare and into
50 * execute, or else we'll get race conditions on the parameters
51 * Might be able to do it with some pool refactoring.
53 * In fact, though the documentation says statements can run with
54 * different interps and threads (IIRC), it doesn't say anything
55 * about race conditions between bind and execute. So we'd better
56 * not even try until and unless someone who knows oracle from the
57 * inside fixes it.
58 #define GLOBAL_PREPARED_STATEMENTS
61 /* shut compiler up */
62 #ifdef DEBUG
63 #define int_errorcode int errorcode
64 #else
65 #define int_errorcode
66 #endif
68 #include "apu.h"
70 #if APU_HAVE_ORACLE
72 #include <ctype.h>
73 #include <stdlib.h>
74 #include <stdio.h>
76 #include <oci.h>
78 #include "apr_strings.h"
79 #include "apr_time.h"
80 #include "apr_hash.h"
81 #include "apr_buckets.h"
83 #define TRANS_TIMEOUT 30
84 #define MAX_ARG_LEN 256 /* in line with other apr_dbd drivers. We alloc this
85 * lots of times, so a large value gets hungry.
86 * Should really make it configurable
88 #define DEFAULT_LONG_SIZE 4096
89 #define DBD_ORACLE_MAX_COLUMNS 256
90 #define NUMERIC_FIELD_SIZE 32
92 #ifdef DEBUG
93 #include <stdio.h>
94 #endif
96 #include "apr_dbd_internal.h"
98 /* declarations */
99 static const char *dbd_oracle_error(apr_dbd_t *sql, int n);
100 static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
101 const char *query, const char *label,
102 int nargs, int nvals, apr_dbd_type_e *types,
103 apr_dbd_prepared_t **statement);
104 static int outputParams(apr_dbd_t*, apr_dbd_prepared_t*);
105 static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
106 apr_dbd_results_t **results,
107 apr_dbd_prepared_t *statement,
108 int seek, const char **values);
109 static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
110 int *nrows, apr_dbd_prepared_t *statement,
111 const char **values);
112 static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
113 apr_dbd_transaction_t **trans);
114 static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans);
116 struct apr_dbd_transaction_t {
117 int mode;
118 enum { TRANS_NONE, TRANS_ERROR, TRANS_1, TRANS_2 } status;
119 apr_dbd_t *handle;
120 OCITrans *trans;
121 OCISnapshot *snapshot1;
122 OCISnapshot *snapshot2;
125 struct apr_dbd_results_t {
126 apr_pool_t *pool;
127 apr_dbd_t* handle;
128 unsigned int rownum;
129 int seek;
130 int nrows;
131 apr_dbd_prepared_t *statement;
134 struct apr_dbd_t {
135 sword status;
136 OCIError *err;
137 OCIServer *svr;
138 OCISvcCtx *svc;
139 OCISession *auth;
140 apr_dbd_transaction_t* trans;
141 apr_pool_t *pool;
142 char buf[200]; /* for error messages */
143 apr_size_t long_size;
146 struct apr_dbd_row_t {
147 int n;
148 apr_dbd_results_t *res;
149 apr_pool_t *pool;
152 typedef struct {
153 apr_dbd_type_e type;
154 sb2 ind;
155 sb4 len;
156 OCIBind *bind;
157 union {
158 void *raw;
159 char *sval;
160 int ival;
161 unsigned int uval;
162 double fval;
163 OCILobLocator *lobval;
164 } value;
165 } bind_arg;
167 typedef struct {
168 int type;
169 sb2 ind;
170 ub2 len; /* length of actual output */
171 OCIDefine *defn;
172 apr_size_t sz; /* length of buf for output */
173 union {
174 void *raw;
175 char *sval;
176 OCILobLocator *lobval;
177 } buf;
178 const char *name;
179 } define_arg;
181 struct apr_dbd_prepared_t {
182 OCIStmt *stmt;
183 int nargs;
184 int nvals;
185 bind_arg *args;
186 int nout;
187 define_arg *out;
188 apr_dbd_t *handle;
189 apr_pool_t *pool;
190 int type;
193 /* AFAICT from the docs, the OCIEnv thingey can be used async
194 * across threads, so lets have a global one.
196 * We'll need shorter-lived envs to deal with requests and connections
198 * Hmmm, that doesn't work: we don't have a usermem framework.
199 * OK, forget about using APR pools here, until we figure out
200 * the right way to do it (if such a thing exists).
202 static OCIEnv *dbd_oracle_env = NULL;
203 #ifdef GLOBAL_PREPARED_STATEMENTS
204 static apr_hash_t *oracle_statements = NULL;
205 #endif
207 /* Oracle specific bucket for BLOB/CLOB types */
208 typedef struct apr_bucket_lob apr_bucket_lob;
210 * A bucket referring to a Oracle BLOB/CLOB
212 struct apr_bucket_lob {
213 /** Number of buckets using this memory */
214 apr_bucket_refcount refcount;
215 /** The row this bucket refers to */
216 const apr_dbd_row_t *row;
217 /** The column this bucket refers to */
218 int col;
219 /** The pool into which any needed structures should
220 * be created while reading from this bucket */
221 apr_pool_t *readpool;
224 static void lob_bucket_destroy(void *data);
225 static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
226 apr_size_t *len, apr_read_type_e block);
227 static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
228 const apr_dbd_row_t *row, int col,
229 apr_off_t offset, apr_size_t len,
230 apr_pool_t *p);
231 static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
232 apr_off_t offset,
233 apr_size_t len, apr_pool_t *p,
234 apr_bucket_alloc_t *list);
236 static const apr_bucket_type_t apr_bucket_type_lob = {
237 "LOB", 5, APR_BUCKET_DATA,
238 lob_bucket_destroy,
239 lob_bucket_read,
240 apr_bucket_setaside_notimpl,
241 apr_bucket_shared_split,
242 apr_bucket_shared_copy
245 static void lob_bucket_destroy(void *data)
247 apr_bucket_lob *f = data;
249 if (apr_bucket_shared_destroy(f)) {
250 /* no need to destroy database objects here; it will get
251 * done automatically when the pool gets cleaned up */
252 apr_bucket_free(f);
256 static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
257 apr_size_t *len, apr_read_type_e block)
259 apr_bucket_lob *a = e->data;
260 const apr_dbd_row_t *row = a->row;
261 apr_dbd_results_t *res = row->res;
262 int col = a->col;
263 apr_bucket *b = NULL;
264 apr_size_t blength = e->length; /* bytes remaining in file past offset */
265 apr_off_t boffset = e->start;
266 define_arg *val = &res->statement->out[col];
267 apr_dbd_t *sql = res->handle;
268 /* Only with 10g, unfortunately
269 oraub8 length = APR_BUCKET_BUFF_SIZE;
271 ub4 length = APR_BUCKET_BUFF_SIZE;
272 char *buf = NULL;
274 *str = NULL; /* in case we die prematurely */
276 /* fetch from offset if not at the beginning */
277 buf = apr_palloc(row->pool, APR_BUCKET_BUFF_SIZE);
278 sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
279 &length, 1 + boffset,
280 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
281 NULL, NULL, 0, SQLCS_IMPLICIT);
282 /* Only with 10g, unfortunately
283 sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,
284 &length, NULL, 1 + boffset,
285 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
286 OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
288 if (sql->status != OCI_SUCCESS) {
289 return APR_EGENERAL;
291 blength -= length;
292 *len = length;
293 *str = buf;
296 * Change the current bucket to refer to what we read,
297 * even if we read nothing because we hit EOF.
299 apr_bucket_pool_make(e, *str, *len, res->pool);
301 /* If we have more to read from the field, then create another bucket */
302 if (blength > 0) {
303 /* for efficiency, we can just build a new apr_bucket struct
304 * to wrap around the existing LOB bucket */
305 b = apr_bucket_alloc(sizeof(*b), e->list);
306 b->start = boffset + *len;
307 b->length = blength;
308 b->data = a;
309 b->type = &apr_bucket_type_lob;
310 b->free = apr_bucket_free;
311 b->list = e->list;
312 APR_BUCKET_INSERT_AFTER(e, b);
314 else {
315 lob_bucket_destroy(a);
318 return APR_SUCCESS;
321 static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
322 const apr_dbd_row_t *row, int col,
323 apr_off_t offset, apr_size_t len,
324 apr_pool_t *p)
326 apr_bucket_lob *f;
328 f = apr_bucket_alloc(sizeof(*f), b->list);
329 f->row = row;
330 f->col = col;
331 f->readpool = p;
333 b = apr_bucket_shared_make(b, f, offset, len);
334 b->type = &apr_bucket_type_lob;
336 return b;
339 static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
340 apr_off_t offset,
341 apr_size_t len, apr_pool_t *p,
342 apr_bucket_alloc_t *list)
344 apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
346 APR_BUCKET_INIT(b);
347 b->free = apr_bucket_free;
348 b->list = list;
349 return apr_bucket_lob_make(b, row, col, offset, len, p);
352 static apr_status_t dbd_free_lobdesc(void *lob)
354 switch (OCIDescriptorFree(lob, OCI_DTYPE_LOB)) {
355 case OCI_SUCCESS:
356 return APR_SUCCESS;
357 default:
358 return APR_EGENERAL;
362 static apr_status_t dbd_free_snapshot(void *snap)
364 switch (OCIDescriptorFree(snap, OCI_DTYPE_SNAP)) {
365 case OCI_SUCCESS:
366 return APR_SUCCESS;
367 default:
368 return APR_EGENERAL;
372 #ifdef GLOBAL_PREPARED_STATEMENTS
373 static apr_status_t freeStatements(void *ptr)
375 apr_status_t rv = APR_SUCCESS;
376 OCIStmt *stmt;
377 apr_hash_index_t *index;
378 apr_pool_t *cachepool = apr_hash_pool_get(oracle_statements);
380 #ifdef PREPARE2
381 OCIError *err;
383 if (OCIHandleAlloc(dbd_oracle_env, (dvoid**)&err, OCI_HTYPE_ERROR, 0, NULL)
384 != OCI_SUCCESS) {
385 return APR_EGENERAL;
387 #endif
389 for (index = apr_hash_first(cachepool, oracle_statements);
390 index != NULL;
391 index = apr_hash_next(index)) {
392 apr_hash_this(index, NULL, NULL, (void**)&stmt);
393 #ifdef PREPARE2
394 if (OCIStmtRelease(stmt, err, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS) {
395 rv = APR_EGENERAL;
397 #else
398 if (OCIHandleFree(stmt, OCI_HTYPE_STMT) != OCI_SUCCESS) {
399 rv = APR_EGENERAL;
401 #endif
403 #ifdef PREPARE2
404 if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) {
405 rv = APR_EGENERAL;
407 #endif
408 return rv;
410 #endif
412 static void dbd_oracle_init(apr_pool_t *pool)
414 if (dbd_oracle_env == NULL) {
415 /* Sadly, OCI_SHARED seems to be impossible to use, due to
416 * various Oracle bugs. See, for example, Oracle MetaLink bug 2972890
417 * and PHP bug http://bugs.php.net/bug.php?id=23733
419 #ifdef OCI_NEW_LENGTH_SEMANTICS
420 OCIEnvCreate(&dbd_oracle_env, OCI_THREADED|OCI_NEW_LENGTH_SEMANTICS,
421 NULL, NULL, NULL, NULL, 0, NULL);
422 #else
423 OCIEnvCreate(&dbd_oracle_env, OCI_THREADED,
424 NULL, NULL, NULL, NULL, 0, NULL);
425 #endif
427 #ifdef GLOBAL_PREPARED_STATEMENTS
428 if (oracle_statements == NULL) {
430 oracle_statements = apr_hash_make(pool);
431 apr_pool_cleanup_register(pool, oracle_statements,
432 freeStatements, apr_pool_cleanup_null);
434 #endif
437 static apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params)
439 apr_dbd_t *ret = apr_pcalloc(pool, sizeof(apr_dbd_t));
440 int_errorcode;
442 char *BLANK = "";
443 struct {
444 const char *field;
445 char *value;
446 } fields[] = {
447 {"user", BLANK},
448 {"pass", BLANK},
449 {"dbname", BLANK},
450 {"server", BLANK},
451 {NULL, NULL}
453 int i;
454 const char *ptr;
455 const char *key;
456 size_t klen;
457 const char *value;
458 size_t vlen;
459 static const char *const delims = " \r\n\t;|,";
461 ret->long_size = DEFAULT_LONG_SIZE;
463 /* Use our own pool, to avoid possible race conditions
464 * on pool ops
466 if (apr_pool_create(&ret->pool, pool) != APR_SUCCESS) {
467 return NULL;
470 /* snitch parsing from the MySQL driver */
471 for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {
472 for (key = ptr-1; isspace(*key); --key);
473 klen = 0;
474 while (isalpha(*key)) {
475 if (key == params) {
476 /* Don't parse off the front of the params */
477 --key;
478 ++klen;
479 break;
481 --key;
482 ++klen;
484 ++key;
485 for (value = ptr+1; isspace(*value); ++value);
486 vlen = strcspn(value, delims);
487 for (i=0; fields[i].field != NULL; ++i) {
488 if (!strncasecmp(fields[i].field, key, klen)) {
489 fields[i].value = apr_pstrndup(pool, value, vlen);
490 break;
493 ptr = value+vlen;
496 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->err,
497 OCI_HTYPE_ERROR, 0, NULL);
498 switch (ret->status) {
499 default:
500 #ifdef DEBUG
501 printf("ret->status is %d\n", ret->status);
502 break;
503 #else
504 return NULL;
505 #endif
506 case OCI_SUCCESS:
507 break;
510 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svr,
511 OCI_HTYPE_SERVER, 0, NULL);
512 switch (ret->status) {
513 default:
514 #ifdef DEBUG
515 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
516 sizeof(ret->buf), OCI_HTYPE_ERROR);
517 printf("OPEN ERROR %d (alloc svr): %s\n", ret->status, ret->buf);
518 break;
519 #else
520 return NULL;
521 #endif
522 case OCI_SUCCESS:
523 break;
526 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svc,
527 OCI_HTYPE_SVCCTX, 0, NULL);
528 switch (ret->status) {
529 default:
530 #ifdef DEBUG
531 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
532 sizeof(ret->buf), OCI_HTYPE_ERROR);
533 printf("OPEN ERROR %d (alloc svc): %s\n", ret->status, ret->buf);
534 break;
535 #else
536 return NULL;
537 #endif
538 case OCI_SUCCESS:
539 break;
542 /* All the examples use the #else */
543 #if CAN_DO_LOGIN
544 ret->status = OCILogon(dbd_oracle_env, ret->err, &ret->svc, fields[0].value,
545 strlen(fields[0].value), fields[1].value,
546 strlen(fields[1].value), fields[2].value,
547 strlen(fields[2].value));
548 switch (ret->status) {
549 default:
550 #ifdef DEBUG
551 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
552 sizeof(ret->buf), OCI_HTYPE_ERROR);
553 printf("OPEN ERROR: %s\n", ret->buf);
554 break;
555 #else
556 return NULL;
557 #endif
558 case OCI_SUCCESS:
559 break;
561 #else
562 ret->status = OCIServerAttach(ret->svr, ret->err, (text*) fields[3].value,
563 strlen(fields[3].value), OCI_DEFAULT);
564 switch (ret->status) {
565 default:
566 #ifdef DEBUG
567 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
568 sizeof(ret->buf), OCI_HTYPE_ERROR);
569 printf("OPEN ERROR %d (server attach): %s\n", ret->status, ret->buf);
570 break;
571 #else
572 return NULL;
573 #endif
574 case OCI_SUCCESS:
575 break;
577 ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->svr, 0,
578 OCI_ATTR_SERVER, ret->err);
579 switch (ret->status) {
580 default:
581 #ifdef DEBUG
582 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
583 sizeof(ret->buf), OCI_HTYPE_ERROR);
584 printf("OPEN ERROR %d (attr set): %s\n", ret->status, ret->buf);
585 break;
586 #else
587 return NULL;
588 #endif
589 case OCI_SUCCESS:
590 break;
592 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->auth,
593 OCI_HTYPE_SESSION, 0, NULL);
594 switch (ret->status) {
595 default:
596 #ifdef DEBUG
597 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
598 sizeof(ret->buf), OCI_HTYPE_ERROR);
599 printf("OPEN ERROR %d (alloc auth): %s\n", ret->status, ret->buf);
600 break;
601 #else
602 return NULL;
603 #endif
604 case OCI_SUCCESS:
605 break;
607 ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[0].value,
608 strlen(fields[0].value), OCI_ATTR_USERNAME, ret->err);
609 switch (ret->status) {
610 default:
611 #ifdef DEBUG
612 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
613 sizeof(ret->buf), OCI_HTYPE_ERROR);
614 printf("OPEN ERROR %d (attr username): %s\n", ret->status, ret->buf);
615 break;
616 #else
617 return NULL;
618 #endif
619 case OCI_SUCCESS:
620 break;
622 ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[1].value,
623 strlen(fields[1].value), OCI_ATTR_PASSWORD, ret->err);
624 switch (ret->status) {
625 default:
626 #ifdef DEBUG
627 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
628 sizeof(ret->buf), OCI_HTYPE_ERROR);
629 printf("OPEN ERROR %d (attr password): %s\n", ret->status, ret->buf);
630 break;
631 #else
632 return NULL;
633 #endif
634 case OCI_SUCCESS:
635 break;
637 ret->status = OCISessionBegin(ret->svc, ret->err, ret->auth,
638 OCI_CRED_RDBMS, OCI_DEFAULT);
639 switch (ret->status) {
640 default:
641 #ifdef DEBUG
642 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
643 sizeof(ret->buf), OCI_HTYPE_ERROR);
644 printf("OPEN ERROR %d (session begin): %s\n", ret->status, ret->buf);
645 break;
646 #else
647 return NULL;
648 #endif
649 case OCI_SUCCESS:
650 break;
652 ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->auth, 0,
653 OCI_ATTR_SESSION, ret->err);
654 switch (ret->status) {
655 default:
656 #ifdef DEBUG
657 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
658 sizeof(ret->buf), OCI_HTYPE_ERROR);
659 printf("OPEN ERROR %d (attr session): %s\n", ret->status, ret->buf);
660 #else
661 return NULL;
662 #endif
663 break;
664 case OCI_SUCCESS:
665 break;
667 #endif
668 return ret;
671 #ifdef EXPORT_NATIVE_FUNCS
672 static apr_size_t dbd_oracle_long_size_set(apr_dbd_t *sql,
673 apr_size_t long_size)
675 apr_size_t old_size = sql->long_size;
676 sql->long_size = long_size;
677 return old_size;
679 #endif
681 static const char *dbd_oracle_get_name(const apr_dbd_results_t *res, int n)
683 define_arg *val = &res->statement->out[n];
685 if ((n < 0) || (n >= res->statement->nout)) {
686 return NULL;
688 return val->name;
691 static int dbd_oracle_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
692 apr_dbd_row_t **rowp, int rownum)
694 apr_dbd_row_t *row = *rowp;
695 apr_dbd_t *sql = res->handle;
696 int_errorcode;
698 if (row == NULL) {
699 row = apr_palloc(pool, sizeof(apr_dbd_row_t));
700 *rowp = row;
701 row->res = res;
702 /* Oracle starts counting at 1 according to the docs */
703 row->n = res->seek ? rownum : 1;
704 row->pool = pool;
706 else {
707 if (res->seek) {
708 row->n = rownum;
710 else {
711 ++row->n;
715 if (res->seek) {
716 sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
717 OCI_FETCH_ABSOLUTE, row->n, OCI_DEFAULT);
719 else {
720 sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
721 OCI_FETCH_NEXT, 0, OCI_DEFAULT);
723 switch (sql->status) {
724 case OCI_SUCCESS:
725 (*rowp)->res = res;
726 return 0;
727 case OCI_NO_DATA:
728 return -1;
729 case OCI_ERROR:
730 #ifdef DEBUG
731 OCIErrorGet(sql->err, 1, NULL, &errorcode,
732 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
733 printf("Execute error %d: %s\n", sql->status, sql->buf);
734 #endif
735 /* fallthrough */
736 default:
737 return 1;
739 return 0;
742 static const char *dbd_oracle_error(apr_dbd_t *sql, int n)
744 /* This is ugly. Needs us to pass in a buffer of unknown size.
745 * Either we put it on the handle, or we have to keep allocing/copying
747 sb4 errorcode;
749 switch (sql->status) {
750 case OCI_SUCCESS:
751 return "OCI_SUCCESS";
752 case OCI_SUCCESS_WITH_INFO:
753 return "OCI_SUCCESS_WITH_INFO";
754 case OCI_NEED_DATA:
755 return "OCI_NEED_DATA";
756 case OCI_NO_DATA:
757 return "OCI_NO_DATA";
758 case OCI_INVALID_HANDLE:
759 return "OCI_INVALID_HANDLE";
760 case OCI_STILL_EXECUTING:
761 return "OCI_STILL_EXECUTING";
762 case OCI_CONTINUE:
763 return "OCI_CONTINUE";
766 switch (OCIErrorGet(sql->err, 1, NULL, &errorcode,
767 (text*) sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR)) {
768 case OCI_SUCCESS:
769 return sql->buf;
770 default:
771 return "internal error: OCIErrorGet failed";
775 static apr_status_t freeStatement(void *statement)
777 int rv = APR_SUCCESS;
778 OCIStmt *stmt = ((apr_dbd_prepared_t*)statement)->stmt;
780 #ifdef PREPARE2
781 OCIError *err;
783 if (OCIHandleAlloc(dbd_oracle_env, (dvoid**)&err, OCI_HTYPE_ERROR,
784 0, NULL) != OCI_SUCCESS) {
785 return APR_EGENERAL;
787 if (OCIStmtRelease(stmt, err, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS) {
788 rv = APR_EGENERAL;
790 if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) {
791 rv = APR_EGENERAL;
793 #else
794 if (OCIHandleFree(stmt, OCI_HTYPE_STMT) != OCI_SUCCESS) {
795 rv = APR_EGENERAL;
797 #endif
799 return rv;
802 static int dbd_oracle_select(apr_pool_t *pool, apr_dbd_t *sql,
803 apr_dbd_results_t **results,
804 const char *query, int seek)
806 int ret = 0;
807 apr_dbd_prepared_t *statement = NULL;
809 ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
810 if (ret != 0) {
811 return ret;
814 ret = dbd_oracle_pselect(pool, sql, results, statement, seek, NULL);
815 if (ret != 0) {
816 return ret;
819 return ret;
822 static int dbd_oracle_query(apr_dbd_t *sql, int *nrows, const char *query)
824 int ret = 0;
825 apr_pool_t *pool;
826 apr_dbd_prepared_t *statement = NULL;
828 if (sql->trans && sql->trans->status == TRANS_ERROR) {
829 return 1;
832 /* make our own pool so that APR allocations don't linger and so that
833 * both Stmt and LOB handles are cleaned up (LOB handles may be
834 * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs)
836 apr_pool_create(&pool, sql->pool);
838 ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
839 if (ret == 0) {
840 ret = dbd_oracle_pquery(pool, sql, nrows, statement, NULL);
841 if (ret == 0) {
842 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT,
843 nrows, 0, OCI_ATTR_ROW_COUNT,
844 sql->err);
848 apr_pool_destroy(pool);
850 return ret;
853 static const char *dbd_oracle_escape(apr_pool_t *pool, const char *arg,
854 apr_dbd_t *sql)
856 return arg; /* OCI has no concept of string escape */
859 static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
860 const char *query, const char *label,
861 int nargs, int nvals, apr_dbd_type_e *types,
862 apr_dbd_prepared_t **statement)
864 int ret = 0;
865 int i;
866 apr_dbd_prepared_t *stmt ;
868 /* prepared statements in a global lookup table would be nice,
869 * but we can't do that here because our pool may die leaving
870 * the cached statement orphaned.
871 * OTOH we can do that with Oracle statements, which aren't on
872 * the pool, so long as we don't register a cleanup on our pool!
874 * FIXME:
875 * There's a race condition between cache-lookup and cache-set
876 * But the worst outcome is a statement prepared more than once
877 * and leaked. Is that worth mutexing for?
878 * Hmmm, yes it probably is ... OK, done
881 if (*statement == NULL) {
882 *statement = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t));
884 stmt = *statement;
885 stmt->handle = sql;
886 stmt->pool = pool;
887 stmt->nargs = nargs;
888 stmt->nvals = nvals;
890 /* If we have a label, we're going to cache it globally.
891 * Check first if we already have it. If not, prepare the
892 * statement under mutex, so we don't end up leaking
893 * concurrent statements
895 * FIXME: Oracle docs say a statement can be used even across
896 * multiple servers, so I assume this is safe .....
898 #ifdef GLOBAL_PREPARED_STATEMENTS
899 if (label != NULL) {
900 stmt->stmt = apr_hash_get(oracle_statements, label, APR_HASH_KEY_STRING);
901 if (stmt->stmt != NULL) {
902 return ret;
904 apr_dbd_mutex_lock();
905 stmt->stmt = apr_hash_get(oracle_statements, label, APR_HASH_KEY_STRING);
906 if (stmt->stmt != NULL) {
907 apr_dbd_mutex_unlock();
908 return ret;
911 #endif
913 /* populate our own args, if any */
914 if (nargs > 0) {
915 stmt->args = apr_pcalloc(pool, nargs*sizeof(bind_arg));
916 for (i = 0; i < nargs; i++) {
917 stmt->args[i].type = types[i];
921 sql->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**) &stmt->stmt,
922 OCI_HTYPE_STMT, 0, NULL);
923 if (sql->status != OCI_SUCCESS) {
924 apr_dbd_mutex_unlock();
925 return 1;
928 sql->status = OCIStmtPrepare(stmt->stmt, sql->err, (text*) query,
929 strlen(query), OCI_NTV_SYNTAX, OCI_DEFAULT);
930 if (sql->status != OCI_SUCCESS) {
931 OCIHandleFree(stmt->stmt, OCI_HTYPE_STMT);
932 apr_dbd_mutex_unlock();
933 return 1;
936 apr_pool_cleanup_register(pool, stmt, freeStatement,
937 apr_pool_cleanup_null);
939 /* Perl gets statement type here */
940 sql->status = OCIAttrGet(stmt->stmt, OCI_HTYPE_STMT, &stmt->type, 0,
941 OCI_ATTR_STMT_TYPE, sql->err);
942 if (sql->status != OCI_SUCCESS) {
943 apr_dbd_mutex_unlock();
944 return 1;
947 /* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
948 #if 0
949 sql->status = OCIAttrSet(stmt->stmt, OCI_HTYPE_STMT, &prefetch_size,
950 sizeof(prefetch_size), OCI_ATTR_PREFETCH_MEMORY,
951 sql->err);
952 if (sql->status != OCI_SUCCESS) {
953 apr_dbd_mutex_unlock();
954 return 1;
956 #endif
958 if (stmt->type == OCI_STMT_SELECT) {
959 ret = outputParams(sql, stmt);
961 #ifdef GLOBAL_PREPARED_STATEMENTS
962 if (label != NULL) {
963 apr_hash_set(oracle_statements, label, APR_HASH_KEY_STRING, stmt->stmt);
964 apr_dbd_mutex_unlock();
966 #endif
967 return ret;
970 static void dbd_oracle_bind(apr_dbd_prepared_t *statement, const char **values)
972 OCIStmt *stmt = statement->stmt;
973 apr_dbd_t *sql = statement->handle;
974 int i, j;
975 sb2 null_ind = -1;
977 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
978 if (values[j] == NULL) {
979 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
980 sql->err, i + 1,
981 NULL, 0, SQLT_STR,
982 &null_ind, NULL,
983 (ub2) 0, (ub4) 0,
984 (ub4 *) 0, OCI_DEFAULT);
986 else {
987 switch (statement->args[i].type) {
988 case APR_DBD_TYPE_BLOB:
990 char *data = (char *)values[j];
991 int size = atoi((char*)values[++j]);
993 /* skip table and column for now */
994 j += 2;
996 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
997 sql->err, i + 1,
998 data, size, SQLT_LBI,
999 &statement->args[i].ind,
1000 NULL,
1001 (ub2) 0, (ub4) 0,
1002 (ub4 *) 0, OCI_DEFAULT);
1004 break;
1005 case APR_DBD_TYPE_CLOB:
1007 char *data = (char *)values[j];
1008 int size = atoi((char*)values[++j]);
1010 /* skip table and column for now */
1011 j += 2;
1013 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1014 sql->err, i + 1,
1015 data, size, SQLT_LNG,
1016 &statement->args[i].ind,
1017 NULL,
1018 (ub2) 0, (ub4) 0,
1019 (ub4 *) 0, OCI_DEFAULT);
1021 break;
1022 default:
1023 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1024 sql->err, i + 1,
1025 (dvoid*) values[j],
1026 strlen(values[j]) + 1,
1027 SQLT_STR,
1028 &statement->args[i].ind,
1029 NULL,
1030 (ub2) 0, (ub4) 0,
1031 (ub4 *) 0, OCI_DEFAULT);
1032 break;
1036 if (sql->status != OCI_SUCCESS) {
1037 return;
1041 return;
1044 static int outputParams(apr_dbd_t *sql, apr_dbd_prepared_t *stmt)
1046 OCIParam *parms;
1047 int i;
1048 int_errorcode;
1049 ub2 paramtype[DBD_ORACLE_MAX_COLUMNS];
1050 ub2 paramsize[DBD_ORACLE_MAX_COLUMNS];
1051 const char *paramname[DBD_ORACLE_MAX_COLUMNS];
1052 ub4 paramnamelen[DBD_ORACLE_MAX_COLUMNS];
1053 /* Perl uses 0 where we used 1 */
1054 sql->status = OCIStmtExecute(sql->svc, stmt->stmt, sql->err, 0, 0,
1055 NULL, NULL, OCI_DESCRIBE_ONLY);
1056 switch (sql->status) {
1057 case OCI_SUCCESS:
1058 case OCI_SUCCESS_WITH_INFO:
1059 break;
1060 case OCI_ERROR:
1061 #ifdef DEBUG
1062 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1063 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1064 printf("Describing prepared statement: %s\n", sql->buf);
1065 #endif
1066 default:
1067 return 1;
1069 while (sql->status == OCI_SUCCESS) {
1070 sql->status = OCIParamGet(stmt->stmt, OCI_HTYPE_STMT,
1071 sql->err, (dvoid**)&parms, stmt->nout+1);
1072 switch (sql->status) {
1073 case OCI_SUCCESS:
1074 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1075 &paramtype[stmt->nout],
1076 0, OCI_ATTR_DATA_TYPE, sql->err);
1077 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1078 &paramsize[stmt->nout],
1079 0, OCI_ATTR_DATA_SIZE, sql->err);
1080 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1081 &paramname[stmt->nout],
1082 &paramnamelen[stmt->nout],
1083 OCI_ATTR_NAME, sql->err);
1084 ++stmt->nout;
1087 switch (sql->status) {
1088 case OCI_SUCCESS:
1089 break;
1090 case OCI_ERROR:
1091 break; /* this is what we expect at end-of-loop */
1092 default:
1093 return 1;
1096 /* OK, the above works. We have the params; now OCIDefine them */
1097 stmt->out = apr_palloc(stmt->pool, stmt->nout*sizeof(define_arg));
1098 for (i=0; i<stmt->nout; ++i) {
1099 stmt->out[i].type = paramtype[i];
1100 stmt->out[i].len = stmt->out[i].sz = paramsize[i];
1101 stmt->out[i].name = apr_pstrmemdup(stmt->pool,
1102 paramname[i], paramnamelen[i]);
1103 switch (stmt->out[i].type) {
1104 default:
1105 switch (stmt->out[i].type) {
1106 case SQLT_NUM: /* 2: numeric, Perl worst case=130+38+3 */
1107 stmt->out[i].sz = 171;
1108 break;
1109 case SQLT_CHR: /* 1: char */
1110 case SQLT_AFC: /* 96: ANSI fixed char */
1111 stmt->out[i].sz *= 4; /* ugh, wasteful UCS-4 handling */
1112 break;
1113 case SQLT_DAT: /* 12: date, depends on NLS date format */
1114 stmt->out[i].sz = 75;
1115 break;
1116 case SQLT_BIN: /* 23: raw binary, perhaps UTF-16? */
1117 stmt->out[i].sz *= 2;
1118 break;
1119 case SQLT_RID: /* 11: rowid */
1120 case SQLT_RDD: /* 104: rowid descriptor */
1121 stmt->out[i].sz = 20;
1122 break;
1123 case SQLT_TIMESTAMP: /* 187: timestamp */
1124 case SQLT_TIMESTAMP_TZ: /* 188: timestamp with time zone */
1125 case SQLT_INTERVAL_YM: /* 189: interval year-to-month */
1126 case SQLT_INTERVAL_DS: /* 190: interval day-to-second */
1127 case SQLT_TIMESTAMP_LTZ: /* 232: timestamp with local time zone */
1128 stmt->out[i].sz = 75;
1129 break;
1130 default:
1131 #ifdef DEBUG
1132 printf("Unsupported data type: %d\n", stmt->out[i].type);
1133 #endif
1134 break;
1136 ++stmt->out[i].sz;
1137 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1138 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1139 sql->err, i+1,
1140 stmt->out[i].buf.sval,
1141 stmt->out[i].sz, SQLT_STR,
1142 &stmt->out[i].ind, &stmt->out[i].len,
1143 0, OCI_DEFAULT);
1144 break;
1145 case SQLT_LNG: /* 8: long */
1146 stmt->out[i].sz = sql->long_size * 4 + 4; /* ugh, UCS-4 handling */
1147 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1148 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1149 sql->err, i+1,
1150 stmt->out[i].buf.raw,
1151 stmt->out[i].sz, SQLT_LVC,
1152 &stmt->out[i].ind, NULL,
1153 0, OCI_DEFAULT);
1154 break;
1155 case SQLT_LBI: /* 24: long binary, perhaps UTF-16? */
1156 stmt->out[i].sz = sql->long_size * 2 + 4; /* room for int prefix */
1157 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1158 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1159 sql->err, i+1,
1160 stmt->out[i].buf.raw,
1161 stmt->out[i].sz, SQLT_LVB,
1162 &stmt->out[i].ind, NULL,
1163 0, OCI_DEFAULT);
1164 break;
1165 case SQLT_BLOB: /* 113 */
1166 case SQLT_CLOB: /* 112 */
1167 /*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1168 sql->status = OCIDescriptorAlloc(dbd_oracle_env,
1169 (dvoid**)&stmt->out[i].buf.lobval,
1170 OCI_DTYPE_LOB, 0, NULL);
1171 apr_pool_cleanup_register(stmt->pool, stmt->out[i].buf.lobval,
1172 dbd_free_lobdesc,
1173 apr_pool_cleanup_null);
1174 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1175 sql->err, i+1,
1176 (dvoid*) &stmt->out[i].buf.lobval,
1177 -1, stmt->out[i].type,
1178 &stmt->out[i].ind, &stmt->out[i].len,
1179 0, OCI_DEFAULT);
1180 break;
1182 switch (sql->status) {
1183 case OCI_SUCCESS:
1184 break;
1185 default:
1186 return 1;
1189 return 0;
1192 static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
1193 int *nrows, apr_dbd_prepared_t *statement,
1194 const char **values)
1196 int_errorcode;
1197 OCISnapshot *oldsnapshot = NULL;
1198 OCISnapshot *newsnapshot = NULL;
1199 apr_dbd_transaction_t* trans = sql->trans;
1200 int exec_mode;
1202 if (trans) {
1203 switch (trans->status) {
1204 case TRANS_ERROR:
1205 return -1;
1206 case TRANS_NONE:
1207 trans = NULL;
1208 break;
1209 case TRANS_1:
1210 oldsnapshot = trans->snapshot1;
1211 newsnapshot = trans->snapshot2;
1212 trans->status = TRANS_2;
1213 break;
1214 case TRANS_2:
1215 oldsnapshot = trans->snapshot2;
1216 newsnapshot = trans->snapshot1;
1217 trans->status = TRANS_1;
1218 break;
1220 exec_mode = OCI_DEFAULT;
1222 else {
1223 exec_mode = OCI_COMMIT_ON_SUCCESS;
1226 dbd_oracle_bind(statement, values);
1228 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1229 oldsnapshot, newsnapshot, exec_mode);
1230 switch (sql->status) {
1231 case OCI_SUCCESS:
1232 break;
1233 case OCI_ERROR:
1234 #ifdef DEBUG
1235 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1236 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1237 printf("Execute error %d: %s\n", sql->status, sql->buf);
1238 #endif
1239 /* fallthrough */
1240 default:
1241 if (TXN_NOTICE_ERRORS(trans)) {
1242 trans->status = TRANS_ERROR;
1244 return 1;
1247 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1248 OCI_ATTR_ROW_COUNT, sql->err);
1249 return 0;
1252 static int dbd_oracle_pvquery(apr_pool_t *pool, apr_dbd_t *sql,
1253 int *nrows, apr_dbd_prepared_t *statement,
1254 va_list args)
1256 const char **values;
1257 int i;
1259 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1260 return -1;
1263 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1265 for (i = 0; i < statement->nvals; i++) {
1266 values[i] = va_arg(args, const char*);
1269 return dbd_oracle_pquery(pool, sql, nrows, statement, values);
1272 static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
1273 apr_dbd_results_t **results,
1274 apr_dbd_prepared_t *statement,
1275 int seek, const char **values)
1277 int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1278 OCISnapshot *oldsnapshot = NULL;
1279 OCISnapshot *newsnapshot = NULL;
1280 apr_dbd_transaction_t* trans = sql->trans;
1282 if (trans) {
1283 switch (trans->status) {
1284 case TRANS_ERROR:
1285 return 1;
1286 case TRANS_NONE:
1287 trans = NULL;
1288 break;
1289 case TRANS_1:
1290 oldsnapshot = trans->snapshot1;
1291 newsnapshot = trans->snapshot2;
1292 trans->status = TRANS_2;
1293 break;
1294 case TRANS_2:
1295 oldsnapshot = trans->snapshot2;
1296 newsnapshot = trans->snapshot1;
1297 trans->status = TRANS_1;
1298 break;
1302 dbd_oracle_bind(statement, values);
1304 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1305 oldsnapshot, newsnapshot, exec_mode);
1306 switch (sql->status) {
1307 int_errorcode;
1308 case OCI_SUCCESS:
1309 break;
1310 case OCI_ERROR:
1311 #ifdef DEBUG
1312 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1313 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1314 printf("Executing prepared statement: %s\n", sql->buf);
1315 #endif
1316 /* fallthrough */
1317 default:
1318 if (TXN_NOTICE_ERRORS(trans)) {
1319 trans->status = TRANS_ERROR;
1321 return 1;
1324 if (!*results) {
1325 *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1327 (*results)->handle = sql;
1328 (*results)->statement = statement;
1329 (*results)->seek = seek;
1330 (*results)->rownum = seek ? 0 : -1;
1331 (*results)->pool = pool;
1333 return 0;
1336 static int dbd_oracle_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
1337 apr_dbd_results_t **results,
1338 apr_dbd_prepared_t *statement,
1339 int seek, va_list args)
1341 const char **values;
1342 int i;
1344 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1345 return -1;
1348 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1350 for (i = 0; i < statement->nvals; i++) {
1351 values[i] = va_arg(args, const char*);
1354 return dbd_oracle_pselect(pool, sql, results, statement, seek, values);
1357 static void dbd_oracle_bbind(apr_dbd_prepared_t * statement,
1358 const void **values)
1360 OCIStmt *stmt = statement->stmt;
1361 apr_dbd_t *sql = statement->handle;
1362 int i, j;
1363 sb2 null_ind = -1;
1364 apr_dbd_type_e type;
1366 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
1367 type = (values[j] == NULL ? APR_DBD_TYPE_NULL
1368 : statement->args[i].type);
1370 switch (type) {
1371 case APR_DBD_TYPE_TINY:
1372 statement->args[i].value.ival = *(char*)values[j];
1373 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1374 sql->err, i + 1,
1375 &statement->args[i].value.ival,
1376 sizeof(statement->args[i].value.ival),
1377 SQLT_INT,
1378 &statement->args[i].ind, NULL,
1379 (ub2) 0, (ub4) 0,
1380 (ub4 *) 0, OCI_DEFAULT);
1381 break;
1382 case APR_DBD_TYPE_UTINY:
1383 statement->args[i].value.uval = *(unsigned char*)values[j];
1384 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1385 sql->err, i + 1,
1386 &statement->args[i].value.uval,
1387 sizeof(statement->args[i].value.uval),
1388 SQLT_UIN,
1389 &statement->args[i].ind, NULL,
1390 (ub2) 0, (ub4) 0,
1391 (ub4 *) 0, OCI_DEFAULT);
1392 break;
1393 case APR_DBD_TYPE_SHORT:
1394 statement->args[i].value.ival = *(short*)values[j];
1395 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1396 sql->err, i + 1,
1397 &statement->args[i].value.ival,
1398 sizeof(statement->args[i].value.ival),
1399 SQLT_INT,
1400 &statement->args[i].ind, NULL,
1401 (ub2) 0, (ub4) 0,
1402 (ub4 *) 0, OCI_DEFAULT);
1403 break;
1404 case APR_DBD_TYPE_USHORT:
1405 statement->args[i].value.uval = *(unsigned short*)values[j];
1406 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1407 sql->err, i + 1,
1408 &statement->args[i].value.uval,
1409 sizeof(statement->args[i].value.uval),
1410 SQLT_UIN,
1411 &statement->args[i].ind, NULL,
1412 (ub2) 0, (ub4) 0,
1413 (ub4 *) 0, OCI_DEFAULT);
1414 break;
1415 case APR_DBD_TYPE_INT:
1416 statement->args[i].value.ival = *(int*)values[j];
1417 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1418 sql->err, i + 1,
1419 &statement->args[i].value.ival,
1420 sizeof(statement->args[i].value.ival),
1421 SQLT_INT,
1422 &statement->args[i].ind, NULL,
1423 (ub2) 0, (ub4) 0,
1424 (ub4 *) 0, OCI_DEFAULT);
1425 break;
1426 case APR_DBD_TYPE_UINT:
1427 statement->args[i].value.uval = *(unsigned int*)values[j];
1428 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1429 sql->err, i + 1,
1430 &statement->args[i].value.uval,
1431 sizeof(statement->args[i].value.uval),
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_LONG:
1438 statement->args[i].value.sval =
1439 apr_psprintf(statement->pool, "%ld", *(long*)values[j]);
1440 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1441 sql->err, i + 1,
1442 statement->args[i].value.sval,
1443 strlen(statement->args[i].value.sval)+1,
1444 SQLT_STR,
1445 &statement->args[i].ind, NULL,
1446 (ub2) 0, (ub4) 0,
1447 (ub4 *) 0, OCI_DEFAULT);
1448 break;
1449 case APR_DBD_TYPE_ULONG:
1450 statement->args[i].value.sval =
1451 apr_psprintf(statement->pool, "%lu",
1452 *(unsigned long*)values[j]);
1453 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1454 sql->err, i + 1,
1455 statement->args[i].value.sval,
1456 strlen(statement->args[i].value.sval)+1,
1457 SQLT_STR,
1458 &statement->args[i].ind, NULL,
1459 (ub2) 0, (ub4) 0,
1460 (ub4 *) 0, OCI_DEFAULT);
1461 break;
1462 case APR_DBD_TYPE_LONGLONG:
1463 statement->args[i].value.sval =
1464 apr_psprintf(statement->pool, "%" APR_INT64_T_FMT,
1465 *(apr_int64_t*)values[j]);
1466 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1467 sql->err, i + 1,
1468 statement->args[i].value.sval,
1469 strlen(statement->args[i].value.sval)+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_ULONGLONG:
1476 statement->args[i].value.sval =
1477 apr_psprintf(statement->pool, "%" APR_UINT64_T_FMT,
1478 *(apr_uint64_t*)values[j]);
1479 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1480 sql->err, i + 1,
1481 statement->args[i].value.sval,
1482 strlen(statement->args[i].value.sval)+1,
1483 SQLT_UIN,
1484 &statement->args[i].ind, NULL,
1485 (ub2) 0, (ub4) 0,
1486 (ub4 *) 0, OCI_DEFAULT);
1487 break;
1488 case APR_DBD_TYPE_FLOAT:
1489 statement->args[i].value.fval = *(float*)values[j];
1490 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1491 sql->err, i + 1,
1492 &statement->args[i].value.fval,
1493 sizeof(statement->args[i].value.fval),
1494 SQLT_FLT,
1495 &statement->args[i].ind, NULL,
1496 (ub2) 0, (ub4) 0,
1497 (ub4 *) 0, OCI_DEFAULT);
1498 break;
1499 case APR_DBD_TYPE_DOUBLE:
1500 statement->args[i].value.fval = *(double*)values[j];
1501 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1502 sql->err, i + 1,
1503 &statement->args[i].value.fval,
1504 sizeof(statement->args[i].value.fval),
1505 SQLT_FLT,
1506 &statement->args[i].ind, NULL,
1507 (ub2) 0, (ub4) 0,
1508 (ub4 *) 0, OCI_DEFAULT);
1509 break;
1510 case APR_DBD_TYPE_STRING:
1511 case APR_DBD_TYPE_TEXT:
1512 case APR_DBD_TYPE_TIME:
1513 case APR_DBD_TYPE_DATE:
1514 case APR_DBD_TYPE_DATETIME:
1515 case APR_DBD_TYPE_TIMESTAMP:
1516 case APR_DBD_TYPE_ZTIMESTAMP:
1517 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1518 sql->err, i + 1,
1519 (dvoid*) values[j],
1520 strlen(values[j]) + 1,
1521 SQLT_STR,
1522 &statement->args[i].ind, NULL,
1523 (ub2) 0, (ub4) 0,
1524 (ub4 *) 0, OCI_DEFAULT);
1525 break;
1526 case APR_DBD_TYPE_BLOB:
1528 char *data = (char *)values[j];
1529 apr_size_t size = *(apr_size_t*)values[++j];
1531 /* skip table and column for now */
1532 j += 2;
1534 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1535 sql->err, i + 1,
1536 data, size, SQLT_LBI,
1537 &statement->args[i].ind,
1538 NULL,
1539 (ub2) 0, (ub4) 0,
1540 (ub4 *) 0, OCI_DEFAULT);
1542 break;
1543 case APR_DBD_TYPE_CLOB:
1545 char *data = (char *)values[j];
1546 apr_size_t size = *(apr_size_t*)values[++j];
1548 /* skip table and column for now */
1549 j += 2;
1551 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1552 sql->err, i + 1,
1553 data, size, SQLT_LNG,
1554 &statement->args[i].ind,
1555 NULL,
1556 (ub2) 0, (ub4) 0,
1557 (ub4 *) 0, OCI_DEFAULT);
1559 break;
1560 case APR_DBD_TYPE_NULL:
1561 default:
1562 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1563 sql->err, i + 1,
1564 NULL, 0, SQLT_STR,
1565 &null_ind, NULL,
1566 (ub2) 0, (ub4) 0,
1567 (ub4 *) 0, OCI_DEFAULT);
1568 break;
1571 if (sql->status != OCI_SUCCESS) {
1572 return;
1576 return;
1579 static int dbd_oracle_pbquery(apr_pool_t * pool, apr_dbd_t * sql,
1580 int *nrows, apr_dbd_prepared_t * statement,
1581 const void **values)
1583 int_errorcode;
1584 OCISnapshot *oldsnapshot = NULL;
1585 OCISnapshot *newsnapshot = NULL;
1586 apr_dbd_transaction_t* trans = sql->trans;
1587 int exec_mode;
1589 if (trans) {
1590 switch (trans->status) {
1591 case TRANS_ERROR:
1592 return -1;
1593 case TRANS_NONE:
1594 trans = NULL;
1595 break;
1596 case TRANS_1:
1597 oldsnapshot = trans->snapshot1;
1598 newsnapshot = trans->snapshot2;
1599 trans->status = TRANS_2;
1600 break;
1601 case TRANS_2:
1602 oldsnapshot = trans->snapshot2;
1603 newsnapshot = trans->snapshot1;
1604 trans->status = TRANS_1;
1605 break;
1607 exec_mode = OCI_DEFAULT;
1609 else {
1610 exec_mode = OCI_COMMIT_ON_SUCCESS;
1613 dbd_oracle_bbind(statement, values);
1615 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1616 oldsnapshot, newsnapshot, exec_mode);
1617 switch (sql->status) {
1618 case OCI_SUCCESS:
1619 break;
1620 case OCI_ERROR:
1621 #ifdef DEBUG
1622 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1623 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1624 printf("Execute error %d: %s\n", sql->status, sql->buf);
1625 #endif
1626 /* fallthrough */
1627 default:
1628 if (TXN_NOTICE_ERRORS(trans)) {
1629 trans->status = TRANS_ERROR;
1631 return 1;
1634 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1635 OCI_ATTR_ROW_COUNT, sql->err);
1636 return 0;
1639 static int dbd_oracle_pvbquery(apr_pool_t * pool, apr_dbd_t * sql,
1640 int *nrows, apr_dbd_prepared_t * statement,
1641 va_list args)
1643 const void **values;
1644 int i;
1646 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1647 return -1;
1650 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1652 for (i = 0; i < statement->nvals; i++) {
1653 values[i] = va_arg(args, const void*);
1656 return dbd_oracle_pbquery(pool, sql, nrows, statement, values);
1659 static int dbd_oracle_pbselect(apr_pool_t * pool, apr_dbd_t * sql,
1660 apr_dbd_results_t ** results,
1661 apr_dbd_prepared_t * statement,
1662 int seek, const void **values)
1664 int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1665 OCISnapshot *oldsnapshot = NULL;
1666 OCISnapshot *newsnapshot = NULL;
1667 apr_dbd_transaction_t* trans = sql->trans;
1669 if (trans) {
1670 switch (trans->status) {
1671 case TRANS_ERROR:
1672 return 1;
1673 case TRANS_NONE:
1674 trans = NULL;
1675 break;
1676 case TRANS_1:
1677 oldsnapshot = trans->snapshot1;
1678 newsnapshot = trans->snapshot2;
1679 trans->status = TRANS_2;
1680 break;
1681 case TRANS_2:
1682 oldsnapshot = trans->snapshot2;
1683 newsnapshot = trans->snapshot1;
1684 trans->status = TRANS_1;
1685 break;
1689 dbd_oracle_bbind(statement, values);
1691 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1692 oldsnapshot, newsnapshot, exec_mode);
1693 switch (sql->status) {
1694 int_errorcode;
1695 case OCI_SUCCESS:
1696 break;
1697 case OCI_ERROR:
1698 #ifdef DEBUG
1699 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1700 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1701 printf("Executing prepared statement: %s\n", sql->buf);
1702 #endif
1703 /* fallthrough */
1704 default:
1705 if (TXN_NOTICE_ERRORS(trans)) {
1706 trans->status = TRANS_ERROR;
1708 return 1;
1711 if (!*results) {
1712 *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1714 (*results)->handle = sql;
1715 (*results)->statement = statement;
1716 (*results)->seek = seek;
1717 (*results)->rownum = seek ? 0 : -1;
1718 (*results)->pool = pool;
1720 return 0;
1723 static int dbd_oracle_pvbselect(apr_pool_t * pool, apr_dbd_t * sql,
1724 apr_dbd_results_t ** results,
1725 apr_dbd_prepared_t * statement, int seek,
1726 va_list args)
1728 const void **values;
1729 int i;
1731 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1732 return -1;
1735 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1737 for (i = 0; i < statement->nvals; i++) {
1738 values[i] = va_arg(args, const void*);
1741 return dbd_oracle_pbselect(pool, sql, results, statement, seek, values);
1744 static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
1745 apr_dbd_transaction_t **trans)
1747 int ret = 0;
1748 int_errorcode;
1749 if (*trans) {
1750 dbd_oracle_end_transaction(*trans);
1752 else {
1753 *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
1754 OCIHandleAlloc(dbd_oracle_env, (dvoid**)&(*trans)->trans,
1755 OCI_HTYPE_TRANS, 0, 0);
1756 OCIAttrSet(sql->svc, OCI_HTYPE_SVCCTX, (*trans)->trans, 0,
1757 OCI_ATTR_TRANS, sql->err);
1761 sql->status = OCITransStart(sql->svc, sql->err, TRANS_TIMEOUT,
1762 OCI_TRANS_NEW);
1763 switch (sql->status) {
1764 case OCI_ERROR:
1765 #ifdef DEBUG
1766 OCIErrorGet(sql->err, 1, NULL, &errorcode, sql->buf,
1767 sizeof(sql->buf), OCI_HTYPE_ERROR);
1768 printf("Transaction: %s\n", sql->buf);
1769 #endif
1770 ret = 1;
1771 break;
1772 case OCI_SUCCESS:
1773 (*trans)->handle = sql;
1774 (*trans)->status = TRANS_1;
1775 sql->trans = *trans;
1776 switch (OCIDescriptorAlloc(dbd_oracle_env,
1777 (dvoid**)&(*trans)->snapshot1,
1778 OCI_DTYPE_SNAP, 0, NULL)) {
1779 case OCI_SUCCESS:
1780 apr_pool_cleanup_register(pool, (*trans)->snapshot1,
1781 dbd_free_snapshot, apr_pool_cleanup_null);
1782 break;
1783 case OCI_INVALID_HANDLE:
1784 ret = 1;
1785 break;
1787 switch (OCIDescriptorAlloc(dbd_oracle_env,
1788 (dvoid**)&(*trans)->snapshot2,
1789 OCI_DTYPE_SNAP, 0, NULL)) {
1790 case OCI_SUCCESS:
1791 apr_pool_cleanup_register(pool, (*trans)->snapshot2,
1792 dbd_free_snapshot, apr_pool_cleanup_null);
1793 break;
1794 case OCI_INVALID_HANDLE:
1795 ret = 1;
1796 break;
1798 break;
1799 default:
1800 ret = 1;
1801 break;
1803 return ret;
1806 static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans)
1808 int ret = 1; /* no transaction is an error cond */
1809 sword status;
1810 apr_dbd_t *handle = trans->handle;
1811 if (trans) {
1812 switch (trans->status) {
1813 case TRANS_NONE: /* No trans is an error here */
1814 status = OCI_ERROR;
1815 break;
1816 case TRANS_ERROR:
1817 status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1818 break;
1819 default:
1820 /* rollback on explicit rollback request */
1821 if (TXN_DO_ROLLBACK(trans)) {
1822 status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1823 } else {
1824 status = OCITransCommit(handle->svc, handle->err, OCI_DEFAULT);
1826 break;
1829 handle->trans = NULL;
1831 switch (status) {
1832 case OCI_SUCCESS:
1833 ret = 0;
1834 break;
1835 default:
1836 ret = 3;
1837 break;
1840 return ret;
1843 static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t *trans)
1845 if (!trans)
1846 return APR_DBD_TRANSACTION_COMMIT;
1848 return trans->mode;
1851 static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t *trans,
1852 int mode)
1854 if (!trans)
1855 return APR_DBD_TRANSACTION_COMMIT;
1857 return trans->mode = (mode & TXN_MODE_BITS);
1860 /* This doesn't work for BLOB because of NULLs, but it can fake it
1861 * if the BLOB is really a string
1863 static const char *dbd_oracle_get_entry(const apr_dbd_row_t *row, int n)
1865 int_errorcode;
1866 ub4 len = 0;
1867 ub1 csform = 0;
1868 ub2 csid = 0;
1869 apr_size_t buflen = 0;
1870 char *buf = NULL;
1871 define_arg *val = &row->res->statement->out[n];
1872 apr_dbd_t *sql = row->res->handle;
1874 if ((n < 0) || (n >= row->res->statement->nout) || (val->ind == -1)) {
1875 return NULL;
1878 switch (val->type) {
1879 case SQLT_BLOB:
1880 case SQLT_CLOB:
1881 sql->status = OCILobGetLength(sql->svc, sql->err, val->buf.lobval,
1882 &len);
1883 switch (sql->status) {
1884 case OCI_SUCCESS:
1885 case OCI_SUCCESS_WITH_INFO:
1886 if (len == 0) {
1887 buf = "";
1889 break;
1890 case OCI_ERROR:
1891 #ifdef DEBUG
1892 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1893 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1894 printf("Finding LOB length: %s\n", sql->buf);
1895 break;
1896 #endif
1897 default:
1898 break;
1901 if (len == 0) {
1902 break;
1905 if (val->type == APR_DBD_TYPE_CLOB) {
1906 #if 1
1907 /* Is this necessary, or can it be defaulted? */
1908 sql->status = OCILobCharSetForm(dbd_oracle_env, sql->err,
1909 val->buf.lobval, &csform);
1910 if (sql->status == OCI_SUCCESS) {
1911 sql->status = OCILobCharSetId(dbd_oracle_env, sql->err,
1912 val->buf.lobval, &csid);
1914 switch (sql->status) {
1915 case OCI_SUCCESS:
1916 case OCI_SUCCESS_WITH_INFO:
1917 buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1918 /* zeroise all - where the string ends depends on charset */
1919 buf = apr_pcalloc(row->pool, buflen);
1920 break;
1921 #ifdef DEBUG
1922 case OCI_ERROR:
1923 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1924 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1925 printf("Reading LOB character set: %s\n", sql->buf);
1926 break; /*** XXX?? ***/
1927 #endif
1928 default:
1929 break; /*** XXX?? ***/
1931 #else /* ignore charset */
1932 buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1933 /* zeroise all - where the string ends depends on charset */
1934 buf = apr_pcalloc(row->pool, buflen);
1935 #endif
1936 } else {
1937 /* BUG: this'll only work if the BLOB looks like a string */
1938 buflen = len;
1939 buf = apr_palloc(row->pool, buflen+1);
1940 buf[buflen] = 0;
1943 if (!buf) {
1944 break;
1947 sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
1948 &len, 1, (dvoid*) buf, buflen,
1949 NULL, NULL, csid, csform);
1950 switch (sql->status) {
1951 case OCI_SUCCESS:
1952 case OCI_SUCCESS_WITH_INFO:
1953 break;
1954 #ifdef DEBUG
1955 case OCI_ERROR:
1956 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1957 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1958 printf("Reading LOB: %s\n", sql->buf);
1959 buf = NULL; /*** XXX?? ***/
1960 break;
1961 #endif
1962 default:
1963 buf = NULL; /*** XXX?? ***/
1964 break;
1967 break;
1968 case SQLT_LNG:
1969 case SQLT_LBI:
1970 /* raw is struct { ub4 len; char *buf; } */
1971 len = *(ub4*) val->buf.raw;
1972 buf = apr_pstrndup(row->pool, val->buf.sval + sizeof(ub4), len);
1973 break;
1974 default:
1975 buf = apr_pstrndup(row->pool, val->buf.sval, val->len);
1976 break;
1978 return (const char*) buf;
1981 /* XXX Should this use Oracle proper API instead of calling get_entry()? */
1982 static apr_status_t dbd_oracle_datum_get(const apr_dbd_row_t *row, int n,
1983 apr_dbd_type_e type, void *data)
1985 define_arg *val = &row->res->statement->out[n];
1986 const char *entry;
1988 if ((n < 0) || (n >= row->res->statement->nout)) {
1989 return APR_EGENERAL;
1992 if(val->ind == -1) {
1993 return APR_ENOENT;
1996 switch (type) {
1997 case APR_DBD_TYPE_TINY:
1998 entry = dbd_oracle_get_entry(row, n);
1999 if (entry == NULL) {
2000 return APR_ENOENT;
2002 *(char*)data = atoi(entry);
2003 break;
2004 case APR_DBD_TYPE_UTINY:
2005 entry = dbd_oracle_get_entry(row, n);
2006 if (entry == NULL) {
2007 return APR_ENOENT;
2009 *(unsigned char*)data = atoi(entry);
2010 break;
2011 case APR_DBD_TYPE_SHORT:
2012 entry = dbd_oracle_get_entry(row, n);
2013 if (entry == NULL) {
2014 return APR_ENOENT;
2016 *(short*)data = atoi(entry);
2017 break;
2018 case APR_DBD_TYPE_USHORT:
2019 entry = dbd_oracle_get_entry(row, n);
2020 if (entry == NULL) {
2021 return APR_ENOENT;
2023 *(unsigned short*)data = atoi(entry);
2024 break;
2025 case APR_DBD_TYPE_INT:
2026 entry = dbd_oracle_get_entry(row, n);
2027 if (entry == NULL) {
2028 return APR_ENOENT;
2030 *(int*)data = atoi(entry);
2031 break;
2032 case APR_DBD_TYPE_UINT:
2033 entry = dbd_oracle_get_entry(row, n);
2034 if (entry == NULL) {
2035 return APR_ENOENT;
2037 *(unsigned int*)data = atoi(entry);
2038 break;
2039 case APR_DBD_TYPE_LONG:
2040 entry = dbd_oracle_get_entry(row, n);
2041 if (entry == NULL) {
2042 return APR_ENOENT;
2044 *(long*)data = atol(entry);
2045 break;
2046 case APR_DBD_TYPE_ULONG:
2047 entry = dbd_oracle_get_entry(row, n);
2048 if (entry == NULL) {
2049 return APR_ENOENT;
2051 *(unsigned long*)data = atol(entry);
2052 break;
2053 case APR_DBD_TYPE_LONGLONG:
2054 entry = dbd_oracle_get_entry(row, n);
2055 if (entry == NULL) {
2056 return APR_ENOENT;
2058 *(apr_int64_t*)data = apr_atoi64(entry);
2059 break;
2060 case APR_DBD_TYPE_ULONGLONG:
2061 entry = dbd_oracle_get_entry(row, n);
2062 if (entry == NULL) {
2063 return APR_ENOENT;
2065 *(apr_uint64_t*)data = apr_atoi64(entry);
2066 break;
2067 case APR_DBD_TYPE_FLOAT:
2068 entry = dbd_oracle_get_entry(row, n);
2069 if (entry == NULL) {
2070 return APR_ENOENT;
2072 *(float*)data = atof(entry);
2073 break;
2074 case APR_DBD_TYPE_DOUBLE:
2075 entry = dbd_oracle_get_entry(row, n);
2076 if (entry == NULL) {
2077 return APR_ENOENT;
2079 *(double*)data = atof(entry);
2080 break;
2081 case APR_DBD_TYPE_STRING:
2082 case APR_DBD_TYPE_TEXT:
2083 case APR_DBD_TYPE_TIME:
2084 case APR_DBD_TYPE_DATE:
2085 case APR_DBD_TYPE_DATETIME:
2086 case APR_DBD_TYPE_TIMESTAMP:
2087 case APR_DBD_TYPE_ZTIMESTAMP:
2088 entry = dbd_oracle_get_entry(row, n);
2089 if (entry == NULL) {
2090 return APR_ENOENT;
2092 *(char**)data = (char*)entry;
2093 break;
2094 case APR_DBD_TYPE_BLOB:
2095 case APR_DBD_TYPE_CLOB:
2097 apr_bucket *e;
2098 apr_bucket_brigade *b = (apr_bucket_brigade*)data;
2099 apr_dbd_t *sql = row->res->handle;
2100 ub4 len = 0;
2102 switch (val->type) {
2103 case SQLT_BLOB:
2104 case SQLT_CLOB:
2105 sql->status = OCILobGetLength(sql->svc, sql->err,
2106 val->buf.lobval, &len);
2107 switch(sql->status) {
2108 case OCI_SUCCESS:
2109 case OCI_SUCCESS_WITH_INFO:
2110 if (len == 0) {
2111 e = apr_bucket_eos_create(b->bucket_alloc);
2113 else {
2114 e = apr_bucket_lob_create(row, n, 0, len,
2115 row->pool, b->bucket_alloc);
2117 break;
2118 default:
2119 return APR_ENOENT;
2121 break;
2122 default:
2123 entry = dbd_oracle_get_entry(row, n);
2124 if (entry == NULL) {
2125 return APR_ENOENT;
2127 e = apr_bucket_pool_create(entry, strlen(entry),
2128 row->pool, b->bucket_alloc);
2129 break;
2131 APR_BRIGADE_INSERT_TAIL(b, e);
2133 break;
2134 case APR_DBD_TYPE_NULL:
2135 *(void**)data = NULL;
2136 break;
2137 default:
2138 return APR_EGENERAL;
2141 return APR_SUCCESS;
2144 static apr_status_t dbd_oracle_close(apr_dbd_t *handle)
2146 /* FIXME: none of the oracle docs/examples say anything about
2147 * closing/releasing handles. Which seems unlikely ...
2150 /* OK, let's grab from cdemo again.
2151 * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
2153 switch (OCISessionEnd(handle->svc, handle->err, handle->auth,
2154 (ub4)OCI_DEFAULT)) {
2155 default:
2156 break;
2158 switch (OCIServerDetach(handle->svr, handle->err, (ub4) OCI_DEFAULT )) {
2159 default:
2160 break;
2162 /* does OCISessionEnd imply this? */
2163 switch (OCIHandleFree((dvoid *) handle->auth, (ub4) OCI_HTYPE_SESSION)) {
2164 default:
2165 break;
2167 switch (OCIHandleFree((dvoid *) handle->svr, (ub4) OCI_HTYPE_SERVER)) {
2168 default:
2169 break;
2171 switch (OCIHandleFree((dvoid *) handle->svc, (ub4) OCI_HTYPE_SVCCTX)) {
2172 default:
2173 break;
2175 switch (OCIHandleFree((dvoid *) handle->err, (ub4) OCI_HTYPE_ERROR)) {
2176 default:
2177 break;
2179 apr_pool_destroy(handle->pool);
2180 return APR_SUCCESS;
2183 static apr_status_t dbd_oracle_check_conn(apr_pool_t *pool,
2184 apr_dbd_t *handle)
2186 /* FIXME: need to find this in the docs */
2187 return APR_ENOTIMPL;
2190 static int dbd_oracle_select_db(apr_pool_t *pool, apr_dbd_t *handle,
2191 const char *name)
2193 /* FIXME: need to find this in the docs */
2194 return APR_ENOTIMPL;
2197 static void *dbd_oracle_native(apr_dbd_t *handle)
2199 /* FIXME: can we do anything better? Oracle doesn't seem to have
2200 * a concept of a handle in the sense we use it.
2202 return dbd_oracle_env;
2205 static int dbd_oracle_num_cols(apr_dbd_results_t* res)
2207 return res->statement->nout;
2210 static int dbd_oracle_num_tuples(apr_dbd_results_t* res)
2212 if (!res->seek) {
2213 return -1;
2215 if (res->nrows >= 0) {
2216 return res->nrows;
2218 res->handle->status = OCIAttrGet(res->statement->stmt, OCI_HTYPE_STMT,
2219 &res->nrows, 0, OCI_ATTR_ROW_COUNT,
2220 res->handle->err);
2221 return res->nrows;
2224 APU_DECLARE_DATA const apr_dbd_driver_t apr_dbd_oracle_driver = {
2225 "oracle",
2226 dbd_oracle_init,
2227 dbd_oracle_native,
2228 dbd_oracle_open,
2229 dbd_oracle_check_conn,
2230 dbd_oracle_close,
2231 dbd_oracle_select_db,
2232 dbd_oracle_start_transaction,
2233 dbd_oracle_end_transaction,
2234 dbd_oracle_query,
2235 dbd_oracle_select,
2236 dbd_oracle_num_cols,
2237 dbd_oracle_num_tuples,
2238 dbd_oracle_get_row,
2239 dbd_oracle_get_entry,
2240 dbd_oracle_error,
2241 dbd_oracle_escape,
2242 dbd_oracle_prepare,
2243 dbd_oracle_pvquery,
2244 dbd_oracle_pvselect,
2245 dbd_oracle_pquery,
2246 dbd_oracle_pselect,
2247 dbd_oracle_get_name,
2248 dbd_oracle_transaction_mode_get,
2249 dbd_oracle_transaction_mode_set,
2250 ":apr%d",
2251 dbd_oracle_pvbquery,
2252 dbd_oracle_pvbselect,
2253 dbd_oracle_pbquery,
2254 dbd_oracle_pbselect,
2255 dbd_oracle_datum_get
2257 #endif