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
92 #define CHECK_CONN_QUERY "SELECT 1 FROM dual"
94 #define ERR_BUF_SIZE 200
100 #include "apr_dbd_internal.h"
103 static const char *dbd_oracle_error(apr_dbd_t
*sql
, int n
);
104 static int dbd_oracle_prepare(apr_pool_t
*pool
, apr_dbd_t
*sql
,
105 const char *query
, const char *label
,
106 int nargs
, int nvals
, apr_dbd_type_e
*types
,
107 apr_dbd_prepared_t
**statement
);
108 static int outputParams(apr_dbd_t
*, apr_dbd_prepared_t
*);
109 static int dbd_oracle_pselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
110 apr_dbd_results_t
**results
,
111 apr_dbd_prepared_t
*statement
,
112 int seek
, const char **values
);
113 static int dbd_oracle_pquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
114 int *nrows
, apr_dbd_prepared_t
*statement
,
115 const char **values
);
116 static int dbd_oracle_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*sql
,
117 apr_dbd_transaction_t
**trans
);
118 static int dbd_oracle_end_transaction(apr_dbd_transaction_t
*trans
);
120 struct apr_dbd_transaction_t
{
122 enum { TRANS_NONE
, TRANS_ERROR
, TRANS_1
, TRANS_2
} status
;
125 OCISnapshot
*snapshot1
;
126 OCISnapshot
*snapshot2
;
129 struct apr_dbd_results_t
{
135 apr_dbd_prepared_t
*statement
;
144 apr_dbd_transaction_t
* trans
;
146 char buf
[ERR_BUF_SIZE
]; /* for error messages */
147 apr_size_t long_size
;
148 apr_dbd_prepared_t
*check_conn_stmt
;
151 struct apr_dbd_row_t
{
153 apr_dbd_results_t
*res
;
168 OCILobLocator
*lobval
;
175 ub2 len
; /* length of actual output */
177 apr_size_t sz
; /* length of buf for output */
181 OCILobLocator
*lobval
;
186 struct apr_dbd_prepared_t
{
198 /* AFAICT from the docs, the OCIEnv thingey can be used async
199 * across threads, so lets have a global one.
201 * We'll need shorter-lived envs to deal with requests and connections
203 * Hmmm, that doesn't work: we don't have a usermem framework.
204 * OK, forget about using APR pools here, until we figure out
205 * the right way to do it (if such a thing exists).
207 static OCIEnv
*dbd_oracle_env
= NULL
;
208 #ifdef GLOBAL_PREPARED_STATEMENTS
209 static apr_hash_t
*oracle_statements
= NULL
;
212 /* Oracle specific bucket for BLOB/CLOB types */
213 typedef struct apr_bucket_lob apr_bucket_lob
;
215 * A bucket referring to a Oracle BLOB/CLOB
217 struct apr_bucket_lob
{
218 /** Number of buckets using this memory */
219 apr_bucket_refcount refcount
;
220 /** The row this bucket refers to */
221 const apr_dbd_row_t
*row
;
222 /** The column this bucket refers to */
224 /** The pool into which any needed structures should
225 * be created while reading from this bucket */
226 apr_pool_t
*readpool
;
229 static void lob_bucket_destroy(void *data
);
230 static apr_status_t
lob_bucket_read(apr_bucket
*e
, const char **str
,
231 apr_size_t
*len
, apr_read_type_e block
);
232 static apr_bucket
*apr_bucket_lob_make(apr_bucket
*b
,
233 const apr_dbd_row_t
*row
, int col
,
234 apr_off_t offset
, apr_size_t len
,
236 static apr_bucket
*apr_bucket_lob_create(const apr_dbd_row_t
*row
, int col
,
238 apr_size_t len
, apr_pool_t
*p
,
239 apr_bucket_alloc_t
*list
);
241 static const apr_bucket_type_t apr_bucket_type_lob
= {
242 "LOB", 5, APR_BUCKET_DATA
,
245 apr_bucket_setaside_notimpl
,
246 apr_bucket_shared_split
,
247 apr_bucket_shared_copy
250 static void lob_bucket_destroy(void *data
)
252 apr_bucket_lob
*f
= data
;
254 if (apr_bucket_shared_destroy(f
)) {
255 /* no need to destroy database objects here; it will get
256 * done automatically when the pool gets cleaned up */
261 static apr_status_t
lob_bucket_read(apr_bucket
*e
, const char **str
,
262 apr_size_t
*len
, apr_read_type_e block
)
264 apr_bucket_lob
*a
= e
->data
;
265 const apr_dbd_row_t
*row
= a
->row
;
266 apr_dbd_results_t
*res
= row
->res
;
268 apr_bucket
*b
= NULL
;
269 apr_size_t blength
= e
->length
; /* bytes remaining in file past offset */
270 apr_off_t boffset
= e
->start
;
271 define_arg
*val
= &res
->statement
->out
[col
];
272 apr_dbd_t
*sql
= res
->handle
;
273 /* Only with 10g, unfortunately
274 oraub8 length = APR_BUCKET_BUFF_SIZE;
276 ub4 length
= APR_BUCKET_BUFF_SIZE
;
279 *str
= NULL
; /* in case we die prematurely */
281 /* fetch from offset if not at the beginning */
282 buf
= apr_palloc(row
->pool
, APR_BUCKET_BUFF_SIZE
);
283 sql
->status
= OCILobRead(sql
->svc
, sql
->err
, val
->buf
.lobval
,
284 &length
, 1 + boffset
,
285 (dvoid
*) buf
, APR_BUCKET_BUFF_SIZE
,
286 NULL
, NULL
, 0, SQLCS_IMPLICIT
);
287 /* Only with 10g, unfortunately
288 sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,
289 &length, NULL, 1 + boffset,
290 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
291 OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
293 if (sql
->status
!= OCI_SUCCESS
) {
301 * Change the current bucket to refer to what we read,
302 * even if we read nothing because we hit EOF.
304 apr_bucket_pool_make(e
, *str
, *len
, res
->pool
);
306 /* If we have more to read from the field, then create another bucket */
308 /* for efficiency, we can just build a new apr_bucket struct
309 * to wrap around the existing LOB bucket */
310 b
= apr_bucket_alloc(sizeof(*b
), e
->list
);
311 b
->start
= boffset
+ *len
;
314 b
->type
= &apr_bucket_type_lob
;
315 b
->free
= apr_bucket_free
;
317 APR_BUCKET_INSERT_AFTER(e
, b
);
320 lob_bucket_destroy(a
);
326 static apr_bucket
*apr_bucket_lob_make(apr_bucket
*b
,
327 const apr_dbd_row_t
*row
, int col
,
328 apr_off_t offset
, apr_size_t len
,
333 f
= apr_bucket_alloc(sizeof(*f
), b
->list
);
338 b
= apr_bucket_shared_make(b
, f
, offset
, len
);
339 b
->type
= &apr_bucket_type_lob
;
344 static apr_bucket
*apr_bucket_lob_create(const apr_dbd_row_t
*row
, int col
,
346 apr_size_t len
, apr_pool_t
*p
,
347 apr_bucket_alloc_t
*list
)
349 apr_bucket
*b
= apr_bucket_alloc(sizeof(*b
), list
);
352 b
->free
= apr_bucket_free
;
354 return apr_bucket_lob_make(b
, row
, col
, offset
, len
, p
);
357 static apr_status_t
dbd_free_lobdesc(void *lob
)
359 switch (OCIDescriptorFree(lob
, OCI_DTYPE_LOB
)) {
367 static apr_status_t
dbd_free_snapshot(void *snap
)
369 switch (OCIDescriptorFree(snap
, OCI_DTYPE_SNAP
)) {
377 #ifdef GLOBAL_PREPARED_STATEMENTS
378 static apr_status_t
freeStatements(void *ptr
)
380 apr_status_t rv
= APR_SUCCESS
;
382 apr_hash_index_t
*index
;
383 apr_pool_t
*cachepool
= apr_hash_pool_get(oracle_statements
);
388 if (OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&err
, OCI_HTYPE_ERROR
, 0, NULL
)
394 for (index
= apr_hash_first(cachepool
, oracle_statements
);
396 index
= apr_hash_next(index
)) {
397 apr_hash_this(index
, NULL
, NULL
, (void**)&stmt
);
399 if (OCIStmtRelease(stmt
, err
, NULL
, 0, OCI_DEFAULT
) != OCI_SUCCESS
) {
403 if (OCIHandleFree(stmt
, OCI_HTYPE_STMT
) != OCI_SUCCESS
) {
409 if (OCIHandleFree(err
, OCI_HTYPE_ERROR
) != OCI_SUCCESS
) {
417 static void dbd_oracle_init(apr_pool_t
*pool
)
419 if (dbd_oracle_env
== NULL
) {
420 /* Sadly, OCI_SHARED seems to be impossible to use, due to
421 * various Oracle bugs. See, for example, Oracle MetaLink bug 2972890
422 * and PHP bug http://bugs.php.net/bug.php?id=23733
424 #ifdef OCI_NEW_LENGTH_SEMANTICS
425 OCIEnvCreate(&dbd_oracle_env
, OCI_THREADED
|OCI_NEW_LENGTH_SEMANTICS
,
426 NULL
, NULL
, NULL
, NULL
, 0, NULL
);
428 OCIEnvCreate(&dbd_oracle_env
, OCI_THREADED
,
429 NULL
, NULL
, NULL
, NULL
, 0, NULL
);
432 #ifdef GLOBAL_PREPARED_STATEMENTS
433 if (oracle_statements
== NULL
) {
435 oracle_statements
= apr_hash_make(pool
);
436 apr_pool_cleanup_register(pool
, oracle_statements
,
437 freeStatements
, apr_pool_cleanup_null
);
442 static apr_dbd_t
*dbd_oracle_open(apr_pool_t
*pool
, const char *params
,
445 apr_dbd_t
*ret
= apr_pcalloc(pool
, sizeof(apr_dbd_t
));
465 static const char *const delims
= " \r\n\t;|,";
468 ret
->long_size
= DEFAULT_LONG_SIZE
;
470 /* snitch parsing from the MySQL driver */
471 for (ptr
= strchr(params
, '='); ptr
; ptr
= strchr(ptr
, '=')) {
472 /* don't dereference memory that may not belong to us */
477 for (key
= ptr
-1; isspace(*key
); --key
);
479 while (isalpha(*key
)) {
481 /* Don't parse off the front of the params */
490 for (value
= ptr
+1; isspace(*value
); ++value
);
491 vlen
= strcspn(value
, delims
);
492 for (i
=0; fields
[i
].field
!= NULL
; ++i
) {
493 if (!strncasecmp(fields
[i
].field
, key
, klen
)) {
494 fields
[i
].value
= apr_pstrndup(pool
, value
, vlen
);
501 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->err
,
502 OCI_HTYPE_ERROR
, 0, NULL
);
503 switch (ret
->status
) {
506 printf("ret->status is %d\n", ret
->status
);
515 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->svr
,
516 OCI_HTYPE_SERVER
, 0, NULL
);
517 switch (ret
->status
) {
520 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
521 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
522 printf("OPEN ERROR %d (alloc svr): %s\n", ret
->status
, ret
->buf
);
525 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
526 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
527 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
534 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->svc
,
535 OCI_HTYPE_SVCCTX
, 0, NULL
);
536 switch (ret
->status
) {
539 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
540 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
541 printf("OPEN ERROR %d (alloc svc): %s\n", ret
->status
, ret
->buf
);
544 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
545 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
546 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
553 /* All the examples use the #else */
555 ret
->status
= OCILogon(dbd_oracle_env
, ret
->err
, &ret
->svc
, fields
[0].value
,
556 strlen(fields
[0].value
), fields
[1].value
,
557 strlen(fields
[1].value
), fields
[2].value
,
558 strlen(fields
[2].value
));
559 switch (ret
->status
) {
562 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
563 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
564 printf("OPEN ERROR: %s\n", 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
= OCIServerAttach(ret
->svr
, ret
->err
, (text
*) fields
[3].value
,
577 strlen(fields
[3].value
), OCI_DEFAULT
);
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 (server attach): %s\n", ret
->status
, ret
->buf
);
586 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
587 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
588 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
594 ret
->status
= OCIAttrSet(ret
->svc
, OCI_HTYPE_SVCCTX
, ret
->svr
, 0,
595 OCI_ATTR_SERVER
, ret
->err
);
596 switch (ret
->status
) {
599 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
600 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
601 printf("OPEN ERROR %d (attr set): %s\n", ret
->status
, ret
->buf
);
604 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
605 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
606 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
612 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->auth
,
613 OCI_HTYPE_SESSION
, 0, NULL
);
614 switch (ret
->status
) {
617 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
618 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
619 printf("OPEN ERROR %d (alloc auth): %s\n", ret
->status
, ret
->buf
);
622 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
623 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
624 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
630 ret
->status
= OCIAttrSet(ret
->auth
, OCI_HTYPE_SESSION
, fields
[0].value
,
631 strlen(fields
[0].value
), OCI_ATTR_USERNAME
, ret
->err
);
632 switch (ret
->status
) {
635 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
636 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
637 printf("OPEN ERROR %d (attr username): %s\n", ret
->status
, ret
->buf
);
640 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
641 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
642 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
648 ret
->status
= OCIAttrSet(ret
->auth
, OCI_HTYPE_SESSION
, fields
[1].value
,
649 strlen(fields
[1].value
), OCI_ATTR_PASSWORD
, ret
->err
);
650 switch (ret
->status
) {
653 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
654 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
655 printf("OPEN ERROR %d (attr password): %s\n", ret
->status
, ret
->buf
);
658 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
659 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
660 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
666 ret
->status
= OCISessionBegin(ret
->svc
, ret
->err
, ret
->auth
,
667 OCI_CRED_RDBMS
, OCI_DEFAULT
);
668 switch (ret
->status
) {
671 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
672 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
673 printf("OPEN ERROR %d (session begin): %s\n", ret
->status
, ret
->buf
);
676 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
677 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
678 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
684 ret
->status
= OCIAttrSet(ret
->svc
, OCI_HTYPE_SVCCTX
, ret
->auth
, 0,
685 OCI_ATTR_SESSION
, ret
->err
);
686 switch (ret
->status
) {
689 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
690 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
691 printf("OPEN ERROR %d (attr session): %s\n", ret
->status
, ret
->buf
);
693 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
694 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
695 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
704 if(dbd_oracle_prepare(pool
, ret
, CHECK_CONN_QUERY
, NULL
, 0, 0, NULL
,
705 &ret
->check_conn_stmt
) != 0) {
712 #ifdef EXPORT_NATIVE_FUNCS
713 static apr_size_t
dbd_oracle_long_size_set(apr_dbd_t
*sql
,
714 apr_size_t long_size
)
716 apr_size_t old_size
= sql
->long_size
;
717 sql
->long_size
= long_size
;
722 static const char *dbd_oracle_get_name(const apr_dbd_results_t
*res
, int n
)
724 define_arg
*val
= &res
->statement
->out
[n
];
726 if ((n
< 0) || (n
>= res
->statement
->nout
)) {
732 static int dbd_oracle_get_row(apr_pool_t
*pool
, apr_dbd_results_t
*res
,
733 apr_dbd_row_t
**rowp
, int rownum
)
735 apr_dbd_row_t
*row
= *rowp
;
736 apr_dbd_t
*sql
= res
->handle
;
740 row
= apr_palloc(pool
, sizeof(apr_dbd_row_t
));
743 /* Oracle starts counting at 1 according to the docs */
744 row
->n
= res
->seek
? rownum
: 1;
757 sql
->status
= OCIStmtFetch2(res
->statement
->stmt
, res
->handle
->err
, 1,
758 OCI_FETCH_ABSOLUTE
, row
->n
, OCI_DEFAULT
);
761 sql
->status
= OCIStmtFetch2(res
->statement
->stmt
, res
->handle
->err
, 1,
762 OCI_FETCH_NEXT
, 0, OCI_DEFAULT
);
764 switch (sql
->status
) {
772 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
773 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
774 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
783 static const char *dbd_oracle_error(apr_dbd_t
*sql
, int n
)
785 /* This is ugly. Needs us to pass in a buffer of unknown size.
786 * Either we put it on the handle, or we have to keep allocing/copying
790 switch (sql
->status
) {
792 return "OCI_SUCCESS";
793 case OCI_SUCCESS_WITH_INFO
:
794 return "OCI_SUCCESS_WITH_INFO";
796 return "OCI_NEED_DATA";
798 return "OCI_NO_DATA";
799 case OCI_INVALID_HANDLE
:
800 return "OCI_INVALID_HANDLE";
801 case OCI_STILL_EXECUTING
:
802 return "OCI_STILL_EXECUTING";
804 return "OCI_CONTINUE";
807 switch (OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
808 (text
*) sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
)) {
812 return "internal error: OCIErrorGet failed";
816 static apr_status_t
freeStatement(void *statement
)
818 int rv
= APR_SUCCESS
;
819 OCIStmt
*stmt
= ((apr_dbd_prepared_t
*)statement
)->stmt
;
824 if (OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&err
, OCI_HTYPE_ERROR
,
825 0, NULL
) != OCI_SUCCESS
) {
828 if (OCIStmtRelease(stmt
, err
, NULL
, 0, OCI_DEFAULT
) != OCI_SUCCESS
) {
831 if (OCIHandleFree(err
, OCI_HTYPE_ERROR
) != OCI_SUCCESS
) {
835 if (OCIHandleFree(stmt
, OCI_HTYPE_STMT
) != OCI_SUCCESS
) {
843 static int dbd_oracle_select(apr_pool_t
*pool
, apr_dbd_t
*sql
,
844 apr_dbd_results_t
**results
,
845 const char *query
, int seek
)
848 apr_dbd_prepared_t
*statement
= NULL
;
850 ret
= dbd_oracle_prepare(pool
, sql
, query
, NULL
, 0, 0, NULL
, &statement
);
855 ret
= dbd_oracle_pselect(pool
, sql
, results
, statement
, seek
, NULL
);
863 static int dbd_oracle_query(apr_dbd_t
*sql
, int *nrows
, const char *query
)
867 apr_dbd_prepared_t
*statement
= NULL
;
869 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
873 /* make our own pool so that APR allocations don't linger and so that
874 * both Stmt and LOB handles are cleaned up (LOB handles may be
875 * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs)
877 apr_pool_create(&pool
, sql
->pool
);
879 ret
= dbd_oracle_prepare(pool
, sql
, query
, NULL
, 0, 0, NULL
, &statement
);
881 ret
= dbd_oracle_pquery(pool
, sql
, nrows
, statement
, NULL
);
883 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
,
884 nrows
, 0, OCI_ATTR_ROW_COUNT
,
889 apr_pool_destroy(pool
);
894 static const char *dbd_oracle_escape(apr_pool_t
*pool
, const char *arg
,
897 return arg
; /* OCI has no concept of string escape */
900 static int dbd_oracle_prepare(apr_pool_t
*pool
, apr_dbd_t
*sql
,
901 const char *query
, const char *label
,
902 int nargs
, int nvals
, apr_dbd_type_e
*types
,
903 apr_dbd_prepared_t
**statement
)
907 apr_dbd_prepared_t
*stmt
;
909 /* prepared statements in a global lookup table would be nice,
910 * but we can't do that here because our pool may die leaving
911 * the cached statement orphaned.
912 * OTOH we can do that with Oracle statements, which aren't on
913 * the pool, so long as we don't register a cleanup on our pool!
916 * There's a race condition between cache-lookup and cache-set
917 * But the worst outcome is a statement prepared more than once
918 * and leaked. Is that worth mutexing for?
919 * Hmmm, yes it probably is ... OK, done
922 if (*statement
== NULL
) {
923 *statement
= apr_pcalloc(pool
, sizeof(apr_dbd_prepared_t
));
931 /* If we have a label, we're going to cache it globally.
932 * Check first if we already have it. If not, prepare the
933 * statement under mutex, so we don't end up leaking
934 * concurrent statements
936 * FIXME: Oracle docs say a statement can be used even across
937 * multiple servers, so I assume this is safe .....
939 #ifdef GLOBAL_PREPARED_STATEMENTS
941 stmt
->stmt
= apr_hash_get(oracle_statements
, label
, APR_HASH_KEY_STRING
);
942 if (stmt
->stmt
!= NULL
) {
945 apr_dbd_mutex_lock();
946 stmt
->stmt
= apr_hash_get(oracle_statements
, label
, APR_HASH_KEY_STRING
);
947 if (stmt
->stmt
!= NULL
) {
948 apr_dbd_mutex_unlock();
954 /* populate our own args, if any */
956 stmt
->args
= apr_pcalloc(pool
, nargs
*sizeof(bind_arg
));
957 for (i
= 0; i
< nargs
; i
++) {
958 stmt
->args
[i
].type
= types
[i
];
962 sql
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**) &stmt
->stmt
,
963 OCI_HTYPE_STMT
, 0, NULL
);
964 if (sql
->status
!= OCI_SUCCESS
) {
965 apr_dbd_mutex_unlock();
969 sql
->status
= OCIStmtPrepare(stmt
->stmt
, sql
->err
, (text
*) query
,
970 strlen(query
), OCI_NTV_SYNTAX
, OCI_DEFAULT
);
971 if (sql
->status
!= OCI_SUCCESS
) {
972 OCIHandleFree(stmt
->stmt
, OCI_HTYPE_STMT
);
973 apr_dbd_mutex_unlock();
977 apr_pool_cleanup_register(pool
, stmt
, freeStatement
,
978 apr_pool_cleanup_null
);
980 /* Perl gets statement type here */
981 sql
->status
= OCIAttrGet(stmt
->stmt
, OCI_HTYPE_STMT
, &stmt
->type
, 0,
982 OCI_ATTR_STMT_TYPE
, sql
->err
);
983 if (sql
->status
!= OCI_SUCCESS
) {
984 apr_dbd_mutex_unlock();
988 /* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
990 sql
->status
= OCIAttrSet(stmt
->stmt
, OCI_HTYPE_STMT
, &prefetch_size
,
991 sizeof(prefetch_size
), OCI_ATTR_PREFETCH_MEMORY
,
993 if (sql
->status
!= OCI_SUCCESS
) {
994 apr_dbd_mutex_unlock();
999 if (stmt
->type
== OCI_STMT_SELECT
) {
1000 ret
= outputParams(sql
, stmt
);
1002 #ifdef GLOBAL_PREPARED_STATEMENTS
1003 if (label
!= NULL
) {
1004 apr_hash_set(oracle_statements
, label
, APR_HASH_KEY_STRING
, stmt
->stmt
);
1005 apr_dbd_mutex_unlock();
1011 static void dbd_oracle_bind(apr_dbd_prepared_t
*statement
, const char **values
)
1013 OCIStmt
*stmt
= statement
->stmt
;
1014 apr_dbd_t
*sql
= statement
->handle
;
1018 for (i
= 0, j
= 0; i
< statement
->nargs
; i
++, j
++) {
1019 if (values
[j
] == NULL
) {
1020 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1025 (ub4
*) 0, OCI_DEFAULT
);
1028 switch (statement
->args
[i
].type
) {
1029 case APR_DBD_TYPE_BLOB
:
1031 char *data
= (char *)values
[j
];
1032 int size
= atoi((char*)values
[++j
]);
1034 /* skip table and column for now */
1037 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1039 data
, size
, SQLT_LBI
,
1040 &statement
->args
[i
].ind
,
1043 (ub4
*) 0, OCI_DEFAULT
);
1046 case APR_DBD_TYPE_CLOB
:
1048 char *data
= (char *)values
[j
];
1049 int size
= atoi((char*)values
[++j
]);
1051 /* skip table and column for now */
1054 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1056 data
, size
, SQLT_LNG
,
1057 &statement
->args
[i
].ind
,
1060 (ub4
*) 0, OCI_DEFAULT
);
1064 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1067 strlen(values
[j
]) + 1,
1069 &statement
->args
[i
].ind
,
1072 (ub4
*) 0, OCI_DEFAULT
);
1077 if (sql
->status
!= OCI_SUCCESS
) {
1085 static int outputParams(apr_dbd_t
*sql
, apr_dbd_prepared_t
*stmt
)
1090 ub2 paramtype
[DBD_ORACLE_MAX_COLUMNS
];
1091 ub2 paramsize
[DBD_ORACLE_MAX_COLUMNS
];
1092 const char *paramname
[DBD_ORACLE_MAX_COLUMNS
];
1093 ub4 paramnamelen
[DBD_ORACLE_MAX_COLUMNS
];
1094 /* Perl uses 0 where we used 1 */
1095 sql
->status
= OCIStmtExecute(sql
->svc
, stmt
->stmt
, sql
->err
, 0, 0,
1096 NULL
, NULL
, OCI_DESCRIBE_ONLY
);
1097 switch (sql
->status
) {
1099 case OCI_SUCCESS_WITH_INFO
:
1103 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1104 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1105 printf("Describing prepared statement: %s\n", sql
->buf
);
1110 while (sql
->status
== OCI_SUCCESS
) {
1111 sql
->status
= OCIParamGet(stmt
->stmt
, OCI_HTYPE_STMT
,
1112 sql
->err
, (dvoid
**)&parms
, stmt
->nout
+1);
1113 switch (sql
->status
) {
1115 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1116 ¶mtype
[stmt
->nout
],
1117 0, OCI_ATTR_DATA_TYPE
, sql
->err
);
1118 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1119 ¶msize
[stmt
->nout
],
1120 0, OCI_ATTR_DATA_SIZE
, sql
->err
);
1121 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1122 ¶mname
[stmt
->nout
],
1123 ¶mnamelen
[stmt
->nout
],
1124 OCI_ATTR_NAME
, sql
->err
);
1128 switch (sql
->status
) {
1132 break; /* this is what we expect at end-of-loop */
1137 /* OK, the above works. We have the params; now OCIDefine them */
1138 stmt
->out
= apr_palloc(stmt
->pool
, stmt
->nout
*sizeof(define_arg
));
1139 for (i
=0; i
<stmt
->nout
; ++i
) {
1140 stmt
->out
[i
].type
= paramtype
[i
];
1141 stmt
->out
[i
].len
= stmt
->out
[i
].sz
= paramsize
[i
];
1142 stmt
->out
[i
].name
= apr_pstrmemdup(stmt
->pool
,
1143 paramname
[i
], paramnamelen
[i
]);
1144 switch (stmt
->out
[i
].type
) {
1146 switch (stmt
->out
[i
].type
) {
1147 case SQLT_NUM
: /* 2: numeric, Perl worst case=130+38+3 */
1148 stmt
->out
[i
].sz
= 171;
1150 case SQLT_CHR
: /* 1: char */
1151 case SQLT_AFC
: /* 96: ANSI fixed char */
1152 stmt
->out
[i
].sz
*= 4; /* ugh, wasteful UCS-4 handling */
1154 case SQLT_DAT
: /* 12: date, depends on NLS date format */
1155 stmt
->out
[i
].sz
= 75;
1157 case SQLT_BIN
: /* 23: raw binary, perhaps UTF-16? */
1158 stmt
->out
[i
].sz
*= 2;
1160 case SQLT_RID
: /* 11: rowid */
1161 case SQLT_RDD
: /* 104: rowid descriptor */
1162 stmt
->out
[i
].sz
= 20;
1164 case SQLT_TIMESTAMP
: /* 187: timestamp */
1165 case SQLT_TIMESTAMP_TZ
: /* 188: timestamp with time zone */
1166 case SQLT_INTERVAL_YM
: /* 189: interval year-to-month */
1167 case SQLT_INTERVAL_DS
: /* 190: interval day-to-second */
1168 case SQLT_TIMESTAMP_LTZ
: /* 232: timestamp with local time zone */
1169 stmt
->out
[i
].sz
= 75;
1173 printf("Unsupported data type: %d\n", stmt
->out
[i
].type
);
1178 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1179 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1181 stmt
->out
[i
].buf
.sval
,
1182 stmt
->out
[i
].sz
, SQLT_STR
,
1183 &stmt
->out
[i
].ind
, &stmt
->out
[i
].len
,
1186 case SQLT_LNG
: /* 8: long */
1187 stmt
->out
[i
].sz
= sql
->long_size
* 4 + 4; /* ugh, UCS-4 handling */
1188 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1189 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1191 stmt
->out
[i
].buf
.raw
,
1192 stmt
->out
[i
].sz
, SQLT_LVC
,
1193 &stmt
->out
[i
].ind
, NULL
,
1196 case SQLT_LBI
: /* 24: long binary, perhaps UTF-16? */
1197 stmt
->out
[i
].sz
= sql
->long_size
* 2 + 4; /* room for int prefix */
1198 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1199 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1201 stmt
->out
[i
].buf
.raw
,
1202 stmt
->out
[i
].sz
, SQLT_LVB
,
1203 &stmt
->out
[i
].ind
, NULL
,
1206 case SQLT_BLOB
: /* 113 */
1207 case SQLT_CLOB
: /* 112 */
1208 /*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1209 sql
->status
= OCIDescriptorAlloc(dbd_oracle_env
,
1210 (dvoid
**)&stmt
->out
[i
].buf
.lobval
,
1211 OCI_DTYPE_LOB
, 0, NULL
);
1212 apr_pool_cleanup_register(stmt
->pool
, stmt
->out
[i
].buf
.lobval
,
1214 apr_pool_cleanup_null
);
1215 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1217 (dvoid
*) &stmt
->out
[i
].buf
.lobval
,
1218 -1, stmt
->out
[i
].type
,
1219 &stmt
->out
[i
].ind
, &stmt
->out
[i
].len
,
1223 switch (sql
->status
) {
1233 static int dbd_oracle_pquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1234 int *nrows
, apr_dbd_prepared_t
*statement
,
1235 const char **values
)
1238 OCISnapshot
*oldsnapshot
= NULL
;
1239 OCISnapshot
*newsnapshot
= NULL
;
1240 apr_dbd_transaction_t
* trans
= sql
->trans
;
1244 switch (trans
->status
) {
1251 oldsnapshot
= trans
->snapshot1
;
1252 newsnapshot
= trans
->snapshot2
;
1253 trans
->status
= TRANS_2
;
1256 oldsnapshot
= trans
->snapshot2
;
1257 newsnapshot
= trans
->snapshot1
;
1258 trans
->status
= TRANS_1
;
1261 exec_mode
= OCI_DEFAULT
;
1264 exec_mode
= OCI_COMMIT_ON_SUCCESS
;
1267 dbd_oracle_bind(statement
, values
);
1269 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 1, 0,
1270 oldsnapshot
, newsnapshot
, exec_mode
);
1271 switch (sql
->status
) {
1276 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1277 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1278 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
1282 if (TXN_NOTICE_ERRORS(trans
)) {
1283 trans
->status
= TRANS_ERROR
;
1288 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
, nrows
, 0,
1289 OCI_ATTR_ROW_COUNT
, sql
->err
);
1293 static int dbd_oracle_pvquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1294 int *nrows
, apr_dbd_prepared_t
*statement
,
1297 const char **values
;
1300 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1304 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1306 for (i
= 0; i
< statement
->nvals
; i
++) {
1307 values
[i
] = va_arg(args
, const char*);
1310 return dbd_oracle_pquery(pool
, sql
, nrows
, statement
, values
);
1313 static int dbd_oracle_pselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1314 apr_dbd_results_t
**results
,
1315 apr_dbd_prepared_t
*statement
,
1316 int seek
, const char **values
)
1318 int exec_mode
= seek
? OCI_STMT_SCROLLABLE_READONLY
: OCI_DEFAULT
;
1319 OCISnapshot
*oldsnapshot
= NULL
;
1320 OCISnapshot
*newsnapshot
= NULL
;
1321 apr_dbd_transaction_t
* trans
= sql
->trans
;
1324 switch (trans
->status
) {
1331 oldsnapshot
= trans
->snapshot1
;
1332 newsnapshot
= trans
->snapshot2
;
1333 trans
->status
= TRANS_2
;
1336 oldsnapshot
= trans
->snapshot2
;
1337 newsnapshot
= trans
->snapshot1
;
1338 trans
->status
= TRANS_1
;
1343 dbd_oracle_bind(statement
, values
);
1345 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 0, 0,
1346 oldsnapshot
, newsnapshot
, exec_mode
);
1347 switch (sql
->status
) {
1353 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1354 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1355 printf("Executing prepared statement: %s\n", sql
->buf
);
1359 if (TXN_NOTICE_ERRORS(trans
)) {
1360 trans
->status
= TRANS_ERROR
;
1366 *results
= apr_palloc(pool
, sizeof(apr_dbd_results_t
));
1368 (*results
)->handle
= sql
;
1369 (*results
)->statement
= statement
;
1370 (*results
)->seek
= seek
;
1371 (*results
)->rownum
= seek
? 0 : -1;
1372 (*results
)->pool
= pool
;
1377 static int dbd_oracle_pvselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1378 apr_dbd_results_t
**results
,
1379 apr_dbd_prepared_t
*statement
,
1380 int seek
, va_list args
)
1382 const char **values
;
1385 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1389 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1391 for (i
= 0; i
< statement
->nvals
; i
++) {
1392 values
[i
] = va_arg(args
, const char*);
1395 return dbd_oracle_pselect(pool
, sql
, results
, statement
, seek
, values
);
1398 static void dbd_oracle_bbind(apr_dbd_prepared_t
* statement
,
1399 const void **values
)
1401 OCIStmt
*stmt
= statement
->stmt
;
1402 apr_dbd_t
*sql
= statement
->handle
;
1405 apr_dbd_type_e type
;
1407 for (i
= 0, j
= 0; i
< statement
->nargs
; i
++, j
++) {
1408 type
= (values
[j
] == NULL
? APR_DBD_TYPE_NULL
1409 : statement
->args
[i
].type
);
1412 case APR_DBD_TYPE_TINY
:
1413 statement
->args
[i
].value
.ival
= *(char*)values
[j
];
1414 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1416 &statement
->args
[i
].value
.ival
,
1417 sizeof(statement
->args
[i
].value
.ival
),
1419 &statement
->args
[i
].ind
, NULL
,
1421 (ub4
*) 0, OCI_DEFAULT
);
1423 case APR_DBD_TYPE_UTINY
:
1424 statement
->args
[i
].value
.uval
= *(unsigned char*)values
[j
];
1425 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1427 &statement
->args
[i
].value
.uval
,
1428 sizeof(statement
->args
[i
].value
.uval
),
1430 &statement
->args
[i
].ind
, NULL
,
1432 (ub4
*) 0, OCI_DEFAULT
);
1434 case APR_DBD_TYPE_SHORT
:
1435 statement
->args
[i
].value
.ival
= *(short*)values
[j
];
1436 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1438 &statement
->args
[i
].value
.ival
,
1439 sizeof(statement
->args
[i
].value
.ival
),
1441 &statement
->args
[i
].ind
, NULL
,
1443 (ub4
*) 0, OCI_DEFAULT
);
1445 case APR_DBD_TYPE_USHORT
:
1446 statement
->args
[i
].value
.uval
= *(unsigned short*)values
[j
];
1447 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1449 &statement
->args
[i
].value
.uval
,
1450 sizeof(statement
->args
[i
].value
.uval
),
1452 &statement
->args
[i
].ind
, NULL
,
1454 (ub4
*) 0, OCI_DEFAULT
);
1456 case APR_DBD_TYPE_INT
:
1457 statement
->args
[i
].value
.ival
= *(int*)values
[j
];
1458 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1460 &statement
->args
[i
].value
.ival
,
1461 sizeof(statement
->args
[i
].value
.ival
),
1463 &statement
->args
[i
].ind
, NULL
,
1465 (ub4
*) 0, OCI_DEFAULT
);
1467 case APR_DBD_TYPE_UINT
:
1468 statement
->args
[i
].value
.uval
= *(unsigned int*)values
[j
];
1469 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1471 &statement
->args
[i
].value
.uval
,
1472 sizeof(statement
->args
[i
].value
.uval
),
1474 &statement
->args
[i
].ind
, NULL
,
1476 (ub4
*) 0, OCI_DEFAULT
);
1478 case APR_DBD_TYPE_LONG
:
1479 statement
->args
[i
].value
.sval
=
1480 apr_psprintf(statement
->pool
, "%ld", *(long*)values
[j
]);
1481 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1483 statement
->args
[i
].value
.sval
,
1484 strlen(statement
->args
[i
].value
.sval
)+1,
1486 &statement
->args
[i
].ind
, NULL
,
1488 (ub4
*) 0, OCI_DEFAULT
);
1490 case APR_DBD_TYPE_ULONG
:
1491 statement
->args
[i
].value
.sval
=
1492 apr_psprintf(statement
->pool
, "%lu",
1493 *(unsigned long*)values
[j
]);
1494 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1496 statement
->args
[i
].value
.sval
,
1497 strlen(statement
->args
[i
].value
.sval
)+1,
1499 &statement
->args
[i
].ind
, NULL
,
1501 (ub4
*) 0, OCI_DEFAULT
);
1503 case APR_DBD_TYPE_LONGLONG
:
1504 statement
->args
[i
].value
.sval
=
1505 apr_psprintf(statement
->pool
, "%" APR_INT64_T_FMT
,
1506 *(apr_int64_t
*)values
[j
]);
1507 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1509 statement
->args
[i
].value
.sval
,
1510 strlen(statement
->args
[i
].value
.sval
)+1,
1512 &statement
->args
[i
].ind
, NULL
,
1514 (ub4
*) 0, OCI_DEFAULT
);
1516 case APR_DBD_TYPE_ULONGLONG
:
1517 statement
->args
[i
].value
.sval
=
1518 apr_psprintf(statement
->pool
, "%" APR_UINT64_T_FMT
,
1519 *(apr_uint64_t
*)values
[j
]);
1520 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1522 statement
->args
[i
].value
.sval
,
1523 strlen(statement
->args
[i
].value
.sval
)+1,
1525 &statement
->args
[i
].ind
, NULL
,
1527 (ub4
*) 0, OCI_DEFAULT
);
1529 case APR_DBD_TYPE_FLOAT
:
1530 statement
->args
[i
].value
.fval
= *(float*)values
[j
];
1531 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1533 &statement
->args
[i
].value
.fval
,
1534 sizeof(statement
->args
[i
].value
.fval
),
1536 &statement
->args
[i
].ind
, NULL
,
1538 (ub4
*) 0, OCI_DEFAULT
);
1540 case APR_DBD_TYPE_DOUBLE
:
1541 statement
->args
[i
].value
.fval
= *(double*)values
[j
];
1542 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1544 &statement
->args
[i
].value
.fval
,
1545 sizeof(statement
->args
[i
].value
.fval
),
1547 &statement
->args
[i
].ind
, NULL
,
1549 (ub4
*) 0, OCI_DEFAULT
);
1551 case APR_DBD_TYPE_STRING
:
1552 case APR_DBD_TYPE_TEXT
:
1553 case APR_DBD_TYPE_TIME
:
1554 case APR_DBD_TYPE_DATE
:
1555 case APR_DBD_TYPE_DATETIME
:
1556 case APR_DBD_TYPE_TIMESTAMP
:
1557 case APR_DBD_TYPE_ZTIMESTAMP
:
1558 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1561 strlen(values
[j
]) + 1,
1563 &statement
->args
[i
].ind
, NULL
,
1565 (ub4
*) 0, OCI_DEFAULT
);
1567 case APR_DBD_TYPE_BLOB
:
1569 char *data
= (char *)values
[j
];
1570 apr_size_t size
= *(apr_size_t
*)values
[++j
];
1572 /* skip table and column for now */
1575 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1577 data
, size
, SQLT_LBI
,
1578 &statement
->args
[i
].ind
,
1581 (ub4
*) 0, OCI_DEFAULT
);
1584 case APR_DBD_TYPE_CLOB
:
1586 char *data
= (char *)values
[j
];
1587 apr_size_t size
= *(apr_size_t
*)values
[++j
];
1589 /* skip table and column for now */
1592 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1594 data
, size
, SQLT_LNG
,
1595 &statement
->args
[i
].ind
,
1598 (ub4
*) 0, OCI_DEFAULT
);
1601 case APR_DBD_TYPE_NULL
:
1603 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1608 (ub4
*) 0, OCI_DEFAULT
);
1612 if (sql
->status
!= OCI_SUCCESS
) {
1620 static int dbd_oracle_pbquery(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1621 int *nrows
, apr_dbd_prepared_t
* statement
,
1622 const void **values
)
1625 OCISnapshot
*oldsnapshot
= NULL
;
1626 OCISnapshot
*newsnapshot
= NULL
;
1627 apr_dbd_transaction_t
* trans
= sql
->trans
;
1631 switch (trans
->status
) {
1638 oldsnapshot
= trans
->snapshot1
;
1639 newsnapshot
= trans
->snapshot2
;
1640 trans
->status
= TRANS_2
;
1643 oldsnapshot
= trans
->snapshot2
;
1644 newsnapshot
= trans
->snapshot1
;
1645 trans
->status
= TRANS_1
;
1648 exec_mode
= OCI_DEFAULT
;
1651 exec_mode
= OCI_COMMIT_ON_SUCCESS
;
1654 dbd_oracle_bbind(statement
, values
);
1656 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 1, 0,
1657 oldsnapshot
, newsnapshot
, exec_mode
);
1658 switch (sql
->status
) {
1663 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1664 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1665 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
1669 if (TXN_NOTICE_ERRORS(trans
)) {
1670 trans
->status
= TRANS_ERROR
;
1675 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
, nrows
, 0,
1676 OCI_ATTR_ROW_COUNT
, sql
->err
);
1680 static int dbd_oracle_pvbquery(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1681 int *nrows
, apr_dbd_prepared_t
* statement
,
1684 const void **values
;
1687 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1691 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1693 for (i
= 0; i
< statement
->nvals
; i
++) {
1694 values
[i
] = va_arg(args
, const void*);
1697 return dbd_oracle_pbquery(pool
, sql
, nrows
, statement
, values
);
1700 static int dbd_oracle_pbselect(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1701 apr_dbd_results_t
** results
,
1702 apr_dbd_prepared_t
* statement
,
1703 int seek
, const void **values
)
1705 int exec_mode
= seek
? OCI_STMT_SCROLLABLE_READONLY
: OCI_DEFAULT
;
1706 OCISnapshot
*oldsnapshot
= NULL
;
1707 OCISnapshot
*newsnapshot
= NULL
;
1708 apr_dbd_transaction_t
* trans
= sql
->trans
;
1711 switch (trans
->status
) {
1718 oldsnapshot
= trans
->snapshot1
;
1719 newsnapshot
= trans
->snapshot2
;
1720 trans
->status
= TRANS_2
;
1723 oldsnapshot
= trans
->snapshot2
;
1724 newsnapshot
= trans
->snapshot1
;
1725 trans
->status
= TRANS_1
;
1730 dbd_oracle_bbind(statement
, values
);
1732 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 0, 0,
1733 oldsnapshot
, newsnapshot
, exec_mode
);
1734 switch (sql
->status
) {
1740 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1741 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1742 printf("Executing prepared statement: %s\n", sql
->buf
);
1746 if (TXN_NOTICE_ERRORS(trans
)) {
1747 trans
->status
= TRANS_ERROR
;
1753 *results
= apr_palloc(pool
, sizeof(apr_dbd_results_t
));
1755 (*results
)->handle
= sql
;
1756 (*results
)->statement
= statement
;
1757 (*results
)->seek
= seek
;
1758 (*results
)->rownum
= seek
? 0 : -1;
1759 (*results
)->pool
= pool
;
1764 static int dbd_oracle_pvbselect(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1765 apr_dbd_results_t
** results
,
1766 apr_dbd_prepared_t
* statement
, int seek
,
1769 const void **values
;
1772 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1776 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1778 for (i
= 0; i
< statement
->nvals
; i
++) {
1779 values
[i
] = va_arg(args
, const void*);
1782 return dbd_oracle_pbselect(pool
, sql
, results
, statement
, seek
, values
);
1785 static int dbd_oracle_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1786 apr_dbd_transaction_t
**trans
)
1791 dbd_oracle_end_transaction(*trans
);
1794 *trans
= apr_pcalloc(pool
, sizeof(apr_dbd_transaction_t
));
1795 OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&(*trans
)->trans
,
1796 OCI_HTYPE_TRANS
, 0, 0);
1797 OCIAttrSet(sql
->svc
, OCI_HTYPE_SVCCTX
, (*trans
)->trans
, 0,
1798 OCI_ATTR_TRANS
, sql
->err
);
1802 sql
->status
= OCITransStart(sql
->svc
, sql
->err
, TRANS_TIMEOUT
,
1804 switch (sql
->status
) {
1807 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
, sql
->buf
,
1808 sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1809 printf("Transaction: %s\n", sql
->buf
);
1814 (*trans
)->handle
= sql
;
1815 (*trans
)->status
= TRANS_1
;
1816 sql
->trans
= *trans
;
1817 switch (OCIDescriptorAlloc(dbd_oracle_env
,
1818 (dvoid
**)&(*trans
)->snapshot1
,
1819 OCI_DTYPE_SNAP
, 0, NULL
)) {
1821 apr_pool_cleanup_register(pool
, (*trans
)->snapshot1
,
1822 dbd_free_snapshot
, apr_pool_cleanup_null
);
1824 case OCI_INVALID_HANDLE
:
1828 switch (OCIDescriptorAlloc(dbd_oracle_env
,
1829 (dvoid
**)&(*trans
)->snapshot2
,
1830 OCI_DTYPE_SNAP
, 0, NULL
)) {
1832 apr_pool_cleanup_register(pool
, (*trans
)->snapshot2
,
1833 dbd_free_snapshot
, apr_pool_cleanup_null
);
1835 case OCI_INVALID_HANDLE
:
1847 static int dbd_oracle_end_transaction(apr_dbd_transaction_t
*trans
)
1849 int ret
= 1; /* no transaction is an error cond */
1851 apr_dbd_t
*handle
= trans
->handle
;
1853 switch (trans
->status
) {
1854 case TRANS_NONE
: /* No trans is an error here */
1858 status
= OCITransRollback(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1861 /* rollback on explicit rollback request */
1862 if (TXN_DO_ROLLBACK(trans
)) {
1863 status
= OCITransRollback(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1865 status
= OCITransCommit(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1870 handle
->trans
= NULL
;
1884 static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t
*trans
)
1887 return APR_DBD_TRANSACTION_COMMIT
;
1892 static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t
*trans
,
1896 return APR_DBD_TRANSACTION_COMMIT
;
1898 return trans
->mode
= (mode
& TXN_MODE_BITS
);
1901 /* This doesn't work for BLOB because of NULLs, but it can fake it
1902 * if the BLOB is really a string
1904 static const char *dbd_oracle_get_entry(const apr_dbd_row_t
*row
, int n
)
1910 apr_size_t buflen
= 0;
1912 define_arg
*val
= &row
->res
->statement
->out
[n
];
1913 apr_dbd_t
*sql
= row
->res
->handle
;
1915 if ((n
< 0) || (n
>= row
->res
->statement
->nout
) || (val
->ind
== -1)) {
1919 switch (val
->type
) {
1922 sql
->status
= OCILobGetLength(sql
->svc
, sql
->err
, val
->buf
.lobval
,
1924 switch (sql
->status
) {
1926 case OCI_SUCCESS_WITH_INFO
:
1933 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1934 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1935 printf("Finding LOB length: %s\n", sql
->buf
);
1946 if (val
->type
== APR_DBD_TYPE_CLOB
) {
1948 /* Is this necessary, or can it be defaulted? */
1949 sql
->status
= OCILobCharSetForm(dbd_oracle_env
, sql
->err
,
1950 val
->buf
.lobval
, &csform
);
1951 if (sql
->status
== OCI_SUCCESS
) {
1952 sql
->status
= OCILobCharSetId(dbd_oracle_env
, sql
->err
,
1953 val
->buf
.lobval
, &csid
);
1955 switch (sql
->status
) {
1957 case OCI_SUCCESS_WITH_INFO
:
1958 buflen
= (len
+1) * 4; /* ugh, wasteful UCS-4 handling */
1959 /* zeroise all - where the string ends depends on charset */
1960 buf
= apr_pcalloc(row
->pool
, buflen
);
1964 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1965 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1966 printf("Reading LOB character set: %s\n", sql
->buf
);
1967 break; /*** XXX?? ***/
1970 break; /*** XXX?? ***/
1972 #else /* ignore charset */
1973 buflen
= (len
+1) * 4; /* ugh, wasteful UCS-4 handling */
1974 /* zeroise all - where the string ends depends on charset */
1975 buf
= apr_pcalloc(row
->pool
, buflen
);
1978 /* BUG: this'll only work if the BLOB looks like a string */
1980 buf
= apr_palloc(row
->pool
, buflen
+1);
1988 sql
->status
= OCILobRead(sql
->svc
, sql
->err
, val
->buf
.lobval
,
1989 &len
, 1, (dvoid
*) buf
, buflen
,
1990 NULL
, NULL
, csid
, csform
);
1991 switch (sql
->status
) {
1993 case OCI_SUCCESS_WITH_INFO
:
1997 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1998 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1999 printf("Reading LOB: %s\n", sql
->buf
);
2000 buf
= NULL
; /*** XXX?? ***/
2004 buf
= NULL
; /*** XXX?? ***/
2011 /* raw is struct { ub4 len; char *buf; } */
2012 len
= *(ub4
*) val
->buf
.raw
;
2013 buf
= apr_pstrndup(row
->pool
, val
->buf
.sval
+ sizeof(ub4
), len
);
2016 buf
= apr_pstrndup(row
->pool
, val
->buf
.sval
, val
->len
);
2019 return (const char*) buf
;
2022 /* XXX Should this use Oracle proper API instead of calling get_entry()? */
2023 static apr_status_t
dbd_oracle_datum_get(const apr_dbd_row_t
*row
, int n
,
2024 apr_dbd_type_e type
, void *data
)
2026 define_arg
*val
= &row
->res
->statement
->out
[n
];
2029 if ((n
< 0) || (n
>= row
->res
->statement
->nout
)) {
2030 return APR_EGENERAL
;
2033 if(val
->ind
== -1) {
2038 case APR_DBD_TYPE_TINY
:
2039 entry
= dbd_oracle_get_entry(row
, n
);
2040 if (entry
== NULL
) {
2043 *(char*)data
= atoi(entry
);
2045 case APR_DBD_TYPE_UTINY
:
2046 entry
= dbd_oracle_get_entry(row
, n
);
2047 if (entry
== NULL
) {
2050 *(unsigned char*)data
= atoi(entry
);
2052 case APR_DBD_TYPE_SHORT
:
2053 entry
= dbd_oracle_get_entry(row
, n
);
2054 if (entry
== NULL
) {
2057 *(short*)data
= atoi(entry
);
2059 case APR_DBD_TYPE_USHORT
:
2060 entry
= dbd_oracle_get_entry(row
, n
);
2061 if (entry
== NULL
) {
2064 *(unsigned short*)data
= atoi(entry
);
2066 case APR_DBD_TYPE_INT
:
2067 entry
= dbd_oracle_get_entry(row
, n
);
2068 if (entry
== NULL
) {
2071 *(int*)data
= atoi(entry
);
2073 case APR_DBD_TYPE_UINT
:
2074 entry
= dbd_oracle_get_entry(row
, n
);
2075 if (entry
== NULL
) {
2078 *(unsigned int*)data
= atoi(entry
);
2080 case APR_DBD_TYPE_LONG
:
2081 entry
= dbd_oracle_get_entry(row
, n
);
2082 if (entry
== NULL
) {
2085 *(long*)data
= atol(entry
);
2087 case APR_DBD_TYPE_ULONG
:
2088 entry
= dbd_oracle_get_entry(row
, n
);
2089 if (entry
== NULL
) {
2092 *(unsigned long*)data
= atol(entry
);
2094 case APR_DBD_TYPE_LONGLONG
:
2095 entry
= dbd_oracle_get_entry(row
, n
);
2096 if (entry
== NULL
) {
2099 *(apr_int64_t
*)data
= apr_atoi64(entry
);
2101 case APR_DBD_TYPE_ULONGLONG
:
2102 entry
= dbd_oracle_get_entry(row
, n
);
2103 if (entry
== NULL
) {
2106 *(apr_uint64_t
*)data
= apr_atoi64(entry
);
2108 case APR_DBD_TYPE_FLOAT
:
2109 entry
= dbd_oracle_get_entry(row
, n
);
2110 if (entry
== NULL
) {
2113 *(float*)data
= atof(entry
);
2115 case APR_DBD_TYPE_DOUBLE
:
2116 entry
= dbd_oracle_get_entry(row
, n
);
2117 if (entry
== NULL
) {
2120 *(double*)data
= atof(entry
);
2122 case APR_DBD_TYPE_STRING
:
2123 case APR_DBD_TYPE_TEXT
:
2124 case APR_DBD_TYPE_TIME
:
2125 case APR_DBD_TYPE_DATE
:
2126 case APR_DBD_TYPE_DATETIME
:
2127 case APR_DBD_TYPE_TIMESTAMP
:
2128 case APR_DBD_TYPE_ZTIMESTAMP
:
2129 entry
= dbd_oracle_get_entry(row
, n
);
2130 if (entry
== NULL
) {
2133 *(char**)data
= (char*)entry
;
2135 case APR_DBD_TYPE_BLOB
:
2136 case APR_DBD_TYPE_CLOB
:
2139 apr_bucket_brigade
*b
= (apr_bucket_brigade
*)data
;
2140 apr_dbd_t
*sql
= row
->res
->handle
;
2143 switch (val
->type
) {
2146 sql
->status
= OCILobGetLength(sql
->svc
, sql
->err
,
2147 val
->buf
.lobval
, &len
);
2148 switch(sql
->status
) {
2150 case OCI_SUCCESS_WITH_INFO
:
2152 e
= apr_bucket_eos_create(b
->bucket_alloc
);
2155 e
= apr_bucket_lob_create(row
, n
, 0, len
,
2156 row
->pool
, b
->bucket_alloc
);
2164 entry
= dbd_oracle_get_entry(row
, n
);
2165 if (entry
== NULL
) {
2168 e
= apr_bucket_pool_create(entry
, strlen(entry
),
2169 row
->pool
, b
->bucket_alloc
);
2172 APR_BRIGADE_INSERT_TAIL(b
, e
);
2175 case APR_DBD_TYPE_NULL
:
2176 *(void**)data
= NULL
;
2179 return APR_EGENERAL
;
2185 static apr_status_t
dbd_oracle_close(apr_dbd_t
*handle
)
2187 /* FIXME: none of the oracle docs/examples say anything about
2188 * closing/releasing handles. Which seems unlikely ...
2191 /* OK, let's grab from cdemo again.
2192 * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
2194 switch (OCISessionEnd(handle
->svc
, handle
->err
, handle
->auth
,
2195 (ub4
)OCI_DEFAULT
)) {
2199 switch (OCIServerDetach(handle
->svr
, handle
->err
, (ub4
) OCI_DEFAULT
)) {
2203 /* does OCISessionEnd imply this? */
2204 switch (OCIHandleFree((dvoid
*) handle
->auth
, (ub4
) OCI_HTYPE_SESSION
)) {
2208 switch (OCIHandleFree((dvoid
*) handle
->svr
, (ub4
) OCI_HTYPE_SERVER
)) {
2212 switch (OCIHandleFree((dvoid
*) handle
->svc
, (ub4
) OCI_HTYPE_SVCCTX
)) {
2216 switch (OCIHandleFree((dvoid
*) handle
->err
, (ub4
) OCI_HTYPE_ERROR
)) {
2223 static apr_status_t
dbd_oracle_check_conn(apr_pool_t
*pool
, apr_dbd_t
*sql
)
2225 apr_dbd_results_t
*res
= NULL
;
2226 apr_dbd_row_t
*row
= NULL
;
2228 if(dbd_oracle_pselect(pool
, sql
, &res
, sql
->check_conn_stmt
,
2230 return APR_EGENERAL
;
2233 if(dbd_oracle_get_row(pool
, res
, &row
, -1) != 0) {
2234 return APR_EGENERAL
;
2237 if(dbd_oracle_get_row(pool
, res
, &row
, -1) != -1) {
2238 return APR_EGENERAL
;
2244 static int dbd_oracle_select_db(apr_pool_t
*pool
, apr_dbd_t
*handle
,
2247 /* FIXME: need to find this in the docs */
2248 return APR_ENOTIMPL
;
2251 static void *dbd_oracle_native(apr_dbd_t
*handle
)
2253 /* FIXME: can we do anything better? Oracle doesn't seem to have
2254 * a concept of a handle in the sense we use it.
2256 return dbd_oracle_env
;
2259 static int dbd_oracle_num_cols(apr_dbd_results_t
* res
)
2261 return res
->statement
->nout
;
2264 static int dbd_oracle_num_tuples(apr_dbd_results_t
* res
)
2269 if (res
->nrows
>= 0) {
2272 res
->handle
->status
= OCIAttrGet(res
->statement
->stmt
, OCI_HTYPE_STMT
,
2273 &res
->nrows
, 0, OCI_ATTR_ROW_COUNT
,
2278 APU_DECLARE_DATA
const apr_dbd_driver_t apr_dbd_oracle_driver
= {
2283 dbd_oracle_check_conn
,
2285 dbd_oracle_select_db
,
2286 dbd_oracle_start_transaction
,
2287 dbd_oracle_end_transaction
,
2290 dbd_oracle_num_cols
,
2291 dbd_oracle_num_tuples
,
2293 dbd_oracle_get_entry
,
2298 dbd_oracle_pvselect
,
2301 dbd_oracle_get_name
,
2302 dbd_oracle_transaction_mode_get
,
2303 dbd_oracle_transaction_mode_set
,
2305 dbd_oracle_pvbquery
,
2306 dbd_oracle_pvbselect
,
2308 dbd_oracle_pbselect
,
2309 dbd_oracle_datum_get