1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 /* Developed initially by Nick Kew and Chris Darroch.
18 * Contributed to the APR project by kind permission of
19 * Pearson Education Core Technology Group (CTG),
20 * formerly Central Media Group (CMG).
23 /* apr_dbd_oracle - a painful attempt
25 * Based first on the documentation at
26 * http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/toc.htm
28 * Those docs have a lot of internal inconsistencies, contradictions, etc
29 * So I've snarfed the demo programs (from Oracle 8, not included in
30 * the current downloadable oracle), and used code from them.
32 * Why do cdemo81.c and cdemo82.c do the same thing in very different ways?
33 * e.g. cdemo82 releases all its handle on shutdown; cdemo81 doesn't
35 * All the ORA* functions return a "sword". Some of them are documented;
36 * others aren't. So I've adopted a policy of using switch statements
37 * everywhere, even when we're not doing anything with the return values.
39 * This makes no attempt at performance tuning, such as setting
40 * prefetch cache size. We need some actual performance data
41 * to make that meaningful. Input from someone with experience
42 * as a sysop using oracle would be a good start.
45 /* shut compiler up */
47 #define int_errorcode int errorcode
62 #include "apr_strings.h"
65 #include "apr_buckets.h"
67 #define TRANS_TIMEOUT 30
68 #define MAX_ARG_LEN 256 /* in line with other apr_dbd drivers. We alloc this
69 * lots of times, so a large value gets hungry.
70 * Should really make it configurable
72 #define DEFAULT_LONG_SIZE 4096
73 #define DBD_ORACLE_MAX_COLUMNS 256
74 #define NUMERIC_FIELD_SIZE 32
76 #define CHECK_CONN_QUERY "SELECT 1 FROM dual"
78 #define ERR_BUF_SIZE 200
84 #include "apr_dbd_internal.h"
87 static const char *dbd_oracle_error(apr_dbd_t
*sql
, int n
);
88 static int dbd_oracle_prepare(apr_pool_t
*pool
, apr_dbd_t
*sql
,
89 const char *query
, const char *label
,
90 int nargs
, int nvals
, apr_dbd_type_e
*types
,
91 apr_dbd_prepared_t
**statement
);
92 static int outputParams(apr_dbd_t
*, apr_dbd_prepared_t
*);
93 static int dbd_oracle_pselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
94 apr_dbd_results_t
**results
,
95 apr_dbd_prepared_t
*statement
,
96 int seek
, const char **values
);
97 static int dbd_oracle_pquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
98 int *nrows
, apr_dbd_prepared_t
*statement
,
100 static int dbd_oracle_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*sql
,
101 apr_dbd_transaction_t
**trans
);
102 static int dbd_oracle_end_transaction(apr_dbd_transaction_t
*trans
);
104 struct apr_dbd_transaction_t
{
106 enum { TRANS_NONE
, TRANS_ERROR
, TRANS_1
, TRANS_2
} status
;
109 OCISnapshot
*snapshot1
;
110 OCISnapshot
*snapshot2
;
113 struct apr_dbd_results_t
{
119 apr_dbd_prepared_t
*statement
;
128 apr_dbd_transaction_t
* trans
;
130 char buf
[ERR_BUF_SIZE
]; /* for error messages */
131 apr_size_t long_size
;
132 apr_dbd_prepared_t
*check_conn_stmt
;
135 struct apr_dbd_row_t
{
137 apr_dbd_results_t
*res
;
152 OCILobLocator
*lobval
;
159 ub2 len
; /* length of actual output */
161 apr_size_t sz
; /* length of buf for output */
165 OCILobLocator
*lobval
;
170 struct apr_dbd_prepared_t
{
182 /* AFAICT from the docs, the OCIEnv thingey can be used async
183 * across threads, so lets have a global one.
185 * We'll need shorter-lived envs to deal with requests and connections
187 * Hmmm, that doesn't work: we don't have a usermem framework.
188 * OK, forget about using APR pools here, until we figure out
189 * the right way to do it (if such a thing exists).
191 static OCIEnv
*dbd_oracle_env
= NULL
;
193 /* Oracle specific bucket for BLOB/CLOB types */
194 typedef struct apr_bucket_lob apr_bucket_lob
;
196 * A bucket referring to a Oracle BLOB/CLOB
198 struct apr_bucket_lob
{
199 /** Number of buckets using this memory */
200 apr_bucket_refcount refcount
;
201 /** The row this bucket refers to */
202 const apr_dbd_row_t
*row
;
203 /** The column this bucket refers to */
205 /** The pool into which any needed structures should
206 * be created while reading from this bucket */
207 apr_pool_t
*readpool
;
210 static void lob_bucket_destroy(void *data
);
211 static apr_status_t
lob_bucket_read(apr_bucket
*e
, const char **str
,
212 apr_size_t
*len
, apr_read_type_e block
);
213 static apr_bucket
*apr_bucket_lob_make(apr_bucket
*b
,
214 const apr_dbd_row_t
*row
, int col
,
215 apr_off_t offset
, apr_size_t len
,
217 static apr_bucket
*apr_bucket_lob_create(const apr_dbd_row_t
*row
, int col
,
219 apr_size_t len
, apr_pool_t
*p
,
220 apr_bucket_alloc_t
*list
);
222 static const apr_bucket_type_t apr_bucket_type_lob
= {
223 "LOB", 5, APR_BUCKET_DATA
,
226 apr_bucket_setaside_notimpl
,
227 apr_bucket_shared_split
,
228 apr_bucket_shared_copy
231 static void lob_bucket_destroy(void *data
)
233 apr_bucket_lob
*f
= data
;
235 if (apr_bucket_shared_destroy(f
)) {
236 /* no need to destroy database objects here; it will get
237 * done automatically when the pool gets cleaned up */
242 static apr_status_t
lob_bucket_read(apr_bucket
*e
, const char **str
,
243 apr_size_t
*len
, apr_read_type_e block
)
245 apr_bucket_lob
*a
= e
->data
;
246 const apr_dbd_row_t
*row
= a
->row
;
247 apr_dbd_results_t
*res
= row
->res
;
249 apr_bucket
*b
= NULL
;
250 apr_size_t blength
= e
->length
; /* bytes remaining in file past offset */
251 apr_off_t boffset
= e
->start
;
252 define_arg
*val
= &res
->statement
->out
[col
];
253 apr_dbd_t
*sql
= res
->handle
;
254 /* Only with 10g, unfortunately
255 oraub8 length = APR_BUCKET_BUFF_SIZE;
257 ub4 length
= APR_BUCKET_BUFF_SIZE
;
260 *str
= NULL
; /* in case we die prematurely */
262 /* fetch from offset if not at the beginning */
263 buf
= apr_palloc(row
->pool
, APR_BUCKET_BUFF_SIZE
);
264 sql
->status
= OCILobRead(sql
->svc
, sql
->err
, val
->buf
.lobval
,
265 &length
, 1 + (size_t)boffset
,
266 (dvoid
*) buf
, APR_BUCKET_BUFF_SIZE
,
267 NULL
, NULL
, 0, SQLCS_IMPLICIT
);
268 /* Only with 10g, unfortunately
269 sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,
270 &length, NULL, 1 + boffset,
271 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
272 OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
274 if (sql
->status
!= OCI_SUCCESS
) {
282 * Change the current bucket to refer to what we read,
283 * even if we read nothing because we hit EOF.
285 apr_bucket_pool_make(e
, *str
, *len
, res
->pool
);
287 /* If we have more to read from the field, then create another bucket */
289 /* for efficiency, we can just build a new apr_bucket struct
290 * to wrap around the existing LOB bucket */
291 b
= apr_bucket_alloc(sizeof(*b
), e
->list
);
292 b
->start
= boffset
+ *len
;
295 b
->type
= &apr_bucket_type_lob
;
296 b
->free
= apr_bucket_free
;
298 APR_BUCKET_INSERT_AFTER(e
, b
);
301 lob_bucket_destroy(a
);
307 static apr_bucket
*apr_bucket_lob_make(apr_bucket
*b
,
308 const apr_dbd_row_t
*row
, int col
,
309 apr_off_t offset
, apr_size_t len
,
314 f
= apr_bucket_alloc(sizeof(*f
), b
->list
);
319 b
= apr_bucket_shared_make(b
, f
, offset
, len
);
320 b
->type
= &apr_bucket_type_lob
;
325 static apr_bucket
*apr_bucket_lob_create(const apr_dbd_row_t
*row
, int col
,
327 apr_size_t len
, apr_pool_t
*p
,
328 apr_bucket_alloc_t
*list
)
330 apr_bucket
*b
= apr_bucket_alloc(sizeof(*b
), list
);
333 b
->free
= apr_bucket_free
;
335 return apr_bucket_lob_make(b
, row
, col
, offset
, len
, p
);
338 static apr_status_t
dbd_free_lobdesc(void *lob
)
340 switch (OCIDescriptorFree(lob
, OCI_DTYPE_LOB
)) {
348 static apr_status_t
dbd_free_snapshot(void *snap
)
350 switch (OCIDescriptorFree(snap
, OCI_DTYPE_SNAP
)) {
358 static void dbd_oracle_init(apr_pool_t
*pool
)
360 if (dbd_oracle_env
== NULL
) {
361 /* Sadly, OCI_SHARED seems to be impossible to use, due to
362 * various Oracle bugs. See, for example, Oracle MetaLink bug 2972890
363 * and PHP bug http://bugs.php.net/bug.php?id=23733
365 #ifdef OCI_NEW_LENGTH_SEMANTICS
366 OCIEnvCreate(&dbd_oracle_env
, OCI_THREADED
|OCI_NEW_LENGTH_SEMANTICS
,
367 NULL
, NULL
, NULL
, NULL
, 0, NULL
);
369 OCIEnvCreate(&dbd_oracle_env
, OCI_THREADED
,
370 NULL
, NULL
, NULL
, NULL
, 0, NULL
);
375 static apr_dbd_t
*dbd_oracle_open(apr_pool_t
*pool
, const char *params
,
378 apr_dbd_t
*ret
= apr_pcalloc(pool
, sizeof(apr_dbd_t
));
398 static const char *const delims
= " \r\n\t;|,";
401 ret
->long_size
= DEFAULT_LONG_SIZE
;
403 /* snitch parsing from the MySQL driver */
404 for (ptr
= strchr(params
, '='); ptr
; ptr
= strchr(ptr
, '=')) {
405 /* don't dereference memory that may not belong to us */
410 for (key
= ptr
-1; apr_isspace(*key
); --key
);
412 while (apr_isalpha(*key
)) {
414 /* Don't parse off the front of the params */
423 for (value
= ptr
+1; apr_isspace(*value
); ++value
);
424 vlen
= strcspn(value
, delims
);
425 for (i
=0; fields
[i
].field
!= NULL
; ++i
) {
426 if (!strncasecmp(fields
[i
].field
, key
, klen
)) {
427 fields
[i
].value
= apr_pstrndup(pool
, value
, vlen
);
434 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->err
,
435 OCI_HTYPE_ERROR
, 0, NULL
);
436 switch (ret
->status
) {
439 printf("ret->status is %d\n", ret
->status
);
448 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->svr
,
449 OCI_HTYPE_SERVER
, 0, NULL
);
450 switch (ret
->status
) {
453 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
454 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
455 printf("OPEN ERROR %d (alloc svr): %s\n", ret
->status
, ret
->buf
);
459 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
460 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
461 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
469 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->svc
,
470 OCI_HTYPE_SVCCTX
, 0, NULL
);
471 switch (ret
->status
) {
474 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
475 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
476 printf("OPEN ERROR %d (alloc svc): %s\n", ret
->status
, ret
->buf
);
480 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
481 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
482 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
490 /* All the examples use the #else */
492 ret
->status
= OCILogon(dbd_oracle_env
, ret
->err
, &ret
->svc
, fields
[0].value
,
493 strlen(fields
[0].value
), fields
[1].value
,
494 strlen(fields
[1].value
), fields
[2].value
,
495 strlen(fields
[2].value
));
496 switch (ret
->status
) {
499 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
500 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
501 printf("OPEN ERROR: %s\n", ret
->buf
);
505 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
506 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
507 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
515 ret
->status
= OCIServerAttach(ret
->svr
, ret
->err
, (text
*) fields
[3].value
,
516 strlen(fields
[3].value
), OCI_DEFAULT
);
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 (server attach): %s\n", ret
->status
, ret
->buf
);
526 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
527 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
528 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
535 ret
->status
= OCIAttrSet(ret
->svc
, OCI_HTYPE_SVCCTX
, ret
->svr
, 0,
536 OCI_ATTR_SERVER
, ret
->err
);
537 switch (ret
->status
) {
540 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
541 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
542 printf("OPEN ERROR %d (attr set): %s\n", ret
->status
, ret
->buf
);
546 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
547 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
548 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
555 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->auth
,
556 OCI_HTYPE_SESSION
, 0, NULL
);
557 switch (ret
->status
) {
560 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
561 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
562 printf("OPEN ERROR %d (alloc auth): %s\n", ret
->status
, ret
->buf
);
566 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
567 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
568 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
575 ret
->status
= OCIAttrSet(ret
->auth
, OCI_HTYPE_SESSION
, fields
[0].value
,
576 strlen(fields
[0].value
), OCI_ATTR_USERNAME
, ret
->err
);
577 switch (ret
->status
) {
580 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
581 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
582 printf("OPEN ERROR %d (attr username): %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
);
595 ret
->status
= OCIAttrSet(ret
->auth
, OCI_HTYPE_SESSION
, fields
[1].value
,
596 strlen(fields
[1].value
), OCI_ATTR_PASSWORD
, ret
->err
);
597 switch (ret
->status
) {
600 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
601 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
602 printf("OPEN ERROR %d (attr password): %s\n", ret
->status
, ret
->buf
);
606 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
607 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
608 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
615 ret
->status
= OCISessionBegin(ret
->svc
, ret
->err
, ret
->auth
,
616 OCI_CRED_RDBMS
, OCI_DEFAULT
);
617 switch (ret
->status
) {
620 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
621 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
622 printf("OPEN ERROR %d (session begin): %s\n", ret
->status
, ret
->buf
);
626 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
627 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
628 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
635 ret
->status
= OCIAttrSet(ret
->svc
, OCI_HTYPE_SVCCTX
, ret
->auth
, 0,
636 OCI_ATTR_SESSION
, ret
->err
);
637 switch (ret
->status
) {
640 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
641 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
642 printf("OPEN ERROR %d (attr session): %s\n", ret
->status
, ret
->buf
);
645 *error
= apr_pcalloc(pool
, ERR_BUF_SIZE
);
646 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, (unsigned char*)(*error
),
647 ERR_BUF_SIZE
, OCI_HTYPE_ERROR
);
657 if(dbd_oracle_prepare(pool
, ret
, CHECK_CONN_QUERY
, NULL
, 0, 0, NULL
,
658 &ret
->check_conn_stmt
) != 0) {
665 #ifdef EXPORT_NATIVE_FUNCS
666 static apr_size_t
dbd_oracle_long_size_set(apr_dbd_t
*sql
,
667 apr_size_t long_size
)
669 apr_size_t old_size
= sql
->long_size
;
670 sql
->long_size
= long_size
;
675 static const char *dbd_oracle_get_name(const apr_dbd_results_t
*res
, int n
)
677 define_arg
*val
= &res
->statement
->out
[n
];
679 if ((n
< 0) || (n
>= res
->statement
->nout
)) {
685 static int dbd_oracle_get_row(apr_pool_t
*pool
, apr_dbd_results_t
*res
,
686 apr_dbd_row_t
**rowp
, int rownum
)
688 apr_dbd_row_t
*row
= *rowp
;
689 apr_dbd_t
*sql
= res
->handle
;
693 row
= apr_palloc(pool
, sizeof(apr_dbd_row_t
));
696 /* Oracle starts counting at 1 according to the docs */
697 row
->n
= res
->seek
? rownum
: 1;
710 sql
->status
= OCIStmtFetch2(res
->statement
->stmt
, res
->handle
->err
, 1,
711 OCI_FETCH_ABSOLUTE
, row
->n
, OCI_DEFAULT
);
714 sql
->status
= OCIStmtFetch2(res
->statement
->stmt
, res
->handle
->err
, 1,
715 OCI_FETCH_NEXT
, 0, OCI_DEFAULT
);
717 switch (sql
->status
) {
725 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
726 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
727 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
736 static const char *dbd_oracle_error(apr_dbd_t
*sql
, int n
)
738 /* This is ugly. Needs us to pass in a buffer of unknown size.
739 * Either we put it on the handle, or we have to keep allocing/copying
743 switch (sql
->status
) {
745 return "OCI_SUCCESS";
746 case OCI_SUCCESS_WITH_INFO
:
747 return "OCI_SUCCESS_WITH_INFO";
749 return "OCI_NEED_DATA";
751 return "OCI_NO_DATA";
752 case OCI_INVALID_HANDLE
:
753 return "OCI_INVALID_HANDLE";
754 case OCI_STILL_EXECUTING
:
755 return "OCI_STILL_EXECUTING";
757 return "OCI_CONTINUE";
760 switch (OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
761 (text
*) sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
)) {
765 return "internal error: OCIErrorGet failed";
769 static apr_status_t
freeStatement(void *statement
)
771 int rv
= APR_SUCCESS
;
772 OCIStmt
*stmt
= ((apr_dbd_prepared_t
*)statement
)->stmt
;
777 if (OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&err
, OCI_HTYPE_ERROR
,
778 0, NULL
) != OCI_SUCCESS
) {
781 if (OCIStmtRelease(stmt
, err
, NULL
, 0, OCI_DEFAULT
) != OCI_SUCCESS
) {
784 if (OCIHandleFree(err
, OCI_HTYPE_ERROR
) != OCI_SUCCESS
) {
788 if (OCIHandleFree(stmt
, OCI_HTYPE_STMT
) != OCI_SUCCESS
) {
796 static int dbd_oracle_select(apr_pool_t
*pool
, apr_dbd_t
*sql
,
797 apr_dbd_results_t
**results
,
798 const char *query
, int seek
)
801 apr_dbd_prepared_t
*statement
= NULL
;
803 ret
= dbd_oracle_prepare(pool
, sql
, query
, NULL
, 0, 0, NULL
, &statement
);
808 ret
= dbd_oracle_pselect(pool
, sql
, results
, statement
, seek
, NULL
);
816 static int dbd_oracle_query(apr_dbd_t
*sql
, int *nrows
, const char *query
)
820 apr_dbd_prepared_t
*statement
= NULL
;
822 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
826 /* make our own pool so that APR allocations don't linger and so that
827 * both Stmt and LOB handles are cleaned up (LOB handles may be
828 * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs)
830 apr_pool_create(&pool
, sql
->pool
);
832 ret
= dbd_oracle_prepare(pool
, sql
, query
, NULL
, 0, 0, NULL
, &statement
);
834 ret
= dbd_oracle_pquery(pool
, sql
, nrows
, statement
, NULL
);
836 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
,
837 nrows
, 0, OCI_ATTR_ROW_COUNT
,
842 apr_pool_destroy(pool
);
847 static const char *dbd_oracle_escape(apr_pool_t
*pool
, const char *arg
,
850 return arg
; /* OCI has no concept of string escape */
853 static int dbd_oracle_prepare(apr_pool_t
*pool
, apr_dbd_t
*sql
,
854 const char *query
, const char *label
,
855 int nargs
, int nvals
, apr_dbd_type_e
*types
,
856 apr_dbd_prepared_t
**statement
)
860 apr_dbd_prepared_t
*stmt
;
862 if (*statement
== NULL
) {
863 *statement
= apr_pcalloc(pool
, sizeof(apr_dbd_prepared_t
));
871 /* populate our own args, if any */
873 stmt
->args
= apr_pcalloc(pool
, nargs
*sizeof(bind_arg
));
874 for (i
= 0; i
< nargs
; i
++) {
875 stmt
->args
[i
].type
= types
[i
];
879 sql
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**) &stmt
->stmt
,
880 OCI_HTYPE_STMT
, 0, NULL
);
881 if (sql
->status
!= OCI_SUCCESS
) {
885 sql
->status
= OCIStmtPrepare(stmt
->stmt
, sql
->err
, (text
*) query
,
886 strlen(query
), OCI_NTV_SYNTAX
, OCI_DEFAULT
);
887 if (sql
->status
!= OCI_SUCCESS
) {
888 OCIHandleFree(stmt
->stmt
, OCI_HTYPE_STMT
);
892 apr_pool_cleanup_register(pool
, stmt
, freeStatement
,
893 apr_pool_cleanup_null
);
895 /* Perl gets statement type here */
896 sql
->status
= OCIAttrGet(stmt
->stmt
, OCI_HTYPE_STMT
, &stmt
->type
, 0,
897 OCI_ATTR_STMT_TYPE
, sql
->err
);
898 if (sql
->status
!= OCI_SUCCESS
) {
902 /* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
904 sql
->status
= OCIAttrSet(stmt
->stmt
, OCI_HTYPE_STMT
, &prefetch_size
,
905 sizeof(prefetch_size
), OCI_ATTR_PREFETCH_MEMORY
,
907 if (sql
->status
!= OCI_SUCCESS
) {
912 if (stmt
->type
== OCI_STMT_SELECT
) {
913 ret
= outputParams(sql
, stmt
);
918 static void dbd_oracle_bind(apr_dbd_prepared_t
*statement
, const char **values
)
920 OCIStmt
*stmt
= statement
->stmt
;
921 apr_dbd_t
*sql
= statement
->handle
;
925 for (i
= 0, j
= 0; i
< statement
->nargs
; i
++, j
++) {
926 if (values
[j
] == NULL
) {
927 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
932 (ub4
*) 0, OCI_DEFAULT
);
935 switch (statement
->args
[i
].type
) {
936 case APR_DBD_TYPE_BLOB
:
938 char *data
= (char *)values
[j
];
939 int size
= atoi((char*)values
[++j
]);
941 /* skip table and column for now */
944 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
946 data
, size
, SQLT_LBI
,
947 &statement
->args
[i
].ind
,
950 (ub4
*) 0, OCI_DEFAULT
);
953 case APR_DBD_TYPE_CLOB
:
955 char *data
= (char *)values
[j
];
956 int size
= atoi((char*)values
[++j
]);
958 /* skip table and column for now */
961 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
963 data
, size
, SQLT_LNG
,
964 &statement
->args
[i
].ind
,
967 (ub4
*) 0, OCI_DEFAULT
);
971 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
974 strlen(values
[j
]) + 1,
976 &statement
->args
[i
].ind
,
979 (ub4
*) 0, OCI_DEFAULT
);
984 if (sql
->status
!= OCI_SUCCESS
) {
992 static int outputParams(apr_dbd_t
*sql
, apr_dbd_prepared_t
*stmt
)
996 ub2 paramtype
[DBD_ORACLE_MAX_COLUMNS
];
997 ub2 paramsize
[DBD_ORACLE_MAX_COLUMNS
];
998 char *paramname
[DBD_ORACLE_MAX_COLUMNS
];
999 ub4 paramnamelen
[DBD_ORACLE_MAX_COLUMNS
];
1002 /* Perl uses 0 where we used 1 */
1003 sql
->status
= OCIStmtExecute(sql
->svc
, stmt
->stmt
, sql
->err
, 0, 0,
1004 NULL
, NULL
, OCI_DESCRIBE_ONLY
);
1005 switch (sql
->status
) {
1007 case OCI_SUCCESS_WITH_INFO
:
1011 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1012 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1013 printf("Describing prepared statement: %s\n", sql
->buf
);
1018 while (sql
->status
== OCI_SUCCESS
) {
1019 sql
->status
= OCIParamGet(stmt
->stmt
, OCI_HTYPE_STMT
,
1020 sql
->err
, (dvoid
**)&parms
, stmt
->nout
+1);
1021 switch (sql
->status
) {
1023 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1024 ¶mtype
[stmt
->nout
],
1025 0, OCI_ATTR_DATA_TYPE
, sql
->err
);
1026 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1027 ¶msize
[stmt
->nout
],
1028 0, OCI_ATTR_DATA_SIZE
, sql
->err
);
1029 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1030 ¶mname
[stmt
->nout
],
1031 ¶mnamelen
[stmt
->nout
],
1032 OCI_ATTR_NAME
, sql
->err
);
1036 switch (sql
->status
) {
1040 break; /* this is what we expect at end-of-loop */
1045 /* OK, the above works. We have the params; now OCIDefine them */
1046 stmt
->out
= apr_palloc(stmt
->pool
, stmt
->nout
*sizeof(define_arg
));
1047 for (i
=0; i
<stmt
->nout
; ++i
) {
1048 stmt
->out
[i
].type
= paramtype
[i
];
1049 stmt
->out
[i
].len
= stmt
->out
[i
].sz
= paramsize
[i
];
1050 stmt
->out
[i
].name
= apr_pstrmemdup(stmt
->pool
,
1051 paramname
[i
], paramnamelen
[i
]);
1052 switch (stmt
->out
[i
].type
) {
1054 switch (stmt
->out
[i
].type
) {
1055 case SQLT_NUM
: /* 2: numeric, Perl worst case=130+38+3 */
1056 stmt
->out
[i
].sz
= 171;
1058 case SQLT_CHR
: /* 1: char */
1059 case SQLT_AFC
: /* 96: ANSI fixed char */
1060 stmt
->out
[i
].sz
*= 4; /* ugh, wasteful UCS-4 handling */
1062 case SQLT_DAT
: /* 12: date, depends on NLS date format */
1063 stmt
->out
[i
].sz
= 75;
1065 case SQLT_BIN
: /* 23: raw binary, perhaps UTF-16? */
1066 stmt
->out
[i
].sz
*= 2;
1068 case SQLT_RID
: /* 11: rowid */
1069 case SQLT_RDD
: /* 104: rowid descriptor */
1070 stmt
->out
[i
].sz
= 20;
1072 case SQLT_TIMESTAMP
: /* 187: timestamp */
1073 case SQLT_TIMESTAMP_TZ
: /* 188: timestamp with time zone */
1074 case SQLT_INTERVAL_YM
: /* 189: interval year-to-month */
1075 case SQLT_INTERVAL_DS
: /* 190: interval day-to-second */
1076 case SQLT_TIMESTAMP_LTZ
: /* 232: timestamp with local time zone */
1077 stmt
->out
[i
].sz
= 75;
1081 printf("Unsupported data type: %d\n", stmt
->out
[i
].type
);
1086 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1087 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1089 stmt
->out
[i
].buf
.sval
,
1090 stmt
->out
[i
].sz
, SQLT_STR
,
1091 &stmt
->out
[i
].ind
, &stmt
->out
[i
].len
,
1094 case SQLT_LNG
: /* 8: long */
1095 stmt
->out
[i
].sz
= sql
->long_size
* 4 + 4; /* ugh, UCS-4 handling */
1096 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1097 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1099 stmt
->out
[i
].buf
.raw
,
1100 stmt
->out
[i
].sz
, SQLT_LVC
,
1101 &stmt
->out
[i
].ind
, NULL
,
1104 case SQLT_LBI
: /* 24: long binary, perhaps UTF-16? */
1105 stmt
->out
[i
].sz
= sql
->long_size
* 2 + 4; /* room for int prefix */
1106 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1107 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1109 stmt
->out
[i
].buf
.raw
,
1110 stmt
->out
[i
].sz
, SQLT_LVB
,
1111 &stmt
->out
[i
].ind
, NULL
,
1114 case SQLT_BLOB
: /* 113 */
1115 case SQLT_CLOB
: /* 112 */
1116 /*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1117 sql
->status
= OCIDescriptorAlloc(dbd_oracle_env
,
1118 (dvoid
**)&stmt
->out
[i
].buf
.lobval
,
1119 OCI_DTYPE_LOB
, 0, NULL
);
1120 apr_pool_cleanup_register(stmt
->pool
, stmt
->out
[i
].buf
.lobval
,
1122 apr_pool_cleanup_null
);
1123 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1125 (dvoid
*) &stmt
->out
[i
].buf
.lobval
,
1126 -1, stmt
->out
[i
].type
,
1127 &stmt
->out
[i
].ind
, &stmt
->out
[i
].len
,
1131 switch (sql
->status
) {
1141 static int dbd_oracle_pquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1142 int *nrows
, apr_dbd_prepared_t
*statement
,
1143 const char **values
)
1145 OCISnapshot
*oldsnapshot
= NULL
;
1146 OCISnapshot
*newsnapshot
= NULL
;
1147 apr_dbd_transaction_t
* trans
= sql
->trans
;
1152 switch (trans
->status
) {
1159 oldsnapshot
= trans
->snapshot1
;
1160 newsnapshot
= trans
->snapshot2
;
1161 trans
->status
= TRANS_2
;
1164 oldsnapshot
= trans
->snapshot2
;
1165 newsnapshot
= trans
->snapshot1
;
1166 trans
->status
= TRANS_1
;
1169 exec_mode
= OCI_DEFAULT
;
1172 exec_mode
= OCI_COMMIT_ON_SUCCESS
;
1175 dbd_oracle_bind(statement
, values
);
1177 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 1, 0,
1178 oldsnapshot
, newsnapshot
, exec_mode
);
1179 switch (sql
->status
) {
1184 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1185 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1186 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
1190 if (TXN_NOTICE_ERRORS(trans
)) {
1191 trans
->status
= TRANS_ERROR
;
1196 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
, nrows
, 0,
1197 OCI_ATTR_ROW_COUNT
, sql
->err
);
1201 static int dbd_oracle_pvquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1202 int *nrows
, apr_dbd_prepared_t
*statement
,
1205 const char **values
;
1208 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1212 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1214 for (i
= 0; i
< statement
->nvals
; i
++) {
1215 values
[i
] = va_arg(args
, const char*);
1218 return dbd_oracle_pquery(pool
, sql
, nrows
, statement
, values
);
1221 static int dbd_oracle_pselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1222 apr_dbd_results_t
**results
,
1223 apr_dbd_prepared_t
*statement
,
1224 int seek
, const char **values
)
1226 int exec_mode
= seek
? OCI_STMT_SCROLLABLE_READONLY
: OCI_DEFAULT
;
1227 OCISnapshot
*oldsnapshot
= NULL
;
1228 OCISnapshot
*newsnapshot
= NULL
;
1229 apr_dbd_transaction_t
* trans
= sql
->trans
;
1233 switch (trans
->status
) {
1240 oldsnapshot
= trans
->snapshot1
;
1241 newsnapshot
= trans
->snapshot2
;
1242 trans
->status
= TRANS_2
;
1245 oldsnapshot
= trans
->snapshot2
;
1246 newsnapshot
= trans
->snapshot1
;
1247 trans
->status
= TRANS_1
;
1252 dbd_oracle_bind(statement
, values
);
1254 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 0, 0,
1255 oldsnapshot
, newsnapshot
, exec_mode
);
1256 switch (sql
->status
) {
1261 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1262 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1263 printf("Executing prepared statement: %s\n", sql
->buf
);
1267 if (TXN_NOTICE_ERRORS(trans
)) {
1268 trans
->status
= TRANS_ERROR
;
1274 *results
= apr_palloc(pool
, sizeof(apr_dbd_results_t
));
1276 (*results
)->handle
= sql
;
1277 (*results
)->statement
= statement
;
1278 (*results
)->seek
= seek
;
1279 (*results
)->rownum
= seek
? 0 : -1;
1280 (*results
)->pool
= pool
;
1285 static int dbd_oracle_pvselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1286 apr_dbd_results_t
**results
,
1287 apr_dbd_prepared_t
*statement
,
1288 int seek
, va_list args
)
1290 const char **values
;
1293 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1297 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1299 for (i
= 0; i
< statement
->nvals
; i
++) {
1300 values
[i
] = va_arg(args
, const char*);
1303 return dbd_oracle_pselect(pool
, sql
, results
, statement
, seek
, values
);
1306 static void dbd_oracle_bbind(apr_dbd_prepared_t
* statement
,
1307 const void **values
)
1309 OCIStmt
*stmt
= statement
->stmt
;
1310 apr_dbd_t
*sql
= statement
->handle
;
1313 apr_dbd_type_e type
;
1315 for (i
= 0, j
= 0; i
< statement
->nargs
; i
++, j
++) {
1316 type
= (values
[j
] == NULL
? APR_DBD_TYPE_NULL
1317 : statement
->args
[i
].type
);
1320 case APR_DBD_TYPE_TINY
:
1321 statement
->args
[i
].value
.ival
= *(char*)values
[j
];
1322 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1324 &statement
->args
[i
].value
.ival
,
1325 sizeof(statement
->args
[i
].value
.ival
),
1327 &statement
->args
[i
].ind
, NULL
,
1329 (ub4
*) 0, OCI_DEFAULT
);
1331 case APR_DBD_TYPE_UTINY
:
1332 statement
->args
[i
].value
.uval
= *(unsigned char*)values
[j
];
1333 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1335 &statement
->args
[i
].value
.uval
,
1336 sizeof(statement
->args
[i
].value
.uval
),
1338 &statement
->args
[i
].ind
, NULL
,
1340 (ub4
*) 0, OCI_DEFAULT
);
1342 case APR_DBD_TYPE_SHORT
:
1343 statement
->args
[i
].value
.ival
= *(short*)values
[j
];
1344 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1346 &statement
->args
[i
].value
.ival
,
1347 sizeof(statement
->args
[i
].value
.ival
),
1349 &statement
->args
[i
].ind
, NULL
,
1351 (ub4
*) 0, OCI_DEFAULT
);
1353 case APR_DBD_TYPE_USHORT
:
1354 statement
->args
[i
].value
.uval
= *(unsigned short*)values
[j
];
1355 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1357 &statement
->args
[i
].value
.uval
,
1358 sizeof(statement
->args
[i
].value
.uval
),
1360 &statement
->args
[i
].ind
, NULL
,
1362 (ub4
*) 0, OCI_DEFAULT
);
1364 case APR_DBD_TYPE_INT
:
1365 statement
->args
[i
].value
.ival
= *(int*)values
[j
];
1366 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1368 &statement
->args
[i
].value
.ival
,
1369 sizeof(statement
->args
[i
].value
.ival
),
1371 &statement
->args
[i
].ind
, NULL
,
1373 (ub4
*) 0, OCI_DEFAULT
);
1375 case APR_DBD_TYPE_UINT
:
1376 statement
->args
[i
].value
.uval
= *(unsigned int*)values
[j
];
1377 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1379 &statement
->args
[i
].value
.uval
,
1380 sizeof(statement
->args
[i
].value
.uval
),
1382 &statement
->args
[i
].ind
, NULL
,
1384 (ub4
*) 0, OCI_DEFAULT
);
1386 case APR_DBD_TYPE_LONG
:
1387 statement
->args
[i
].value
.sval
=
1388 apr_psprintf(statement
->pool
, "%ld", *(long*)values
[j
]);
1389 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1391 statement
->args
[i
].value
.sval
,
1392 strlen(statement
->args
[i
].value
.sval
)+1,
1394 &statement
->args
[i
].ind
, NULL
,
1396 (ub4
*) 0, OCI_DEFAULT
);
1398 case APR_DBD_TYPE_ULONG
:
1399 statement
->args
[i
].value
.sval
=
1400 apr_psprintf(statement
->pool
, "%lu",
1401 *(unsigned long*)values
[j
]);
1402 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1404 statement
->args
[i
].value
.sval
,
1405 strlen(statement
->args
[i
].value
.sval
)+1,
1407 &statement
->args
[i
].ind
, NULL
,
1409 (ub4
*) 0, OCI_DEFAULT
);
1411 case APR_DBD_TYPE_LONGLONG
:
1412 statement
->args
[i
].value
.sval
=
1413 apr_psprintf(statement
->pool
, "%" APR_INT64_T_FMT
,
1414 *(apr_int64_t
*)values
[j
]);
1415 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1417 statement
->args
[i
].value
.sval
,
1418 strlen(statement
->args
[i
].value
.sval
)+1,
1420 &statement
->args
[i
].ind
, NULL
,
1422 (ub4
*) 0, OCI_DEFAULT
);
1424 case APR_DBD_TYPE_ULONGLONG
:
1425 statement
->args
[i
].value
.sval
=
1426 apr_psprintf(statement
->pool
, "%" APR_UINT64_T_FMT
,
1427 *(apr_uint64_t
*)values
[j
]);
1428 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1430 statement
->args
[i
].value
.sval
,
1431 strlen(statement
->args
[i
].value
.sval
)+1,
1433 &statement
->args
[i
].ind
, NULL
,
1435 (ub4
*) 0, OCI_DEFAULT
);
1437 case APR_DBD_TYPE_FLOAT
:
1438 statement
->args
[i
].value
.fval
= *(float*)values
[j
];
1439 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1441 &statement
->args
[i
].value
.fval
,
1442 sizeof(statement
->args
[i
].value
.fval
),
1444 &statement
->args
[i
].ind
, NULL
,
1446 (ub4
*) 0, OCI_DEFAULT
);
1448 case APR_DBD_TYPE_DOUBLE
:
1449 statement
->args
[i
].value
.fval
= *(double*)values
[j
];
1450 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1452 &statement
->args
[i
].value
.fval
,
1453 sizeof(statement
->args
[i
].value
.fval
),
1455 &statement
->args
[i
].ind
, NULL
,
1457 (ub4
*) 0, OCI_DEFAULT
);
1459 case APR_DBD_TYPE_STRING
:
1460 case APR_DBD_TYPE_TEXT
:
1461 case APR_DBD_TYPE_TIME
:
1462 case APR_DBD_TYPE_DATE
:
1463 case APR_DBD_TYPE_DATETIME
:
1464 case APR_DBD_TYPE_TIMESTAMP
:
1465 case APR_DBD_TYPE_ZTIMESTAMP
:
1466 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1469 strlen(values
[j
]) + 1,
1471 &statement
->args
[i
].ind
, NULL
,
1473 (ub4
*) 0, OCI_DEFAULT
);
1475 case APR_DBD_TYPE_BLOB
:
1477 char *data
= (char *)values
[j
];
1478 apr_size_t size
= *(apr_size_t
*)values
[++j
];
1480 /* skip table and column for now */
1483 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1485 data
, size
, SQLT_LBI
,
1486 &statement
->args
[i
].ind
,
1489 (ub4
*) 0, OCI_DEFAULT
);
1492 case APR_DBD_TYPE_CLOB
:
1494 char *data
= (char *)values
[j
];
1495 apr_size_t size
= *(apr_size_t
*)values
[++j
];
1497 /* skip table and column for now */
1500 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1502 data
, size
, SQLT_LNG
,
1503 &statement
->args
[i
].ind
,
1506 (ub4
*) 0, OCI_DEFAULT
);
1509 case APR_DBD_TYPE_NULL
:
1511 sql
->status
= OCIBindByPos(stmt
, &statement
->args
[i
].bind
,
1516 (ub4
*) 0, OCI_DEFAULT
);
1520 if (sql
->status
!= OCI_SUCCESS
) {
1528 static int dbd_oracle_pbquery(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1529 int *nrows
, apr_dbd_prepared_t
* statement
,
1530 const void **values
)
1532 OCISnapshot
*oldsnapshot
= NULL
;
1533 OCISnapshot
*newsnapshot
= NULL
;
1534 apr_dbd_transaction_t
* trans
= sql
->trans
;
1539 switch (trans
->status
) {
1546 oldsnapshot
= trans
->snapshot1
;
1547 newsnapshot
= trans
->snapshot2
;
1548 trans
->status
= TRANS_2
;
1551 oldsnapshot
= trans
->snapshot2
;
1552 newsnapshot
= trans
->snapshot1
;
1553 trans
->status
= TRANS_1
;
1556 exec_mode
= OCI_DEFAULT
;
1559 exec_mode
= OCI_COMMIT_ON_SUCCESS
;
1562 dbd_oracle_bbind(statement
, values
);
1564 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 1, 0,
1565 oldsnapshot
, newsnapshot
, exec_mode
);
1566 switch (sql
->status
) {
1571 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1572 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1573 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
1577 if (TXN_NOTICE_ERRORS(trans
)) {
1578 trans
->status
= TRANS_ERROR
;
1583 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
, nrows
, 0,
1584 OCI_ATTR_ROW_COUNT
, sql
->err
);
1588 static int dbd_oracle_pvbquery(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1589 int *nrows
, apr_dbd_prepared_t
* statement
,
1592 const void **values
;
1595 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1599 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1601 for (i
= 0; i
< statement
->nvals
; i
++) {
1602 values
[i
] = va_arg(args
, const void*);
1605 return dbd_oracle_pbquery(pool
, sql
, nrows
, statement
, values
);
1608 static int dbd_oracle_pbselect(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1609 apr_dbd_results_t
** results
,
1610 apr_dbd_prepared_t
* statement
,
1611 int seek
, const void **values
)
1613 int exec_mode
= seek
? OCI_STMT_SCROLLABLE_READONLY
: OCI_DEFAULT
;
1614 OCISnapshot
*oldsnapshot
= NULL
;
1615 OCISnapshot
*newsnapshot
= NULL
;
1616 apr_dbd_transaction_t
* trans
= sql
->trans
;
1620 switch (trans
->status
) {
1627 oldsnapshot
= trans
->snapshot1
;
1628 newsnapshot
= trans
->snapshot2
;
1629 trans
->status
= TRANS_2
;
1632 oldsnapshot
= trans
->snapshot2
;
1633 newsnapshot
= trans
->snapshot1
;
1634 trans
->status
= TRANS_1
;
1639 dbd_oracle_bbind(statement
, values
);
1641 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 0, 0,
1642 oldsnapshot
, newsnapshot
, exec_mode
);
1643 switch (sql
->status
) {
1648 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1649 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1650 printf("Executing prepared statement: %s\n", sql
->buf
);
1654 if (TXN_NOTICE_ERRORS(trans
)) {
1655 trans
->status
= TRANS_ERROR
;
1661 *results
= apr_palloc(pool
, sizeof(apr_dbd_results_t
));
1663 (*results
)->handle
= sql
;
1664 (*results
)->statement
= statement
;
1665 (*results
)->seek
= seek
;
1666 (*results
)->rownum
= seek
? 0 : -1;
1667 (*results
)->pool
= pool
;
1672 static int dbd_oracle_pvbselect(apr_pool_t
* pool
, apr_dbd_t
* sql
,
1673 apr_dbd_results_t
** results
,
1674 apr_dbd_prepared_t
* statement
, int seek
,
1677 const void **values
;
1680 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
1684 values
= apr_palloc(pool
, sizeof(*values
) * statement
->nvals
);
1686 for (i
= 0; i
< statement
->nvals
; i
++) {
1687 values
[i
] = va_arg(args
, const void*);
1690 return dbd_oracle_pbselect(pool
, sql
, results
, statement
, seek
, values
);
1693 static int dbd_oracle_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1694 apr_dbd_transaction_t
**trans
)
1699 dbd_oracle_end_transaction(*trans
);
1702 *trans
= apr_pcalloc(pool
, sizeof(apr_dbd_transaction_t
));
1703 OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&(*trans
)->trans
,
1704 OCI_HTYPE_TRANS
, 0, 0);
1705 OCIAttrSet(sql
->svc
, OCI_HTYPE_SVCCTX
, (*trans
)->trans
, 0,
1706 OCI_ATTR_TRANS
, sql
->err
);
1710 sql
->status
= OCITransStart(sql
->svc
, sql
->err
, TRANS_TIMEOUT
,
1712 switch (sql
->status
) {
1715 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
, sql
->buf
,
1716 sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1717 printf("Transaction: %s\n", sql
->buf
);
1722 (*trans
)->handle
= sql
;
1723 (*trans
)->status
= TRANS_1
;
1724 sql
->trans
= *trans
;
1725 switch (OCIDescriptorAlloc(dbd_oracle_env
,
1726 (dvoid
**)&(*trans
)->snapshot1
,
1727 OCI_DTYPE_SNAP
, 0, NULL
)) {
1729 apr_pool_cleanup_register(pool
, (*trans
)->snapshot1
,
1730 dbd_free_snapshot
, apr_pool_cleanup_null
);
1732 case OCI_INVALID_HANDLE
:
1736 switch (OCIDescriptorAlloc(dbd_oracle_env
,
1737 (dvoid
**)&(*trans
)->snapshot2
,
1738 OCI_DTYPE_SNAP
, 0, NULL
)) {
1740 apr_pool_cleanup_register(pool
, (*trans
)->snapshot2
,
1741 dbd_free_snapshot
, apr_pool_cleanup_null
);
1743 case OCI_INVALID_HANDLE
:
1755 static int dbd_oracle_end_transaction(apr_dbd_transaction_t
*trans
)
1757 int ret
= 1; /* no transaction is an error cond */
1759 apr_dbd_t
*handle
= trans
->handle
;
1761 switch (trans
->status
) {
1762 case TRANS_NONE
: /* No trans is an error here */
1766 status
= OCITransRollback(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1769 /* rollback on explicit rollback request */
1770 if (TXN_DO_ROLLBACK(trans
)) {
1771 status
= OCITransRollback(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1773 status
= OCITransCommit(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1778 handle
->trans
= NULL
;
1792 static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t
*trans
)
1795 return APR_DBD_TRANSACTION_COMMIT
;
1800 static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t
*trans
,
1804 return APR_DBD_TRANSACTION_COMMIT
;
1806 return trans
->mode
= (mode
& TXN_MODE_BITS
);
1809 /* This doesn't work for BLOB because of NULLs, but it can fake it
1810 * if the BLOB is really a string
1812 static const char *dbd_oracle_get_entry(const apr_dbd_row_t
*row
, int n
)
1817 apr_size_t buflen
= 0;
1819 define_arg
*val
= &row
->res
->statement
->out
[n
];
1820 apr_dbd_t
*sql
= row
->res
->handle
;
1823 if ((n
< 0) || (n
>= row
->res
->statement
->nout
) || (val
->ind
== -1)) {
1827 switch (val
->type
) {
1830 sql
->status
= OCILobGetLength(sql
->svc
, sql
->err
, val
->buf
.lobval
,
1832 switch (sql
->status
) {
1834 case OCI_SUCCESS_WITH_INFO
:
1841 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1842 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1843 printf("Finding LOB length: %s\n", sql
->buf
);
1854 if (val
->type
== APR_DBD_TYPE_CLOB
) {
1856 /* Is this necessary, or can it be defaulted? */
1857 sql
->status
= OCILobCharSetForm(dbd_oracle_env
, sql
->err
,
1858 val
->buf
.lobval
, &csform
);
1859 if (sql
->status
== OCI_SUCCESS
) {
1860 sql
->status
= OCILobCharSetId(dbd_oracle_env
, sql
->err
,
1861 val
->buf
.lobval
, &csid
);
1863 switch (sql
->status
) {
1865 case OCI_SUCCESS_WITH_INFO
:
1866 buflen
= (len
+1) * 4; /* ugh, wasteful UCS-4 handling */
1867 /* zeroise all - where the string ends depends on charset */
1868 buf
= apr_pcalloc(row
->pool
, buflen
);
1872 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1873 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1874 printf("Reading LOB character set: %s\n", sql
->buf
);
1875 break; /*** XXX?? ***/
1878 break; /*** XXX?? ***/
1880 #else /* ignore charset */
1881 buflen
= (len
+1) * 4; /* ugh, wasteful UCS-4 handling */
1882 /* zeroise all - where the string ends depends on charset */
1883 buf
= apr_pcalloc(row
->pool
, buflen
);
1886 /* BUG: this'll only work if the BLOB looks like a string */
1888 buf
= apr_palloc(row
->pool
, buflen
+1);
1896 sql
->status
= OCILobRead(sql
->svc
, sql
->err
, val
->buf
.lobval
,
1897 &len
, 1, (dvoid
*) buf
, buflen
,
1898 NULL
, NULL
, csid
, csform
);
1899 switch (sql
->status
) {
1901 case OCI_SUCCESS_WITH_INFO
:
1905 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1906 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1907 printf("Reading LOB: %s\n", sql
->buf
);
1908 buf
= NULL
; /*** XXX?? ***/
1912 buf
= NULL
; /*** XXX?? ***/
1919 /* raw is struct { ub4 len; char *buf; } */
1920 len
= *(ub4
*) val
->buf
.raw
;
1921 buf
= apr_pstrndup(row
->pool
, val
->buf
.sval
+ sizeof(ub4
), len
);
1924 buf
= apr_pstrndup(row
->pool
, val
->buf
.sval
, val
->len
);
1927 return (const char*) buf
;
1930 /* XXX Should this use Oracle proper API instead of calling get_entry()? */
1931 static apr_status_t
dbd_oracle_datum_get(const apr_dbd_row_t
*row
, int n
,
1932 apr_dbd_type_e type
, void *data
)
1934 define_arg
*val
= &row
->res
->statement
->out
[n
];
1937 if ((n
< 0) || (n
>= row
->res
->statement
->nout
)) {
1938 return APR_EGENERAL
;
1941 if(val
->ind
== -1) {
1946 case APR_DBD_TYPE_TINY
:
1947 entry
= dbd_oracle_get_entry(row
, n
);
1948 if (entry
== NULL
) {
1951 *(char*)data
= atoi(entry
);
1953 case APR_DBD_TYPE_UTINY
:
1954 entry
= dbd_oracle_get_entry(row
, n
);
1955 if (entry
== NULL
) {
1958 *(unsigned char*)data
= atoi(entry
);
1960 case APR_DBD_TYPE_SHORT
:
1961 entry
= dbd_oracle_get_entry(row
, n
);
1962 if (entry
== NULL
) {
1965 *(short*)data
= atoi(entry
);
1967 case APR_DBD_TYPE_USHORT
:
1968 entry
= dbd_oracle_get_entry(row
, n
);
1969 if (entry
== NULL
) {
1972 *(unsigned short*)data
= atoi(entry
);
1974 case APR_DBD_TYPE_INT
:
1975 entry
= dbd_oracle_get_entry(row
, n
);
1976 if (entry
== NULL
) {
1979 *(int*)data
= atoi(entry
);
1981 case APR_DBD_TYPE_UINT
:
1982 entry
= dbd_oracle_get_entry(row
, n
);
1983 if (entry
== NULL
) {
1986 *(unsigned int*)data
= atoi(entry
);
1988 case APR_DBD_TYPE_LONG
:
1989 entry
= dbd_oracle_get_entry(row
, n
);
1990 if (entry
== NULL
) {
1993 *(long*)data
= atol(entry
);
1995 case APR_DBD_TYPE_ULONG
:
1996 entry
= dbd_oracle_get_entry(row
, n
);
1997 if (entry
== NULL
) {
2000 *(unsigned long*)data
= atol(entry
);
2002 case APR_DBD_TYPE_LONGLONG
:
2003 entry
= dbd_oracle_get_entry(row
, n
);
2004 if (entry
== NULL
) {
2007 *(apr_int64_t
*)data
= apr_atoi64(entry
);
2009 case APR_DBD_TYPE_ULONGLONG
:
2010 entry
= dbd_oracle_get_entry(row
, n
);
2011 if (entry
== NULL
) {
2014 *(apr_uint64_t
*)data
= apr_atoi64(entry
);
2016 case APR_DBD_TYPE_FLOAT
:
2017 entry
= dbd_oracle_get_entry(row
, n
);
2018 if (entry
== NULL
) {
2021 *(float*)data
= (float)atof(entry
);
2023 case APR_DBD_TYPE_DOUBLE
:
2024 entry
= dbd_oracle_get_entry(row
, n
);
2025 if (entry
== NULL
) {
2028 *(double*)data
= atof(entry
);
2030 case APR_DBD_TYPE_STRING
:
2031 case APR_DBD_TYPE_TEXT
:
2032 case APR_DBD_TYPE_TIME
:
2033 case APR_DBD_TYPE_DATE
:
2034 case APR_DBD_TYPE_DATETIME
:
2035 case APR_DBD_TYPE_TIMESTAMP
:
2036 case APR_DBD_TYPE_ZTIMESTAMP
:
2037 entry
= dbd_oracle_get_entry(row
, n
);
2038 if (entry
== NULL
) {
2041 *(char**)data
= (char*)entry
;
2043 case APR_DBD_TYPE_BLOB
:
2044 case APR_DBD_TYPE_CLOB
:
2047 apr_bucket_brigade
*b
= (apr_bucket_brigade
*)data
;
2048 apr_dbd_t
*sql
= row
->res
->handle
;
2051 switch (val
->type
) {
2054 sql
->status
= OCILobGetLength(sql
->svc
, sql
->err
,
2055 val
->buf
.lobval
, &len
);
2056 switch(sql
->status
) {
2058 case OCI_SUCCESS_WITH_INFO
:
2060 e
= apr_bucket_eos_create(b
->bucket_alloc
);
2063 e
= apr_bucket_lob_create(row
, n
, 0, len
,
2064 row
->pool
, b
->bucket_alloc
);
2072 entry
= dbd_oracle_get_entry(row
, n
);
2073 if (entry
== NULL
) {
2076 e
= apr_bucket_pool_create(entry
, strlen(entry
),
2077 row
->pool
, b
->bucket_alloc
);
2080 APR_BRIGADE_INSERT_TAIL(b
, e
);
2083 case APR_DBD_TYPE_NULL
:
2084 *(void**)data
= NULL
;
2087 return APR_EGENERAL
;
2093 static apr_status_t
dbd_oracle_close(apr_dbd_t
*handle
)
2095 /* FIXME: none of the oracle docs/examples say anything about
2096 * closing/releasing handles. Which seems unlikely ...
2099 /* OK, let's grab from cdemo again.
2100 * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
2102 switch (OCISessionEnd(handle
->svc
, handle
->err
, handle
->auth
,
2103 (ub4
)OCI_DEFAULT
)) {
2107 switch (OCIServerDetach(handle
->svr
, handle
->err
, (ub4
) OCI_DEFAULT
)) {
2111 /* does OCISessionEnd imply this? */
2112 switch (OCIHandleFree((dvoid
*) handle
->auth
, (ub4
) OCI_HTYPE_SESSION
)) {
2116 switch (OCIHandleFree((dvoid
*) handle
->svr
, (ub4
) OCI_HTYPE_SERVER
)) {
2120 switch (OCIHandleFree((dvoid
*) handle
->svc
, (ub4
) OCI_HTYPE_SVCCTX
)) {
2124 switch (OCIHandleFree((dvoid
*) handle
->err
, (ub4
) OCI_HTYPE_ERROR
)) {
2131 static apr_status_t
dbd_oracle_check_conn(apr_pool_t
*pool
, apr_dbd_t
*sql
)
2133 apr_dbd_results_t
*res
= NULL
;
2134 apr_dbd_row_t
*row
= NULL
;
2136 if(dbd_oracle_pselect(pool
, sql
, &res
, sql
->check_conn_stmt
,
2138 return APR_EGENERAL
;
2141 if(dbd_oracle_get_row(pool
, res
, &row
, -1) != 0) {
2142 return APR_EGENERAL
;
2145 if(dbd_oracle_get_row(pool
, res
, &row
, -1) != -1) {
2146 return APR_EGENERAL
;
2152 static int dbd_oracle_select_db(apr_pool_t
*pool
, apr_dbd_t
*handle
,
2155 /* FIXME: need to find this in the docs */
2156 return APR_ENOTIMPL
;
2159 static void *dbd_oracle_native(apr_dbd_t
*handle
)
2161 /* FIXME: can we do anything better? Oracle doesn't seem to have
2162 * a concept of a handle in the sense we use it.
2164 return dbd_oracle_env
;
2167 static int dbd_oracle_num_cols(apr_dbd_results_t
* res
)
2169 return res
->statement
->nout
;
2172 static int dbd_oracle_num_tuples(apr_dbd_results_t
* res
)
2177 if (res
->nrows
>= 0) {
2180 res
->handle
->status
= OCIAttrGet(res
->statement
->stmt
, OCI_HTYPE_STMT
,
2181 &res
->nrows
, 0, OCI_ATTR_ROW_COUNT
,
2186 APU_MODULE_DECLARE_DATA
const apr_dbd_driver_t apr_dbd_oracle_driver
= {
2191 dbd_oracle_check_conn
,
2193 dbd_oracle_select_db
,
2194 dbd_oracle_start_transaction
,
2195 dbd_oracle_end_transaction
,
2198 dbd_oracle_num_cols
,
2199 dbd_oracle_num_tuples
,
2201 dbd_oracle_get_entry
,
2206 dbd_oracle_pvselect
,
2209 dbd_oracle_get_name
,
2210 dbd_oracle_transaction_mode_get
,
2211 dbd_oracle_transaction_mode_set
,
2213 dbd_oracle_pvbquery
,
2214 dbd_oracle_pvbselect
,
2216 dbd_oracle_pbselect
,
2217 dbd_oracle_datum_get