Introduce apr_dbd_open_ex()
[apr-util.git] / dbd / apr_dbd_oracle.c
blobf057f6e4c526d6870bc4f2100f9228635a118e7e
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 #define CHECK_CONN_QUERY "SELECT 1 FROM dual"
94 #define ERR_BUF_SIZE 200
96 #ifdef DEBUG
97 #include <stdio.h>
98 #endif
100 #include "apr_dbd_internal.h"
102 /* declarations */
103 static const char *dbd_oracle_error(apr_dbd_t *sql, int n);
104 static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
105 const char *query, const char *label,
106 int nargs, int nvals, apr_dbd_type_e *types,
107 apr_dbd_prepared_t **statement);
108 static int outputParams(apr_dbd_t*, apr_dbd_prepared_t*);
109 static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
110 apr_dbd_results_t **results,
111 apr_dbd_prepared_t *statement,
112 int seek, const char **values);
113 static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
114 int *nrows, apr_dbd_prepared_t *statement,
115 const char **values);
116 static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
117 apr_dbd_transaction_t **trans);
118 static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans);
120 struct apr_dbd_transaction_t {
121 int mode;
122 enum { TRANS_NONE, TRANS_ERROR, TRANS_1, TRANS_2 } status;
123 apr_dbd_t *handle;
124 OCITrans *trans;
125 OCISnapshot *snapshot1;
126 OCISnapshot *snapshot2;
129 struct apr_dbd_results_t {
130 apr_pool_t *pool;
131 apr_dbd_t* handle;
132 unsigned int rownum;
133 int seek;
134 int nrows;
135 apr_dbd_prepared_t *statement;
138 struct apr_dbd_t {
139 sword status;
140 OCIError *err;
141 OCIServer *svr;
142 OCISvcCtx *svc;
143 OCISession *auth;
144 apr_dbd_transaction_t* trans;
145 apr_pool_t *pool;
146 char buf[ERR_BUF_SIZE]; /* for error messages */
147 apr_size_t long_size;
148 apr_dbd_prepared_t *check_conn_stmt;
151 struct apr_dbd_row_t {
152 int n;
153 apr_dbd_results_t *res;
154 apr_pool_t *pool;
157 typedef struct {
158 apr_dbd_type_e type;
159 sb2 ind;
160 sb4 len;
161 OCIBind *bind;
162 union {
163 void *raw;
164 char *sval;
165 int ival;
166 unsigned int uval;
167 double fval;
168 OCILobLocator *lobval;
169 } value;
170 } bind_arg;
172 typedef struct {
173 int type;
174 sb2 ind;
175 ub2 len; /* length of actual output */
176 OCIDefine *defn;
177 apr_size_t sz; /* length of buf for output */
178 union {
179 void *raw;
180 char *sval;
181 OCILobLocator *lobval;
182 } buf;
183 const char *name;
184 } define_arg;
186 struct apr_dbd_prepared_t {
187 OCIStmt *stmt;
188 int nargs;
189 int nvals;
190 bind_arg *args;
191 int nout;
192 define_arg *out;
193 apr_dbd_t *handle;
194 apr_pool_t *pool;
195 int type;
198 /* AFAICT from the docs, the OCIEnv thingey can be used async
199 * across threads, so lets have a global one.
201 * We'll need shorter-lived envs to deal with requests and connections
203 * Hmmm, that doesn't work: we don't have a usermem framework.
204 * OK, forget about using APR pools here, until we figure out
205 * the right way to do it (if such a thing exists).
207 static OCIEnv *dbd_oracle_env = NULL;
208 #ifdef GLOBAL_PREPARED_STATEMENTS
209 static apr_hash_t *oracle_statements = NULL;
210 #endif
212 /* Oracle specific bucket for BLOB/CLOB types */
213 typedef struct apr_bucket_lob apr_bucket_lob;
215 * A bucket referring to a Oracle BLOB/CLOB
217 struct apr_bucket_lob {
218 /** Number of buckets using this memory */
219 apr_bucket_refcount refcount;
220 /** The row this bucket refers to */
221 const apr_dbd_row_t *row;
222 /** The column this bucket refers to */
223 int col;
224 /** The pool into which any needed structures should
225 * be created while reading from this bucket */
226 apr_pool_t *readpool;
229 static void lob_bucket_destroy(void *data);
230 static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
231 apr_size_t *len, apr_read_type_e block);
232 static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
233 const apr_dbd_row_t *row, int col,
234 apr_off_t offset, apr_size_t len,
235 apr_pool_t *p);
236 static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
237 apr_off_t offset,
238 apr_size_t len, apr_pool_t *p,
239 apr_bucket_alloc_t *list);
241 static const apr_bucket_type_t apr_bucket_type_lob = {
242 "LOB", 5, APR_BUCKET_DATA,
243 lob_bucket_destroy,
244 lob_bucket_read,
245 apr_bucket_setaside_notimpl,
246 apr_bucket_shared_split,
247 apr_bucket_shared_copy
250 static void lob_bucket_destroy(void *data)
252 apr_bucket_lob *f = data;
254 if (apr_bucket_shared_destroy(f)) {
255 /* no need to destroy database objects here; it will get
256 * done automatically when the pool gets cleaned up */
257 apr_bucket_free(f);
261 static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
262 apr_size_t *len, apr_read_type_e block)
264 apr_bucket_lob *a = e->data;
265 const apr_dbd_row_t *row = a->row;
266 apr_dbd_results_t *res = row->res;
267 int col = a->col;
268 apr_bucket *b = NULL;
269 apr_size_t blength = e->length; /* bytes remaining in file past offset */
270 apr_off_t boffset = e->start;
271 define_arg *val = &res->statement->out[col];
272 apr_dbd_t *sql = res->handle;
273 /* Only with 10g, unfortunately
274 oraub8 length = APR_BUCKET_BUFF_SIZE;
276 ub4 length = APR_BUCKET_BUFF_SIZE;
277 char *buf = NULL;
279 *str = NULL; /* in case we die prematurely */
281 /* fetch from offset if not at the beginning */
282 buf = apr_palloc(row->pool, APR_BUCKET_BUFF_SIZE);
283 sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
284 &length, 1 + boffset,
285 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
286 NULL, NULL, 0, SQLCS_IMPLICIT);
287 /* Only with 10g, unfortunately
288 sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,
289 &length, NULL, 1 + boffset,
290 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
291 OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
293 if (sql->status != OCI_SUCCESS) {
294 return APR_EGENERAL;
296 blength -= length;
297 *len = length;
298 *str = buf;
301 * Change the current bucket to refer to what we read,
302 * even if we read nothing because we hit EOF.
304 apr_bucket_pool_make(e, *str, *len, res->pool);
306 /* If we have more to read from the field, then create another bucket */
307 if (blength > 0) {
308 /* for efficiency, we can just build a new apr_bucket struct
309 * to wrap around the existing LOB bucket */
310 b = apr_bucket_alloc(sizeof(*b), e->list);
311 b->start = boffset + *len;
312 b->length = blength;
313 b->data = a;
314 b->type = &apr_bucket_type_lob;
315 b->free = apr_bucket_free;
316 b->list = e->list;
317 APR_BUCKET_INSERT_AFTER(e, b);
319 else {
320 lob_bucket_destroy(a);
323 return APR_SUCCESS;
326 static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
327 const apr_dbd_row_t *row, int col,
328 apr_off_t offset, apr_size_t len,
329 apr_pool_t *p)
331 apr_bucket_lob *f;
333 f = apr_bucket_alloc(sizeof(*f), b->list);
334 f->row = row;
335 f->col = col;
336 f->readpool = p;
338 b = apr_bucket_shared_make(b, f, offset, len);
339 b->type = &apr_bucket_type_lob;
341 return b;
344 static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
345 apr_off_t offset,
346 apr_size_t len, apr_pool_t *p,
347 apr_bucket_alloc_t *list)
349 apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
351 APR_BUCKET_INIT(b);
352 b->free = apr_bucket_free;
353 b->list = list;
354 return apr_bucket_lob_make(b, row, col, offset, len, p);
357 static apr_status_t dbd_free_lobdesc(void *lob)
359 switch (OCIDescriptorFree(lob, OCI_DTYPE_LOB)) {
360 case OCI_SUCCESS:
361 return APR_SUCCESS;
362 default:
363 return APR_EGENERAL;
367 static apr_status_t dbd_free_snapshot(void *snap)
369 switch (OCIDescriptorFree(snap, OCI_DTYPE_SNAP)) {
370 case OCI_SUCCESS:
371 return APR_SUCCESS;
372 default:
373 return APR_EGENERAL;
377 #ifdef GLOBAL_PREPARED_STATEMENTS
378 static apr_status_t freeStatements(void *ptr)
380 apr_status_t rv = APR_SUCCESS;
381 OCIStmt *stmt;
382 apr_hash_index_t *index;
383 apr_pool_t *cachepool = apr_hash_pool_get(oracle_statements);
385 #ifdef PREPARE2
386 OCIError *err;
388 if (OCIHandleAlloc(dbd_oracle_env, (dvoid**)&err, OCI_HTYPE_ERROR, 0, NULL)
389 != OCI_SUCCESS) {
390 return APR_EGENERAL;
392 #endif
394 for (index = apr_hash_first(cachepool, oracle_statements);
395 index != NULL;
396 index = apr_hash_next(index)) {
397 apr_hash_this(index, NULL, NULL, (void**)&stmt);
398 #ifdef PREPARE2
399 if (OCIStmtRelease(stmt, err, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS) {
400 rv = APR_EGENERAL;
402 #else
403 if (OCIHandleFree(stmt, OCI_HTYPE_STMT) != OCI_SUCCESS) {
404 rv = APR_EGENERAL;
406 #endif
408 #ifdef PREPARE2
409 if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) {
410 rv = APR_EGENERAL;
412 #endif
413 return rv;
415 #endif
417 static void dbd_oracle_init(apr_pool_t *pool)
419 if (dbd_oracle_env == NULL) {
420 /* Sadly, OCI_SHARED seems to be impossible to use, due to
421 * various Oracle bugs. See, for example, Oracle MetaLink bug 2972890
422 * and PHP bug http://bugs.php.net/bug.php?id=23733
424 #ifdef OCI_NEW_LENGTH_SEMANTICS
425 OCIEnvCreate(&dbd_oracle_env, OCI_THREADED|OCI_NEW_LENGTH_SEMANTICS,
426 NULL, NULL, NULL, NULL, 0, NULL);
427 #else
428 OCIEnvCreate(&dbd_oracle_env, OCI_THREADED,
429 NULL, NULL, NULL, NULL, 0, NULL);
430 #endif
432 #ifdef GLOBAL_PREPARED_STATEMENTS
433 if (oracle_statements == NULL) {
435 oracle_statements = apr_hash_make(pool);
436 apr_pool_cleanup_register(pool, oracle_statements,
437 freeStatements, apr_pool_cleanup_null);
439 #endif
442 static apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params,
443 const char **error)
445 apr_dbd_t *ret = apr_pcalloc(pool, sizeof(apr_dbd_t));
446 int errorcode;
448 char *BLANK = "";
449 struct {
450 const char *field;
451 char *value;
452 } fields[] = {
453 {"user", BLANK},
454 {"pass", BLANK},
455 {"dbname", BLANK},
456 {"server", BLANK},
457 {NULL, NULL}
459 int i;
460 const char *ptr;
461 const char *key;
462 size_t klen;
463 const char *value;
464 size_t vlen;
465 static const char *const delims = " \r\n\t;|,";
467 ret->pool = pool;
468 ret->long_size = DEFAULT_LONG_SIZE;
470 /* snitch parsing from the MySQL driver */
471 for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {
472 /* don't dereference memory that may not belong to us */
473 if (ptr == params) {
474 ++ptr;
475 continue;
477 for (key = ptr-1; isspace(*key); --key);
478 klen = 0;
479 while (isalpha(*key)) {
480 if (key == params) {
481 /* Don't parse off the front of the params */
482 --key;
483 ++klen;
484 break;
486 --key;
487 ++klen;
489 ++key;
490 for (value = ptr+1; isspace(*value); ++value);
491 vlen = strcspn(value, delims);
492 for (i=0; fields[i].field != NULL; ++i) {
493 if (!strncasecmp(fields[i].field, key, klen)) {
494 fields[i].value = apr_pstrndup(pool, value, vlen);
495 break;
498 ptr = value+vlen;
501 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->err,
502 OCI_HTYPE_ERROR, 0, NULL);
503 switch (ret->status) {
504 default:
505 #ifdef DEBUG
506 printf("ret->status is %d\n", ret->status);
507 break;
508 #else
509 return NULL;
510 #endif
511 case OCI_SUCCESS:
512 break;
515 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svr,
516 OCI_HTYPE_SERVER, 0, NULL);
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 (alloc svr): %s\n", ret->status, ret->buf);
523 break;
524 #else
525 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
526 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
527 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
528 return NULL;
529 #endif
530 case OCI_SUCCESS:
531 break;
534 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svc,
535 OCI_HTYPE_SVCCTX, 0, NULL);
536 switch (ret->status) {
537 default:
538 #ifdef DEBUG
539 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
540 sizeof(ret->buf), OCI_HTYPE_ERROR);
541 printf("OPEN ERROR %d (alloc svc): %s\n", ret->status, ret->buf);
542 break;
543 #else
544 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
545 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
546 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
547 return NULL;
548 #endif
549 case OCI_SUCCESS:
550 break;
553 /* All the examples use the #else */
554 #if CAN_DO_LOGIN
555 ret->status = OCILogon(dbd_oracle_env, ret->err, &ret->svc, fields[0].value,
556 strlen(fields[0].value), fields[1].value,
557 strlen(fields[1].value), fields[2].value,
558 strlen(fields[2].value));
559 switch (ret->status) {
560 default:
561 #ifdef DEBUG
562 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
563 sizeof(ret->buf), OCI_HTYPE_ERROR);
564 printf("OPEN ERROR: %s\n", ret->buf);
565 break;
566 #else
567 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
568 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
569 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
570 return NULL;
571 #endif
572 case OCI_SUCCESS:
573 break;
575 #else
576 ret->status = OCIServerAttach(ret->svr, ret->err, (text*) fields[3].value,
577 strlen(fields[3].value), OCI_DEFAULT);
578 switch (ret->status) {
579 default:
580 #ifdef DEBUG
581 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
582 sizeof(ret->buf), OCI_HTYPE_ERROR);
583 printf("OPEN ERROR %d (server attach): %s\n", ret->status, ret->buf);
584 break;
585 #else
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);
589 return NULL;
590 #endif
591 case OCI_SUCCESS:
592 break;
594 ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->svr, 0,
595 OCI_ATTR_SERVER, ret->err);
596 switch (ret->status) {
597 default:
598 #ifdef DEBUG
599 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
600 sizeof(ret->buf), OCI_HTYPE_ERROR);
601 printf("OPEN ERROR %d (attr set): %s\n", ret->status, ret->buf);
602 break;
603 #else
604 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
605 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
606 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
607 return NULL;
608 #endif
609 case OCI_SUCCESS:
610 break;
612 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->auth,
613 OCI_HTYPE_SESSION, 0, NULL);
614 switch (ret->status) {
615 default:
616 #ifdef DEBUG
617 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
618 sizeof(ret->buf), OCI_HTYPE_ERROR);
619 printf("OPEN ERROR %d (alloc auth): %s\n", ret->status, ret->buf);
620 break;
621 #else
622 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
623 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
624 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
625 return NULL;
626 #endif
627 case OCI_SUCCESS:
628 break;
630 ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[0].value,
631 strlen(fields[0].value), OCI_ATTR_USERNAME, ret->err);
632 switch (ret->status) {
633 default:
634 #ifdef DEBUG
635 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
636 sizeof(ret->buf), OCI_HTYPE_ERROR);
637 printf("OPEN ERROR %d (attr username): %s\n", ret->status, ret->buf);
638 break;
639 #else
640 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
641 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
642 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
643 return NULL;
644 #endif
645 case OCI_SUCCESS:
646 break;
648 ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[1].value,
649 strlen(fields[1].value), OCI_ATTR_PASSWORD, ret->err);
650 switch (ret->status) {
651 default:
652 #ifdef DEBUG
653 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
654 sizeof(ret->buf), OCI_HTYPE_ERROR);
655 printf("OPEN ERROR %d (attr password): %s\n", ret->status, ret->buf);
656 break;
657 #else
658 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
659 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
660 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
661 return NULL;
662 #endif
663 case OCI_SUCCESS:
664 break;
666 ret->status = OCISessionBegin(ret->svc, ret->err, ret->auth,
667 OCI_CRED_RDBMS, OCI_DEFAULT);
668 switch (ret->status) {
669 default:
670 #ifdef DEBUG
671 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
672 sizeof(ret->buf), OCI_HTYPE_ERROR);
673 printf("OPEN ERROR %d (session begin): %s\n", ret->status, ret->buf);
674 break;
675 #else
676 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
677 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
678 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
679 return NULL;
680 #endif
681 case OCI_SUCCESS:
682 break;
684 ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->auth, 0,
685 OCI_ATTR_SESSION, ret->err);
686 switch (ret->status) {
687 default:
688 #ifdef DEBUG
689 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
690 sizeof(ret->buf), OCI_HTYPE_ERROR);
691 printf("OPEN ERROR %d (attr session): %s\n", ret->status, ret->buf);
692 #else
693 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
694 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
695 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
696 return NULL;
697 #endif
698 break;
699 case OCI_SUCCESS:
700 break;
702 #endif
704 if(dbd_oracle_prepare(pool, ret, CHECK_CONN_QUERY, NULL, 0, 0, NULL,
705 &ret->check_conn_stmt) != 0) {
706 return NULL;
709 return ret;
712 #ifdef EXPORT_NATIVE_FUNCS
713 static apr_size_t dbd_oracle_long_size_set(apr_dbd_t *sql,
714 apr_size_t long_size)
716 apr_size_t old_size = sql->long_size;
717 sql->long_size = long_size;
718 return old_size;
720 #endif
722 static const char *dbd_oracle_get_name(const apr_dbd_results_t *res, int n)
724 define_arg *val = &res->statement->out[n];
726 if ((n < 0) || (n >= res->statement->nout)) {
727 return NULL;
729 return val->name;
732 static int dbd_oracle_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
733 apr_dbd_row_t **rowp, int rownum)
735 apr_dbd_row_t *row = *rowp;
736 apr_dbd_t *sql = res->handle;
737 int_errorcode;
739 if (row == NULL) {
740 row = apr_palloc(pool, sizeof(apr_dbd_row_t));
741 *rowp = row;
742 row->res = res;
743 /* Oracle starts counting at 1 according to the docs */
744 row->n = res->seek ? rownum : 1;
745 row->pool = pool;
747 else {
748 if (res->seek) {
749 row->n = rownum;
751 else {
752 ++row->n;
756 if (res->seek) {
757 sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
758 OCI_FETCH_ABSOLUTE, row->n, OCI_DEFAULT);
760 else {
761 sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
762 OCI_FETCH_NEXT, 0, OCI_DEFAULT);
764 switch (sql->status) {
765 case OCI_SUCCESS:
766 (*rowp)->res = res;
767 return 0;
768 case OCI_NO_DATA:
769 return -1;
770 case OCI_ERROR:
771 #ifdef DEBUG
772 OCIErrorGet(sql->err, 1, NULL, &errorcode,
773 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
774 printf("Execute error %d: %s\n", sql->status, sql->buf);
775 #endif
776 /* fallthrough */
777 default:
778 return 1;
780 return 0;
783 static const char *dbd_oracle_error(apr_dbd_t *sql, int n)
785 /* This is ugly. Needs us to pass in a buffer of unknown size.
786 * Either we put it on the handle, or we have to keep allocing/copying
788 sb4 errorcode;
790 switch (sql->status) {
791 case OCI_SUCCESS:
792 return "OCI_SUCCESS";
793 case OCI_SUCCESS_WITH_INFO:
794 return "OCI_SUCCESS_WITH_INFO";
795 case OCI_NEED_DATA:
796 return "OCI_NEED_DATA";
797 case OCI_NO_DATA:
798 return "OCI_NO_DATA";
799 case OCI_INVALID_HANDLE:
800 return "OCI_INVALID_HANDLE";
801 case OCI_STILL_EXECUTING:
802 return "OCI_STILL_EXECUTING";
803 case OCI_CONTINUE:
804 return "OCI_CONTINUE";
807 switch (OCIErrorGet(sql->err, 1, NULL, &errorcode,
808 (text*) sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR)) {
809 case OCI_SUCCESS:
810 return sql->buf;
811 default:
812 return "internal error: OCIErrorGet failed";
816 static apr_status_t freeStatement(void *statement)
818 int rv = APR_SUCCESS;
819 OCIStmt *stmt = ((apr_dbd_prepared_t*)statement)->stmt;
821 #ifdef PREPARE2
822 OCIError *err;
824 if (OCIHandleAlloc(dbd_oracle_env, (dvoid**)&err, OCI_HTYPE_ERROR,
825 0, NULL) != OCI_SUCCESS) {
826 return APR_EGENERAL;
828 if (OCIStmtRelease(stmt, err, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS) {
829 rv = APR_EGENERAL;
831 if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) {
832 rv = APR_EGENERAL;
834 #else
835 if (OCIHandleFree(stmt, OCI_HTYPE_STMT) != OCI_SUCCESS) {
836 rv = APR_EGENERAL;
838 #endif
840 return rv;
843 static int dbd_oracle_select(apr_pool_t *pool, apr_dbd_t *sql,
844 apr_dbd_results_t **results,
845 const char *query, int seek)
847 int ret = 0;
848 apr_dbd_prepared_t *statement = NULL;
850 ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
851 if (ret != 0) {
852 return ret;
855 ret = dbd_oracle_pselect(pool, sql, results, statement, seek, NULL);
856 if (ret != 0) {
857 return ret;
860 return ret;
863 static int dbd_oracle_query(apr_dbd_t *sql, int *nrows, const char *query)
865 int ret = 0;
866 apr_pool_t *pool;
867 apr_dbd_prepared_t *statement = NULL;
869 if (sql->trans && sql->trans->status == TRANS_ERROR) {
870 return 1;
873 /* make our own pool so that APR allocations don't linger and so that
874 * both Stmt and LOB handles are cleaned up (LOB handles may be
875 * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs)
877 apr_pool_create(&pool, sql->pool);
879 ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
880 if (ret == 0) {
881 ret = dbd_oracle_pquery(pool, sql, nrows, statement, NULL);
882 if (ret == 0) {
883 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT,
884 nrows, 0, OCI_ATTR_ROW_COUNT,
885 sql->err);
889 apr_pool_destroy(pool);
891 return ret;
894 static const char *dbd_oracle_escape(apr_pool_t *pool, const char *arg,
895 apr_dbd_t *sql)
897 return arg; /* OCI has no concept of string escape */
900 static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
901 const char *query, const char *label,
902 int nargs, int nvals, apr_dbd_type_e *types,
903 apr_dbd_prepared_t **statement)
905 int ret = 0;
906 int i;
907 apr_dbd_prepared_t *stmt ;
909 /* prepared statements in a global lookup table would be nice,
910 * but we can't do that here because our pool may die leaving
911 * the cached statement orphaned.
912 * OTOH we can do that with Oracle statements, which aren't on
913 * the pool, so long as we don't register a cleanup on our pool!
915 * FIXME:
916 * There's a race condition between cache-lookup and cache-set
917 * But the worst outcome is a statement prepared more than once
918 * and leaked. Is that worth mutexing for?
919 * Hmmm, yes it probably is ... OK, done
922 if (*statement == NULL) {
923 *statement = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t));
925 stmt = *statement;
926 stmt->handle = sql;
927 stmt->pool = pool;
928 stmt->nargs = nargs;
929 stmt->nvals = nvals;
931 /* If we have a label, we're going to cache it globally.
932 * Check first if we already have it. If not, prepare the
933 * statement under mutex, so we don't end up leaking
934 * concurrent statements
936 * FIXME: Oracle docs say a statement can be used even across
937 * multiple servers, so I assume this is safe .....
939 #ifdef GLOBAL_PREPARED_STATEMENTS
940 if (label != NULL) {
941 stmt->stmt = apr_hash_get(oracle_statements, label, APR_HASH_KEY_STRING);
942 if (stmt->stmt != NULL) {
943 return ret;
945 apr_dbd_mutex_lock();
946 stmt->stmt = apr_hash_get(oracle_statements, label, APR_HASH_KEY_STRING);
947 if (stmt->stmt != NULL) {
948 apr_dbd_mutex_unlock();
949 return ret;
952 #endif
954 /* populate our own args, if any */
955 if (nargs > 0) {
956 stmt->args = apr_pcalloc(pool, nargs*sizeof(bind_arg));
957 for (i = 0; i < nargs; i++) {
958 stmt->args[i].type = types[i];
962 sql->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**) &stmt->stmt,
963 OCI_HTYPE_STMT, 0, NULL);
964 if (sql->status != OCI_SUCCESS) {
965 apr_dbd_mutex_unlock();
966 return 1;
969 sql->status = OCIStmtPrepare(stmt->stmt, sql->err, (text*) query,
970 strlen(query), OCI_NTV_SYNTAX, OCI_DEFAULT);
971 if (sql->status != OCI_SUCCESS) {
972 OCIHandleFree(stmt->stmt, OCI_HTYPE_STMT);
973 apr_dbd_mutex_unlock();
974 return 1;
977 apr_pool_cleanup_register(pool, stmt, freeStatement,
978 apr_pool_cleanup_null);
980 /* Perl gets statement type here */
981 sql->status = OCIAttrGet(stmt->stmt, OCI_HTYPE_STMT, &stmt->type, 0,
982 OCI_ATTR_STMT_TYPE, sql->err);
983 if (sql->status != OCI_SUCCESS) {
984 apr_dbd_mutex_unlock();
985 return 1;
988 /* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
989 #if 0
990 sql->status = OCIAttrSet(stmt->stmt, OCI_HTYPE_STMT, &prefetch_size,
991 sizeof(prefetch_size), OCI_ATTR_PREFETCH_MEMORY,
992 sql->err);
993 if (sql->status != OCI_SUCCESS) {
994 apr_dbd_mutex_unlock();
995 return 1;
997 #endif
999 if (stmt->type == OCI_STMT_SELECT) {
1000 ret = outputParams(sql, stmt);
1002 #ifdef GLOBAL_PREPARED_STATEMENTS
1003 if (label != NULL) {
1004 apr_hash_set(oracle_statements, label, APR_HASH_KEY_STRING, stmt->stmt);
1005 apr_dbd_mutex_unlock();
1007 #endif
1008 return ret;
1011 static void dbd_oracle_bind(apr_dbd_prepared_t *statement, const char **values)
1013 OCIStmt *stmt = statement->stmt;
1014 apr_dbd_t *sql = statement->handle;
1015 int i, j;
1016 sb2 null_ind = -1;
1018 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
1019 if (values[j] == NULL) {
1020 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1021 sql->err, i + 1,
1022 NULL, 0, SQLT_STR,
1023 &null_ind, NULL,
1024 (ub2) 0, (ub4) 0,
1025 (ub4 *) 0, OCI_DEFAULT);
1027 else {
1028 switch (statement->args[i].type) {
1029 case APR_DBD_TYPE_BLOB:
1031 char *data = (char *)values[j];
1032 int size = atoi((char*)values[++j]);
1034 /* skip table and column for now */
1035 j += 2;
1037 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1038 sql->err, i + 1,
1039 data, size, SQLT_LBI,
1040 &statement->args[i].ind,
1041 NULL,
1042 (ub2) 0, (ub4) 0,
1043 (ub4 *) 0, OCI_DEFAULT);
1045 break;
1046 case APR_DBD_TYPE_CLOB:
1048 char *data = (char *)values[j];
1049 int size = atoi((char*)values[++j]);
1051 /* skip table and column for now */
1052 j += 2;
1054 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1055 sql->err, i + 1,
1056 data, size, SQLT_LNG,
1057 &statement->args[i].ind,
1058 NULL,
1059 (ub2) 0, (ub4) 0,
1060 (ub4 *) 0, OCI_DEFAULT);
1062 break;
1063 default:
1064 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1065 sql->err, i + 1,
1066 (dvoid*) values[j],
1067 strlen(values[j]) + 1,
1068 SQLT_STR,
1069 &statement->args[i].ind,
1070 NULL,
1071 (ub2) 0, (ub4) 0,
1072 (ub4 *) 0, OCI_DEFAULT);
1073 break;
1077 if (sql->status != OCI_SUCCESS) {
1078 return;
1082 return;
1085 static int outputParams(apr_dbd_t *sql, apr_dbd_prepared_t *stmt)
1087 OCIParam *parms;
1088 int i;
1089 int_errorcode;
1090 ub2 paramtype[DBD_ORACLE_MAX_COLUMNS];
1091 ub2 paramsize[DBD_ORACLE_MAX_COLUMNS];
1092 const char *paramname[DBD_ORACLE_MAX_COLUMNS];
1093 ub4 paramnamelen[DBD_ORACLE_MAX_COLUMNS];
1094 /* Perl uses 0 where we used 1 */
1095 sql->status = OCIStmtExecute(sql->svc, stmt->stmt, sql->err, 0, 0,
1096 NULL, NULL, OCI_DESCRIBE_ONLY);
1097 switch (sql->status) {
1098 case OCI_SUCCESS:
1099 case OCI_SUCCESS_WITH_INFO:
1100 break;
1101 case OCI_ERROR:
1102 #ifdef DEBUG
1103 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1104 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1105 printf("Describing prepared statement: %s\n", sql->buf);
1106 #endif
1107 default:
1108 return 1;
1110 while (sql->status == OCI_SUCCESS) {
1111 sql->status = OCIParamGet(stmt->stmt, OCI_HTYPE_STMT,
1112 sql->err, (dvoid**)&parms, stmt->nout+1);
1113 switch (sql->status) {
1114 case OCI_SUCCESS:
1115 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1116 &paramtype[stmt->nout],
1117 0, OCI_ATTR_DATA_TYPE, sql->err);
1118 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1119 &paramsize[stmt->nout],
1120 0, OCI_ATTR_DATA_SIZE, sql->err);
1121 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1122 &paramname[stmt->nout],
1123 &paramnamelen[stmt->nout],
1124 OCI_ATTR_NAME, sql->err);
1125 ++stmt->nout;
1128 switch (sql->status) {
1129 case OCI_SUCCESS:
1130 break;
1131 case OCI_ERROR:
1132 break; /* this is what we expect at end-of-loop */
1133 default:
1134 return 1;
1137 /* OK, the above works. We have the params; now OCIDefine them */
1138 stmt->out = apr_palloc(stmt->pool, stmt->nout*sizeof(define_arg));
1139 for (i=0; i<stmt->nout; ++i) {
1140 stmt->out[i].type = paramtype[i];
1141 stmt->out[i].len = stmt->out[i].sz = paramsize[i];
1142 stmt->out[i].name = apr_pstrmemdup(stmt->pool,
1143 paramname[i], paramnamelen[i]);
1144 switch (stmt->out[i].type) {
1145 default:
1146 switch (stmt->out[i].type) {
1147 case SQLT_NUM: /* 2: numeric, Perl worst case=130+38+3 */
1148 stmt->out[i].sz = 171;
1149 break;
1150 case SQLT_CHR: /* 1: char */
1151 case SQLT_AFC: /* 96: ANSI fixed char */
1152 stmt->out[i].sz *= 4; /* ugh, wasteful UCS-4 handling */
1153 break;
1154 case SQLT_DAT: /* 12: date, depends on NLS date format */
1155 stmt->out[i].sz = 75;
1156 break;
1157 case SQLT_BIN: /* 23: raw binary, perhaps UTF-16? */
1158 stmt->out[i].sz *= 2;
1159 break;
1160 case SQLT_RID: /* 11: rowid */
1161 case SQLT_RDD: /* 104: rowid descriptor */
1162 stmt->out[i].sz = 20;
1163 break;
1164 case SQLT_TIMESTAMP: /* 187: timestamp */
1165 case SQLT_TIMESTAMP_TZ: /* 188: timestamp with time zone */
1166 case SQLT_INTERVAL_YM: /* 189: interval year-to-month */
1167 case SQLT_INTERVAL_DS: /* 190: interval day-to-second */
1168 case SQLT_TIMESTAMP_LTZ: /* 232: timestamp with local time zone */
1169 stmt->out[i].sz = 75;
1170 break;
1171 default:
1172 #ifdef DEBUG
1173 printf("Unsupported data type: %d\n", stmt->out[i].type);
1174 #endif
1175 break;
1177 ++stmt->out[i].sz;
1178 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1179 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1180 sql->err, i+1,
1181 stmt->out[i].buf.sval,
1182 stmt->out[i].sz, SQLT_STR,
1183 &stmt->out[i].ind, &stmt->out[i].len,
1184 0, OCI_DEFAULT);
1185 break;
1186 case SQLT_LNG: /* 8: long */
1187 stmt->out[i].sz = sql->long_size * 4 + 4; /* ugh, UCS-4 handling */
1188 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1189 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1190 sql->err, i+1,
1191 stmt->out[i].buf.raw,
1192 stmt->out[i].sz, SQLT_LVC,
1193 &stmt->out[i].ind, NULL,
1194 0, OCI_DEFAULT);
1195 break;
1196 case SQLT_LBI: /* 24: long binary, perhaps UTF-16? */
1197 stmt->out[i].sz = sql->long_size * 2 + 4; /* room for int prefix */
1198 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1199 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1200 sql->err, i+1,
1201 stmt->out[i].buf.raw,
1202 stmt->out[i].sz, SQLT_LVB,
1203 &stmt->out[i].ind, NULL,
1204 0, OCI_DEFAULT);
1205 break;
1206 case SQLT_BLOB: /* 113 */
1207 case SQLT_CLOB: /* 112 */
1208 /*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1209 sql->status = OCIDescriptorAlloc(dbd_oracle_env,
1210 (dvoid**)&stmt->out[i].buf.lobval,
1211 OCI_DTYPE_LOB, 0, NULL);
1212 apr_pool_cleanup_register(stmt->pool, stmt->out[i].buf.lobval,
1213 dbd_free_lobdesc,
1214 apr_pool_cleanup_null);
1215 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1216 sql->err, i+1,
1217 (dvoid*) &stmt->out[i].buf.lobval,
1218 -1, stmt->out[i].type,
1219 &stmt->out[i].ind, &stmt->out[i].len,
1220 0, OCI_DEFAULT);
1221 break;
1223 switch (sql->status) {
1224 case OCI_SUCCESS:
1225 break;
1226 default:
1227 return 1;
1230 return 0;
1233 static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
1234 int *nrows, apr_dbd_prepared_t *statement,
1235 const char **values)
1237 int_errorcode;
1238 OCISnapshot *oldsnapshot = NULL;
1239 OCISnapshot *newsnapshot = NULL;
1240 apr_dbd_transaction_t* trans = sql->trans;
1241 int exec_mode;
1243 if (trans) {
1244 switch (trans->status) {
1245 case TRANS_ERROR:
1246 return -1;
1247 case TRANS_NONE:
1248 trans = NULL;
1249 break;
1250 case TRANS_1:
1251 oldsnapshot = trans->snapshot1;
1252 newsnapshot = trans->snapshot2;
1253 trans->status = TRANS_2;
1254 break;
1255 case TRANS_2:
1256 oldsnapshot = trans->snapshot2;
1257 newsnapshot = trans->snapshot1;
1258 trans->status = TRANS_1;
1259 break;
1261 exec_mode = OCI_DEFAULT;
1263 else {
1264 exec_mode = OCI_COMMIT_ON_SUCCESS;
1267 dbd_oracle_bind(statement, values);
1269 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1270 oldsnapshot, newsnapshot, exec_mode);
1271 switch (sql->status) {
1272 case OCI_SUCCESS:
1273 break;
1274 case OCI_ERROR:
1275 #ifdef DEBUG
1276 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1277 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1278 printf("Execute error %d: %s\n", sql->status, sql->buf);
1279 #endif
1280 /* fallthrough */
1281 default:
1282 if (TXN_NOTICE_ERRORS(trans)) {
1283 trans->status = TRANS_ERROR;
1285 return 1;
1288 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1289 OCI_ATTR_ROW_COUNT, sql->err);
1290 return 0;
1293 static int dbd_oracle_pvquery(apr_pool_t *pool, apr_dbd_t *sql,
1294 int *nrows, apr_dbd_prepared_t *statement,
1295 va_list args)
1297 const char **values;
1298 int i;
1300 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1301 return -1;
1304 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1306 for (i = 0; i < statement->nvals; i++) {
1307 values[i] = va_arg(args, const char*);
1310 return dbd_oracle_pquery(pool, sql, nrows, statement, values);
1313 static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
1314 apr_dbd_results_t **results,
1315 apr_dbd_prepared_t *statement,
1316 int seek, const char **values)
1318 int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1319 OCISnapshot *oldsnapshot = NULL;
1320 OCISnapshot *newsnapshot = NULL;
1321 apr_dbd_transaction_t* trans = sql->trans;
1323 if (trans) {
1324 switch (trans->status) {
1325 case TRANS_ERROR:
1326 return 1;
1327 case TRANS_NONE:
1328 trans = NULL;
1329 break;
1330 case TRANS_1:
1331 oldsnapshot = trans->snapshot1;
1332 newsnapshot = trans->snapshot2;
1333 trans->status = TRANS_2;
1334 break;
1335 case TRANS_2:
1336 oldsnapshot = trans->snapshot2;
1337 newsnapshot = trans->snapshot1;
1338 trans->status = TRANS_1;
1339 break;
1343 dbd_oracle_bind(statement, values);
1345 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1346 oldsnapshot, newsnapshot, exec_mode);
1347 switch (sql->status) {
1348 int_errorcode;
1349 case OCI_SUCCESS:
1350 break;
1351 case OCI_ERROR:
1352 #ifdef DEBUG
1353 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1354 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1355 printf("Executing prepared statement: %s\n", sql->buf);
1356 #endif
1357 /* fallthrough */
1358 default:
1359 if (TXN_NOTICE_ERRORS(trans)) {
1360 trans->status = TRANS_ERROR;
1362 return 1;
1365 if (!*results) {
1366 *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1368 (*results)->handle = sql;
1369 (*results)->statement = statement;
1370 (*results)->seek = seek;
1371 (*results)->rownum = seek ? 0 : -1;
1372 (*results)->pool = pool;
1374 return 0;
1377 static int dbd_oracle_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
1378 apr_dbd_results_t **results,
1379 apr_dbd_prepared_t *statement,
1380 int seek, va_list args)
1382 const char **values;
1383 int i;
1385 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1386 return -1;
1389 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1391 for (i = 0; i < statement->nvals; i++) {
1392 values[i] = va_arg(args, const char*);
1395 return dbd_oracle_pselect(pool, sql, results, statement, seek, values);
1398 static void dbd_oracle_bbind(apr_dbd_prepared_t * statement,
1399 const void **values)
1401 OCIStmt *stmt = statement->stmt;
1402 apr_dbd_t *sql = statement->handle;
1403 int i, j;
1404 sb2 null_ind = -1;
1405 apr_dbd_type_e type;
1407 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
1408 type = (values[j] == NULL ? APR_DBD_TYPE_NULL
1409 : statement->args[i].type);
1411 switch (type) {
1412 case APR_DBD_TYPE_TINY:
1413 statement->args[i].value.ival = *(char*)values[j];
1414 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1415 sql->err, i + 1,
1416 &statement->args[i].value.ival,
1417 sizeof(statement->args[i].value.ival),
1418 SQLT_INT,
1419 &statement->args[i].ind, NULL,
1420 (ub2) 0, (ub4) 0,
1421 (ub4 *) 0, OCI_DEFAULT);
1422 break;
1423 case APR_DBD_TYPE_UTINY:
1424 statement->args[i].value.uval = *(unsigned char*)values[j];
1425 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1426 sql->err, i + 1,
1427 &statement->args[i].value.uval,
1428 sizeof(statement->args[i].value.uval),
1429 SQLT_UIN,
1430 &statement->args[i].ind, NULL,
1431 (ub2) 0, (ub4) 0,
1432 (ub4 *) 0, OCI_DEFAULT);
1433 break;
1434 case APR_DBD_TYPE_SHORT:
1435 statement->args[i].value.ival = *(short*)values[j];
1436 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1437 sql->err, i + 1,
1438 &statement->args[i].value.ival,
1439 sizeof(statement->args[i].value.ival),
1440 SQLT_INT,
1441 &statement->args[i].ind, NULL,
1442 (ub2) 0, (ub4) 0,
1443 (ub4 *) 0, OCI_DEFAULT);
1444 break;
1445 case APR_DBD_TYPE_USHORT:
1446 statement->args[i].value.uval = *(unsigned short*)values[j];
1447 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1448 sql->err, i + 1,
1449 &statement->args[i].value.uval,
1450 sizeof(statement->args[i].value.uval),
1451 SQLT_UIN,
1452 &statement->args[i].ind, NULL,
1453 (ub2) 0, (ub4) 0,
1454 (ub4 *) 0, OCI_DEFAULT);
1455 break;
1456 case APR_DBD_TYPE_INT:
1457 statement->args[i].value.ival = *(int*)values[j];
1458 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1459 sql->err, i + 1,
1460 &statement->args[i].value.ival,
1461 sizeof(statement->args[i].value.ival),
1462 SQLT_INT,
1463 &statement->args[i].ind, NULL,
1464 (ub2) 0, (ub4) 0,
1465 (ub4 *) 0, OCI_DEFAULT);
1466 break;
1467 case APR_DBD_TYPE_UINT:
1468 statement->args[i].value.uval = *(unsigned int*)values[j];
1469 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1470 sql->err, i + 1,
1471 &statement->args[i].value.uval,
1472 sizeof(statement->args[i].value.uval),
1473 SQLT_UIN,
1474 &statement->args[i].ind, NULL,
1475 (ub2) 0, (ub4) 0,
1476 (ub4 *) 0, OCI_DEFAULT);
1477 break;
1478 case APR_DBD_TYPE_LONG:
1479 statement->args[i].value.sval =
1480 apr_psprintf(statement->pool, "%ld", *(long*)values[j]);
1481 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1482 sql->err, i + 1,
1483 statement->args[i].value.sval,
1484 strlen(statement->args[i].value.sval)+1,
1485 SQLT_STR,
1486 &statement->args[i].ind, NULL,
1487 (ub2) 0, (ub4) 0,
1488 (ub4 *) 0, OCI_DEFAULT);
1489 break;
1490 case APR_DBD_TYPE_ULONG:
1491 statement->args[i].value.sval =
1492 apr_psprintf(statement->pool, "%lu",
1493 *(unsigned long*)values[j]);
1494 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1495 sql->err, i + 1,
1496 statement->args[i].value.sval,
1497 strlen(statement->args[i].value.sval)+1,
1498 SQLT_STR,
1499 &statement->args[i].ind, NULL,
1500 (ub2) 0, (ub4) 0,
1501 (ub4 *) 0, OCI_DEFAULT);
1502 break;
1503 case APR_DBD_TYPE_LONGLONG:
1504 statement->args[i].value.sval =
1505 apr_psprintf(statement->pool, "%" APR_INT64_T_FMT,
1506 *(apr_int64_t*)values[j]);
1507 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1508 sql->err, i + 1,
1509 statement->args[i].value.sval,
1510 strlen(statement->args[i].value.sval)+1,
1511 SQLT_STR,
1512 &statement->args[i].ind, NULL,
1513 (ub2) 0, (ub4) 0,
1514 (ub4 *) 0, OCI_DEFAULT);
1515 break;
1516 case APR_DBD_TYPE_ULONGLONG:
1517 statement->args[i].value.sval =
1518 apr_psprintf(statement->pool, "%" APR_UINT64_T_FMT,
1519 *(apr_uint64_t*)values[j]);
1520 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1521 sql->err, i + 1,
1522 statement->args[i].value.sval,
1523 strlen(statement->args[i].value.sval)+1,
1524 SQLT_UIN,
1525 &statement->args[i].ind, NULL,
1526 (ub2) 0, (ub4) 0,
1527 (ub4 *) 0, OCI_DEFAULT);
1528 break;
1529 case APR_DBD_TYPE_FLOAT:
1530 statement->args[i].value.fval = *(float*)values[j];
1531 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1532 sql->err, i + 1,
1533 &statement->args[i].value.fval,
1534 sizeof(statement->args[i].value.fval),
1535 SQLT_FLT,
1536 &statement->args[i].ind, NULL,
1537 (ub2) 0, (ub4) 0,
1538 (ub4 *) 0, OCI_DEFAULT);
1539 break;
1540 case APR_DBD_TYPE_DOUBLE:
1541 statement->args[i].value.fval = *(double*)values[j];
1542 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1543 sql->err, i + 1,
1544 &statement->args[i].value.fval,
1545 sizeof(statement->args[i].value.fval),
1546 SQLT_FLT,
1547 &statement->args[i].ind, NULL,
1548 (ub2) 0, (ub4) 0,
1549 (ub4 *) 0, OCI_DEFAULT);
1550 break;
1551 case APR_DBD_TYPE_STRING:
1552 case APR_DBD_TYPE_TEXT:
1553 case APR_DBD_TYPE_TIME:
1554 case APR_DBD_TYPE_DATE:
1555 case APR_DBD_TYPE_DATETIME:
1556 case APR_DBD_TYPE_TIMESTAMP:
1557 case APR_DBD_TYPE_ZTIMESTAMP:
1558 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1559 sql->err, i + 1,
1560 (dvoid*) values[j],
1561 strlen(values[j]) + 1,
1562 SQLT_STR,
1563 &statement->args[i].ind, NULL,
1564 (ub2) 0, (ub4) 0,
1565 (ub4 *) 0, OCI_DEFAULT);
1566 break;
1567 case APR_DBD_TYPE_BLOB:
1569 char *data = (char *)values[j];
1570 apr_size_t size = *(apr_size_t*)values[++j];
1572 /* skip table and column for now */
1573 j += 2;
1575 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1576 sql->err, i + 1,
1577 data, size, SQLT_LBI,
1578 &statement->args[i].ind,
1579 NULL,
1580 (ub2) 0, (ub4) 0,
1581 (ub4 *) 0, OCI_DEFAULT);
1583 break;
1584 case APR_DBD_TYPE_CLOB:
1586 char *data = (char *)values[j];
1587 apr_size_t size = *(apr_size_t*)values[++j];
1589 /* skip table and column for now */
1590 j += 2;
1592 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1593 sql->err, i + 1,
1594 data, size, SQLT_LNG,
1595 &statement->args[i].ind,
1596 NULL,
1597 (ub2) 0, (ub4) 0,
1598 (ub4 *) 0, OCI_DEFAULT);
1600 break;
1601 case APR_DBD_TYPE_NULL:
1602 default:
1603 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1604 sql->err, i + 1,
1605 NULL, 0, SQLT_STR,
1606 &null_ind, NULL,
1607 (ub2) 0, (ub4) 0,
1608 (ub4 *) 0, OCI_DEFAULT);
1609 break;
1612 if (sql->status != OCI_SUCCESS) {
1613 return;
1617 return;
1620 static int dbd_oracle_pbquery(apr_pool_t * pool, apr_dbd_t * sql,
1621 int *nrows, apr_dbd_prepared_t * statement,
1622 const void **values)
1624 int_errorcode;
1625 OCISnapshot *oldsnapshot = NULL;
1626 OCISnapshot *newsnapshot = NULL;
1627 apr_dbd_transaction_t* trans = sql->trans;
1628 int exec_mode;
1630 if (trans) {
1631 switch (trans->status) {
1632 case TRANS_ERROR:
1633 return -1;
1634 case TRANS_NONE:
1635 trans = NULL;
1636 break;
1637 case TRANS_1:
1638 oldsnapshot = trans->snapshot1;
1639 newsnapshot = trans->snapshot2;
1640 trans->status = TRANS_2;
1641 break;
1642 case TRANS_2:
1643 oldsnapshot = trans->snapshot2;
1644 newsnapshot = trans->snapshot1;
1645 trans->status = TRANS_1;
1646 break;
1648 exec_mode = OCI_DEFAULT;
1650 else {
1651 exec_mode = OCI_COMMIT_ON_SUCCESS;
1654 dbd_oracle_bbind(statement, values);
1656 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1657 oldsnapshot, newsnapshot, exec_mode);
1658 switch (sql->status) {
1659 case OCI_SUCCESS:
1660 break;
1661 case OCI_ERROR:
1662 #ifdef DEBUG
1663 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1664 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1665 printf("Execute error %d: %s\n", sql->status, sql->buf);
1666 #endif
1667 /* fallthrough */
1668 default:
1669 if (TXN_NOTICE_ERRORS(trans)) {
1670 trans->status = TRANS_ERROR;
1672 return 1;
1675 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1676 OCI_ATTR_ROW_COUNT, sql->err);
1677 return 0;
1680 static int dbd_oracle_pvbquery(apr_pool_t * pool, apr_dbd_t * sql,
1681 int *nrows, apr_dbd_prepared_t * statement,
1682 va_list args)
1684 const void **values;
1685 int i;
1687 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1688 return -1;
1691 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1693 for (i = 0; i < statement->nvals; i++) {
1694 values[i] = va_arg(args, const void*);
1697 return dbd_oracle_pbquery(pool, sql, nrows, statement, values);
1700 static int dbd_oracle_pbselect(apr_pool_t * pool, apr_dbd_t * sql,
1701 apr_dbd_results_t ** results,
1702 apr_dbd_prepared_t * statement,
1703 int seek, const void **values)
1705 int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1706 OCISnapshot *oldsnapshot = NULL;
1707 OCISnapshot *newsnapshot = NULL;
1708 apr_dbd_transaction_t* trans = sql->trans;
1710 if (trans) {
1711 switch (trans->status) {
1712 case TRANS_ERROR:
1713 return 1;
1714 case TRANS_NONE:
1715 trans = NULL;
1716 break;
1717 case TRANS_1:
1718 oldsnapshot = trans->snapshot1;
1719 newsnapshot = trans->snapshot2;
1720 trans->status = TRANS_2;
1721 break;
1722 case TRANS_2:
1723 oldsnapshot = trans->snapshot2;
1724 newsnapshot = trans->snapshot1;
1725 trans->status = TRANS_1;
1726 break;
1730 dbd_oracle_bbind(statement, values);
1732 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1733 oldsnapshot, newsnapshot, exec_mode);
1734 switch (sql->status) {
1735 int_errorcode;
1736 case OCI_SUCCESS:
1737 break;
1738 case OCI_ERROR:
1739 #ifdef DEBUG
1740 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1741 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1742 printf("Executing prepared statement: %s\n", sql->buf);
1743 #endif
1744 /* fallthrough */
1745 default:
1746 if (TXN_NOTICE_ERRORS(trans)) {
1747 trans->status = TRANS_ERROR;
1749 return 1;
1752 if (!*results) {
1753 *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1755 (*results)->handle = sql;
1756 (*results)->statement = statement;
1757 (*results)->seek = seek;
1758 (*results)->rownum = seek ? 0 : -1;
1759 (*results)->pool = pool;
1761 return 0;
1764 static int dbd_oracle_pvbselect(apr_pool_t * pool, apr_dbd_t * sql,
1765 apr_dbd_results_t ** results,
1766 apr_dbd_prepared_t * statement, int seek,
1767 va_list args)
1769 const void **values;
1770 int i;
1772 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1773 return -1;
1776 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1778 for (i = 0; i < statement->nvals; i++) {
1779 values[i] = va_arg(args, const void*);
1782 return dbd_oracle_pbselect(pool, sql, results, statement, seek, values);
1785 static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
1786 apr_dbd_transaction_t **trans)
1788 int ret = 0;
1789 int_errorcode;
1790 if (*trans) {
1791 dbd_oracle_end_transaction(*trans);
1793 else {
1794 *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
1795 OCIHandleAlloc(dbd_oracle_env, (dvoid**)&(*trans)->trans,
1796 OCI_HTYPE_TRANS, 0, 0);
1797 OCIAttrSet(sql->svc, OCI_HTYPE_SVCCTX, (*trans)->trans, 0,
1798 OCI_ATTR_TRANS, sql->err);
1802 sql->status = OCITransStart(sql->svc, sql->err, TRANS_TIMEOUT,
1803 OCI_TRANS_NEW);
1804 switch (sql->status) {
1805 case OCI_ERROR:
1806 #ifdef DEBUG
1807 OCIErrorGet(sql->err, 1, NULL, &errorcode, sql->buf,
1808 sizeof(sql->buf), OCI_HTYPE_ERROR);
1809 printf("Transaction: %s\n", sql->buf);
1810 #endif
1811 ret = 1;
1812 break;
1813 case OCI_SUCCESS:
1814 (*trans)->handle = sql;
1815 (*trans)->status = TRANS_1;
1816 sql->trans = *trans;
1817 switch (OCIDescriptorAlloc(dbd_oracle_env,
1818 (dvoid**)&(*trans)->snapshot1,
1819 OCI_DTYPE_SNAP, 0, NULL)) {
1820 case OCI_SUCCESS:
1821 apr_pool_cleanup_register(pool, (*trans)->snapshot1,
1822 dbd_free_snapshot, apr_pool_cleanup_null);
1823 break;
1824 case OCI_INVALID_HANDLE:
1825 ret = 1;
1826 break;
1828 switch (OCIDescriptorAlloc(dbd_oracle_env,
1829 (dvoid**)&(*trans)->snapshot2,
1830 OCI_DTYPE_SNAP, 0, NULL)) {
1831 case OCI_SUCCESS:
1832 apr_pool_cleanup_register(pool, (*trans)->snapshot2,
1833 dbd_free_snapshot, apr_pool_cleanup_null);
1834 break;
1835 case OCI_INVALID_HANDLE:
1836 ret = 1;
1837 break;
1839 break;
1840 default:
1841 ret = 1;
1842 break;
1844 return ret;
1847 static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans)
1849 int ret = 1; /* no transaction is an error cond */
1850 sword status;
1851 apr_dbd_t *handle = trans->handle;
1852 if (trans) {
1853 switch (trans->status) {
1854 case TRANS_NONE: /* No trans is an error here */
1855 status = OCI_ERROR;
1856 break;
1857 case TRANS_ERROR:
1858 status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1859 break;
1860 default:
1861 /* rollback on explicit rollback request */
1862 if (TXN_DO_ROLLBACK(trans)) {
1863 status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1864 } else {
1865 status = OCITransCommit(handle->svc, handle->err, OCI_DEFAULT);
1867 break;
1870 handle->trans = NULL;
1872 switch (status) {
1873 case OCI_SUCCESS:
1874 ret = 0;
1875 break;
1876 default:
1877 ret = 3;
1878 break;
1881 return ret;
1884 static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t *trans)
1886 if (!trans)
1887 return APR_DBD_TRANSACTION_COMMIT;
1889 return trans->mode;
1892 static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t *trans,
1893 int mode)
1895 if (!trans)
1896 return APR_DBD_TRANSACTION_COMMIT;
1898 return trans->mode = (mode & TXN_MODE_BITS);
1901 /* This doesn't work for BLOB because of NULLs, but it can fake it
1902 * if the BLOB is really a string
1904 static const char *dbd_oracle_get_entry(const apr_dbd_row_t *row, int n)
1906 int_errorcode;
1907 ub4 len = 0;
1908 ub1 csform = 0;
1909 ub2 csid = 0;
1910 apr_size_t buflen = 0;
1911 char *buf = NULL;
1912 define_arg *val = &row->res->statement->out[n];
1913 apr_dbd_t *sql = row->res->handle;
1915 if ((n < 0) || (n >= row->res->statement->nout) || (val->ind == -1)) {
1916 return NULL;
1919 switch (val->type) {
1920 case SQLT_BLOB:
1921 case SQLT_CLOB:
1922 sql->status = OCILobGetLength(sql->svc, sql->err, val->buf.lobval,
1923 &len);
1924 switch (sql->status) {
1925 case OCI_SUCCESS:
1926 case OCI_SUCCESS_WITH_INFO:
1927 if (len == 0) {
1928 buf = "";
1930 break;
1931 case OCI_ERROR:
1932 #ifdef DEBUG
1933 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1934 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1935 printf("Finding LOB length: %s\n", sql->buf);
1936 break;
1937 #endif
1938 default:
1939 break;
1942 if (len == 0) {
1943 break;
1946 if (val->type == APR_DBD_TYPE_CLOB) {
1947 #if 1
1948 /* Is this necessary, or can it be defaulted? */
1949 sql->status = OCILobCharSetForm(dbd_oracle_env, sql->err,
1950 val->buf.lobval, &csform);
1951 if (sql->status == OCI_SUCCESS) {
1952 sql->status = OCILobCharSetId(dbd_oracle_env, sql->err,
1953 val->buf.lobval, &csid);
1955 switch (sql->status) {
1956 case OCI_SUCCESS:
1957 case OCI_SUCCESS_WITH_INFO:
1958 buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1959 /* zeroise all - where the string ends depends on charset */
1960 buf = apr_pcalloc(row->pool, buflen);
1961 break;
1962 #ifdef DEBUG
1963 case OCI_ERROR:
1964 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1965 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1966 printf("Reading LOB character set: %s\n", sql->buf);
1967 break; /*** XXX?? ***/
1968 #endif
1969 default:
1970 break; /*** XXX?? ***/
1972 #else /* ignore charset */
1973 buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1974 /* zeroise all - where the string ends depends on charset */
1975 buf = apr_pcalloc(row->pool, buflen);
1976 #endif
1977 } else {
1978 /* BUG: this'll only work if the BLOB looks like a string */
1979 buflen = len;
1980 buf = apr_palloc(row->pool, buflen+1);
1981 buf[buflen] = 0;
1984 if (!buf) {
1985 break;
1988 sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
1989 &len, 1, (dvoid*) buf, buflen,
1990 NULL, NULL, csid, csform);
1991 switch (sql->status) {
1992 case OCI_SUCCESS:
1993 case OCI_SUCCESS_WITH_INFO:
1994 break;
1995 #ifdef DEBUG
1996 case OCI_ERROR:
1997 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1998 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1999 printf("Reading LOB: %s\n", sql->buf);
2000 buf = NULL; /*** XXX?? ***/
2001 break;
2002 #endif
2003 default:
2004 buf = NULL; /*** XXX?? ***/
2005 break;
2008 break;
2009 case SQLT_LNG:
2010 case SQLT_LBI:
2011 /* raw is struct { ub4 len; char *buf; } */
2012 len = *(ub4*) val->buf.raw;
2013 buf = apr_pstrndup(row->pool, val->buf.sval + sizeof(ub4), len);
2014 break;
2015 default:
2016 buf = apr_pstrndup(row->pool, val->buf.sval, val->len);
2017 break;
2019 return (const char*) buf;
2022 /* XXX Should this use Oracle proper API instead of calling get_entry()? */
2023 static apr_status_t dbd_oracle_datum_get(const apr_dbd_row_t *row, int n,
2024 apr_dbd_type_e type, void *data)
2026 define_arg *val = &row->res->statement->out[n];
2027 const char *entry;
2029 if ((n < 0) || (n >= row->res->statement->nout)) {
2030 return APR_EGENERAL;
2033 if(val->ind == -1) {
2034 return APR_ENOENT;
2037 switch (type) {
2038 case APR_DBD_TYPE_TINY:
2039 entry = dbd_oracle_get_entry(row, n);
2040 if (entry == NULL) {
2041 return APR_ENOENT;
2043 *(char*)data = atoi(entry);
2044 break;
2045 case APR_DBD_TYPE_UTINY:
2046 entry = dbd_oracle_get_entry(row, n);
2047 if (entry == NULL) {
2048 return APR_ENOENT;
2050 *(unsigned char*)data = atoi(entry);
2051 break;
2052 case APR_DBD_TYPE_SHORT:
2053 entry = dbd_oracle_get_entry(row, n);
2054 if (entry == NULL) {
2055 return APR_ENOENT;
2057 *(short*)data = atoi(entry);
2058 break;
2059 case APR_DBD_TYPE_USHORT:
2060 entry = dbd_oracle_get_entry(row, n);
2061 if (entry == NULL) {
2062 return APR_ENOENT;
2064 *(unsigned short*)data = atoi(entry);
2065 break;
2066 case APR_DBD_TYPE_INT:
2067 entry = dbd_oracle_get_entry(row, n);
2068 if (entry == NULL) {
2069 return APR_ENOENT;
2071 *(int*)data = atoi(entry);
2072 break;
2073 case APR_DBD_TYPE_UINT:
2074 entry = dbd_oracle_get_entry(row, n);
2075 if (entry == NULL) {
2076 return APR_ENOENT;
2078 *(unsigned int*)data = atoi(entry);
2079 break;
2080 case APR_DBD_TYPE_LONG:
2081 entry = dbd_oracle_get_entry(row, n);
2082 if (entry == NULL) {
2083 return APR_ENOENT;
2085 *(long*)data = atol(entry);
2086 break;
2087 case APR_DBD_TYPE_ULONG:
2088 entry = dbd_oracle_get_entry(row, n);
2089 if (entry == NULL) {
2090 return APR_ENOENT;
2092 *(unsigned long*)data = atol(entry);
2093 break;
2094 case APR_DBD_TYPE_LONGLONG:
2095 entry = dbd_oracle_get_entry(row, n);
2096 if (entry == NULL) {
2097 return APR_ENOENT;
2099 *(apr_int64_t*)data = apr_atoi64(entry);
2100 break;
2101 case APR_DBD_TYPE_ULONGLONG:
2102 entry = dbd_oracle_get_entry(row, n);
2103 if (entry == NULL) {
2104 return APR_ENOENT;
2106 *(apr_uint64_t*)data = apr_atoi64(entry);
2107 break;
2108 case APR_DBD_TYPE_FLOAT:
2109 entry = dbd_oracle_get_entry(row, n);
2110 if (entry == NULL) {
2111 return APR_ENOENT;
2113 *(float*)data = atof(entry);
2114 break;
2115 case APR_DBD_TYPE_DOUBLE:
2116 entry = dbd_oracle_get_entry(row, n);
2117 if (entry == NULL) {
2118 return APR_ENOENT;
2120 *(double*)data = atof(entry);
2121 break;
2122 case APR_DBD_TYPE_STRING:
2123 case APR_DBD_TYPE_TEXT:
2124 case APR_DBD_TYPE_TIME:
2125 case APR_DBD_TYPE_DATE:
2126 case APR_DBD_TYPE_DATETIME:
2127 case APR_DBD_TYPE_TIMESTAMP:
2128 case APR_DBD_TYPE_ZTIMESTAMP:
2129 entry = dbd_oracle_get_entry(row, n);
2130 if (entry == NULL) {
2131 return APR_ENOENT;
2133 *(char**)data = (char*)entry;
2134 break;
2135 case APR_DBD_TYPE_BLOB:
2136 case APR_DBD_TYPE_CLOB:
2138 apr_bucket *e;
2139 apr_bucket_brigade *b = (apr_bucket_brigade*)data;
2140 apr_dbd_t *sql = row->res->handle;
2141 ub4 len = 0;
2143 switch (val->type) {
2144 case SQLT_BLOB:
2145 case SQLT_CLOB:
2146 sql->status = OCILobGetLength(sql->svc, sql->err,
2147 val->buf.lobval, &len);
2148 switch(sql->status) {
2149 case OCI_SUCCESS:
2150 case OCI_SUCCESS_WITH_INFO:
2151 if (len == 0) {
2152 e = apr_bucket_eos_create(b->bucket_alloc);
2154 else {
2155 e = apr_bucket_lob_create(row, n, 0, len,
2156 row->pool, b->bucket_alloc);
2158 break;
2159 default:
2160 return APR_ENOENT;
2162 break;
2163 default:
2164 entry = dbd_oracle_get_entry(row, n);
2165 if (entry == NULL) {
2166 return APR_ENOENT;
2168 e = apr_bucket_pool_create(entry, strlen(entry),
2169 row->pool, b->bucket_alloc);
2170 break;
2172 APR_BRIGADE_INSERT_TAIL(b, e);
2174 break;
2175 case APR_DBD_TYPE_NULL:
2176 *(void**)data = NULL;
2177 break;
2178 default:
2179 return APR_EGENERAL;
2182 return APR_SUCCESS;
2185 static apr_status_t dbd_oracle_close(apr_dbd_t *handle)
2187 /* FIXME: none of the oracle docs/examples say anything about
2188 * closing/releasing handles. Which seems unlikely ...
2191 /* OK, let's grab from cdemo again.
2192 * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
2194 switch (OCISessionEnd(handle->svc, handle->err, handle->auth,
2195 (ub4)OCI_DEFAULT)) {
2196 default:
2197 break;
2199 switch (OCIServerDetach(handle->svr, handle->err, (ub4) OCI_DEFAULT )) {
2200 default:
2201 break;
2203 /* does OCISessionEnd imply this? */
2204 switch (OCIHandleFree((dvoid *) handle->auth, (ub4) OCI_HTYPE_SESSION)) {
2205 default:
2206 break;
2208 switch (OCIHandleFree((dvoid *) handle->svr, (ub4) OCI_HTYPE_SERVER)) {
2209 default:
2210 break;
2212 switch (OCIHandleFree((dvoid *) handle->svc, (ub4) OCI_HTYPE_SVCCTX)) {
2213 default:
2214 break;
2216 switch (OCIHandleFree((dvoid *) handle->err, (ub4) OCI_HTYPE_ERROR)) {
2217 default:
2218 break;
2220 return APR_SUCCESS;
2223 static apr_status_t dbd_oracle_check_conn(apr_pool_t *pool, apr_dbd_t *sql)
2225 apr_dbd_results_t *res = NULL;
2226 apr_dbd_row_t *row = NULL;
2228 if(dbd_oracle_pselect(pool, sql, &res, sql->check_conn_stmt,
2229 0, NULL) != 0) {
2230 return APR_EGENERAL;
2233 if(dbd_oracle_get_row(pool, res, &row, -1) != 0) {
2234 return APR_EGENERAL;
2237 if(dbd_oracle_get_row(pool, res, &row, -1) != -1) {
2238 return APR_EGENERAL;
2241 return APR_SUCCESS;
2244 static int dbd_oracle_select_db(apr_pool_t *pool, apr_dbd_t *handle,
2245 const char *name)
2247 /* FIXME: need to find this in the docs */
2248 return APR_ENOTIMPL;
2251 static void *dbd_oracle_native(apr_dbd_t *handle)
2253 /* FIXME: can we do anything better? Oracle doesn't seem to have
2254 * a concept of a handle in the sense we use it.
2256 return dbd_oracle_env;
2259 static int dbd_oracle_num_cols(apr_dbd_results_t* res)
2261 return res->statement->nout;
2264 static int dbd_oracle_num_tuples(apr_dbd_results_t* res)
2266 if (!res->seek) {
2267 return -1;
2269 if (res->nrows >= 0) {
2270 return res->nrows;
2272 res->handle->status = OCIAttrGet(res->statement->stmt, OCI_HTYPE_STMT,
2273 &res->nrows, 0, OCI_ATTR_ROW_COUNT,
2274 res->handle->err);
2275 return res->nrows;
2278 APU_DECLARE_DATA const apr_dbd_driver_t apr_dbd_oracle_driver = {
2279 "oracle",
2280 dbd_oracle_init,
2281 dbd_oracle_native,
2282 dbd_oracle_open,
2283 dbd_oracle_check_conn,
2284 dbd_oracle_close,
2285 dbd_oracle_select_db,
2286 dbd_oracle_start_transaction,
2287 dbd_oracle_end_transaction,
2288 dbd_oracle_query,
2289 dbd_oracle_select,
2290 dbd_oracle_num_cols,
2291 dbd_oracle_num_tuples,
2292 dbd_oracle_get_row,
2293 dbd_oracle_get_entry,
2294 dbd_oracle_error,
2295 dbd_oracle_escape,
2296 dbd_oracle_prepare,
2297 dbd_oracle_pvquery,
2298 dbd_oracle_pvselect,
2299 dbd_oracle_pquery,
2300 dbd_oracle_pselect,
2301 dbd_oracle_get_name,
2302 dbd_oracle_transaction_mode_get,
2303 dbd_oracle_transaction_mode_set,
2304 ":apr%d",
2305 dbd_oracle_pvbquery,
2306 dbd_oracle_pvbselect,
2307 dbd_oracle_pbquery,
2308 dbd_oracle_pbselect,
2309 dbd_oracle_datum_get
2311 #endif