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
58 #define GLOBAL_PREPARED_STATEMENTS
61 /* shut compiler up */
63 #define int_errorcode int errorcode
78 #include "apr_strings.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
96 #include "apr_dbd_internal.h"
99 static const char *dbd_oracle_error(apr_dbd_t
*sql
, int n
);
100 static int dbd_oracle_prepare(apr_pool_t
*pool
, apr_dbd_t
*sql
,
101 const char *query
, const char *label
,
102 int nargs
, int nvals
, apr_dbd_type_e
*types
,
103 apr_dbd_prepared_t
**statement
);
104 static int outputParams(apr_dbd_t
*, apr_dbd_prepared_t
*);
105 static int dbd_oracle_pselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
106 apr_dbd_results_t
**results
,
107 apr_dbd_prepared_t
*statement
,
108 int seek
, const char **values
);
109 static int dbd_oracle_pquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
110 int *nrows
, apr_dbd_prepared_t
*statement
,
111 const char **values
);
112 static int dbd_oracle_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*sql
,
113 apr_dbd_transaction_t
**trans
);
114 static int dbd_oracle_end_transaction(apr_dbd_transaction_t
*trans
);
116 struct apr_dbd_transaction_t
{
118 enum { TRANS_NONE
, TRANS_ERROR
, TRANS_1
, TRANS_2
} status
;
121 OCISnapshot
*snapshot1
;
122 OCISnapshot
*snapshot2
;
125 struct apr_dbd_results_t
{
131 apr_dbd_prepared_t
*statement
;
140 apr_dbd_transaction_t
* trans
;
142 char buf
[200]; /* for error messages */
143 apr_size_t long_size
;
146 struct apr_dbd_row_t
{
148 apr_dbd_results_t
*res
;
163 OCILobLocator
*lobval
;
170 ub2 len
; /* length of actual output */
172 apr_size_t sz
; /* length of buf for output */
176 OCILobLocator
*lobval
;
181 struct apr_dbd_prepared_t
{
193 /* AFAICT from the docs, the OCIEnv thingey can be used async
194 * across threads, so lets have a global one.
196 * We'll need shorter-lived envs to deal with requests and connections
198 * Hmmm, that doesn't work: we don't have a usermem framework.
199 * OK, forget about using APR pools here, until we figure out
200 * the right way to do it (if such a thing exists).
202 static OCIEnv
*dbd_oracle_env
= NULL
;
203 #ifdef GLOBAL_PREPARED_STATEMENTS
204 static apr_hash_t
*oracle_statements
= NULL
;
207 /* Oracle specific bucket for BLOB/CLOB types */
208 typedef struct apr_bucket_lob apr_bucket_lob
;
210 * A bucket referring to a Oracle BLOB/CLOB
212 struct apr_bucket_lob
{
213 /** Number of buckets using this memory */
214 apr_bucket_refcount refcount
;
215 /** The row this bucket refers to */
216 const apr_dbd_row_t
*row
;
217 /** The column this bucket refers to */
219 /** The pool into which any needed structures should
220 * be created while reading from this bucket */
221 apr_pool_t
*readpool
;
224 static void lob_bucket_destroy(void *data
);
225 static apr_status_t
lob_bucket_read(apr_bucket
*e
, const char **str
,
226 apr_size_t
*len
, apr_read_type_e block
);
227 static apr_bucket
*apr_bucket_lob_make(apr_bucket
*b
,
228 const apr_dbd_row_t
*row
, int col
,
229 apr_off_t offset
, apr_size_t len
,
231 static apr_bucket
*apr_bucket_lob_create(const apr_dbd_row_t
*row
, int col
,
233 apr_size_t len
, apr_pool_t
*p
,
234 apr_bucket_alloc_t
*list
);
236 static const apr_bucket_type_t apr_bucket_type_lob
= {
237 "LOB", 5, APR_BUCKET_DATA
,
240 apr_bucket_setaside_notimpl
,
241 apr_bucket_shared_split
,
242 apr_bucket_shared_copy
245 static void lob_bucket_destroy(void *data
)
247 apr_bucket_lob
*f
= data
;
249 if (apr_bucket_shared_destroy(f
)) {
250 /* no need to destroy database objects here; it will get
251 * done automatically when the pool gets cleaned up */
256 static apr_status_t
lob_bucket_read(apr_bucket
*e
, const char **str
,
257 apr_size_t
*len
, apr_read_type_e block
)
259 apr_bucket_lob
*a
= e
->data
;
260 const apr_dbd_row_t
*row
= a
->row
;
261 apr_dbd_results_t
*res
= row
->res
;
263 apr_bucket
*b
= NULL
;
264 apr_size_t blength
= e
->length
; /* bytes remaining in file past offset */
265 apr_off_t boffset
= e
->start
;
266 define_arg
*val
= &res
->statement
->out
[col
];
267 apr_dbd_t
*sql
= res
->handle
;
268 /* Only with 10g, unfortunately
269 oraub8 length = APR_BUCKET_BUFF_SIZE;
271 ub4 length
= APR_BUCKET_BUFF_SIZE
;
274 *str
= NULL
; /* in case we die prematurely */
276 /* fetch from offset if not at the beginning */
277 buf
= apr_palloc(row
->pool
, APR_BUCKET_BUFF_SIZE
);
278 sql
->status
= OCILobRead(sql
->svc
, sql
->err
, val
->buf
.lobval
,
279 &length
, 1 + boffset
,
280 (dvoid
*) buf
, APR_BUCKET_BUFF_SIZE
,
281 NULL
, NULL
, 0, SQLCS_IMPLICIT
);
282 /* Only with 10g, unfortunately
283 sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,
284 &length, NULL, 1 + boffset,
285 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
286 OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
288 if (sql
->status
!= OCI_SUCCESS
) {
296 * Change the current bucket to refer to what we read,
297 * even if we read nothing because we hit EOF.
299 apr_bucket_pool_make(e
, *str
, *len
, res
->pool
);
301 /* If we have more to read from the field, then create another bucket */
303 /* for efficiency, we can just build a new apr_bucket struct
304 * to wrap around the existing LOB bucket */
305 b
= apr_bucket_alloc(sizeof(*b
), e
->list
);
306 b
->start
= boffset
+ *len
;
309 b
->type
= &apr_bucket_type_lob
;
310 b
->free
= apr_bucket_free
;
312 APR_BUCKET_INSERT_AFTER(e
, b
);
315 lob_bucket_destroy(a
);
321 static apr_bucket
*apr_bucket_lob_make(apr_bucket
*b
,
322 const apr_dbd_row_t
*row
, int col
,
323 apr_off_t offset
, apr_size_t len
,
328 f
= apr_bucket_alloc(sizeof(*f
), b
->list
);
333 b
= apr_bucket_shared_make(b
, f
, offset
, len
);
334 b
->type
= &apr_bucket_type_lob
;
339 static apr_bucket
*apr_bucket_lob_create(const apr_dbd_row_t
*row
, int col
,
341 apr_size_t len
, apr_pool_t
*p
,
342 apr_bucket_alloc_t
*list
)
344 apr_bucket
*b
= apr_bucket_alloc(sizeof(*b
), list
);
347 b
->free
= apr_bucket_free
;
349 return apr_bucket_lob_make(b
, row
, col
, offset
, len
, p
);
352 static apr_status_t
dbd_free_lobdesc(void *lob
)
354 switch (OCIDescriptorFree(lob
, OCI_DTYPE_LOB
)) {
362 static apr_status_t
dbd_free_snapshot(void *snap
)
364 switch (OCIDescriptorFree(snap
, OCI_DTYPE_SNAP
)) {
372 #ifdef GLOBAL_PREPARED_STATEMENTS
373 static apr_status_t
freeStatements(void *ptr
)
375 apr_status_t rv
= APR_SUCCESS
;
377 apr_hash_index_t
*index
;
378 apr_pool_t
*cachepool
= apr_hash_pool_get(oracle_statements
);
383 if (OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&err
, OCI_HTYPE_ERROR
, 0, NULL
)
389 for (index
= apr_hash_first(cachepool
, oracle_statements
);
391 index
= apr_hash_next(index
)) {
392 apr_hash_this(index
, NULL
, NULL
, (void**)&stmt
);
394 if (OCIStmtRelease(stmt
, err
, NULL
, 0, OCI_DEFAULT
) != OCI_SUCCESS
) {
398 if (OCIHandleFree(stmt
, OCI_HTYPE_STMT
) != OCI_SUCCESS
) {
404 if (OCIHandleFree(err
, OCI_HTYPE_ERROR
) != OCI_SUCCESS
) {
412 static void dbd_oracle_init(apr_pool_t
*pool
)
414 if (dbd_oracle_env
== NULL
) {
415 /* Sadly, OCI_SHARED seems to be impossible to use, due to
416 * various Oracle bugs. See, for example, Oracle MetaLink bug 2972890
417 * and PHP bug http://bugs.php.net/bug.php?id=23733
419 #ifdef OCI_NEW_LENGTH_SEMANTICS
420 OCIEnvCreate(&dbd_oracle_env
, OCI_THREADED
|OCI_NEW_LENGTH_SEMANTICS
,
421 NULL
, NULL
, NULL
, NULL
, 0, NULL
);
423 OCIEnvCreate(&dbd_oracle_env
, OCI_THREADED
,
424 NULL
, NULL
, NULL
, NULL
, 0, NULL
);
427 #ifdef GLOBAL_PREPARED_STATEMENTS
428 if (oracle_statements
== NULL
) {
430 oracle_statements
= apr_hash_make(pool
);
431 apr_pool_cleanup_register(pool
, oracle_statements
,
432 freeStatements
, apr_pool_cleanup_null
);
437 static apr_dbd_t
*dbd_oracle_open(apr_pool_t
*pool
, const char *params
)
439 apr_dbd_t
*ret
= apr_pcalloc(pool
, sizeof(apr_dbd_t
));
459 static const char *const delims
= " \r\n\t;|,";
461 ret
->long_size
= DEFAULT_LONG_SIZE
;
463 /* Use our own pool, to avoid possible race conditions
466 if (apr_pool_create(&ret
->pool
, pool
) != APR_SUCCESS
) {
470 /* snitch parsing from the MySQL driver */
471 for (ptr
= strchr(params
, '='); ptr
; ptr
= strchr(ptr
, '=')) {
472 for (key
= ptr
-1; isspace(*key
); --key
);
474 while (isalpha(*key
)) {
476 /* Don't parse off the front of the params */
485 for (value
= ptr
+1; isspace(*value
); ++value
);
486 vlen
= strcspn(value
, delims
);
487 for (i
=0; fields
[i
].field
!= NULL
; ++i
) {
488 if (!strncasecmp(fields
[i
].field
, key
, klen
)) {
489 fields
[i
].value
= apr_pstrndup(pool
, value
, vlen
);
496 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->err
,
497 OCI_HTYPE_ERROR
, 0, NULL
);
498 switch (ret
->status
) {
501 printf("ret->status is %d\n", ret
->status
);
510 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->svr
,
511 OCI_HTYPE_SERVER
, 0, NULL
);
512 switch (ret
->status
) {
515 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
516 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
517 printf("OPEN ERROR %d (alloc svr): %s\n", ret
->status
, ret
->buf
);
526 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->svc
,
527 OCI_HTYPE_SVCCTX
, 0, NULL
);
528 switch (ret
->status
) {
531 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
532 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
533 printf("OPEN ERROR %d (alloc svc): %s\n", ret
->status
, ret
->buf
);
542 /* All the examples use the #else */
544 ret
->status
= OCILogon(dbd_oracle_env
, ret
->err
, &ret
->svc
, fields
[0].value
,
545 strlen(fields
[0].value
), fields
[1].value
,
546 strlen(fields
[1].value
), fields
[2].value
,
547 strlen(fields
[2].value
));
548 switch (ret
->status
) {
551 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
552 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
553 printf("OPEN ERROR: %s\n", ret
->buf
);
562 ret
->status
= OCIServerAttach(ret
->svr
, ret
->err
, (text
*) fields
[3].value
,
563 strlen(fields
[3].value
), OCI_DEFAULT
);
564 switch (ret
->status
) {
567 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
568 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
569 printf("OPEN ERROR %d (server attach): %s\n", ret
->status
, ret
->buf
);
577 ret
->status
= OCIAttrSet(ret
->svc
, OCI_HTYPE_SVCCTX
, ret
->svr
, 0,
578 OCI_ATTR_SERVER
, ret
->err
);
579 switch (ret
->status
) {
582 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
583 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
584 printf("OPEN ERROR %d (attr set): %s\n", ret
->status
, ret
->buf
);
592 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->auth
,
593 OCI_HTYPE_SESSION
, 0, NULL
);
594 switch (ret
->status
) {
597 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
598 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
599 printf("OPEN ERROR %d (alloc auth): %s\n", ret
->status
, ret
->buf
);
607 ret
->status
= OCIAttrSet(ret
->auth
, OCI_HTYPE_SESSION
, fields
[0].value
,
608 strlen(fields
[0].value
), OCI_ATTR_USERNAME
, ret
->err
);
609 switch (ret
->status
) {
612 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
613 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
614 printf("OPEN ERROR %d (attr username): %s\n", ret
->status
, ret
->buf
);
622 ret
->status
= OCIAttrSet(ret
->auth
, OCI_HTYPE_SESSION
, fields
[1].value
,
623 strlen(fields
[1].value
), OCI_ATTR_PASSWORD
, ret
->err
);
624 switch (ret
->status
) {
627 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
628 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
629 printf("OPEN ERROR %d (attr password): %s\n", ret
->status
, ret
->buf
);
637 ret
->status
= OCISessionBegin(ret
->svc
, ret
->err
, ret
->auth
,
638 OCI_CRED_RDBMS
, OCI_DEFAULT
);
639 switch (ret
->status
) {
642 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
643 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
644 printf("OPEN ERROR %d (session begin): %s\n", ret
->status
, ret
->buf
);
652 ret
->status
= OCIAttrSet(ret
->svc
, OCI_HTYPE_SVCCTX
, ret
->auth
, 0,
653 OCI_ATTR_SESSION
, ret
->err
);
654 switch (ret
->status
) {
657 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
658 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
659 printf("OPEN ERROR %d (attr session): %s\n", ret
->status
, ret
->buf
);
671 #ifdef EXPORT_NATIVE_FUNCS
672 static apr_size_t
dbd_oracle_long_size_set(apr_dbd_t
*sql
,
673 apr_size_t long_size
)
675 apr_size_t old_size
= sql
->long_size
;
676 sql
->long_size
= long_size
;
681 static const char *dbd_oracle_get_name(const apr_dbd_results_t
*res
, int n
)
683 define_arg
*val
= &res
->statement
->out
[n
];
685 if ((n
< 0) || (n
>= res
->statement
->nout
)) {
691 static int dbd_oracle_get_row(apr_pool_t
*pool
, apr_dbd_results_t
*res
,
692 apr_dbd_row_t
**rowp
, int rownum
)
694 apr_dbd_row_t
*row
= *rowp
;
695 apr_dbd_t
*sql
= res
->handle
;
699 row
= apr_palloc(pool
, sizeof(apr_dbd_row_t
));
702 /* Oracle starts counting at 1 according to the docs */
703 row
->n
= res
->seek
? rownum
: 1;
716 sql
->status
= OCIStmtFetch2(res
->statement
->stmt
, res
->handle
->err
, 1,
717 OCI_FETCH_ABSOLUTE
, row
->n
, OCI_DEFAULT
);
720 sql
->status
= OCIStmtFetch2(res
->statement
->stmt
, res
->handle
->err
, 1,
721 OCI_FETCH_NEXT
, 0, OCI_DEFAULT
);
723 switch (sql
->status
) {
731 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
732 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
733 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
742 static const char *dbd_oracle_error(apr_dbd_t
*sql
, int n
)
744 /* This is ugly. Needs us to pass in a buffer of unknown size.
745 * Either we put it on the handle, or we have to keep allocing/copying
749 switch (sql
->status
) {
751 return "OCI_SUCCESS";
752 case OCI_SUCCESS_WITH_INFO
:
753 return "OCI_SUCCESS_WITH_INFO";
755 return "OCI_NEED_DATA";
757 return "OCI_NO_DATA";
758 case OCI_INVALID_HANDLE
:
759 return "OCI_INVALID_HANDLE";
760 case OCI_STILL_EXECUTING
:
761 return "OCI_STILL_EXECUTING";
763 return "OCI_CONTINUE";
766 switch (OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
767 (text
*) sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
)) {
771 return "internal error: OCIErrorGet failed";
775 static apr_status_t
freeStatement(void *statement
)
777 int rv
= APR_SUCCESS
;
778 OCIStmt
*stmt
= ((apr_dbd_prepared_t
*)statement
)->stmt
;
783 if (OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&err
, OCI_HTYPE_ERROR
,
784 0, NULL
) != OCI_SUCCESS
) {
787 if (OCIStmtRelease(stmt
, err
, NULL
, 0, OCI_DEFAULT
) != OCI_SUCCESS
) {
790 if (OCIHandleFree(err
, OCI_HTYPE_ERROR
) != OCI_SUCCESS
) {
794 if (OCIHandleFree(stmt
, OCI_HTYPE_STMT
) != OCI_SUCCESS
) {
802 static int dbd_oracle_select(apr_pool_t
*pool
, apr_dbd_t
*sql
,
803 apr_dbd_results_t
**results
,
804 const char *query
, int seek
)
807 apr_dbd_prepared_t
*statement
= NULL
;
809 ret
= dbd_oracle_prepare(pool
, sql
, query
, NULL
, 0, 0, NULL
, &statement
);
814 ret
= dbd_oracle_pselect(pool
, sql
, results
, statement
, seek
, NULL
);
822 static int dbd_oracle_query(apr_dbd_t
*sql
, int *nrows
, const char *query
)
826 apr_dbd_prepared_t
*statement
= NULL
;
828 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
832 /* make our own pool so that APR allocations don't linger and so that
833 * both Stmt and LOB handles are cleaned up (LOB handles may be
834 * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs)
836 apr_pool_create(&pool
, sql
->pool
);
838 ret
= dbd_oracle_prepare(pool
, sql
, query
, NULL
, 0, 0, NULL
, &statement
);
840 ret
= dbd_oracle_pquery(pool
, sql
, nrows
, statement
, NULL
);
842 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
,
843 nrows
, 0, OCI_ATTR_ROW_COUNT
,
848 apr_pool_destroy(pool
);
853 static const char *dbd_oracle_escape(apr_pool_t
*pool
, const char *arg
,
856 return arg
; /* OCI has no concept of string escape */
859 static int dbd_oracle_prepare(apr_pool_t
*pool
, apr_dbd_t
*sql
,
860 const char *query
, const char *label
,
861 int nargs
, int nvals
, apr_dbd_type_e
*types
,
862 apr_dbd_prepared_t
**statement
)
866 apr_dbd_prepared_t
*stmt
;
868 /* prepared statements in a global lookup table would be nice,
869 * but we can't do that here because our pool may die leaving
870 * the cached statement orphaned.
871 * OTOH we can do that with Oracle statements, which aren't on
872 * the pool, so long as we don't register a cleanup on our pool!
875 * There's a race condition between cache-lookup and cache-set
876 * But the worst outcome is a statement prepared more than once
877 * and leaked. Is that worth mutexing for?
878 * Hmmm, yes it probably is ... OK, done
881 if (*statement
== NULL
) {
882 *statement
= apr_pcalloc(pool
, sizeof(apr_dbd_prepared_t
));
890 /* If we have a label, we're going to cache it globally.
891 * Check first if we already have it. If not, prepare the
892 * statement under mutex, so we don't end up leaking
893 * concurrent statements
895 * FIXME: Oracle docs say a statement can be used even across
896 * multiple servers, so I assume this is safe .....
898 #ifdef GLOBAL_PREPARED_STATEMENTS
900 stmt
->stmt
= apr_hash_get(oracle_statements
, label
, APR_HASH_KEY_STRING
);
901 if (stmt
->stmt
!= NULL
) {
904 apr_dbd_mutex_lock();
905 stmt
->stmt
= apr_hash_get(oracle_statements
, label
, APR_HASH_KEY_STRING
);
906 if (stmt
->stmt
!= NULL
) {
907 apr_dbd_mutex_unlock();
913 /* populate our own args, if any */
915 stmt
->args
= apr_pcalloc(pool
, nargs
*sizeof(bind_arg
));
916 for (i
= 0; i
< nargs
; i
++) {
917 stmt
->args
[i
].type
= types
[i
];
921 sql
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**) &stmt
->stmt
,
922 OCI_HTYPE_STMT
, 0, NULL
);
923 if (sql
->status
!= OCI_SUCCESS
) {
924 apr_dbd_mutex_unlock();
928 sql
->status
= OCIStmtPrepare(stmt
->stmt
, sql
->err
, (text
*) query
,
929 strlen(query
), OCI_NTV_SYNTAX
, OCI_DEFAULT
);
930 if (sql
->status
!= OCI_SUCCESS
) {
931 OCIHandleFree(stmt
->stmt
, OCI_HTYPE_STMT
);
932 apr_dbd_mutex_unlock();
936 apr_pool_cleanup_register(pool
, stmt
, freeStatement
,
937 apr_pool_cleanup_null
);
939 /* Perl gets statement type here */
940 sql
->status
= OCIAttrGet(stmt
->stmt
, OCI_HTYPE_STMT
, &stmt
->type
, 0,
941 OCI_ATTR_STMT_TYPE
, sql
->err
);
942 if (sql
->status
!= OCI_SUCCESS
) {
943 apr_dbd_mutex_unlock();
947 /* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
949 sql
->status
= OCIAttrSet(stmt
->stmt
, OCI_HTYPE_STMT
, &prefetch_size
,
950 sizeof(prefetch_size
), OCI_ATTR_PREFETCH_MEMORY
,
952 if (sql
->status
!= OCI_SUCCESS
) {
953 apr_dbd_mutex_unlock();
958 if (stmt
->type
== OCI_STMT_SELECT
) {
959 ret
= outputParams(sql
, stmt
);
961 #ifdef GLOBAL_PREPARED_STATEMENTS
963 apr_hash_set(oracle_statements
, label
, APR_HASH_KEY_STRING
, stmt
->stmt
);
964 apr_dbd_mutex_unlock();
970 static void dbd_oracle_bind(apr_dbd_prepared_t
*statement
, const char **values
)
972 OCIStmt
*stmt
= statement
->stmt
;
973 apr_dbd_t
*sql
= statement
->handle
;
977 for (i
= 0, j
= 0; i
< statement
->nargs
; i
++, j
++) {
978 if (values
[j
] == NULL
) {
979 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
984 (ub4
*) 0, OCI_DEFAULT
);
987 switch (statement
->args
[i
].type
) {
988 case APR_DBD_TYPE_BLOB
:
990 char *data
= (char *)values
[j
];
991 int size
= atoi((char*)values
[++j
]);
993 /* skip table and column for now */
996 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
998 data
, size
, SQLT_LBI
,
999 &statement
->args
[i
].ind
,
1002 (ub4
*) 0, OCI_DEFAULT
);
1005 case APR_DBD_TYPE_CLOB
:
1007 char *data
= (char *)values
[j
];
1008 int size
= atoi((char*)values
[++j
]);
1010 /* skip table and column for now */
1013 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1015 data
, size
, SQLT_LNG
,
1016 &statement
->args
[i
].ind
,
1019 (ub4
*) 0, OCI_DEFAULT
);
1023 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1026 strlen(values
[j
]) + 1,
1028 &statement
->args
[i
].ind
,
1031 (ub4
*) 0, OCI_DEFAULT
);
1036 if (sql
->status
!= OCI_SUCCESS
) {
1044 static int outputParams(apr_dbd_t
*sql
, apr_dbd_prepared_t
*stmt
)
1049 ub2 paramtype
[DBD_ORACLE_MAX_COLUMNS
];
1050 ub2 paramsize
[DBD_ORACLE_MAX_COLUMNS
];
1051 const char *paramname
[DBD_ORACLE_MAX_COLUMNS
];
1052 ub4 paramnamelen
[DBD_ORACLE_MAX_COLUMNS
];
1053 /* Perl uses 0 where we used 1 */
1054 sql
->status
= OCIStmtExecute(sql
->svc
, stmt
->stmt
, sql
->err
, 0, 0,
1055 NULL
, NULL
, OCI_DESCRIBE_ONLY
);
1056 switch (sql
->status
) {
1058 case OCI_SUCCESS_WITH_INFO
:
1062 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1063 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1064 printf("Describing prepared statement: %s\n", sql
->buf
);
1069 while (sql
->status
== OCI_SUCCESS
) {
1070 sql
->status
= OCIParamGet(stmt
->stmt
, OCI_HTYPE_STMT
,
1071 sql
->err
, (dvoid
**)&parms
, stmt
->nout
+1);
1072 switch (sql
->status
) {
1074 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1075 ¶mtype
[stmt
->nout
],
1076 0, OCI_ATTR_DATA_TYPE
, sql
->err
);
1077 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1078 ¶msize
[stmt
->nout
],
1079 0, OCI_ATTR_DATA_SIZE
, sql
->err
);
1080 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1081 ¶mname
[stmt
->nout
],
1082 ¶mnamelen
[stmt
->nout
],
1083 OCI_ATTR_NAME
, sql
->err
);
1087 switch (sql
->status
) {
1091 break; /* this is what we expect at end-of-loop */
1096 /* OK, the above works. We have the params; now OCIDefine them */
1097 stmt
->out
= apr_palloc(stmt
->pool
, stmt
->nout
*sizeof(define_arg
));
1098 for (i
=0; i
<stmt
->nout
; ++i
) {
1099 stmt
->out
[i
].type
= paramtype
[i
];
1100 stmt
->out
[i
].len
= stmt
->out
[i
].sz
= paramsize
[i
];
1101 stmt
->out
[i
].name
= apr_pstrmemdup(stmt
->pool
,
1102 paramname
[i
], paramnamelen
[i
]);
1103 switch (stmt
->out
[i
].type
) {
1105 switch (stmt
->out
[i
].type
) {
1106 case SQLT_NUM
: /* 2: numeric, Perl worst case=130+38+3 */
1107 stmt
->out
[i
].sz
= 171;
1109 case SQLT_CHR
: /* 1: char */
1110 case SQLT_AFC
: /* 96: ANSI fixed char */
1111 stmt
->out
[i
].sz
*= 4; /* ugh, wasteful UCS-4 handling */
1113 case SQLT_DAT
: /* 12: date, depends on NLS date format */
1114 stmt
->out
[i
].sz
= 75;
1116 case SQLT_BIN
: /* 23: raw binary, perhaps UTF-16? */
1117 stmt
->out
[i
].sz
*= 2;
1119 case SQLT_RID
: /* 11: rowid */
1120 case SQLT_RDD
: /* 104: rowid descriptor */
1121 stmt
->out
[i
].sz
= 20;
1123 case SQLT_TIMESTAMP
: /* 187: timestamp */
1124 case SQLT_TIMESTAMP_TZ
: /* 188: timestamp with time zone */
1125 case SQLT_INTERVAL_YM
: /* 189: interval year-to-month */
1126 case SQLT_INTERVAL_DS
: /* 190: interval day-to-second */
1127 case SQLT_TIMESTAMP_LTZ
: /* 232: timestamp with local time zone */
1128 stmt
->out
[i
].sz
= 75;
1132 printf("Unsupported data type: %d\n", stmt
->out
[i
].type
);
1137 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1138 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1140 stmt
->out
[i
].buf
.sval
,
1141 stmt
->out
[i
].sz
, SQLT_STR
,
1142 &stmt
->out
[i
].ind
, &stmt
->out
[i
].len
,
1145 case SQLT_LNG
: /* 8: long */
1146 stmt
->out
[i
].sz
= sql
->long_size
* 4 + 4; /* ugh, UCS-4 handling */
1147 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1148 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1150 stmt
->out
[i
].buf
.raw
,
1151 stmt
->out
[i
].sz
, SQLT_LVC
,
1152 &stmt
->out
[i
].ind
, NULL
,
1155 case SQLT_LBI
: /* 24: long binary, perhaps UTF-16? */
1156 stmt
->out
[i
].sz
= sql
->long_size
* 2 + 4; /* room for int prefix */
1157 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1158 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1160 stmt
->out
[i
].buf
.raw
,
1161 stmt
->out
[i
].sz
, SQLT_LVB
,
1162 &stmt
->out
[i
].ind
, NULL
,
1165 case SQLT_BLOB
: /* 113 */
1166 case SQLT_CLOB
: /* 112 */
1167 /*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1168 sql
->status
= OCIDescriptorAlloc(dbd_oracle_env
,
1169 (dvoid
**)&stmt
->out
[i
].buf
.lobval
,
1170 OCI_DTYPE_LOB
, 0, NULL
);
1171 apr_pool_cleanup_register(stmt
->pool
, stmt
->out
[i
].buf
.lobval
,
1173 apr_pool_cleanup_null
);
1174 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1176 (dvoid
*) &stmt
->out
[i
].buf
.lobval
,
1177 -1, stmt
->out
[i
].type
,
1178 &stmt
->out
[i
].ind
, &stmt
->out
[i
].len
,
1182 switch (sql
->status
) {
1192 static int dbd_oracle_pquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1193 int *nrows
, apr_dbd_prepared_t
*statement
,
1194 const char **values
)
1197 OCISnapshot
*oldsnapshot
= NULL
;
1198 OCISnapshot
*newsnapshot
= NULL
;
1199 apr_dbd_transaction_t
* trans
= sql
->trans
;
1203 switch (trans
->status
) {
1210 oldsnapshot
= trans
->snapshot1
;
1211 newsnapshot
= trans
->snapshot2
;
1212 trans
->status
= TRANS_2
;
1215 oldsnapshot
= trans
->snapshot2
;
1216 newsnapshot
= trans
->snapshot1
;
1217 trans
->status
= TRANS_1
;
1220 exec_mode
= OCI_DEFAULT
;
1223 exec_mode
= OCI_COMMIT_ON_SUCCESS
;
1226 dbd_oracle_bind(statement
, values
);
1228 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 1, 0,
1229 oldsnapshot
, newsnapshot
, exec_mode
);
1230 switch (sql
->status
) {
1235 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1236 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1237 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
1241 if (TXN_NOTICE_ERRORS(trans
)) {
1242 trans
->status
= TRANS_ERROR
;
1247 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
, nrows
, 0,
1248 OCI_ATTR_ROW_COUNT
, sql
->err
);
1252 static int dbd_oracle_pvquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1253 int *nrows
, apr_dbd_prepared_t
*statement
,
1256 const char **values
;
1259 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1263 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1265 for (i
= 0; i
< statement
->nvals
; i
++) {
1266 values
[i
] = va_arg(args
, const char*);
1269 return dbd_oracle_pquery(pool
, sql
, nrows
, statement
, values
);
1272 static int dbd_oracle_pselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1273 apr_dbd_results_t
**results
,
1274 apr_dbd_prepared_t
*statement
,
1275 int seek
, const char **values
)
1277 int exec_mode
= seek
? OCI_STMT_SCROLLABLE_READONLY
: OCI_DEFAULT
;
1278 OCISnapshot
*oldsnapshot
= NULL
;
1279 OCISnapshot
*newsnapshot
= NULL
;
1280 apr_dbd_transaction_t
* trans
= sql
->trans
;
1283 switch (trans
->status
) {
1290 oldsnapshot
= trans
->snapshot1
;
1291 newsnapshot
= trans
->snapshot2
;
1292 trans
->status
= TRANS_2
;
1295 oldsnapshot
= trans
->snapshot2
;
1296 newsnapshot
= trans
->snapshot1
;
1297 trans
->status
= TRANS_1
;
1302 dbd_oracle_bind(statement
, values
);
1304 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 0, 0,
1305 oldsnapshot
, newsnapshot
, exec_mode
);
1306 switch (sql
->status
) {
1312 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1313 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1314 printf("Executing prepared statement: %s\n", sql
->buf
);
1318 if (TXN_NOTICE_ERRORS(trans
)) {
1319 trans
->status
= TRANS_ERROR
;
1325 *results
= apr_palloc(pool
, sizeof(apr_dbd_results_t
));
1327 (*results
)->handle
= sql
;
1328 (*results
)->statement
= statement
;
1329 (*results
)->seek
= seek
;
1330 (*results
)->rownum
= seek
? 0 : -1;
1331 (*results
)->pool
= pool
;
1336 static int dbd_oracle_pvselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1337 apr_dbd_results_t
**results
,
1338 apr_dbd_prepared_t
*statement
,
1339 int seek
, va_list args
)
1341 const char **values
;
1344 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1348 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1350 for (i
= 0; i
< statement
->nvals
; i
++) {
1351 values
[i
] = va_arg(args
, const char*);
1354 return dbd_oracle_pselect(pool
, sql
, results
, statement
, seek
, values
);
1357 static void dbd_oracle_bbind(apr_dbd_prepared_t
* statement
,
1358 const void **values
)
1360 OCIStmt
*stmt
= statement
->stmt
;
1361 apr_dbd_t
*sql
= statement
->handle
;
1364 apr_dbd_type_e type
;
1366 for (i
= 0, j
= 0; i
< statement
->nargs
; i
++, j
++) {
1367 type
= (values
[j
] == NULL
? APR_DBD_TYPE_NULL
1368 : statement
->args
[i
].type
);
1371 case APR_DBD_TYPE_TINY
:
1372 statement
->args
[i
].value
.ival
= *(char*)values
[j
];
1373 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1375 &statement
->args
[i
].value
.ival
,
1376 sizeof(statement
->args
[i
].value
.ival
),
1378 &statement
->args
[i
].ind
, NULL
,
1380 (ub4
*) 0, OCI_DEFAULT
);
1382 case APR_DBD_TYPE_UTINY
:
1383 statement
->args
[i
].value
.uval
= *(unsigned char*)values
[j
];
1384 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1386 &statement
->args
[i
].value
.uval
,
1387 sizeof(statement
->args
[i
].value
.uval
),
1389 &statement
->args
[i
].ind
, NULL
,
1391 (ub4
*) 0, OCI_DEFAULT
);
1393 case APR_DBD_TYPE_SHORT
:
1394 statement
->args
[i
].value
.ival
= *(short*)values
[j
];
1395 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1397 &statement
->args
[i
].value
.ival
,
1398 sizeof(statement
->args
[i
].value
.ival
),
1400 &statement
->args
[i
].ind
, NULL
,
1402 (ub4
*) 0, OCI_DEFAULT
);
1404 case APR_DBD_TYPE_USHORT
:
1405 statement
->args
[i
].value
.uval
= *(unsigned short*)values
[j
];
1406 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1408 &statement
->args
[i
].value
.uval
,
1409 sizeof(statement
->args
[i
].value
.uval
),
1411 &statement
->args
[i
].ind
, NULL
,
1413 (ub4
*) 0, OCI_DEFAULT
);
1415 case APR_DBD_TYPE_INT
:
1416 statement
->args
[i
].value
.ival
= *(int*)values
[j
];
1417 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1419 &statement
->args
[i
].value
.ival
,
1420 sizeof(statement
->args
[i
].value
.ival
),
1422 &statement
->args
[i
].ind
, NULL
,
1424 (ub4
*) 0, OCI_DEFAULT
);
1426 case APR_DBD_TYPE_UINT
:
1427 statement
->args
[i
].value
.uval
= *(unsigned int*)values
[j
];
1428 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1430 &statement
->args
[i
].value
.uval
,
1431 sizeof(statement
->args
[i
].value
.uval
),
1433 &statement
->args
[i
].ind
, NULL
,
1435 (ub4
*) 0, OCI_DEFAULT
);
1437 case APR_DBD_TYPE_LONG
:
1438 statement
->args
[i
].value
.sval
=
1439 apr_psprintf(statement
->pool
, "%ld", *(long*)values
[j
]);
1440 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1442 statement
->args
[i
].value
.sval
,
1443 strlen(statement
->args
[i
].value
.sval
)+1,
1445 &statement
->args
[i
].ind
, NULL
,
1447 (ub4
*) 0, OCI_DEFAULT
);
1449 case APR_DBD_TYPE_ULONG
:
1450 statement
->args
[i
].value
.sval
=
1451 apr_psprintf(statement
->pool
, "%lu",
1452 *(unsigned long*)values
[j
]);
1453 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1455 statement
->args
[i
].value
.sval
,
1456 strlen(statement
->args
[i
].value
.sval
)+1,
1458 &statement
->args
[i
].ind
, NULL
,
1460 (ub4
*) 0, OCI_DEFAULT
);
1462 case APR_DBD_TYPE_LONGLONG
:
1463 statement
->args
[i
].value
.sval
=
1464 apr_psprintf(statement
->pool
, "%" APR_INT64_T_FMT
,
1465 *(apr_int64_t
*)values
[j
]);
1466 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1468 statement
->args
[i
].value
.sval
,
1469 strlen(statement
->args
[i
].value
.sval
)+1,
1471 &statement
->args
[i
].ind
, NULL
,
1473 (ub4
*) 0, OCI_DEFAULT
);
1475 case APR_DBD_TYPE_ULONGLONG
:
1476 statement
->args
[i
].value
.sval
=
1477 apr_psprintf(statement
->pool
, "%" APR_UINT64_T_FMT
,
1478 *(apr_uint64_t
*)values
[j
]);
1479 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1481 statement
->args
[i
].value
.sval
,
1482 strlen(statement
->args
[i
].value
.sval
)+1,
1484 &statement
->args
[i
].ind
, NULL
,
1486 (ub4
*) 0, OCI_DEFAULT
);
1488 case APR_DBD_TYPE_FLOAT
:
1489 statement
->args
[i
].value
.fval
= *(float*)values
[j
];
1490 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1492 &statement
->args
[i
].value
.fval
,
1493 sizeof(statement
->args
[i
].value
.fval
),
1495 &statement
->args
[i
].ind
, NULL
,
1497 (ub4
*) 0, OCI_DEFAULT
);
1499 case APR_DBD_TYPE_DOUBLE
:
1500 statement
->args
[i
].value
.fval
= *(double*)values
[j
];
1501 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1503 &statement
->args
[i
].value
.fval
,
1504 sizeof(statement
->args
[i
].value
.fval
),
1506 &statement
->args
[i
].ind
, NULL
,
1508 (ub4
*) 0, OCI_DEFAULT
);
1510 case APR_DBD_TYPE_STRING
:
1511 case APR_DBD_TYPE_TEXT
:
1512 case APR_DBD_TYPE_TIME
:
1513 case APR_DBD_TYPE_DATE
:
1514 case APR_DBD_TYPE_DATETIME
:
1515 case APR_DBD_TYPE_TIMESTAMP
:
1516 case APR_DBD_TYPE_ZTIMESTAMP
:
1517 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1520 strlen(values
[j
]) + 1,
1522 &statement
->args
[i
].ind
, NULL
,
1524 (ub4
*) 0, OCI_DEFAULT
);
1526 case APR_DBD_TYPE_BLOB
:
1528 char *data
= (char *)values
[j
];
1529 apr_size_t size
= *(apr_size_t
*)values
[++j
];
1531 /* skip table and column for now */
1534 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1536 data
, size
, SQLT_LBI
,
1537 &statement
->args
[i
].ind
,
1540 (ub4
*) 0, OCI_DEFAULT
);
1543 case APR_DBD_TYPE_CLOB
:
1545 char *data
= (char *)values
[j
];
1546 apr_size_t size
= *(apr_size_t
*)values
[++j
];
1548 /* skip table and column for now */
1551 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1553 data
, size
, SQLT_LNG
,
1554 &statement
->args
[i
].ind
,
1557 (ub4
*) 0, OCI_DEFAULT
);
1560 case APR_DBD_TYPE_NULL
:
1562 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1567 (ub4
*) 0, OCI_DEFAULT
);
1571 if (sql
->status
!= OCI_SUCCESS
) {
1579 static int dbd_oracle_pbquery(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1580 int *nrows
, apr_dbd_prepared_t
* statement
,
1581 const void **values
)
1584 OCISnapshot
*oldsnapshot
= NULL
;
1585 OCISnapshot
*newsnapshot
= NULL
;
1586 apr_dbd_transaction_t
* trans
= sql
->trans
;
1590 switch (trans
->status
) {
1597 oldsnapshot
= trans
->snapshot1
;
1598 newsnapshot
= trans
->snapshot2
;
1599 trans
->status
= TRANS_2
;
1602 oldsnapshot
= trans
->snapshot2
;
1603 newsnapshot
= trans
->snapshot1
;
1604 trans
->status
= TRANS_1
;
1607 exec_mode
= OCI_DEFAULT
;
1610 exec_mode
= OCI_COMMIT_ON_SUCCESS
;
1613 dbd_oracle_bbind(statement
, values
);
1615 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 1, 0,
1616 oldsnapshot
, newsnapshot
, exec_mode
);
1617 switch (sql
->status
) {
1622 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1623 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1624 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
1628 if (TXN_NOTICE_ERRORS(trans
)) {
1629 trans
->status
= TRANS_ERROR
;
1634 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
, nrows
, 0,
1635 OCI_ATTR_ROW_COUNT
, sql
->err
);
1639 static int dbd_oracle_pvbquery(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1640 int *nrows
, apr_dbd_prepared_t
* statement
,
1643 const void **values
;
1646 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1650 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1652 for (i
= 0; i
< statement
->nvals
; i
++) {
1653 values
[i
] = va_arg(args
, const void*);
1656 return dbd_oracle_pbquery(pool
, sql
, nrows
, statement
, values
);
1659 static int dbd_oracle_pbselect(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1660 apr_dbd_results_t
** results
,
1661 apr_dbd_prepared_t
* statement
,
1662 int seek
, const void **values
)
1664 int exec_mode
= seek
? OCI_STMT_SCROLLABLE_READONLY
: OCI_DEFAULT
;
1665 OCISnapshot
*oldsnapshot
= NULL
;
1666 OCISnapshot
*newsnapshot
= NULL
;
1667 apr_dbd_transaction_t
* trans
= sql
->trans
;
1670 switch (trans
->status
) {
1677 oldsnapshot
= trans
->snapshot1
;
1678 newsnapshot
= trans
->snapshot2
;
1679 trans
->status
= TRANS_2
;
1682 oldsnapshot
= trans
->snapshot2
;
1683 newsnapshot
= trans
->snapshot1
;
1684 trans
->status
= TRANS_1
;
1689 dbd_oracle_bbind(statement
, values
);
1691 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 0, 0,
1692 oldsnapshot
, newsnapshot
, exec_mode
);
1693 switch (sql
->status
) {
1699 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1700 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1701 printf("Executing prepared statement: %s\n", sql
->buf
);
1705 if (TXN_NOTICE_ERRORS(trans
)) {
1706 trans
->status
= TRANS_ERROR
;
1712 *results
= apr_palloc(pool
, sizeof(apr_dbd_results_t
));
1714 (*results
)->handle
= sql
;
1715 (*results
)->statement
= statement
;
1716 (*results
)->seek
= seek
;
1717 (*results
)->rownum
= seek
? 0 : -1;
1718 (*results
)->pool
= pool
;
1723 static int dbd_oracle_pvbselect(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1724 apr_dbd_results_t
** results
,
1725 apr_dbd_prepared_t
* statement
, int seek
,
1728 const void **values
;
1731 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1735 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1737 for (i
= 0; i
< statement
->nvals
; i
++) {
1738 values
[i
] = va_arg(args
, const void*);
1741 return dbd_oracle_pbselect(pool
, sql
, results
, statement
, seek
, values
);
1744 static int dbd_oracle_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1745 apr_dbd_transaction_t
**trans
)
1750 dbd_oracle_end_transaction(*trans
);
1753 *trans
= apr_pcalloc(pool
, sizeof(apr_dbd_transaction_t
));
1754 OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&(*trans
)->trans
,
1755 OCI_HTYPE_TRANS
, 0, 0);
1756 OCIAttrSet(sql
->svc
, OCI_HTYPE_SVCCTX
, (*trans
)->trans
, 0,
1757 OCI_ATTR_TRANS
, sql
->err
);
1761 sql
->status
= OCITransStart(sql
->svc
, sql
->err
, TRANS_TIMEOUT
,
1763 switch (sql
->status
) {
1766 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
, sql
->buf
,
1767 sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1768 printf("Transaction: %s\n", sql
->buf
);
1773 (*trans
)->handle
= sql
;
1774 (*trans
)->status
= TRANS_1
;
1775 sql
->trans
= *trans
;
1776 switch (OCIDescriptorAlloc(dbd_oracle_env
,
1777 (dvoid
**)&(*trans
)->snapshot1
,
1778 OCI_DTYPE_SNAP
, 0, NULL
)) {
1780 apr_pool_cleanup_register(pool
, (*trans
)->snapshot1
,
1781 dbd_free_snapshot
, apr_pool_cleanup_null
);
1783 case OCI_INVALID_HANDLE
:
1787 switch (OCIDescriptorAlloc(dbd_oracle_env
,
1788 (dvoid
**)&(*trans
)->snapshot2
,
1789 OCI_DTYPE_SNAP
, 0, NULL
)) {
1791 apr_pool_cleanup_register(pool
, (*trans
)->snapshot2
,
1792 dbd_free_snapshot
, apr_pool_cleanup_null
);
1794 case OCI_INVALID_HANDLE
:
1806 static int dbd_oracle_end_transaction(apr_dbd_transaction_t
*trans
)
1808 int ret
= 1; /* no transaction is an error cond */
1810 apr_dbd_t
*handle
= trans
->handle
;
1812 switch (trans
->status
) {
1813 case TRANS_NONE
: /* No trans is an error here */
1817 status
= OCITransRollback(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1820 /* rollback on explicit rollback request */
1821 if (TXN_DO_ROLLBACK(trans
)) {
1822 status
= OCITransRollback(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1824 status
= OCITransCommit(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1829 handle
->trans
= NULL
;
1843 static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t
*trans
)
1846 return APR_DBD_TRANSACTION_COMMIT
;
1851 static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t
*trans
,
1855 return APR_DBD_TRANSACTION_COMMIT
;
1857 return trans
->mode
= (mode
& TXN_MODE_BITS
);
1860 /* This doesn't work for BLOB because of NULLs, but it can fake it
1861 * if the BLOB is really a string
1863 static const char *dbd_oracle_get_entry(const apr_dbd_row_t
*row
, int n
)
1869 apr_size_t buflen
= 0;
1871 define_arg
*val
= &row
->res
->statement
->out
[n
];
1872 apr_dbd_t
*sql
= row
->res
->handle
;
1874 if ((n
< 0) || (n
>= row
->res
->statement
->nout
) || (val
->ind
== -1)) {
1878 switch (val
->type
) {
1881 sql
->status
= OCILobGetLength(sql
->svc
, sql
->err
, val
->buf
.lobval
,
1883 switch (sql
->status
) {
1885 case OCI_SUCCESS_WITH_INFO
:
1892 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1893 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1894 printf("Finding LOB length: %s\n", sql
->buf
);
1905 if (val
->type
== APR_DBD_TYPE_CLOB
) {
1907 /* Is this necessary, or can it be defaulted? */
1908 sql
->status
= OCILobCharSetForm(dbd_oracle_env
, sql
->err
,
1909 val
->buf
.lobval
, &csform
);
1910 if (sql
->status
== OCI_SUCCESS
) {
1911 sql
->status
= OCILobCharSetId(dbd_oracle_env
, sql
->err
,
1912 val
->buf
.lobval
, &csid
);
1914 switch (sql
->status
) {
1916 case OCI_SUCCESS_WITH_INFO
:
1917 buflen
= (len
+1) * 4; /* ugh, wasteful UCS-4 handling */
1918 /* zeroise all - where the string ends depends on charset */
1919 buf
= apr_pcalloc(row
->pool
, buflen
);
1923 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1924 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1925 printf("Reading LOB character set: %s\n", sql
->buf
);
1926 break; /*** XXX?? ***/
1929 break; /*** XXX?? ***/
1931 #else /* ignore charset */
1932 buflen
= (len
+1) * 4; /* ugh, wasteful UCS-4 handling */
1933 /* zeroise all - where the string ends depends on charset */
1934 buf
= apr_pcalloc(row
->pool
, buflen
);
1937 /* BUG: this'll only work if the BLOB looks like a string */
1939 buf
= apr_palloc(row
->pool
, buflen
+1);
1947 sql
->status
= OCILobRead(sql
->svc
, sql
->err
, val
->buf
.lobval
,
1948 &len
, 1, (dvoid
*) buf
, buflen
,
1949 NULL
, NULL
, csid
, csform
);
1950 switch (sql
->status
) {
1952 case OCI_SUCCESS_WITH_INFO
:
1956 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1957 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1958 printf("Reading LOB: %s\n", sql
->buf
);
1959 buf
= NULL
; /*** XXX?? ***/
1963 buf
= NULL
; /*** XXX?? ***/
1970 /* raw is struct { ub4 len; char *buf; } */
1971 len
= *(ub4
*) val
->buf
.raw
;
1972 buf
= apr_pstrndup(row
->pool
, val
->buf
.sval
+ sizeof(ub4
), len
);
1975 buf
= apr_pstrndup(row
->pool
, val
->buf
.sval
, val
->len
);
1978 return (const char*) buf
;
1981 /* XXX Should this use Oracle proper API instead of calling get_entry()? */
1982 static apr_status_t
dbd_oracle_datum_get(const apr_dbd_row_t
*row
, int n
,
1983 apr_dbd_type_e type
, void *data
)
1985 define_arg
*val
= &row
->res
->statement
->out
[n
];
1988 if ((n
< 0) || (n
>= row
->res
->statement
->nout
)) {
1989 return APR_EGENERAL
;
1992 if(val
->ind
== -1) {
1997 case APR_DBD_TYPE_TINY
:
1998 entry
= dbd_oracle_get_entry(row
, n
);
1999 if (entry
== NULL
) {
2002 *(char*)data
= atoi(entry
);
2004 case APR_DBD_TYPE_UTINY
:
2005 entry
= dbd_oracle_get_entry(row
, n
);
2006 if (entry
== NULL
) {
2009 *(unsigned char*)data
= atoi(entry
);
2011 case APR_DBD_TYPE_SHORT
:
2012 entry
= dbd_oracle_get_entry(row
, n
);
2013 if (entry
== NULL
) {
2016 *(short*)data
= atoi(entry
);
2018 case APR_DBD_TYPE_USHORT
:
2019 entry
= dbd_oracle_get_entry(row
, n
);
2020 if (entry
== NULL
) {
2023 *(unsigned short*)data
= atoi(entry
);
2025 case APR_DBD_TYPE_INT
:
2026 entry
= dbd_oracle_get_entry(row
, n
);
2027 if (entry
== NULL
) {
2030 *(int*)data
= atoi(entry
);
2032 case APR_DBD_TYPE_UINT
:
2033 entry
= dbd_oracle_get_entry(row
, n
);
2034 if (entry
== NULL
) {
2037 *(unsigned int*)data
= atoi(entry
);
2039 case APR_DBD_TYPE_LONG
:
2040 entry
= dbd_oracle_get_entry(row
, n
);
2041 if (entry
== NULL
) {
2044 *(long*)data
= atol(entry
);
2046 case APR_DBD_TYPE_ULONG
:
2047 entry
= dbd_oracle_get_entry(row
, n
);
2048 if (entry
== NULL
) {
2051 *(unsigned long*)data
= atol(entry
);
2053 case APR_DBD_TYPE_LONGLONG
:
2054 entry
= dbd_oracle_get_entry(row
, n
);
2055 if (entry
== NULL
) {
2058 *(apr_int64_t
*)data
= apr_atoi64(entry
);
2060 case APR_DBD_TYPE_ULONGLONG
:
2061 entry
= dbd_oracle_get_entry(row
, n
);
2062 if (entry
== NULL
) {
2065 *(apr_uint64_t
*)data
= apr_atoi64(entry
);
2067 case APR_DBD_TYPE_FLOAT
:
2068 entry
= dbd_oracle_get_entry(row
, n
);
2069 if (entry
== NULL
) {
2072 *(float*)data
= atof(entry
);
2074 case APR_DBD_TYPE_DOUBLE
:
2075 entry
= dbd_oracle_get_entry(row
, n
);
2076 if (entry
== NULL
) {
2079 *(double*)data
= atof(entry
);
2081 case APR_DBD_TYPE_STRING
:
2082 case APR_DBD_TYPE_TEXT
:
2083 case APR_DBD_TYPE_TIME
:
2084 case APR_DBD_TYPE_DATE
:
2085 case APR_DBD_TYPE_DATETIME
:
2086 case APR_DBD_TYPE_TIMESTAMP
:
2087 case APR_DBD_TYPE_ZTIMESTAMP
:
2088 entry
= dbd_oracle_get_entry(row
, n
);
2089 if (entry
== NULL
) {
2092 *(char**)data
= (char*)entry
;
2094 case APR_DBD_TYPE_BLOB
:
2095 case APR_DBD_TYPE_CLOB
:
2098 apr_bucket_brigade
*b
= (apr_bucket_brigade
*)data
;
2099 apr_dbd_t
*sql
= row
->res
->handle
;
2102 switch (val
->type
) {
2105 sql
->status
= OCILobGetLength(sql
->svc
, sql
->err
,
2106 val
->buf
.lobval
, &len
);
2107 switch(sql
->status
) {
2109 case OCI_SUCCESS_WITH_INFO
:
2111 e
= apr_bucket_eos_create(b
->bucket_alloc
);
2114 e
= apr_bucket_lob_create(row
, n
, 0, len
,
2115 row
->pool
, b
->bucket_alloc
);
2123 entry
= dbd_oracle_get_entry(row
, n
);
2124 if (entry
== NULL
) {
2127 e
= apr_bucket_pool_create(entry
, strlen(entry
),
2128 row
->pool
, b
->bucket_alloc
);
2131 APR_BRIGADE_INSERT_TAIL(b
, e
);
2134 case APR_DBD_TYPE_NULL
:
2135 *(void**)data
= NULL
;
2138 return APR_EGENERAL
;
2144 static apr_status_t
dbd_oracle_close(apr_dbd_t
*handle
)
2146 /* FIXME: none of the oracle docs/examples say anything about
2147 * closing/releasing handles. Which seems unlikely ...
2150 /* OK, let's grab from cdemo again.
2151 * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
2153 switch (OCISessionEnd(handle
->svc
, handle
->err
, handle
->auth
,
2154 (ub4
)OCI_DEFAULT
)) {
2158 switch (OCIServerDetach(handle
->svr
, handle
->err
, (ub4
) OCI_DEFAULT
)) {
2162 /* does OCISessionEnd imply this? */
2163 switch (OCIHandleFree((dvoid
*) handle
->auth
, (ub4
) OCI_HTYPE_SESSION
)) {
2167 switch (OCIHandleFree((dvoid
*) handle
->svr
, (ub4
) OCI_HTYPE_SERVER
)) {
2171 switch (OCIHandleFree((dvoid
*) handle
->svc
, (ub4
) OCI_HTYPE_SVCCTX
)) {
2175 switch (OCIHandleFree((dvoid
*) handle
->err
, (ub4
) OCI_HTYPE_ERROR
)) {
2179 apr_pool_destroy(handle
->pool
);
2183 static apr_status_t
dbd_oracle_check_conn(apr_pool_t
*pool
,
2186 /* FIXME: need to find this in the docs */
2187 return APR_ENOTIMPL
;
2190 static int dbd_oracle_select_db(apr_pool_t
*pool
, apr_dbd_t
*handle
,
2193 /* FIXME: need to find this in the docs */
2194 return APR_ENOTIMPL
;
2197 static void *dbd_oracle_native(apr_dbd_t
*handle
)
2199 /* FIXME: can we do anything better? Oracle doesn't seem to have
2200 * a concept of a handle in the sense we use it.
2202 return dbd_oracle_env
;
2205 static int dbd_oracle_num_cols(apr_dbd_results_t
* res
)
2207 return res
->statement
->nout
;
2210 static int dbd_oracle_num_tuples(apr_dbd_results_t
* res
)
2215 if (res
->nrows
>= 0) {
2218 res
->handle
->status
= OCIAttrGet(res
->statement
->stmt
, OCI_HTYPE_STMT
,
2219 &res
->nrows
, 0, OCI_ATTR_ROW_COUNT
,
2224 APU_DECLARE_DATA
const apr_dbd_driver_t apr_dbd_oracle_driver
= {
2229 dbd_oracle_check_conn
,
2231 dbd_oracle_select_db
,
2232 dbd_oracle_start_transaction
,
2233 dbd_oracle_end_transaction
,
2236 dbd_oracle_num_cols
,
2237 dbd_oracle_num_tuples
,
2239 dbd_oracle_get_entry
,
2244 dbd_oracle_pvselect
,
2247 dbd_oracle_get_name
,
2248 dbd_oracle_transaction_mode_get
,
2249 dbd_oracle_transaction_mode_set
,
2251 dbd_oracle_pvbquery
,
2252 dbd_oracle_pvbselect
,
2254 dbd_oracle_pbselect
,
2255 dbd_oracle_datum_get