1 /* Copyright 2005 The Apache Software Foundation or its licensors, as
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * 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"
82 #define TRANS_TIMEOUT 30
83 #define MAX_ARG_LEN 256 /* in line with other apr_dbd drivers. We alloc this
84 * lots of times, so a large value gets hungry.
85 * Should really make it configurable
87 #define DEFAULT_LONG_SIZE 4096
88 #define DBD_ORACLE_MAX_COLUMNS 256
89 #define NUMERIC_FIELD_SIZE 32
93 APR_DBD_ORACLE_STRING
,
106 #include "apr_dbd_internal.h"
109 static const char *dbd_oracle_error(apr_dbd_t
*sql
, int n
);
110 static int dbd_oracle_prepare(apr_pool_t
*pool
, apr_dbd_t
*sql
,
111 const char *query
, const char *label
,
112 apr_dbd_prepared_t
**statement
);
113 static int outputParams(apr_dbd_t
*, apr_dbd_prepared_t
*);
114 static int dbd_oracle_pselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
115 apr_dbd_results_t
**results
,
116 apr_dbd_prepared_t
*statement
,
117 int seek
, int nargs
, const char **values
);
118 static int dbd_oracle_pquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
119 int *nrows
, apr_dbd_prepared_t
*statement
,
120 int nargs
, const char **values
);
121 static int dbd_oracle_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*sql
,
122 apr_dbd_transaction_t
**trans
);
123 static int dbd_oracle_end_transaction(apr_dbd_transaction_t
*trans
);
125 struct apr_dbd_transaction_t
{
126 enum { TRANS_NONE
, TRANS_ERROR
, TRANS_1
, TRANS_2
} status
;
129 OCISnapshot
*snapshot1
;
130 OCISnapshot
*snapshot2
;
133 struct apr_dbd_results_t
{
138 apr_dbd_prepared_t
*statement
;
147 apr_dbd_transaction_t
* trans
;
149 char buf
[200]; /* for error messages */
150 apr_size_t long_size
;
153 struct apr_dbd_row_t
{
155 apr_dbd_results_t
*res
;
169 OCILobLocator
*lobval
;
176 ub2 len
; /* length of actual output */
178 apr_size_t sz
; /* length of buf for output */
182 OCILobLocator
*lobval
;
187 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).
208 static OCIEnv
*dbd_oracle_env
= NULL
;
209 #ifdef GLOBAL_PREPARED_STATEMENTS
210 static apr_hash_t
*oracle_statements
= NULL
;
213 static apr_status_t
dbd_free_lobdesc(void *lob
)
215 switch (OCIDescriptorFree(lob
, OCI_DTYPE_LOB
)) {
223 static apr_status_t
dbd_free_snapshot(void *snap
)
225 switch (OCIDescriptorFree(snap
, OCI_DTYPE_SNAP
)) {
233 #ifdef GLOBAL_PREPARED_STATEMENTS
234 static apr_status_t
freeStatements(void *ptr
)
236 apr_status_t rv
= APR_SUCCESS
;
239 apr_hash_index_t
*index
;
240 apr_pool_t
*cachepool
= apr_hash_pool_get(oracle_statements
);
242 if (OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&err
, OCI_HTYPE_ERROR
, 0, NULL
)
247 for (index
= apr_hash_first(cachepool
, oracle_statements
);
249 index
= apr_hash_next(index
)) {
250 apr_hash_this(index
, NULL
, NULL
, (void**)&stmt
);
251 if (OCIStmtRelease(stmt
, err
, NULL
, 0, OCI_DEFAULT
) != OCI_SUCCESS
) {
254 if (OCIHandleFree(stmt
, OCI_HTYPE_STMT
) != OCI_SUCCESS
) {
258 if (OCIHandleFree(err
, OCI_HTYPE_ERROR
) != OCI_SUCCESS
) {
265 static void dbd_oracle_init(apr_pool_t
*pool
)
267 if (dbd_oracle_env
== NULL
) {
268 /* Sadly, OCI_SHARED seems to be impossible to use, due to
269 * various Oracle bugs. See, for example, Oracle MetaLink bug 2972890
270 * and PHP bug http://bugs.php.net/bug.php?id=23733
272 OCIEnvCreate(&dbd_oracle_env
, OCI_THREADED
, NULL
,
273 NULL
, NULL
, NULL
, 0, NULL
);
275 #ifdef GLOBAL_PREPARED_STATEMENTS
276 if (oracle_statements
== NULL
) {
278 oracle_statements
= apr_hash_make(pool
);
279 apr_pool_cleanup_register(pool
, oracle_statements
,
280 freeStatements
, apr_pool_cleanup_null
);
285 static apr_dbd_t
*dbd_oracle_open(apr_pool_t
*pool
, const char *params
)
287 apr_dbd_t
*ret
= apr_pcalloc(pool
, sizeof(apr_dbd_t
));
307 static const char *const delims
= " \r\n\t;|,";
309 ret
->long_size
= DEFAULT_LONG_SIZE
;
311 /* Use our own pool, to avoid possible race conditions
314 if (apr_pool_create(&ret
->pool
, pool
) != APR_SUCCESS
) {
318 /* snitch parsing from the MySQL driver */
319 for (ptr
= strchr(params
, '='); ptr
; ptr
= strchr(ptr
, '=')) {
320 for (key
= ptr
-1; isspace(*key
); --key
);
322 while (isalpha(*key
)) {
324 /* Don't parse off the front of the params */
333 for (value
= ptr
+1; isspace(*value
); ++value
);
334 vlen
= strcspn(value
, delims
);
335 for (i
=0; fields
[i
].field
!= NULL
; ++i
) {
336 if (!strncasecmp(fields
[i
].field
, key
, klen
)) {
337 fields
[i
].value
= apr_pstrndup(pool
, value
, vlen
);
344 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->err
,
345 OCI_HTYPE_ERROR
, 0, NULL
);
346 switch (ret
->status
) {
349 printf("ret->status is %d\n", ret
->status
);
358 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->svr
,
359 OCI_HTYPE_SERVER
, 0, NULL
);
360 switch (ret
->status
) {
363 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
364 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
365 printf("OPEN ERROR %d (alloc svr): %s\n", ret
->status
, ret
->buf
);
374 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->svc
,
375 OCI_HTYPE_SVCCTX
, 0, NULL
);
376 switch (ret
->status
) {
379 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
380 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
381 printf("OPEN ERROR %d (alloc svc): %s\n", ret
->status
, ret
->buf
);
390 /* All the examples use the #else */
392 ret
->status
= OCILogon(dbd_oracle_env
, ret
->err
, &ret
->svc
, fields
[0].value
,
393 strlen(fields
[0].value
), fields
[1].value
,
394 strlen(fields
[1].value
), fields
[2].value
,
395 strlen(fields
[2].value
));
396 switch (ret
->status
) {
399 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
400 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
401 printf("OPEN ERROR: %s\n", ret
->buf
);
410 ret
->status
= OCIServerAttach(ret
->svr
, ret
->err
, fields
[3].value
,
411 strlen(fields
[3].value
), OCI_DEFAULT
);
412 switch (ret
->status
) {
415 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
416 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
417 printf("OPEN ERROR %d (server attach): %s\n", ret
->status
, ret
->buf
);
425 ret
->status
= OCIAttrSet(ret
->svc
, OCI_HTYPE_SVCCTX
, ret
->svr
, 0,
426 OCI_ATTR_SERVER
, ret
->err
);
427 switch (ret
->status
) {
430 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
431 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
432 printf("OPEN ERROR %d (attr set): %s\n", ret
->status
, ret
->buf
);
440 ret
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&ret
->auth
,
441 OCI_HTYPE_SESSION
, 0, NULL
);
442 switch (ret
->status
) {
445 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
446 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
447 printf("OPEN ERROR %d (alloc auth): %s\n", ret
->status
, ret
->buf
);
455 ret
->status
= OCIAttrSet(ret
->auth
, OCI_HTYPE_SESSION
, fields
[0].value
,
456 strlen(fields
[0].value
), OCI_ATTR_USERNAME
, ret
->err
);
457 switch (ret
->status
) {
460 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
461 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
462 printf("OPEN ERROR %d (attr username): %s\n", ret
->status
, ret
->buf
);
470 ret
->status
= OCIAttrSet(ret
->auth
, OCI_HTYPE_SESSION
, fields
[1].value
,
471 strlen(fields
[1].value
), OCI_ATTR_PASSWORD
, ret
->err
);
472 switch (ret
->status
) {
475 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
476 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
477 printf("OPEN ERROR %d (attr password): %s\n", ret
->status
, ret
->buf
);
485 ret
->status
= OCISessionBegin(ret
->svc
, ret
->err
, ret
->auth
,
486 OCI_CRED_RDBMS
, OCI_DEFAULT
);
487 switch (ret
->status
) {
490 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
491 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
492 printf("OPEN ERROR %d (session begin): %s\n", ret
->status
, ret
->buf
);
500 ret
->status
= OCIAttrSet(ret
->svc
, OCI_HTYPE_SVCCTX
, ret
->auth
, 0,
501 OCI_ATTR_SESSION
, ret
->err
);
502 switch (ret
->status
) {
505 OCIErrorGet(ret
->err
, 1, NULL
, &errorcode
, ret
->buf
,
506 sizeof(ret
->buf
), OCI_HTYPE_ERROR
);
507 printf("OPEN ERROR %d (attr session): %s\n", ret
->status
, ret
->buf
);
519 #ifdef EXPORT_NATIVE_FUNCS
520 static apr_size_t
dbd_oracle_long_size_set(apr_dbd_t
*sql
,
521 apr_size_t long_size
)
523 apr_size_t old_size
= sql
->long_size
;
524 sql
->long_size
= long_size
;
529 static const char *dbd_oracle_get_name(const apr_dbd_results_t
*res
, int n
)
531 define_arg
*val
= &res
->statement
->out
[n
];
533 if ((n
< 0) || (n
>= res
->statement
->nout
)) {
539 static int dbd_oracle_get_row(apr_pool_t
*pool
, apr_dbd_results_t
*res
,
540 apr_dbd_row_t
**rowp
, int rownum
)
542 apr_dbd_row_t
*row
= *rowp
;
543 apr_dbd_t
*sql
= res
->handle
;
547 row
= apr_palloc(pool
, sizeof(apr_dbd_row_t
));
550 /* Oracle starts counting at 1 according to the docs */
551 row
->n
= res
->seek
? rownum
: 1;
564 sql
->status
= OCIStmtFetch2(res
->statement
->stmt
, res
->handle
->err
, 1,
565 OCI_FETCH_ABSOLUTE
, row
->n
, OCI_DEFAULT
);
568 sql
->status
= OCIStmtFetch2(res
->statement
->stmt
, res
->handle
->err
, 1,
569 OCI_FETCH_NEXT
, 0, OCI_DEFAULT
);
571 switch (sql
->status
) {
579 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
580 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
581 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
590 static const char *dbd_oracle_error(apr_dbd_t
*sql
, int n
)
592 /* This is ugly. Needs us to pass in a buffer of unknown size.
593 * Either we put it on the handle, or we have to keep allocing/copying
597 switch (sql
->status
) {
599 return "OCI_SUCCESS";
600 case OCI_SUCCESS_WITH_INFO
:
601 return "OCI_SUCCESS_WITH_INFO";
603 return "OCI_NEED_DATA";
605 return "OCI_NO_DATA";
606 case OCI_INVALID_HANDLE
:
607 return "OCI_INVALID_HANDLE";
608 case OCI_STILL_EXECUTING
:
609 return "OCI_STILL_EXECUTING";
611 return "OCI_CONTINUE";
614 switch (OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
615 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
)) {
619 return "internal error: OCIErrorGet failed";
623 static int freeStatement(void *statement
)
627 apr_dbd_t
*sql
= ((apr_dbd_prepared_t
*)statement
)->handle
;
628 OCIStmt
*stmt
= ((apr_dbd_prepared_t
*)statement
)->stmt
;
629 OCIError
*err
= sql
->err
;
631 sql
->status
= OCIStmtRelease(stmt
, err
, NULL
, 0, OCI_DEFAULT
);
632 switch (sql
->status
) {
640 sql
->status
= OCIHandleFree(stmt
, OCI_HTYPE_STMT
);
641 switch (sql
->status
) {
652 static int dbd_oracle_select(apr_pool_t
*pool
, apr_dbd_t
*sql
,
653 apr_dbd_results_t
**results
,
654 const char *query
, int seek
)
657 apr_dbd_prepared_t
*statement
= NULL
;
659 ret
= dbd_oracle_prepare(pool
, sql
, query
, NULL
, &statement
);
664 ret
= dbd_oracle_pselect(pool
, sql
, results
, statement
, seek
, 0, NULL
);
672 static int dbd_oracle_query(apr_dbd_t
*sql
, int *nrows
, const char *query
)
676 apr_dbd_prepared_t
*statement
= NULL
;
678 if (sql
->trans
&& sql
->trans
->status
== TRANS_ERROR
) {
682 /* make our own pool so that APR allocations don't linger and so that
683 * both Stmt and LOB handles are cleaned up (LOB handles may be
684 * allocated when preparing APR_DBD_ORACLE_CLOB/BLOBs)
686 apr_pool_create(&pool
, sql
->pool
);
688 ret
= dbd_oracle_prepare(pool
, sql
, query
, NULL
, &statement
);
690 ret
= dbd_oracle_pquery(pool
, sql
, nrows
, statement
, 0, NULL
);
692 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
,
693 nrows
, 0, OCI_ATTR_ROW_COUNT
,
698 apr_pool_destroy(pool
);
703 static const char *dbd_oracle_escape(apr_pool_t
*pool
, const char *arg
,
706 return arg
; /* OCI has no concept of string escape */
709 static int dbd_oracle_prepare(apr_pool_t
*pool
, apr_dbd_t
*sql
,
710 const char *query
, const char *label
,
711 apr_dbd_prepared_t
**statement
)
720 apr_dbd_prepared_t
*stmt
;
722 /* prepared statements in a global lookup table would be nice,
723 * but we can't do that here because our pool may die leaving
724 * the cached statement orphaned.
725 * OTOH we can do that with Oracle statements, which aren't on
726 * the pool, so long as we don't register a cleanup on our pool!
729 * There's a race condition between cache-lookup and cache-set
730 * But the worst outcome is a statement prepared more than once
731 * and leaked. Is that worth mutexing for?
732 * Hmmm, yes it probably is ... OK, done
735 if (*statement
== NULL
) {
736 *statement
= apr_pcalloc(pool
, sizeof(apr_dbd_prepared_t
));
742 /* If we have a label, we're going to cache it globally.
743 * Check first if we already have it. If not, prepare the
744 * statement under mutex, so we don't end up leaking
745 * concurrent statements
747 * FIXME: Oracle docs say a statement can be used even across
748 * multiple servers, so I assume this is safe .....
750 #ifdef GLOBAL_PREPARED_STATEMENTS
752 stmt
->stmt
= apr_hash_get(oracle_statements
, label
, APR_HASH_KEY_STRING
);
753 if (stmt
->stmt
!= NULL
) {
756 apr_dbd_mutex_lock();
757 stmt
->stmt
= apr_hash_get(oracle_statements
, label
, APR_HASH_KEY_STRING
);
758 if (stmt
->stmt
!= NULL
) {
759 apr_dbd_mutex_unlock();
764 /* translate from apr_dbd to native query format */
765 for (sqlptr
= (char*)query
; *sqlptr
; ++sqlptr
) {
766 if ((sqlptr
[0] == '%') && isalnum(sqlptr
[1])) {
769 else if ((sqlptr
[0] == '%') && (sqlptr
[1] == '%')) {
774 length
= strlen(query
) + 1;
775 for (i
= stmt
->nargs
; i
> 0; i
/= 10) {
778 length
+= (2 + bindlen
) * stmt
->nargs
; /* replace "%x" with ":aprN" */
780 oraptr
= orastr
= apr_palloc(pool
, length
);
782 if (stmt
->nargs
> 0) {
783 stmt
->args
= apr_pcalloc(pool
, stmt
->nargs
*sizeof(bind_arg
));
784 for (i
=0; i
<stmt
->nargs
; ++i
) {
785 stmt
->args
[i
].type
= APR_DBD_ORACLE_STRING
;
790 for (sqlptr
= (char*)query
; *sqlptr
; ++sqlptr
) {
791 if ((sqlptr
[0] == '%') && isalnum(sqlptr
[1])) {
792 while (isdigit(*++sqlptr
)) {
793 stmt
->args
[i
].len
*= 10;
794 stmt
->args
[i
].len
+= (*sqlptr
- '0');
796 oraptr
+= apr_snprintf(oraptr
, length
- (oraptr
- orastr
),
800 stmt
->args
[i
].type
= APR_DBD_ORACLE_INT
;
803 stmt
->args
[i
].type
= APR_DBD_ORACLE_FLOAT
;
806 stmt
->args
[i
].type
= APR_DBD_ORACLE_LOB
;
808 /* BLOB and CLOB won't work - use LOB instead */
810 stmt
->args
[i
].type
= APR_DBD_ORACLE_CLOB
;
813 stmt
->args
[i
].type
= APR_DBD_ORACLE_BLOB
;
815 /* default is STRING, but we already set that */
817 stmt
->args
[i
].type
= APR_DBD_ORACLE_STRING
;
822 else if ((sqlptr
[0] == '%') && (sqlptr
[1] == '%')) {
824 *oraptr
++ = *sqlptr
++;
832 sql
->status
= OCIHandleAlloc(dbd_oracle_env
, (dvoid
**) &stmt
->stmt
,
833 OCI_HTYPE_STMT
, 0, NULL
);
834 switch (sql
->status
) {
838 apr_dbd_mutex_unlock();
842 sql
->status
= OCIStmtPrepare(stmt
->stmt
, sql
->err
, orastr
,
843 strlen(orastr
), OCI_NTV_SYNTAX
, OCI_DEFAULT
);
844 switch (sql
->status
) {
848 OCIHandleFree(stmt
->stmt
, OCI_HTYPE_STMT
);
849 apr_dbd_mutex_unlock();
853 apr_pool_cleanup_register(pool
, stmt
, freeStatement
,
854 apr_pool_cleanup_null
);
856 /* Perl gets statement type here */
857 sql
->status
= OCIAttrGet(stmt
->stmt
, OCI_HTYPE_STMT
, &stmt
->type
, 0,
858 OCI_ATTR_STMT_TYPE
, sql
->err
);
859 switch (sql
->status
) {
863 apr_dbd_mutex_unlock();
867 /* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
869 sql
->status
= OCIAttrSet(stmt
->stmt
, OCI_HTYPE_STMT
, &prefetch_size
,
870 sizeof(prefetch_size
), OCI_ATTR_PREFETCH_MEMORY
,
872 switch (sql
->status
) {
876 apr_dbd_mutex_unlock();
881 sql
->status
= OCI_SUCCESS
;
882 for (i
= 0; i
< stmt
->nargs
; ++i
) {
883 switch (stmt
->args
[i
].type
) {
885 case APR_DBD_ORACLE_STRING
:
886 if (stmt
->args
[i
].len
== 0) {
887 stmt
->args
[i
].len
= MAX_ARG_LEN
;
889 stmt
->args
[i
].value
.stringval
= apr_palloc(pool
, stmt
->args
[i
].len
);
890 sql
->status
= OCIBindByPos(stmt
->stmt
, &stmt
->args
[i
].bind
,
892 stmt
->args
[i
].value
.stringval
,
898 (ub4
*) 0, OCI_DEFAULT
);
900 case APR_DBD_ORACLE_FLOAT
:
901 stmt
->args
[i
].value
.raw
= apr_palloc(pool
, NUMERIC_FIELD_SIZE
);
902 sql
->status
= OCIBindByPos(stmt
->stmt
, &stmt
->args
[i
].bind
,
904 (void*)&stmt
->args
[i
].value
.floatval
,
905 sizeof(stmt
->args
[i
].value
.floatval
),
910 (ub4
*) 0, OCI_DEFAULT
);
912 case APR_DBD_ORACLE_INT
:
913 stmt
->args
[i
].value
.raw
= apr_palloc(pool
, NUMERIC_FIELD_SIZE
);
914 sql
->status
= OCIBindByPos(stmt
->stmt
, &stmt
->args
[i
].bind
,
916 (void*)stmt
->args
[i
].value
.ival
,
917 sizeof(*stmt
->args
[i
].value
.ival
),
922 (ub4
*) 0, OCI_DEFAULT
);
924 /* lots of examples in the docs use this for LOB
925 * but it relies on knowing the size in advance and
926 * holding it in memory
928 case APR_DBD_ORACLE_LOB
:
929 break; /* bind LOBs at write-time */
930 /* This is also cited in the docs for LOB, if we don't
931 * want the whole thing in memory
933 case APR_DBD_ORACLE_BLOB
:
934 sql
->status
= OCIDescriptorAlloc(dbd_oracle_env
,
935 (dvoid
**)&stmt
->args
[i
].value
.lobval
,
936 OCI_DTYPE_LOB
, 0, NULL
);
937 apr_pool_cleanup_register(pool
, stmt
->args
[i
].value
.lobval
,
939 apr_pool_cleanup_null
);
940 sql
->status
= OCIBindByPos(stmt
->stmt
, &stmt
->args
[i
].bind
,
942 (void*) &stmt
->args
[i
].value
.lobval
,
948 (ub4
*) 0, OCI_DEFAULT
);
950 /* This is also cited in the docs for LOB, if we don't
951 * want the whole thing in memory
953 case APR_DBD_ORACLE_CLOB
:
954 sql
->status
= OCIDescriptorAlloc(dbd_oracle_env
,
955 (dvoid
**)&stmt
->args
[i
].value
.lobval
,
956 OCI_DTYPE_LOB
, 0, NULL
);
957 apr_pool_cleanup_register(pool
, stmt
->args
[i
].value
.lobval
,
959 apr_pool_cleanup_null
);
960 sql
->status
= OCIBindByPos(stmt
->stmt
, &stmt
->args
[i
].bind
,
962 (dvoid
*) &stmt
->args
[i
].value
.lobval
,
968 (ub4
*) 0, OCI_DEFAULT
);
971 switch (sql
->status
) {
975 apr_dbd_mutex_unlock();
979 switch (stmt
->type
) {
980 case OCI_STMT_SELECT
:
981 ret
= outputParams(sql
, stmt
);
986 #ifdef GLOBAL_PREPARED_STATEMENTS
988 apr_hash_set(oracle_statements
, label
, APR_HASH_KEY_STRING
, stmt
->stmt
);
989 apr_dbd_mutex_unlock();
995 static int outputParams(apr_dbd_t
*sql
, apr_dbd_prepared_t
*stmt
)
1000 ub2 paramtype
[DBD_ORACLE_MAX_COLUMNS
];
1001 ub2 paramsize
[DBD_ORACLE_MAX_COLUMNS
];
1002 const char *paramname
[DBD_ORACLE_MAX_COLUMNS
];
1003 ub4 paramnamelen
[DBD_ORACLE_MAX_COLUMNS
];
1004 /* Perl uses 0 where we used 1 */
1005 sql
->status
= OCIStmtExecute(sql
->svc
, stmt
->stmt
, sql
->err
, 0, 0,
1006 NULL
, NULL
, OCI_DESCRIBE_ONLY
);
1007 switch (sql
->status
) {
1009 case OCI_SUCCESS_WITH_INFO
:
1013 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1014 sql
->buf
, sizeof(sql
->buf
),
1016 printf("Describing prepared statement: %s\n", sql
->buf
);
1021 while (sql
->status
== OCI_SUCCESS
) {
1022 sql
->status
= OCIParamGet(stmt
->stmt
, OCI_HTYPE_STMT
,
1023 sql
->err
, (dvoid
**)&parms
, stmt
->nout
+1);
1024 switch (sql
->status
) {
1026 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1027 ¶mtype
[stmt
->nout
],
1028 0, OCI_ATTR_DATA_TYPE
, sql
->err
);
1029 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1030 ¶msize
[stmt
->nout
],
1031 0, OCI_ATTR_DATA_SIZE
, sql
->err
);
1032 sql
->status
= OCIAttrGet(parms
, OCI_DTYPE_PARAM
,
1033 ¶mname
[stmt
->nout
],
1034 ¶mnamelen
[stmt
->nout
],
1035 OCI_ATTR_NAME
, sql
->err
);
1039 switch (sql
->status
) {
1043 break; /* this is what we expect at end-of-loop */
1048 /* OK, the above works. We have the params; now OCIDefine them */
1049 stmt
->out
= apr_palloc(stmt
->pool
, stmt
->nout
*sizeof(define_arg
));
1050 for (i
=0; i
<stmt
->nout
; ++i
) {
1051 stmt
->out
[i
].type
= paramtype
[i
];
1052 stmt
->out
[i
].len
= stmt
->out
[i
].sz
= paramsize
[i
];
1053 stmt
->out
[i
].name
= apr_pstrmemdup(stmt
->pool
,
1054 paramname
[i
], paramnamelen
[i
]);
1055 switch (stmt
->out
[i
].type
) {
1057 switch (stmt
->out
[i
].type
) {
1058 case SQLT_NUM
: /* 2: numeric, Perl worst case=130+38+3 */
1059 stmt
->out
[i
].sz
= 171;
1061 case SQLT_CHR
: /* 1: char */
1062 case SQLT_AFC
: /* 96: ANSI fixed char */
1063 stmt
->out
[i
].sz
*= 4; /* ugh, wasteful UCS-4 handling */
1065 case SQLT_DAT
: /* 12: date, depends on NLS date format */
1066 stmt
->out
[i
].sz
= 75;
1068 case SQLT_BIN
: /* 23: raw binary, perhaps UTF-16? */
1069 stmt
->out
[i
].sz
*= 2;
1071 case SQLT_RID
: /* 11: rowid */
1072 case SQLT_RDD
: /* 104: rowid descriptor */
1073 stmt
->out
[i
].sz
= 20;
1075 case SQLT_TIMESTAMP
: /* 187: timestamp */
1076 case SQLT_TIMESTAMP_TZ
: /* 188: timestamp with time zone */
1077 case SQLT_INTERVAL_YM
: /* 189: interval year-to-month */
1078 case SQLT_INTERVAL_DS
: /* 190: interval day-to-second */
1079 case SQLT_TIMESTAMP_LTZ
: /* 232: timestamp with local time zone */
1080 stmt
->out
[i
].sz
= 75;
1084 printf("Unsupported data type: %d\n", stmt
->out
[i
].type
);
1089 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1090 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1092 stmt
->out
[i
].buf
.stringval
,
1093 stmt
->out
[i
].sz
, SQLT_STR
,
1094 &stmt
->out
[i
].ind
, &stmt
->out
[i
].len
,
1097 case SQLT_LNG
: /* 8: long */
1098 stmt
->out
[i
].sz
= sql
->long_size
* 4 + 4; /* ugh, UCS-4 handling */
1099 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1100 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1102 stmt
->out
[i
].buf
.raw
,
1103 stmt
->out
[i
].sz
, SQLT_LVC
,
1104 &stmt
->out
[i
].ind
, NULL
,
1107 case SQLT_LBI
: /* 24: long binary, perhaps UTF-16? */
1108 stmt
->out
[i
].sz
= sql
->long_size
* 2 + 4; /* room for int prefix */
1109 stmt
->out
[i
].buf
.raw
= apr_palloc(stmt
->pool
, stmt
->out
[i
].sz
);
1110 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1112 stmt
->out
[i
].buf
.raw
,
1113 stmt
->out
[i
].sz
, SQLT_LVB
,
1114 &stmt
->out
[i
].ind
, NULL
,
1117 case SQLT_BLOB
: /* 113 */
1118 case SQLT_CLOB
: /* 112 */
1119 /*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1120 sql
->status
= OCIDescriptorAlloc(dbd_oracle_env
,
1121 (dvoid
**)&stmt
->out
[i
].buf
.lobval
,
1122 OCI_DTYPE_LOB
, 0, NULL
);
1123 apr_pool_cleanup_register(stmt
->pool
, stmt
->out
[i
].buf
.lobval
,
1125 apr_pool_cleanup_null
);
1126 sql
->status
= OCIDefineByPos(stmt
->stmt
, &stmt
->out
[i
].defn
,
1128 (dvoid
*) &stmt
->out
[i
].buf
.lobval
,
1129 -1, stmt
->out
[i
].type
,
1130 &stmt
->out
[i
].ind
, &stmt
->out
[i
].len
,
1134 switch (sql
->status
) {
1144 static int dbd_oracle_pvquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1145 int *nrows
, apr_dbd_prepared_t
*statement
,
1148 const char *arg
= NULL
;
1149 OCISnapshot
*oldsnapshot
= NULL
;
1150 OCISnapshot
*newsnapshot
= NULL
;
1151 apr_dbd_transaction_t
* trans
= sql
->trans
;
1158 switch (trans
->status
) {
1165 oldsnapshot
= trans
->snapshot1
;
1166 newsnapshot
= trans
->snapshot2
;
1167 trans
->status
= TRANS_2
;
1170 oldsnapshot
= trans
->snapshot2
;
1171 newsnapshot
= trans
->snapshot1
;
1172 trans
->status
= TRANS_1
;
1175 exec_mode
= OCI_DEFAULT
;
1178 exec_mode
= OCI_COMMIT_ON_SUCCESS
;
1181 /* we've bound these vars, so now we just copy data in to them */
1182 for (i
=0; i
<statement
->nargs
; ++i
) {
1183 switch (statement
->args
[i
].type
) {
1184 case APR_DBD_ORACLE_INT
:
1185 n
= va_arg(args
, int);
1186 sprintf(statement
->args
[i
].value
.stringval
, "%d", n
);
1188 case APR_DBD_ORACLE_FLOAT
:
1189 *statement
->args
[i
].value
.floatval
= va_arg(args
, double);
1191 case APR_DBD_ORACLE_BLOB
:
1192 case APR_DBD_ORACLE_CLOB
:
1195 case APR_DBD_ORACLE_LOB
:
1196 /* requires strlen() over large data, which may fail for binary */
1197 statement
->args
[i
].value
.raw
= va_arg(args
, char*);
1198 statement
->args
[i
].len
=
1199 strlen(statement
->args
[i
].value
.stringval
);
1200 sql
->status
= OCIBindByPos(statement
->stmt
,
1201 &statement
->args
[i
].bind
,
1203 (void*)statement
->args
[i
].value
.raw
,
1204 statement
->args
[i
].len
, SQLT_LNG
,
1205 &statement
->args
[i
].ind
,
1208 (ub4
*) 0, OCI_DEFAULT
);
1210 case APR_DBD_ORACLE_STRING
:
1212 arg
= va_arg(args
, char*);
1213 if (strlen(arg
) >= statement
->args
[i
].len
) {
1214 strncpy(statement
->args
[i
].value
.stringval
, arg
,
1215 statement
->args
[i
].len
-1);
1218 strcpy(statement
->args
[i
].value
.stringval
, arg
);
1224 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 1, 0,
1225 oldsnapshot
, newsnapshot
, exec_mode
);
1226 switch (sql
->status
) {
1231 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1232 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1233 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
1238 trans
->status
= TRANS_ERROR
;
1243 for (i
=0; i
<statement
->nargs
; ++i
) {
1244 /* what should these really be? */
1245 ub1 csfrm
= SQLCS_IMPLICIT
;
1247 ub4 len
= statement
->args
[i
].len
;
1248 switch (statement
->args
[i
].type
) {
1249 case APR_DBD_ORACLE_BLOB
:
1250 case APR_DBD_ORACLE_CLOB
:
1251 /* doesn't work - use APR_DBD_ORACLE_LOB instead */
1252 sql
->status
= OCILobEnableBuffering(sql
->svc
, sql
->err
,statement
->args
[i
].value
.lobval
);
1254 if (sql
->status
== OCI_ERROR
) {
1255 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1256 sql
->buf
, sizeof(sql
->buf
),
1258 printf("LOB error %d: %s\n", sql
->status
, sql
->buf
);
1261 sql
->status
= OCILobWrite(sql
->svc
, sql
->err
,
1262 statement
->args
[i
].value
.lobval
,
1263 &len
, 0, (dvoid
*) arg
, strlen(arg
),
1264 OCI_ONE_PIECE
, NULL
, NULL
, csid
, csfrm
);
1269 switch (sql
->status
) {
1274 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1275 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1276 printf("LOB error %d: %s\n", sql
->status
, sql
->buf
);
1281 trans
->status
= TRANS_ERROR
;
1287 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
, nrows
, 0,
1288 OCI_ATTR_ROW_COUNT
, sql
->err
);
1292 static int dbd_oracle_pquery(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1293 int *nrows
, apr_dbd_prepared_t
*statement
,
1294 int nargs
, const char **values
)
1297 OCISnapshot
*oldsnapshot
= NULL
;
1298 OCISnapshot
*newsnapshot
= NULL
;
1299 apr_dbd_transaction_t
* trans
= sql
->trans
;
1304 switch (trans
->status
) {
1311 oldsnapshot
= trans
->snapshot1
;
1312 newsnapshot
= trans
->snapshot2
;
1313 trans
->status
= TRANS_2
;
1316 oldsnapshot
= trans
->snapshot2
;
1317 newsnapshot
= trans
->snapshot1
;
1318 trans
->status
= TRANS_1
;
1321 exec_mode
= OCI_DEFAULT
;
1324 exec_mode
= OCI_COMMIT_ON_SUCCESS
;
1327 /* we've bound these vars, so now we just copy data in to them */
1328 if (nargs
> statement
->nargs
) {
1329 nargs
= statement
->nargs
;
1331 for (i
=0; i
<nargs
; ++i
) {
1332 switch (statement
->args
[i
].type
) {
1333 case APR_DBD_ORACLE_INT
:
1334 sscanf(values
[i
], "%d", statement
->args
[i
].value
.ival
);
1336 case APR_DBD_ORACLE_FLOAT
:
1337 sscanf(values
[i
], "%lf", statement
->args
[i
].value
.floatval
);
1339 case APR_DBD_ORACLE_BLOB
:
1340 case APR_DBD_ORACLE_CLOB
:
1341 sql
->status
= OCIAttrSet(statement
->args
[i
].value
.lobval
,
1342 OCI_DTYPE_LOB
, &null
, 0,
1343 OCI_ATTR_LOBEMPTY
, sql
->err
);
1345 case APR_DBD_ORACLE_LOB
:
1346 /* requires strlen() over large data, which may fail for binary */
1347 statement
->args
[i
].value
.raw
= (char*)values
[i
];
1348 statement
->args
[i
].len
=
1349 strlen(statement
->args
[i
].value
.stringval
);
1350 sql
->status
= OCIBindByPos(statement
->stmt
,
1351 &statement
->args
[i
].bind
,
1353 (void*)statement
->args
[i
].value
.raw
,
1354 statement
->args
[i
].len
, SQLT_LNG
,
1355 &statement
->args
[i
].ind
,
1358 (ub4
*) 0, OCI_DEFAULT
);
1360 case APR_DBD_ORACLE_STRING
:
1362 if (strlen(values
[i
]) >= statement
->args
[i
].len
) {
1363 strncpy(statement
->args
[i
].value
.stringval
, values
[i
],
1364 statement
->args
[i
].len
-1);
1367 strcpy(statement
->args
[i
].value
.stringval
, values
[i
]);
1373 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 1, 0,
1374 oldsnapshot
, newsnapshot
, exec_mode
);
1375 switch (sql
->status
) {
1380 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1381 sql
->buf
, sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1382 printf("Execute error %d: %s\n", sql
->status
, sql
->buf
);
1387 trans
->status
= TRANS_ERROR
;
1392 sql
->status
= OCIAttrGet(statement
->stmt
, OCI_HTYPE_STMT
, nrows
, 0,
1393 OCI_ATTR_ROW_COUNT
, sql
->err
);
1397 static int dbd_oracle_pvselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1398 apr_dbd_results_t
**results
,
1399 apr_dbd_prepared_t
*statement
,
1400 int seek
, va_list args
)
1404 int exec_mode
= seek
? OCI_STMT_SCROLLABLE_READONLY
: OCI_DEFAULT
;
1405 OCISnapshot
*oldsnapshot
= NULL
;
1406 OCISnapshot
*newsnapshot
= NULL
;
1407 apr_dbd_transaction_t
* trans
= sql
->trans
;
1411 switch (trans
->status
) {
1418 oldsnapshot
= trans
->snapshot1
;
1419 newsnapshot
= trans
->snapshot2
;
1420 trans
->status
= TRANS_2
;
1423 oldsnapshot
= trans
->snapshot2
;
1424 newsnapshot
= trans
->snapshot1
;
1425 trans
->status
= TRANS_1
;
1430 /* we've bound these vars, so now we just copy data in to them */
1431 for (i
=0; i
<statement
->nargs
; ++i
) {
1433 switch (statement
->args
[i
].type
) {
1434 case APR_DBD_ORACLE_INT
:
1435 *statement
->args
[i
].value
.ival
= va_arg(args
, int);
1437 case APR_DBD_ORACLE_FLOAT
:
1438 *statement
->args
[i
].value
.floatval
= va_arg(args
, double);
1440 case APR_DBD_ORACLE_BLOB
:
1441 case APR_DBD_ORACLE_CLOB
:
1442 sql
->status
= OCIAttrSet(statement
->args
[i
].value
.lobval
,
1443 OCI_DTYPE_LOB
, &null
, 0,
1444 OCI_ATTR_LOBEMPTY
, sql
->err
);
1446 case APR_DBD_ORACLE_STRING
:
1448 arg
= va_arg(args
, char*);
1450 if (len
>= statement
->args
[i
].len
) {
1451 len
= statement
->args
[i
].len
- 1;
1452 strncpy(statement
->args
[i
].value
.stringval
, arg
, len
);
1453 statement
->args
[i
].value
.stringval
[len
] = '\0';
1456 strcpy(statement
->args
[i
].value
.stringval
, arg
);
1459 sql
->status
= OCIAttrSet(statement
->args
[i
].bind
,
1460 OCI_DTYPE_PARAM
, &len
, 0,
1461 OCI_ATTR_DATA_SIZE
, sql
->err
);
1466 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 0, 0,
1467 oldsnapshot
, newsnapshot
, exec_mode
);
1468 switch (sql
->status
) {
1473 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1474 sql
->buf
, sizeof(sql
->buf
),
1476 printf("Executing prepared statement: %s\n", sql
->buf
);
1480 trans
->status
= TRANS_ERROR
;
1486 *results
= apr_palloc(pool
, sizeof(apr_dbd_results_t
));
1488 (*results
)->handle
= sql
;
1489 (*results
)->statement
= statement
;
1490 (*results
)->seek
= seek
;
1491 (*results
)->rownum
= seek
? 0 : -1;
1496 static int dbd_oracle_pselect(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1497 apr_dbd_results_t
**results
,
1498 apr_dbd_prepared_t
*statement
,
1499 int seek
, int nargs
, const char **values
)
1502 int exec_mode
= seek
? OCI_STMT_SCROLLABLE_READONLY
: OCI_DEFAULT
;
1503 OCISnapshot
*oldsnapshot
= NULL
;
1504 OCISnapshot
*newsnapshot
= NULL
;
1505 apr_dbd_transaction_t
* trans
= sql
->trans
;
1508 switch (trans
->status
) {
1515 oldsnapshot
= trans
->snapshot1
;
1516 newsnapshot
= trans
->snapshot2
;
1517 trans
->status
= TRANS_2
;
1520 oldsnapshot
= trans
->snapshot2
;
1521 newsnapshot
= trans
->snapshot1
;
1522 trans
->status
= TRANS_1
;
1527 /* we've bound these vars, so now we just copy data in to them */
1528 if (nargs
> statement
->nargs
) {
1529 nargs
= statement
->nargs
;
1531 for (i
=0; i
<nargs
; ++i
) {
1533 switch (statement
->args
[i
].type
) {
1534 case APR_DBD_ORACLE_INT
:
1535 sscanf(values
[i
], "%d", &foo
);
1536 *statement
->args
[i
].value
.ival
= foo
;
1538 case APR_DBD_ORACLE_FLOAT
:
1539 sscanf(values
[i
], "%lf", statement
->args
[i
].value
.floatval
);
1541 case APR_DBD_ORACLE_BLOB
:
1542 case APR_DBD_ORACLE_CLOB
:
1543 sql
->status
= OCIAttrSet(statement
->args
[i
].value
.lobval
,
1544 OCI_DTYPE_LOB
, &null
, 0,
1545 OCI_ATTR_LOBEMPTY
, sql
->err
);
1547 case APR_DBD_ORACLE_STRING
:
1549 if (strlen(values
[i
]) >= MAX_ARG_LEN
) {
1550 strncpy(statement
->args
[i
].value
.stringval
, values
[i
],
1554 strcpy(statement
->args
[i
].value
.stringval
, values
[i
]);
1560 sql
->status
= OCIStmtExecute(sql
->svc
, statement
->stmt
, sql
->err
, 0, 0,
1561 oldsnapshot
, newsnapshot
, exec_mode
);
1562 switch (sql
->status
) {
1568 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1569 sql
->buf
, sizeof(sql
->buf
),
1571 printf("Executing prepared statement: %s\n", sql
->buf
);
1575 trans
->status
= TRANS_ERROR
;
1581 *results
= apr_palloc(pool
, sizeof(apr_dbd_results_t
));
1583 (*results
)->handle
= sql
;
1584 (*results
)->statement
= statement
;
1585 (*results
)->seek
= seek
;
1586 (*results
)->rownum
= seek
? 0 : -1;
1591 static int dbd_oracle_start_transaction(apr_pool_t
*pool
, apr_dbd_t
*sql
,
1592 apr_dbd_transaction_t
**trans
)
1597 dbd_oracle_end_transaction(*trans
);
1600 *trans
= apr_pcalloc(pool
, sizeof(apr_dbd_transaction_t
));
1601 OCIHandleAlloc(dbd_oracle_env
, (dvoid
**)&(*trans
)->trans
,
1602 OCI_HTYPE_TRANS
, 0, 0);
1603 OCIAttrSet(sql
->svc
, OCI_HTYPE_SVCCTX
, (*trans
)->trans
, 0,
1604 OCI_ATTR_TRANS
, sql
->err
);
1608 sql
->status
= OCITransStart(sql
->svc
, sql
->err
, TRANS_TIMEOUT
,
1610 switch (sql
->status
) {
1613 OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
, sql
->buf
,
1614 sizeof(sql
->buf
), OCI_HTYPE_ERROR
);
1615 printf("Transaction: %s\n", sql
->buf
);
1620 (*trans
)->handle
= sql
;
1621 (*trans
)->status
= TRANS_1
;
1622 sql
->trans
= *trans
;
1623 switch (OCIDescriptorAlloc(dbd_oracle_env
,
1624 (dvoid
**)&(*trans
)->snapshot1
,
1625 OCI_DTYPE_SNAP
, 0, NULL
)) {
1627 apr_pool_cleanup_register(pool
, (*trans
)->snapshot1
,
1628 dbd_free_snapshot
, apr_pool_cleanup_null
);
1630 case OCI_INVALID_HANDLE
:
1634 switch (OCIDescriptorAlloc(dbd_oracle_env
,
1635 (dvoid
**)&(*trans
)->snapshot2
,
1636 OCI_DTYPE_SNAP
, 0, NULL
)) {
1638 apr_pool_cleanup_register(pool
, (*trans
)->snapshot2
,
1639 dbd_free_snapshot
, apr_pool_cleanup_null
);
1641 case OCI_INVALID_HANDLE
:
1653 static int dbd_oracle_end_transaction(apr_dbd_transaction_t
*trans
)
1655 int ret
= 1; /* no transaction is an error cond */
1657 apr_dbd_t
*handle
= trans
->handle
;
1659 switch (trans
->status
) {
1660 case TRANS_NONE
: /* No trans is an error here */
1664 status
= OCITransRollback(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1667 status
= OCITransCommit(handle
->svc
, handle
->err
, OCI_DEFAULT
);
1671 handle
->trans
= NULL
;
1685 /* This doesn't work for BLOB because of NULLs, but it can fake it
1686 * if the BLOB is really a string
1688 static const char *dbd_oracle_get_entry(const apr_dbd_row_t
*row
, int n
)
1694 apr_size_t buflen
= 0;
1696 define_arg
*val
= &row
->res
->statement
->out
[n
];
1697 apr_dbd_t
*sql
= row
->res
->handle
;
1699 if ((n
< 0) || (n
>= row
->res
->statement
->nout
) || (val
->ind
== -1)) {
1703 switch (val
->type
) {
1706 sql
->status
= OCILobGetLength(sql
->svc
, sql
->err
, val
->buf
.lobval
,
1708 switch (sql
->status
) {
1710 case OCI_SUCCESS_WITH_INFO
:
1717 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1718 sql
->buf
, sizeof(sql
->buf
),
1720 printf("Finding LOB length: %s\n", sql
->buf
);
1731 if (val
->type
== APR_DBD_ORACLE_CLOB
) {
1734 /* Is this necessary, or can it be defaulted? */
1735 sql
->status
= OCILobCharSetForm(dbd_oracle_env
, sql
->err
,
1736 val
->buf
.lobval
, &csform
);
1737 if (sql
->status
== OCI_SUCCESS
) {
1738 sql
->status
= OCILobCharSetId(dbd_oracle_env
, sql
->err
,
1739 val
->buf
.lobval
, &csid
);
1741 switch (sql
->status
) {
1743 case OCI_SUCCESS_WITH_INFO
:
1744 buflen
= (len
+1) * 4; /* ugh, wasteful UCS-4 handling */
1745 /* zeroise all - where the string ends depends on charset */
1746 buf
= apr_pcalloc(row
->pool
, buflen
);
1750 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1751 sql
->buf
, sizeof(sql
->buf
),
1753 printf("Reading LOB character set: %s\n", sql
->buf
);
1754 break; /*** XXX?? ***/
1757 break; /*** XXX?? ***/
1759 #else /* ignore charset */
1760 buflen
= (len
+1) * 4; /* ugh, wasteful UCS-4 handling */
1761 /* zeroise all - where the string ends depends on charset */
1762 buf
= apr_pcalloc(row
->pool
, buflen
);
1765 /* BUG: this'll only work if the BLOB looks like a string */
1767 buf
= apr_palloc(row
->pool
, buflen
+1);
1775 sql
->status
= OCILobRead(sql
->svc
, sql
->err
, val
->buf
.lobval
,
1776 &len
, 1, (dvoid
*) buf
, buflen
,
1777 NULL
, NULL
, csid
, csform
);
1778 switch (sql
->status
) {
1780 case OCI_SUCCESS_WITH_INFO
:
1784 sql
->status
= OCIErrorGet(sql
->err
, 1, NULL
, &errorcode
,
1785 sql
->buf
, sizeof(sql
->buf
),
1787 printf("Reading LOB: %s\n", sql
->buf
);
1788 buf
= NULL
; /*** XXX?? ***/
1792 buf
= NULL
; /*** XXX?? ***/
1799 /* raw is struct { ub4 len; char *buf; } */
1800 len
= *(ub4
*) val
->buf
.raw
;
1801 buf
= apr_pstrndup(row
->pool
, val
->buf
.stringval
+ sizeof(ub4
), len
);
1804 buf
= apr_pstrndup(row
->pool
, val
->buf
.stringval
, val
->len
);
1807 return (const char*) buf
;
1810 static apr_status_t
dbd_oracle_close(apr_dbd_t
*handle
)
1812 /* FIXME: none of the oracle docs/examples say anything about
1813 * closing/releasing handles. Which seems unlikely ...
1816 /* OK, let's grab from cdemo again.
1817 * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
1819 switch (OCISessionEnd(handle
->svc
, handle
->err
, handle
->auth
,
1820 (ub4
)OCI_DEFAULT
)) {
1824 switch (OCIServerDetach(handle
->svr
, handle
->err
, (ub4
) OCI_DEFAULT
)) {
1828 /* does OCISessionEnd imply this? */
1829 switch (OCIHandleFree((dvoid
*) handle
->auth
, (ub4
) OCI_HTYPE_SESSION
)) {
1833 switch (OCIHandleFree((dvoid
*) handle
->svr
, (ub4
) OCI_HTYPE_SERVER
)) {
1837 switch (OCIHandleFree((dvoid
*) handle
->svc
, (ub4
) OCI_HTYPE_SVCCTX
)) {
1841 switch (OCIHandleFree((dvoid
*) handle
->err
, (ub4
) OCI_HTYPE_ERROR
)) {
1845 apr_pool_destroy(handle
->pool
);
1849 static apr_status_t
dbd_oracle_check_conn(apr_pool_t
*pool
,
1852 /* FIXME: need to find this in the docs */
1853 return APR_ENOTIMPL
;
1856 static int dbd_oracle_select_db(apr_pool_t
*pool
, apr_dbd_t
*handle
,
1859 /* FIXME: need to find this in the docs */
1860 return APR_ENOTIMPL
;
1863 static void *dbd_oracle_native(apr_dbd_t
*handle
)
1865 /* FIXME: can we do anything better? Oracle doesn't seem to have
1866 * a concept of a handle in the sense we use it.
1868 return dbd_oracle_env
;
1871 static int dbd_oracle_num_cols(apr_dbd_results_t
* res
)
1873 return res
->statement
->nout
;
1876 static int dbd_oracle_num_tuples(apr_dbd_results_t
* res
)
1881 if (res
->nrows
>= 0) {
1884 res
->handle
->status
= OCIAttrGet(res
->statement
->stmt
, OCI_HTYPE_STMT
,
1885 &res
->nrows
, 0, OCI_ATTR_ROW_COUNT
,
1890 APU_DECLARE_DATA
const apr_dbd_driver_t apr_dbd_oracle_driver
= {
1895 dbd_oracle_check_conn
,
1897 dbd_oracle_select_db
,
1898 dbd_oracle_start_transaction
,
1899 dbd_oracle_end_transaction
,
1902 dbd_oracle_num_cols
,
1903 dbd_oracle_num_tuples
,
1905 dbd_oracle_get_entry
,
1910 dbd_oracle_pvselect
,