1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 /* Developed initially by Nick Kew and Chris Darroch.
18 * Contributed to the APR project by kind permission of
19 * Pearson Education Core Technology Group (CTG),
20 * formerly Central Media Group (CMG).
23 /* apr_dbd_oracle - a painful attempt
25 * Based first on the documentation at
26 * http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/toc.htm
28 * Those docs have a lot of internal inconsistencies, contradictions, etc
29 * So I've snarfed the demo programs (from Oracle 8, not included in
30 * the current downloadable oracle), and used code from them.
32 * Why do cdemo81.c and cdemo82.c do the same thing in very different ways?
33 * e.g. cdemo82 releases all its handle on shutdown; cdemo81 doesn't
35 * All the ORA* functions return a "sword". Some of them are documented;
36 * others aren't. So I've adopted a policy of using switch statements
37 * everywhere, even when we're not doing anything with the return values.
39 * This makes no attempt at performance tuning, such as setting
40 * prefetch cache size. We need some actual performance data
41 * to make that meaningful. Input from someone with experience
42 * as a sysop using oracle would be a good start.
45 /* shut compiler up */
47 #define int_errorcode int errorcode
62 #include "apr_strings.h"
66 #include "apr_buckets.h"
68 #define TRANS_TIMEOUT 30
69 #define MAX_ARG_LEN 256 /* in line with other apr_dbd drivers. We alloc this
70 * lots of times, so a large value gets hungry.
71 * Should really make it configurable
73 #define DEFAULT_LONG_SIZE 4096
74 #define DBD_ORACLE_MAX_COLUMNS 256
75 #define NUMERIC_FIELD_SIZE 32
77 #define CHECK_CONN_QUERY "SELECT 1 FROM dual"
79 #define ERR_BUF_SIZE 200
85 #include "apr_dbd_internal.h"
88 static const char *dbd_oracle_error(apr_dbd_t *sql, int n);
89 static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
90 const char *query, const char *label,
91 int nargs, int nvals, apr_dbd_type_e *types,
92 apr_dbd_prepared_t **statement);
93 static int outputParams(apr_dbd_t*, apr_dbd_prepared_t*);
94 static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
95 apr_dbd_results_t **results,
96 apr_dbd_prepared_t *statement,
97 int seek, const char **values);
98 static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
99 int *nrows, apr_dbd_prepared_t *statement,
100 const char **values);
101 static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
102 apr_dbd_transaction_t **trans);
103 static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans);
105 struct apr_dbd_transaction_t {
107 enum { TRANS_NONE, TRANS_ERROR, TRANS_1, TRANS_2 } status;
110 OCISnapshot *snapshot1;
111 OCISnapshot *snapshot2;
114 struct apr_dbd_results_t {
120 apr_dbd_prepared_t *statement;
129 apr_dbd_transaction_t* trans;
131 char buf[ERR_BUF_SIZE]; /* for error messages */
132 apr_size_t long_size;
133 apr_dbd_prepared_t *check_conn_stmt;
136 struct apr_dbd_row_t {
138 apr_dbd_results_t *res;
153 OCILobLocator *lobval;
160 ub2 len; /* length of actual output */
162 apr_size_t sz; /* length of buf for output */
166 OCILobLocator *lobval;
171 struct apr_dbd_prepared_t {
183 /* AFAICT from the docs, the OCIEnv thingey can be used async
184 * across threads, so lets have a global one.
186 * We'll need shorter-lived envs to deal with requests and connections
188 * Hmmm, that doesn't work: we don't have a usermem framework.
189 * OK, forget about using APR pools here, until we figure out
190 * the right way to do it (if such a thing exists).
192 static OCIEnv *dbd_oracle_env = NULL;
194 /* Oracle specific bucket for BLOB/CLOB types */
195 typedef struct apr_bucket_lob apr_bucket_lob;
197 * A bucket referring to a Oracle BLOB/CLOB
199 struct apr_bucket_lob {
200 /** Number of buckets using this memory */
201 apr_bucket_refcount refcount;
202 /** The row this bucket refers to */
203 const apr_dbd_row_t *row;
204 /** The column this bucket refers to */
206 /** The pool into which any needed structures should
207 * be created while reading from this bucket */
208 apr_pool_t *readpool;
211 static void lob_bucket_destroy(void *data);
212 static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
213 apr_size_t *len, apr_read_type_e block);
214 static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
215 const apr_dbd_row_t *row, int col,
216 apr_off_t offset, apr_size_t len,
218 static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
220 apr_size_t len, apr_pool_t *p,
221 apr_bucket_alloc_t *list);
223 static const apr_bucket_type_t apr_bucket_type_lob = {
224 "LOB", 5, APR_BUCKET_DATA,
227 apr_bucket_setaside_notimpl,
228 apr_bucket_shared_split,
229 apr_bucket_shared_copy
232 static void lob_bucket_destroy(void *data)
234 apr_bucket_lob *f = data;
236 if (apr_bucket_shared_destroy(f)) {
237 /* no need to destroy database objects here; it will get
238 * done automatically when the pool gets cleaned up */
243 static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
244 apr_size_t *len, apr_read_type_e block)
246 apr_bucket_lob *a = e->data;
247 const apr_dbd_row_t *row = a->row;
248 apr_dbd_results_t *res = row->res;
250 apr_bucket *b = NULL;
251 apr_size_t blength = e->length; /* bytes remaining in file past offset */
252 apr_off_t boffset = e->start;
253 define_arg *val = &res->statement->out[col];
254 apr_dbd_t *sql = res->handle;
255 /* Only with 10g, unfortunately
256 oraub8 length = APR_BUCKET_BUFF_SIZE;
258 ub4 length = APR_BUCKET_BUFF_SIZE;
261 *str = NULL; /* in case we die prematurely */
263 /* fetch from offset if not at the beginning */
264 buf = apr_palloc(row->pool, APR_BUCKET_BUFF_SIZE);
265 sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
266 &length, 1 + (size_t)boffset,
267 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
268 NULL, NULL, 0, SQLCS_IMPLICIT);
269 /* Only with 10g, unfortunately
270 sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,
271 &length, NULL, 1 + boffset,
272 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
273 OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
275 if (sql->status != OCI_SUCCESS) {
283 * Change the current bucket to refer to what we read,
284 * even if we read nothing because we hit EOF.
286 apr_bucket_pool_make(e, *str, *len, res->pool);
288 /* If we have more to read from the field, then create another bucket */
290 /* for efficiency, we can just build a new apr_bucket struct
291 * to wrap around the existing LOB bucket */
292 b = apr_bucket_alloc(sizeof(*b), e->list);
293 b->start = boffset + *len;
296 b->type = &apr_bucket_type_lob;
297 b->free = apr_bucket_free;
299 APR_BUCKET_INSERT_AFTER(e, b);
302 lob_bucket_destroy(a);
308 static apr_bucket *apr_bucket_lob_make(apr_bucket *b,
309 const apr_dbd_row_t *row, int col,
310 apr_off_t offset, apr_size_t len,
315 f = apr_bucket_alloc(sizeof(*f), b->list);
320 b = apr_bucket_shared_make(b, f, offset, len);
321 b->type = &apr_bucket_type_lob;
326 static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col,
328 apr_size_t len, apr_pool_t *p,
329 apr_bucket_alloc_t *list)
331 apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
334 b->free = apr_bucket_free;
336 return apr_bucket_lob_make(b, row, col, offset, len, p);
339 static apr_status_t dbd_free_lobdesc(void *lob)
341 switch (OCIDescriptorFree(lob, OCI_DTYPE_LOB)) {
349 static apr_status_t dbd_free_snapshot(void *snap)
351 switch (OCIDescriptorFree(snap, OCI_DTYPE_SNAP)) {
359 static void dbd_oracle_init(apr_pool_t *pool)
361 if (dbd_oracle_env == NULL) {
362 /* Sadly, OCI_SHARED seems to be impossible to use, due to
363 * various Oracle bugs. See, for example, Oracle MetaLink bug 2972890
364 * and PHP bug http://bugs.php.net/bug.php?id=23733
366 #ifdef OCI_NEW_LENGTH_SEMANTICS
367 OCIEnvCreate(&dbd_oracle_env, OCI_THREADED|OCI_NEW_LENGTH_SEMANTICS,
368 NULL, NULL, NULL, NULL, 0, NULL);
370 OCIEnvCreate(&dbd_oracle_env, OCI_THREADED,
371 NULL, NULL, NULL, NULL, 0, NULL);
376 static apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params,
379 apr_dbd_t *ret = apr_pcalloc(pool, sizeof(apr_dbd_t));
399 static const char *const delims = " \r\n\t;|,";
402 ret->long_size = DEFAULT_LONG_SIZE;
404 /* snitch parsing from the MySQL driver */
405 for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {
406 /* don't dereference memory that may not belong to us */
411 for (key = ptr-1; apr_isspace(*key); --key);
413 while (apr_isalpha(*key)) {
415 /* Don't parse off the front of the params */
424 for (value = ptr+1; apr_isspace(*value); ++value);
425 vlen = strcspn(value, delims);
426 for (i=0; fields[i].field != NULL; ++i) {
427 if (!strncasecmp(fields[i].field, key, klen)) {
428 fields[i].value = apr_pstrndup(pool, value, vlen);
435 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->err,
436 OCI_HTYPE_ERROR, 0, NULL);
437 switch (ret->status) {
440 printf("ret->status is %d\n", ret->status);
449 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svr,
450 OCI_HTYPE_SERVER, 0, NULL);
451 switch (ret->status) {
454 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
455 sizeof(ret->buf), OCI_HTYPE_ERROR);
456 printf("OPEN ERROR %d (alloc svr): %s\n", ret->status, ret->buf);
460 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
461 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
462 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
470 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svc,
471 OCI_HTYPE_SVCCTX, 0, NULL);
472 switch (ret->status) {
475 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
476 sizeof(ret->buf), OCI_HTYPE_ERROR);
477 printf("OPEN ERROR %d (alloc svc): %s\n", ret->status, ret->buf);
481 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
482 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
483 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
491 /* All the examples use the #else */
493 ret->status = OCILogon(dbd_oracle_env, ret->err, &ret->svc, fields[0].value,
494 strlen(fields[0].value), fields[1].value,
495 strlen(fields[1].value), fields[2].value,
496 strlen(fields[2].value));
497 switch (ret->status) {
500 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
501 sizeof(ret->buf), OCI_HTYPE_ERROR);
502 printf("OPEN ERROR: %s\n", ret->buf);
506 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
507 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
508 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
516 ret->status = OCIServerAttach(ret->svr, ret->err, (text*) fields[3].value,
517 strlen(fields[3].value), OCI_DEFAULT);
518 switch (ret->status) {
521 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
522 sizeof(ret->buf), OCI_HTYPE_ERROR);
523 printf("OPEN ERROR %d (server attach): %s\n", ret->status, ret->buf);
527 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
528 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
529 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
536 ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->svr, 0,
537 OCI_ATTR_SERVER, ret->err);
538 switch (ret->status) {
541 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
542 sizeof(ret->buf), OCI_HTYPE_ERROR);
543 printf("OPEN ERROR %d (attr set): %s\n", ret->status, ret->buf);
547 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
548 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
549 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
556 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->auth,
557 OCI_HTYPE_SESSION, 0, NULL);
558 switch (ret->status) {
561 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
562 sizeof(ret->buf), OCI_HTYPE_ERROR);
563 printf("OPEN ERROR %d (alloc auth): %s\n", ret->status, ret->buf);
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);
576 ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[0].value,
577 strlen(fields[0].value), OCI_ATTR_USERNAME, ret->err);
578 switch (ret->status) {
581 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
582 sizeof(ret->buf), OCI_HTYPE_ERROR);
583 printf("OPEN ERROR %d (attr username): %s\n", ret->status, ret->buf);
587 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
588 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
589 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
596 ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[1].value,
597 strlen(fields[1].value), OCI_ATTR_PASSWORD, ret->err);
598 switch (ret->status) {
601 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
602 sizeof(ret->buf), OCI_HTYPE_ERROR);
603 printf("OPEN ERROR %d (attr password): %s\n", ret->status, ret->buf);
607 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
608 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
609 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
616 ret->status = OCISessionBegin(ret->svc, ret->err, ret->auth,
617 OCI_CRED_RDBMS, OCI_DEFAULT);
618 switch (ret->status) {
621 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
622 sizeof(ret->buf), OCI_HTYPE_ERROR);
623 printf("OPEN ERROR %d (session begin): %s\n", ret->status, ret->buf);
627 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
628 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
629 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
636 ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->auth, 0,
637 OCI_ATTR_SESSION, ret->err);
638 switch (ret->status) {
641 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
642 sizeof(ret->buf), OCI_HTYPE_ERROR);
643 printf("OPEN ERROR %d (attr session): %s\n", ret->status, ret->buf);
646 *error = apr_pcalloc(pool, ERR_BUF_SIZE);
647 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
648 ERR_BUF_SIZE, OCI_HTYPE_ERROR);
658 if(dbd_oracle_prepare(pool, ret, CHECK_CONN_QUERY, NULL, 0, 0, NULL,
659 &ret->check_conn_stmt) != 0) {
666 #ifdef EXPORT_NATIVE_FUNCS
667 static apr_size_t dbd_oracle_long_size_set(apr_dbd_t *sql,
668 apr_size_t long_size)
670 apr_size_t old_size = sql->long_size;
671 sql->long_size = long_size;
676 static const char *dbd_oracle_get_name(const apr_dbd_results_t *res, int n)
678 define_arg *val = &res->statement->out[n];
680 if ((n < 0) || (n >= res->statement->nout)) {
686 static int dbd_oracle_get_row(apr_pool_t *pool, apr_dbd_results_t *res,
687 apr_dbd_row_t **rowp, int rownum)
689 apr_dbd_row_t *row = *rowp;
690 apr_dbd_t *sql = res->handle;
694 row = apr_palloc(pool, sizeof(apr_dbd_row_t));
697 /* Oracle starts counting at 1 according to the docs */
698 row->n = res->seek ? rownum : 1;
711 sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
712 OCI_FETCH_ABSOLUTE, row->n, OCI_DEFAULT);
715 sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
716 OCI_FETCH_NEXT, 0, OCI_DEFAULT);
718 switch (sql->status) {
726 OCIErrorGet(sql->err, 1, NULL, &errorcode,
727 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
728 printf("Execute error %d: %s\n", sql->status, sql->buf);
737 static const char *dbd_oracle_error(apr_dbd_t *sql, int n)
739 /* This is ugly. Needs us to pass in a buffer of unknown size.
740 * Either we put it on the handle, or we have to keep allocing/copying
744 switch (sql->status) {
746 return "OCI_SUCCESS";
747 case OCI_SUCCESS_WITH_INFO:
748 return "OCI_SUCCESS_WITH_INFO";
750 return "OCI_NEED_DATA";
752 return "OCI_NO_DATA";
753 case OCI_INVALID_HANDLE:
754 return "OCI_INVALID_HANDLE";
755 case OCI_STILL_EXECUTING:
756 return "OCI_STILL_EXECUTING";
758 return "OCI_CONTINUE";
761 switch (OCIErrorGet(sql->err, 1, NULL, &errorcode,
762 (text*) sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR)) {
766 return "internal error: OCIErrorGet failed";
770 static apr_status_t freeStatement(void *statement)
772 int rv = APR_SUCCESS;
773 OCIStmt *stmt = ((apr_dbd_prepared_t*)statement)->stmt;
778 if (OCIHandleAlloc(dbd_oracle_env, (dvoid**)&err, OCI_HTYPE_ERROR,
779 0, NULL) != OCI_SUCCESS) {
782 if (OCIStmtRelease(stmt, err, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS) {
785 if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) {
789 if (OCIHandleFree(stmt, OCI_HTYPE_STMT) != OCI_SUCCESS) {
797 static int dbd_oracle_select(apr_pool_t *pool, apr_dbd_t *sql,
798 apr_dbd_results_t **results,
799 const char *query, int seek)
802 apr_dbd_prepared_t *statement = NULL;
804 ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
809 ret = dbd_oracle_pselect(pool, sql, results, statement, seek, NULL);
817 static int dbd_oracle_query(apr_dbd_t *sql, int *nrows, const char *query)
821 apr_dbd_prepared_t *statement = NULL;
823 if (sql->trans && sql->trans->status == TRANS_ERROR) {
827 /* make our own pool so that APR allocations don't linger and so that
828 * both Stmt and LOB handles are cleaned up (LOB handles may be
829 * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs)
831 apr_pool_create(&pool, sql->pool);
833 ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement);
835 ret = dbd_oracle_pquery(pool, sql, nrows, statement, NULL);
837 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT,
838 nrows, 0, OCI_ATTR_ROW_COUNT,
843 apr_pool_destroy(pool);
848 static const char *dbd_oracle_escape(apr_pool_t *pool, const char *arg,
851 return arg; /* OCI has no concept of string escape */
854 static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql,
855 const char *query, const char *label,
856 int nargs, int nvals, apr_dbd_type_e *types,
857 apr_dbd_prepared_t **statement)
861 apr_dbd_prepared_t *stmt ;
863 if (*statement == NULL) {
864 *statement = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t));
872 /* populate our own args, if any */
874 stmt->args = apr_pcalloc(pool, nargs*sizeof(bind_arg));
875 for (i = 0; i < nargs; i++) {
876 stmt->args[i].type = types[i];
880 sql->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**) &stmt->stmt,
881 OCI_HTYPE_STMT, 0, NULL);
882 if (sql->status != OCI_SUCCESS) {
886 sql->status = OCIStmtPrepare(stmt->stmt, sql->err, (text*) query,
887 strlen(query), OCI_NTV_SYNTAX, OCI_DEFAULT);
888 if (sql->status != OCI_SUCCESS) {
889 OCIHandleFree(stmt->stmt, OCI_HTYPE_STMT);
893 apr_pool_cleanup_register(pool, stmt, freeStatement,
894 apr_pool_cleanup_null);
896 /* Perl gets statement type here */
897 sql->status = OCIAttrGet(stmt->stmt, OCI_HTYPE_STMT, &stmt->type, 0,
898 OCI_ATTR_STMT_TYPE, sql->err);
899 if (sql->status != OCI_SUCCESS) {
903 /* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
905 sql->status = OCIAttrSet(stmt->stmt, OCI_HTYPE_STMT, &prefetch_size,
906 sizeof(prefetch_size), OCI_ATTR_PREFETCH_MEMORY,
908 if (sql->status != OCI_SUCCESS) {
913 if (stmt->type == OCI_STMT_SELECT) {
914 ret = outputParams(sql, stmt);
919 static void dbd_oracle_bind(apr_dbd_prepared_t *statement, const char **values)
921 OCIStmt *stmt = statement->stmt;
922 apr_dbd_t *sql = statement->handle;
926 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
927 if (values[j] == NULL) {
928 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
933 (ub4 *) 0, OCI_DEFAULT);
936 switch (statement->args[i].type) {
937 case APR_DBD_TYPE_BLOB:
939 char *data = (char *)values[j];
940 int size = atoi((char*)values[++j]);
942 /* skip table and column for now */
945 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
947 data, size, SQLT_LBI,
948 &statement->args[i].ind,
951 (ub4 *) 0, OCI_DEFAULT);
954 case APR_DBD_TYPE_CLOB:
956 char *data = (char *)values[j];
957 int size = atoi((char*)values[++j]);
959 /* skip table and column for now */
962 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
964 data, size, SQLT_LNG,
965 &statement->args[i].ind,
968 (ub4 *) 0, OCI_DEFAULT);
972 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
975 strlen(values[j]) + 1,
977 &statement->args[i].ind,
980 (ub4 *) 0, OCI_DEFAULT);
985 if (sql->status != OCI_SUCCESS) {
993 static int outputParams(apr_dbd_t *sql, apr_dbd_prepared_t *stmt)
997 ub2 paramtype[DBD_ORACLE_MAX_COLUMNS];
998 ub2 paramsize[DBD_ORACLE_MAX_COLUMNS];
999 char *paramname[DBD_ORACLE_MAX_COLUMNS];
1000 ub4 paramnamelen[DBD_ORACLE_MAX_COLUMNS];
1003 /* Perl uses 0 where we used 1 */
1004 sql->status = OCIStmtExecute(sql->svc, stmt->stmt, sql->err, 0, 0,
1005 NULL, NULL, OCI_DESCRIBE_ONLY);
1006 switch (sql->status) {
1008 case OCI_SUCCESS_WITH_INFO:
1012 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1013 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1014 printf("Describing prepared statement: %s\n", sql->buf);
1019 while (sql->status == OCI_SUCCESS) {
1020 sql->status = OCIParamGet(stmt->stmt, OCI_HTYPE_STMT,
1021 sql->err, (dvoid**)&parms, stmt->nout+1);
1022 switch (sql->status) {
1024 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1025 ¶mtype[stmt->nout],
1026 0, OCI_ATTR_DATA_TYPE, sql->err);
1027 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1028 ¶msize[stmt->nout],
1029 0, OCI_ATTR_DATA_SIZE, sql->err);
1030 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM,
1031 ¶mname[stmt->nout],
1032 ¶mnamelen[stmt->nout],
1033 OCI_ATTR_NAME, sql->err);
1037 switch (sql->status) {
1041 break; /* this is what we expect at end-of-loop */
1046 /* OK, the above works. We have the params; now OCIDefine them */
1047 stmt->out = apr_palloc(stmt->pool, stmt->nout*sizeof(define_arg));
1048 for (i=0; i<stmt->nout; ++i) {
1049 stmt->out[i].type = paramtype[i];
1050 stmt->out[i].len = stmt->out[i].sz = paramsize[i];
1051 stmt->out[i].name = apr_pstrmemdup(stmt->pool,
1052 paramname[i], paramnamelen[i]);
1053 switch (stmt->out[i].type) {
1055 switch (stmt->out[i].type) {
1056 case SQLT_NUM: /* 2: numeric, Perl worst case=130+38+3 */
1057 stmt->out[i].sz = 171;
1059 case SQLT_CHR: /* 1: char */
1060 case SQLT_AFC: /* 96: ANSI fixed char */
1061 stmt->out[i].sz *= 4; /* ugh, wasteful UCS-4 handling */
1063 case SQLT_DAT: /* 12: date, depends on NLS date format */
1064 stmt->out[i].sz = 75;
1066 case SQLT_BIN: /* 23: raw binary, perhaps UTF-16? */
1067 stmt->out[i].sz *= 2;
1069 case SQLT_RID: /* 11: rowid */
1070 case SQLT_RDD: /* 104: rowid descriptor */
1071 stmt->out[i].sz = 20;
1073 case SQLT_TIMESTAMP: /* 187: timestamp */
1074 case SQLT_TIMESTAMP_TZ: /* 188: timestamp with time zone */
1075 case SQLT_INTERVAL_YM: /* 189: interval year-to-month */
1076 case SQLT_INTERVAL_DS: /* 190: interval day-to-second */
1077 case SQLT_TIMESTAMP_LTZ: /* 232: timestamp with local time zone */
1078 stmt->out[i].sz = 75;
1082 printf("Unsupported data type: %d\n", stmt->out[i].type);
1087 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1088 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1090 stmt->out[i].buf.sval,
1091 stmt->out[i].sz, SQLT_STR,
1092 &stmt->out[i].ind, &stmt->out[i].len,
1095 case SQLT_LNG: /* 8: long */
1096 stmt->out[i].sz = sql->long_size * 4 + 4; /* ugh, UCS-4 handling */
1097 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1098 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1100 stmt->out[i].buf.raw,
1101 stmt->out[i].sz, SQLT_LVC,
1102 &stmt->out[i].ind, NULL,
1105 case SQLT_LBI: /* 24: long binary, perhaps UTF-16? */
1106 stmt->out[i].sz = sql->long_size * 2 + 4; /* room for int prefix */
1107 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1108 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1110 stmt->out[i].buf.raw,
1111 stmt->out[i].sz, SQLT_LVB,
1112 &stmt->out[i].ind, NULL,
1115 case SQLT_BLOB: /* 113 */
1116 case SQLT_CLOB: /* 112 */
1117 /*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1118 sql->status = OCIDescriptorAlloc(dbd_oracle_env,
1119 (dvoid**)&stmt->out[i].buf.lobval,
1120 OCI_DTYPE_LOB, 0, NULL);
1121 apr_pool_cleanup_register(stmt->pool, stmt->out[i].buf.lobval,
1123 apr_pool_cleanup_null);
1124 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1126 (dvoid*) &stmt->out[i].buf.lobval,
1127 -1, stmt->out[i].type,
1128 &stmt->out[i].ind, &stmt->out[i].len,
1132 switch (sql->status) {
1142 static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql,
1143 int *nrows, apr_dbd_prepared_t *statement,
1144 const char **values)
1146 OCISnapshot *oldsnapshot = NULL;
1147 OCISnapshot *newsnapshot = NULL;
1148 apr_dbd_transaction_t* trans = sql->trans;
1153 switch (trans->status) {
1160 oldsnapshot = trans->snapshot1;
1161 newsnapshot = trans->snapshot2;
1162 trans->status = TRANS_2;
1165 oldsnapshot = trans->snapshot2;
1166 newsnapshot = trans->snapshot1;
1167 trans->status = TRANS_1;
1170 exec_mode = OCI_DEFAULT;
1173 exec_mode = OCI_COMMIT_ON_SUCCESS;
1176 dbd_oracle_bind(statement, values);
1178 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1179 oldsnapshot, newsnapshot, exec_mode);
1180 switch (sql->status) {
1185 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1186 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1187 printf("Execute error %d: %s\n", sql->status, sql->buf);
1191 if (TXN_NOTICE_ERRORS(trans)) {
1192 trans->status = TRANS_ERROR;
1197 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1198 OCI_ATTR_ROW_COUNT, sql->err);
1202 static int dbd_oracle_pvquery(apr_pool_t *pool, apr_dbd_t *sql,
1203 int *nrows, apr_dbd_prepared_t *statement,
1206 const char **values;
1209 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1213 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1215 for (i = 0; i < statement->nvals; i++) {
1216 values[i] = va_arg(args, const char*);
1219 return dbd_oracle_pquery(pool, sql, nrows, statement, values);
1222 static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql,
1223 apr_dbd_results_t **results,
1224 apr_dbd_prepared_t *statement,
1225 int seek, const char **values)
1227 int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1228 OCISnapshot *oldsnapshot = NULL;
1229 OCISnapshot *newsnapshot = NULL;
1230 apr_dbd_transaction_t* trans = sql->trans;
1234 switch (trans->status) {
1241 oldsnapshot = trans->snapshot1;
1242 newsnapshot = trans->snapshot2;
1243 trans->status = TRANS_2;
1246 oldsnapshot = trans->snapshot2;
1247 newsnapshot = trans->snapshot1;
1248 trans->status = TRANS_1;
1253 dbd_oracle_bind(statement, values);
1255 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1256 oldsnapshot, newsnapshot, exec_mode);
1257 switch (sql->status) {
1262 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1263 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1264 printf("Executing prepared statement: %s\n", sql->buf);
1268 if (TXN_NOTICE_ERRORS(trans)) {
1269 trans->status = TRANS_ERROR;
1275 *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1277 (*results)->handle = sql;
1278 (*results)->statement = statement;
1279 (*results)->seek = seek;
1280 (*results)->rownum = seek ? 0 : -1;
1281 (*results)->pool = pool;
1286 static int dbd_oracle_pvselect(apr_pool_t *pool, apr_dbd_t *sql,
1287 apr_dbd_results_t **results,
1288 apr_dbd_prepared_t *statement,
1289 int seek, va_list args)
1291 const char **values;
1294 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1298 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1300 for (i = 0; i < statement->nvals; i++) {
1301 values[i] = va_arg(args, const char*);
1304 return dbd_oracle_pselect(pool, sql, results, statement, seek, values);
1307 static void dbd_oracle_bbind(apr_dbd_prepared_t * statement,
1308 const void **values)
1310 OCIStmt *stmt = statement->stmt;
1311 apr_dbd_t *sql = statement->handle;
1314 apr_dbd_type_e type;
1316 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
1317 type = (values[j] == NULL ? APR_DBD_TYPE_NULL
1318 : statement->args[i].type);
1321 case APR_DBD_TYPE_TINY:
1322 statement->args[i].value.ival = *(char*)values[j];
1323 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1325 &statement->args[i].value.ival,
1326 sizeof(statement->args[i].value.ival),
1328 &statement->args[i].ind, NULL,
1330 (ub4 *) 0, OCI_DEFAULT);
1332 case APR_DBD_TYPE_UTINY:
1333 statement->args[i].value.uval = *(unsigned char*)values[j];
1334 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1336 &statement->args[i].value.uval,
1337 sizeof(statement->args[i].value.uval),
1339 &statement->args[i].ind, NULL,
1341 (ub4 *) 0, OCI_DEFAULT);
1343 case APR_DBD_TYPE_SHORT:
1344 statement->args[i].value.ival = *(short*)values[j];
1345 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1347 &statement->args[i].value.ival,
1348 sizeof(statement->args[i].value.ival),
1350 &statement->args[i].ind, NULL,
1352 (ub4 *) 0, OCI_DEFAULT);
1354 case APR_DBD_TYPE_USHORT:
1355 statement->args[i].value.uval = *(unsigned short*)values[j];
1356 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1358 &statement->args[i].value.uval,
1359 sizeof(statement->args[i].value.uval),
1361 &statement->args[i].ind, NULL,
1363 (ub4 *) 0, OCI_DEFAULT);
1365 case APR_DBD_TYPE_INT:
1366 statement->args[i].value.ival = *(int*)values[j];
1367 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1369 &statement->args[i].value.ival,
1370 sizeof(statement->args[i].value.ival),
1372 &statement->args[i].ind, NULL,
1374 (ub4 *) 0, OCI_DEFAULT);
1376 case APR_DBD_TYPE_UINT:
1377 statement->args[i].value.uval = *(unsigned int*)values[j];
1378 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1380 &statement->args[i].value.uval,
1381 sizeof(statement->args[i].value.uval),
1383 &statement->args[i].ind, NULL,
1385 (ub4 *) 0, OCI_DEFAULT);
1387 case APR_DBD_TYPE_LONG:
1388 statement->args[i].value.sval =
1389 apr_psprintf(statement->pool, "%ld", *(long*)values[j]);
1390 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1392 statement->args[i].value.sval,
1393 strlen(statement->args[i].value.sval)+1,
1395 &statement->args[i].ind, NULL,
1397 (ub4 *) 0, OCI_DEFAULT);
1399 case APR_DBD_TYPE_ULONG:
1400 statement->args[i].value.sval =
1401 apr_psprintf(statement->pool, "%lu",
1402 *(unsigned long*)values[j]);
1403 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1405 statement->args[i].value.sval,
1406 strlen(statement->args[i].value.sval)+1,
1408 &statement->args[i].ind, NULL,
1410 (ub4 *) 0, OCI_DEFAULT);
1412 case APR_DBD_TYPE_LONGLONG:
1413 statement->args[i].value.sval =
1414 apr_psprintf(statement->pool, "%" APR_INT64_T_FMT,
1415 *(apr_int64_t*)values[j]);
1416 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1418 statement->args[i].value.sval,
1419 strlen(statement->args[i].value.sval)+1,
1421 &statement->args[i].ind, NULL,
1423 (ub4 *) 0, OCI_DEFAULT);
1425 case APR_DBD_TYPE_ULONGLONG:
1426 statement->args[i].value.sval =
1427 apr_psprintf(statement->pool, "%" APR_UINT64_T_FMT,
1428 *(apr_uint64_t*)values[j]);
1429 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1431 statement->args[i].value.sval,
1432 strlen(statement->args[i].value.sval)+1,
1434 &statement->args[i].ind, NULL,
1436 (ub4 *) 0, OCI_DEFAULT);
1438 case APR_DBD_TYPE_FLOAT:
1439 statement->args[i].value.fval = *(float*)values[j];
1440 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1442 &statement->args[i].value.fval,
1443 sizeof(statement->args[i].value.fval),
1445 &statement->args[i].ind, NULL,
1447 (ub4 *) 0, OCI_DEFAULT);
1449 case APR_DBD_TYPE_DOUBLE:
1450 statement->args[i].value.fval = *(double*)values[j];
1451 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1453 &statement->args[i].value.fval,
1454 sizeof(statement->args[i].value.fval),
1456 &statement->args[i].ind, NULL,
1458 (ub4 *) 0, OCI_DEFAULT);
1460 case APR_DBD_TYPE_STRING:
1461 case APR_DBD_TYPE_TEXT:
1462 case APR_DBD_TYPE_TIME:
1463 case APR_DBD_TYPE_DATE:
1464 case APR_DBD_TYPE_DATETIME:
1465 case APR_DBD_TYPE_TIMESTAMP:
1466 case APR_DBD_TYPE_ZTIMESTAMP:
1467 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1470 strlen(values[j]) + 1,
1472 &statement->args[i].ind, NULL,
1474 (ub4 *) 0, OCI_DEFAULT);
1476 case APR_DBD_TYPE_BLOB:
1478 char *data = (char *)values[j];
1479 apr_size_t size = *(apr_size_t*)values[++j];
1481 /* skip table and column for now */
1484 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1486 data, size, SQLT_LBI,
1487 &statement->args[i].ind,
1490 (ub4 *) 0, OCI_DEFAULT);
1493 case APR_DBD_TYPE_CLOB:
1495 char *data = (char *)values[j];
1496 apr_size_t size = *(apr_size_t*)values[++j];
1498 /* skip table and column for now */
1501 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1503 data, size, SQLT_LNG,
1504 &statement->args[i].ind,
1507 (ub4 *) 0, OCI_DEFAULT);
1510 case APR_DBD_TYPE_NULL:
1512 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1517 (ub4 *) 0, OCI_DEFAULT);
1521 if (sql->status != OCI_SUCCESS) {
1529 static int dbd_oracle_pbquery(apr_pool_t * pool, apr_dbd_t * sql,
1530 int *nrows, apr_dbd_prepared_t * statement,
1531 const void **values)
1533 OCISnapshot *oldsnapshot = NULL;
1534 OCISnapshot *newsnapshot = NULL;
1535 apr_dbd_transaction_t* trans = sql->trans;
1540 switch (trans->status) {
1547 oldsnapshot = trans->snapshot1;
1548 newsnapshot = trans->snapshot2;
1549 trans->status = TRANS_2;
1552 oldsnapshot = trans->snapshot2;
1553 newsnapshot = trans->snapshot1;
1554 trans->status = TRANS_1;
1557 exec_mode = OCI_DEFAULT;
1560 exec_mode = OCI_COMMIT_ON_SUCCESS;
1563 dbd_oracle_bbind(statement, values);
1565 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1566 oldsnapshot, newsnapshot, exec_mode);
1567 switch (sql->status) {
1572 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1573 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1574 printf("Execute error %d: %s\n", sql->status, sql->buf);
1578 if (TXN_NOTICE_ERRORS(trans)) {
1579 trans->status = TRANS_ERROR;
1584 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1585 OCI_ATTR_ROW_COUNT, sql->err);
1589 static int dbd_oracle_pvbquery(apr_pool_t * pool, apr_dbd_t * sql,
1590 int *nrows, apr_dbd_prepared_t * statement,
1593 const void **values;
1596 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1600 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1602 for (i = 0; i < statement->nvals; i++) {
1603 values[i] = va_arg(args, const void*);
1606 return dbd_oracle_pbquery(pool, sql, nrows, statement, values);
1609 static int dbd_oracle_pbselect(apr_pool_t * pool, apr_dbd_t * sql,
1610 apr_dbd_results_t ** results,
1611 apr_dbd_prepared_t * statement,
1612 int seek, const void **values)
1614 int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
1615 OCISnapshot *oldsnapshot = NULL;
1616 OCISnapshot *newsnapshot = NULL;
1617 apr_dbd_transaction_t* trans = sql->trans;
1621 switch (trans->status) {
1628 oldsnapshot = trans->snapshot1;
1629 newsnapshot = trans->snapshot2;
1630 trans->status = TRANS_2;
1633 oldsnapshot = trans->snapshot2;
1634 newsnapshot = trans->snapshot1;
1635 trans->status = TRANS_1;
1640 dbd_oracle_bbind(statement, values);
1642 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1643 oldsnapshot, newsnapshot, exec_mode);
1644 switch (sql->status) {
1649 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1650 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1651 printf("Executing prepared statement: %s\n", sql->buf);
1655 if (TXN_NOTICE_ERRORS(trans)) {
1656 trans->status = TRANS_ERROR;
1662 *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1664 (*results)->handle = sql;
1665 (*results)->statement = statement;
1666 (*results)->seek = seek;
1667 (*results)->rownum = seek ? 0 : -1;
1668 (*results)->pool = pool;
1673 static int dbd_oracle_pvbselect(apr_pool_t * pool, apr_dbd_t * sql,
1674 apr_dbd_results_t ** results,
1675 apr_dbd_prepared_t * statement, int seek,
1678 const void **values;
1681 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1685 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1687 for (i = 0; i < statement->nvals; i++) {
1688 values[i] = va_arg(args, const void*);
1691 return dbd_oracle_pbselect(pool, sql, results, statement, seek, values);
1694 static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql,
1695 apr_dbd_transaction_t **trans)
1700 dbd_oracle_end_transaction(*trans);
1703 *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t));
1704 OCIHandleAlloc(dbd_oracle_env, (dvoid**)&(*trans)->trans,
1705 OCI_HTYPE_TRANS, 0, 0);
1706 OCIAttrSet(sql->svc, OCI_HTYPE_SVCCTX, (*trans)->trans, 0,
1707 OCI_ATTR_TRANS, sql->err);
1711 sql->status = OCITransStart(sql->svc, sql->err, TRANS_TIMEOUT,
1713 switch (sql->status) {
1716 OCIErrorGet(sql->err, 1, NULL, &errorcode, sql->buf,
1717 sizeof(sql->buf), OCI_HTYPE_ERROR);
1718 printf("Transaction: %s\n", sql->buf);
1723 (*trans)->handle = sql;
1724 (*trans)->status = TRANS_1;
1725 sql->trans = *trans;
1726 switch (OCIDescriptorAlloc(dbd_oracle_env,
1727 (dvoid**)&(*trans)->snapshot1,
1728 OCI_DTYPE_SNAP, 0, NULL)) {
1730 apr_pool_cleanup_register(pool, (*trans)->snapshot1,
1731 dbd_free_snapshot, apr_pool_cleanup_null);
1733 case OCI_INVALID_HANDLE:
1737 switch (OCIDescriptorAlloc(dbd_oracle_env,
1738 (dvoid**)&(*trans)->snapshot2,
1739 OCI_DTYPE_SNAP, 0, NULL)) {
1741 apr_pool_cleanup_register(pool, (*trans)->snapshot2,
1742 dbd_free_snapshot, apr_pool_cleanup_null);
1744 case OCI_INVALID_HANDLE:
1756 static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans)
1758 int ret = 1; /* no transaction is an error cond */
1760 apr_dbd_t *handle = trans->handle;
1762 switch (trans->status) {
1763 case TRANS_NONE: /* No trans is an error here */
1767 status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1770 /* rollback on explicit rollback request */
1771 if (TXN_DO_ROLLBACK(trans)) {
1772 status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT);
1774 status = OCITransCommit(handle->svc, handle->err, OCI_DEFAULT);
1779 handle->trans = NULL;
1793 static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t *trans)
1796 return APR_DBD_TRANSACTION_COMMIT;
1801 static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t *trans,
1805 return APR_DBD_TRANSACTION_COMMIT;
1807 return trans->mode = (mode & TXN_MODE_BITS);
1810 /* This doesn't work for BLOB because of NULLs, but it can fake it
1811 * if the BLOB is really a string
1813 static const char *dbd_oracle_get_entry(const apr_dbd_row_t *row, int n)
1818 apr_size_t buflen = 0;
1820 define_arg *val = &row->res->statement->out[n];
1821 apr_dbd_t *sql = row->res->handle;
1824 if ((n < 0) || (n >= row->res->statement->nout) || (val->ind == -1)) {
1828 switch (val->type) {
1831 sql->status = OCILobGetLength(sql->svc, sql->err, val->buf.lobval,
1833 switch (sql->status) {
1835 case OCI_SUCCESS_WITH_INFO:
1842 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1843 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1844 printf("Finding LOB length: %s\n", sql->buf);
1855 if (val->type == APR_DBD_TYPE_CLOB) {
1857 /* Is this necessary, or can it be defaulted? */
1858 sql->status = OCILobCharSetForm(dbd_oracle_env, sql->err,
1859 val->buf.lobval, &csform);
1860 if (sql->status == OCI_SUCCESS) {
1861 sql->status = OCILobCharSetId(dbd_oracle_env, sql->err,
1862 val->buf.lobval, &csid);
1864 switch (sql->status) {
1866 case OCI_SUCCESS_WITH_INFO:
1867 buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1868 /* zeroise all - where the string ends depends on charset */
1869 buf = apr_pcalloc(row->pool, buflen);
1873 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1874 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1875 printf("Reading LOB character set: %s\n", sql->buf);
1876 break; /*** XXX?? ***/
1879 break; /*** XXX?? ***/
1881 #else /* ignore charset */
1882 buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1883 /* zeroise all - where the string ends depends on charset */
1884 buf = apr_pcalloc(row->pool, buflen);
1887 /* BUG: this'll only work if the BLOB looks like a string */
1889 buf = apr_palloc(row->pool, buflen+1);
1897 sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
1898 &len, 1, (dvoid*) buf, buflen,
1899 NULL, NULL, csid, csform);
1900 switch (sql->status) {
1902 case OCI_SUCCESS_WITH_INFO:
1906 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1907 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1908 printf("Reading LOB: %s\n", sql->buf);
1909 buf = NULL; /*** XXX?? ***/
1913 buf = NULL; /*** XXX?? ***/
1920 /* raw is struct { ub4 len; char *buf; } */
1921 len = *(ub4*) val->buf.raw;
1922 buf = apr_pstrndup(row->pool, val->buf.sval + sizeof(ub4), len);
1925 buf = apr_pstrndup(row->pool, val->buf.sval, val->len);
1928 return (const char*) buf;
1931 /* XXX Should this use Oracle proper API instead of calling get_entry()? */
1932 static apr_status_t dbd_oracle_datum_get(const apr_dbd_row_t *row, int n,
1933 apr_dbd_type_e type, void *data)
1935 define_arg *val = &row->res->statement->out[n];
1938 if ((n < 0) || (n >= row->res->statement->nout)) {
1939 return APR_EGENERAL;
1942 if(val->ind == -1) {
1947 case APR_DBD_TYPE_TINY:
1948 entry = dbd_oracle_get_entry(row, n);
1949 if (entry == NULL) {
1952 *(char*)data = atoi(entry);
1954 case APR_DBD_TYPE_UTINY:
1955 entry = dbd_oracle_get_entry(row, n);
1956 if (entry == NULL) {
1959 *(unsigned char*)data = atoi(entry);
1961 case APR_DBD_TYPE_SHORT:
1962 entry = dbd_oracle_get_entry(row, n);
1963 if (entry == NULL) {
1966 *(short*)data = atoi(entry);
1968 case APR_DBD_TYPE_USHORT:
1969 entry = dbd_oracle_get_entry(row, n);
1970 if (entry == NULL) {
1973 *(unsigned short*)data = atoi(entry);
1975 case APR_DBD_TYPE_INT:
1976 entry = dbd_oracle_get_entry(row, n);
1977 if (entry == NULL) {
1980 *(int*)data = atoi(entry);
1982 case APR_DBD_TYPE_UINT:
1983 entry = dbd_oracle_get_entry(row, n);
1984 if (entry == NULL) {
1987 *(unsigned int*)data = atoi(entry);
1989 case APR_DBD_TYPE_LONG:
1990 entry = dbd_oracle_get_entry(row, n);
1991 if (entry == NULL) {
1994 *(long*)data = atol(entry);
1996 case APR_DBD_TYPE_ULONG:
1997 entry = dbd_oracle_get_entry(row, n);
1998 if (entry == NULL) {
2001 *(unsigned long*)data = atol(entry);
2003 case APR_DBD_TYPE_LONGLONG:
2004 entry = dbd_oracle_get_entry(row, n);
2005 if (entry == NULL) {
2008 *(apr_int64_t*)data = apr_atoi64(entry);
2010 case APR_DBD_TYPE_ULONGLONG:
2011 entry = dbd_oracle_get_entry(row, n);
2012 if (entry == NULL) {
2015 *(apr_uint64_t*)data = apr_atoi64(entry);
2017 case APR_DBD_TYPE_FLOAT:
2018 entry = dbd_oracle_get_entry(row, n);
2019 if (entry == NULL) {
2022 *(float*)data = (float)atof(entry);
2024 case APR_DBD_TYPE_DOUBLE:
2025 entry = dbd_oracle_get_entry(row, n);
2026 if (entry == NULL) {
2029 *(double*)data = atof(entry);
2031 case APR_DBD_TYPE_STRING:
2032 case APR_DBD_TYPE_TEXT:
2033 case APR_DBD_TYPE_TIME:
2034 case APR_DBD_TYPE_DATE:
2035 case APR_DBD_TYPE_DATETIME:
2036 case APR_DBD_TYPE_TIMESTAMP:
2037 case APR_DBD_TYPE_ZTIMESTAMP:
2038 entry = dbd_oracle_get_entry(row, n);
2039 if (entry == NULL) {
2042 *(char**)data = (char*)entry;
2044 case APR_DBD_TYPE_BLOB:
2045 case APR_DBD_TYPE_CLOB:
2048 apr_bucket_brigade *b = (apr_bucket_brigade*)data;
2049 apr_dbd_t *sql = row->res->handle;
2052 switch (val->type) {
2055 sql->status = OCILobGetLength(sql->svc, sql->err,
2056 val->buf.lobval, &len);
2057 switch(sql->status) {
2059 case OCI_SUCCESS_WITH_INFO:
2061 e = apr_bucket_eos_create(b->bucket_alloc);
2064 e = apr_bucket_lob_create(row, n, 0, len,
2065 row->pool, b->bucket_alloc);
2073 entry = dbd_oracle_get_entry(row, n);
2074 if (entry == NULL) {
2077 e = apr_bucket_pool_create(entry, strlen(entry),
2078 row->pool, b->bucket_alloc);
2081 APR_BRIGADE_INSERT_TAIL(b, e);
2084 case APR_DBD_TYPE_NULL:
2085 *(void**)data = NULL;
2088 return APR_EGENERAL;
2094 static apr_status_t dbd_oracle_close(apr_dbd_t *handle)
2096 /* FIXME: none of the oracle docs/examples say anything about
2097 * closing/releasing handles. Which seems unlikely ...
2100 /* OK, let's grab from cdemo again.
2101 * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
2103 switch (OCISessionEnd(handle->svc, handle->err, handle->auth,
2104 (ub4)OCI_DEFAULT)) {
2108 switch (OCIServerDetach(handle->svr, handle->err, (ub4) OCI_DEFAULT )) {
2112 /* does OCISessionEnd imply this? */
2113 switch (OCIHandleFree((dvoid *) handle->auth, (ub4) OCI_HTYPE_SESSION)) {
2117 switch (OCIHandleFree((dvoid *) handle->svr, (ub4) OCI_HTYPE_SERVER)) {
2121 switch (OCIHandleFree((dvoid *) handle->svc, (ub4) OCI_HTYPE_SVCCTX)) {
2125 switch (OCIHandleFree((dvoid *) handle->err, (ub4) OCI_HTYPE_ERROR)) {
2132 static apr_status_t dbd_oracle_check_conn(apr_pool_t *pool, apr_dbd_t *sql)
2134 apr_dbd_results_t *res = NULL;
2135 apr_dbd_row_t *row = NULL;
2137 if(dbd_oracle_pselect(pool, sql, &res, sql->check_conn_stmt,
2139 return APR_EGENERAL;
2142 if(dbd_oracle_get_row(pool, res, &row, -1) != 0) {
2143 return APR_EGENERAL;
2146 if(dbd_oracle_get_row(pool, res, &row, -1) != -1) {
2147 return APR_EGENERAL;
2153 static int dbd_oracle_select_db(apr_pool_t *pool, apr_dbd_t *handle,
2156 /* FIXME: need to find this in the docs */
2157 return APR_ENOTIMPL;
2160 static void *dbd_oracle_native(apr_dbd_t *handle)
2162 /* FIXME: can we do anything better? Oracle doesn't seem to have
2163 * a concept of a handle in the sense we use it.
2165 return dbd_oracle_env;
2168 static int dbd_oracle_num_cols(apr_dbd_results_t* res)
2170 return res->statement->nout;
2173 static int dbd_oracle_num_tuples(apr_dbd_results_t* res)
2178 if (res->nrows >= 0) {
2181 res->handle->status = OCIAttrGet(res->statement->stmt, OCI_HTYPE_STMT,
2182 &res->nrows, 0, OCI_ATTR_ROW_COUNT,
2187 APU_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_oracle_driver = {
2192 dbd_oracle_check_conn,
2194 dbd_oracle_select_db,
2195 dbd_oracle_start_transaction,
2196 dbd_oracle_end_transaction,
2199 dbd_oracle_num_cols,
2200 dbd_oracle_num_tuples,
2202 dbd_oracle_get_entry,
2207 dbd_oracle_pvselect,
2210 dbd_oracle_get_name,
2211 dbd_oracle_transaction_mode_get,
2212 dbd_oracle_transaction_mode_set,
2214 dbd_oracle_pvbquery,
2215 dbd_oracle_pvbselect,
2217 dbd_oracle_pbselect,
2218 dbd_oracle_datum_get