Apache HTTPD
apr_dbd_oracle.c
Go to the documentation of this file.
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
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).
21 */
22
23/* apr_dbd_oracle - a painful attempt
24 *
25 * Based first on the documentation at
26 * http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/toc.htm
27 *
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.
31 *
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
34 *
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.
38 *
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.
43 */
44
45/* shut compiler up */
46#ifdef DEBUG
47#define int_errorcode int errorcode
48#else
49#define int_errorcode
50#endif
51
52#include "apu.h"
53
54#if APU_HAVE_ORACLE
55
56#include <ctype.h>
57#include <stdlib.h>
58#include <stdio.h>
59
60#include <oci.h>
61
62#include "apr_strings.h"
63#include "apr_lib.h"
64#include "apr_time.h"
65#include "apr_hash.h"
66#include "apr_buckets.h"
67
68#define TRANS_TIMEOUT 30
69#define MAX_ARG_LEN 256 /* in line with other apr_dbd drivers. We alloc this
70 * lots of times, so a large value gets hungry.
71 * Should really make it configurable
72 */
73#define DEFAULT_LONG_SIZE 4096
74#define DBD_ORACLE_MAX_COLUMNS 256
75#define NUMERIC_FIELD_SIZE 32
76
77#define CHECK_CONN_QUERY "SELECT 1 FROM dual"
78
79#define ERR_BUF_SIZE 200
80
81#ifdef DEBUG
82#include <stdio.h>
83#endif
84
85#include "apr_dbd_internal.h"
86
87/* declarations */
88static const char *dbd_oracle_error(apr_dbd_t *sql, int n);
90 const char *query, const char *label,
95 apr_dbd_results_t **results,
97 int seek, const char **values);
100 const char **values);
104
106 int mode;
112};
113
114struct apr_dbd_results_t {
117 unsigned int rownum;
118 int seek;
119 int nrows;
121};
122
123struct apr_dbd_t {
125 OCIError *err;
126 OCIServer *svr;
127 OCISvcCtx *svc;
128 OCISession *auth;
131 char buf[ERR_BUF_SIZE]; /* for error messages */
134};
135
136struct apr_dbd_row_t {
137 int n;
140};
141
142typedef struct {
144 sb2 ind;
145 sb4 len;
146 OCIBind *bind;
147 union {
148 void *raw;
149 char *sval;
150 int ival;
151 unsigned int uval;
152 double fval;
154 } value;
155} bind_arg;
156
157typedef struct {
158 int type;
159 sb2 ind;
160 ub2 len; /* length of actual output */
162 apr_size_t sz; /* length of buf for output */
163 union {
164 void *raw;
165 char *sval;
167 } buf;
168 const char *name;
169} define_arg;
170
171struct apr_dbd_prepared_t {
172 OCIStmt *stmt;
173 int nargs;
174 int nvals;
175 bind_arg *args;
176 int nout;
180 ub2 type;
181};
182
183/* AFAICT from the docs, the OCIEnv thingey can be used async
184 * across threads, so lets have a global one.
185 *
186 * We'll need shorter-lived envs to deal with requests and connections
187 *
188 * Hmmm, that doesn't work: we don't have a usermem framework.
189 * OK, forget about using APR pools here, until we figure out
190 * the right way to do it (if such a thing exists).
191 */
192static OCIEnv *dbd_oracle_env = NULL;
193
194/* Oracle specific bucket for BLOB/CLOB types */
195typedef struct apr_bucket_lob apr_bucket_lob;
199struct apr_bucket_lob {
201 apr_bucket_refcount refcount;
203 const apr_dbd_row_t *row;
205 int col;
208 apr_pool_t *readpool;
209};
210
211static void lob_bucket_destroy(void *data);
212static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
215 const apr_dbd_row_t *row, int col,
217 apr_pool_t *p);
222
224 "LOB", 5, APR_BUCKET_DATA,
230};
231
232static void lob_bucket_destroy(void *data)
233{
235
237 /* no need to destroy database objects here; it will get
238 * done automatically when the pool gets cleaned up */
240 }
241}
242
243static apr_status_t lob_bucket_read(apr_bucket *e, const char **str,
245{
247 const apr_dbd_row_t *row = a->row;
248 apr_dbd_results_t *res = row->res;
249 int col = a->col;
250 apr_bucket *b = NULL;
251 apr_size_t blength = e->length; /* bytes remaining in file past offset */
253 define_arg *val = &res->statement->out[col];
254 apr_dbd_t *sql = res->handle;
255/* Only with 10g, unfortunately
256 oraub8 length = APR_BUCKET_BUFF_SIZE;
257*/
259 char *buf = NULL;
260
261 *str = NULL; /* in case we die prematurely */
262
263 /* fetch from offset if not at the beginning */
265 sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
266 &length, 1 + (size_t)boffset,
269/* Only with 10g, unfortunately
270 sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval,
271 &length, NULL, 1 + boffset,
272 (dvoid*) buf, APR_BUCKET_BUFF_SIZE,
273 OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
274*/
275 if (sql->status != OCI_SUCCESS) {
276 return APR_EGENERAL;
277 }
278 blength -= length;
279 *len = length;
280 *str = buf;
281
282 /*
283 * Change the current bucket to refer to what we read,
284 * even if we read nothing because we hit EOF.
285 */
286 apr_bucket_pool_make(e, *str, *len, res->pool);
287
288 /* If we have more to read from the field, then create another bucket */
289 if (blength > 0) {
290 /* for efficiency, we can just build a new apr_bucket struct
291 * to wrap around the existing LOB bucket */
292 b = apr_bucket_alloc(sizeof(*b), e->list);
293 b->start = boffset + *len;
294 b->length = blength;
295 b->data = a;
296 b->type = &apr_bucket_type_lob;
297 b->free = apr_bucket_free;
298 b->list = e->list;
300 }
301 else {
303 }
304
305 return APR_SUCCESS;
306}
307
309 const apr_dbd_row_t *row, int col,
311 apr_pool_t *p)
312{
314
315 f = apr_bucket_alloc(sizeof(*f), b->list);
316 f->row = row;
317 f->col = col;
318 f->readpool = p;
319
321 b->type = &apr_bucket_type_lob;
322
323 return b;
324}
325
330{
331 apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
332
334 b->free = apr_bucket_free;
335 b->list = list;
336 return apr_bucket_lob_make(b, row, col, offset, len, p);
337}
338
340{
342 case OCI_SUCCESS:
343 return APR_SUCCESS;
344 default:
345 return APR_EGENERAL;
346 }
347}
348
350{
352 case OCI_SUCCESS:
353 return APR_SUCCESS;
354 default:
355 return APR_EGENERAL;
356 }
357}
358
359static void dbd_oracle_init(apr_pool_t *pool)
360{
361 if (dbd_oracle_env == NULL) {
362 /* Sadly, OCI_SHARED seems to be impossible to use, due to
363 * various Oracle bugs. See, for example, Oracle MetaLink bug 2972890
364 * and PHP bug http://bugs.php.net/bug.php?id=23733
365 */
366#ifdef OCI_NEW_LENGTH_SEMANTICS
368 NULL, NULL, NULL, NULL, 0, NULL);
369#else
371 NULL, NULL, NULL, NULL, 0, NULL);
372#endif
373 }
374}
375
376static apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params,
377 const char **error)
378{
380 int errorcode;
381
382 char *BLANK = "";
383 struct {
384 const char *field;
385 char *value;
386 } fields[] = {
387 {"user", BLANK},
388 {"pass", BLANK},
389 {"dbname", BLANK},
390 {"server", BLANK},
391 {NULL, NULL}
392 };
393 int i;
394 const char *ptr;
395 const char *key;
396 size_t klen;
397 const char *value;
398 size_t vlen;
399 static const char *const delims = " \r\n\t;|,";
400
401 ret->pool = pool;
402 ret->long_size = DEFAULT_LONG_SIZE;
403
404 /* snitch parsing from the MySQL driver */
405 for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {
406 /* don't dereference memory that may not belong to us */
407 if (ptr == params) {
408 ++ptr;
409 continue;
410 }
411 for (key = ptr-1; apr_isspace(*key); --key);
412 klen = 0;
413 while (apr_isalpha(*key)) {
414 if (key == params) {
415 /* Don't parse off the front of the params */
416 --key;
417 ++klen;
418 break;
419 }
420 --key;
421 ++klen;
422 }
423 ++key;
424 for (value = ptr+1; apr_isspace(*value); ++value);
426 for (i=0; fields[i].field != NULL; ++i) {
427 if (!strncasecmp(fields[i].field, key, klen)) {
428 fields[i].value = apr_pstrndup(pool, value, vlen);
429 break;
430 }
431 }
432 ptr = value+vlen;
433 }
434
435 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->err,
437 switch (ret->status) {
438 default:
439#ifdef DEBUG
440 printf("ret->status is %d\n", ret->status);
441 break;
442#else
443 return NULL;
444#endif
445 case OCI_SUCCESS:
446 break;
447 }
448
449 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svr,
451 switch (ret->status) {
452 default:
453#ifdef DEBUG
454 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
455 sizeof(ret->buf), OCI_HTYPE_ERROR);
456 printf("OPEN ERROR %d (alloc svr): %s\n", ret->status, ret->buf);
457 break;
458#else
459 if (error) {
461 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
463 }
464 return NULL;
465#endif
466 case OCI_SUCCESS:
467 break;
468 }
469
470 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svc,
472 switch (ret->status) {
473 default:
474#ifdef DEBUG
475 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
476 sizeof(ret->buf), OCI_HTYPE_ERROR);
477 printf("OPEN ERROR %d (alloc svc): %s\n", ret->status, ret->buf);
478 break;
479#else
480 if (error) {
482 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
484 }
485 return NULL;
486#endif
487 case OCI_SUCCESS:
488 break;
489 }
490
491/* All the examples use the #else */
492#if CAN_DO_LOGIN
493 ret->status = OCILogon(dbd_oracle_env, ret->err, &ret->svc, fields[0].value,
494 strlen(fields[0].value), fields[1].value,
495 strlen(fields[1].value), fields[2].value,
496 strlen(fields[2].value));
497 switch (ret->status) {
498 default:
499#ifdef DEBUG
500 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
501 sizeof(ret->buf), OCI_HTYPE_ERROR);
502 printf("OPEN ERROR: %s\n", ret->buf);
503 break;
504#else
505 if (error) {
507 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
509 }
510 return NULL;
511#endif
512 case OCI_SUCCESS:
513 break;
514 }
515#else
516 ret->status = OCIServerAttach(ret->svr, ret->err, (text*) fields[3].value,
517 strlen(fields[3].value), OCI_DEFAULT);
518 switch (ret->status) {
519 default:
520#ifdef DEBUG
521 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
522 sizeof(ret->buf), OCI_HTYPE_ERROR);
523 printf("OPEN ERROR %d (server attach): %s\n", ret->status, ret->buf);
524 break;
525#else
526 if (error) {
528 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
530 }
531 return NULL;
532#endif
533 case OCI_SUCCESS:
534 break;
535 }
536 ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->svr, 0,
537 OCI_ATTR_SERVER, ret->err);
538 switch (ret->status) {
539 default:
540#ifdef DEBUG
541 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
542 sizeof(ret->buf), OCI_HTYPE_ERROR);
543 printf("OPEN ERROR %d (attr set): %s\n", ret->status, ret->buf);
544 break;
545#else
546 if (error) {
548 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
550 }
551 return NULL;
552#endif
553 case OCI_SUCCESS:
554 break;
555 }
556 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->auth,
558 switch (ret->status) {
559 default:
560#ifdef DEBUG
561 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
562 sizeof(ret->buf), OCI_HTYPE_ERROR);
563 printf("OPEN ERROR %d (alloc auth): %s\n", ret->status, ret->buf);
564 break;
565#else
566 if (error) {
568 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
570 }
571 return NULL;
572#endif
573 case OCI_SUCCESS:
574 break;
575 }
576 ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[0].value,
577 strlen(fields[0].value), OCI_ATTR_USERNAME, ret->err);
578 switch (ret->status) {
579 default:
580#ifdef DEBUG
581 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
582 sizeof(ret->buf), OCI_HTYPE_ERROR);
583 printf("OPEN ERROR %d (attr username): %s\n", ret->status, ret->buf);
584 break;
585#else
586 if (error) {
588 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
590 }
591 return NULL;
592#endif
593 case OCI_SUCCESS:
594 break;
595 }
596 ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[1].value,
597 strlen(fields[1].value), OCI_ATTR_PASSWORD, ret->err);
598 switch (ret->status) {
599 default:
600#ifdef DEBUG
601 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
602 sizeof(ret->buf), OCI_HTYPE_ERROR);
603 printf("OPEN ERROR %d (attr password): %s\n", ret->status, ret->buf);
604 break;
605#else
606 if (error) {
608 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
610 }
611 return NULL;
612#endif
613 case OCI_SUCCESS:
614 break;
615 }
616 ret->status = OCISessionBegin(ret->svc, ret->err, ret->auth,
618 switch (ret->status) {
619 default:
620#ifdef DEBUG
621 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
622 sizeof(ret->buf), OCI_HTYPE_ERROR);
623 printf("OPEN ERROR %d (session begin): %s\n", ret->status, ret->buf);
624 break;
625#else
626 if (error) {
628 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
630 }
631 return NULL;
632#endif
633 case OCI_SUCCESS:
634 break;
635 }
636 ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->auth, 0,
637 OCI_ATTR_SESSION, ret->err);
638 switch (ret->status) {
639 default:
640#ifdef DEBUG
641 OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf,
642 sizeof(ret->buf), OCI_HTYPE_ERROR);
643 printf("OPEN ERROR %d (attr session): %s\n", ret->status, ret->buf);
644#else
645 if (error) {
647 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error),
649 }
650 return NULL;
651#endif
652 break;
653 case OCI_SUCCESS:
654 break;
655 }
656#endif
657
659 &ret->check_conn_stmt) != 0) {
660 return NULL;
661 }
662
663 return ret;
664}
665
666#ifdef EXPORT_NATIVE_FUNCS
669{
670 apr_size_t old_size = sql->long_size;
671 sql->long_size = long_size;
672 return old_size;
673}
674#endif
675
676static const char *dbd_oracle_get_name(const apr_dbd_results_t *res, int n)
677{
678 define_arg *val = &res->statement->out[n];
679
680 if ((n < 0) || (n >= res->statement->nout)) {
681 return NULL;
682 }
683 return val->name;
684}
685
688{
690 apr_dbd_t *sql = res->handle;
692
693 if (row == NULL) {
694 row = apr_palloc(pool, sizeof(apr_dbd_row_t));
695 *rowp = row;
696 row->res = res;
697 /* Oracle starts counting at 1 according to the docs */
698 row->n = res->seek ? rownum : 1;
699 row->pool = pool;
700 }
701 else {
702 if (res->seek) {
703 row->n = rownum;
704 }
705 else {
706 ++row->n;
707 }
708 }
709
710 if (res->seek) {
711 sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
713 }
714 else {
715 sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1,
717 }
718 switch (sql->status) {
719 case OCI_SUCCESS:
720 (*rowp)->res = res;
721 return 0;
722 case OCI_NO_DATA:
723 return -1;
724 case OCI_ERROR:
725#ifdef DEBUG
726 OCIErrorGet(sql->err, 1, NULL, &errorcode,
727 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
728 printf("Execute error %d: %s\n", sql->status, sql->buf);
729#endif
730 /* fallthrough */
731 default:
732 return 1;
733 }
734 return 0;
735}
736
737static const char *dbd_oracle_error(apr_dbd_t *sql, int n)
738{
739 /* This is ugly. Needs us to pass in a buffer of unknown size.
740 * Either we put it on the handle, or we have to keep allocing/copying
741 */
743
744 switch (sql->status) {
745 case OCI_SUCCESS:
746 return "OCI_SUCCESS";
748 return "OCI_SUCCESS_WITH_INFO";
749 case OCI_NEED_DATA:
750 return "OCI_NEED_DATA";
751 case OCI_NO_DATA:
752 return "OCI_NO_DATA";
754 return "OCI_INVALID_HANDLE";
756 return "OCI_STILL_EXECUTING";
757 case OCI_CONTINUE:
758 return "OCI_CONTINUE";
759 }
760
761 switch (OCIErrorGet(sql->err, 1, NULL, &errorcode,
762 (text*) sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR)) {
763 case OCI_SUCCESS:
764 return sql->buf;
765 default:
766 return "internal error: OCIErrorGet failed";
767 }
768}
769
771{
772 int rv = APR_SUCCESS;
774
775#ifdef PREPARE2
776 OCIError *err;
777
779 0, NULL) != OCI_SUCCESS) {
780 return APR_EGENERAL;
781 }
783 rv = APR_EGENERAL;
784 }
786 rv = APR_EGENERAL;
787 }
788#else
790 rv = APR_EGENERAL;
791 }
792#endif
793
794 return rv;
795}
796
798 apr_dbd_results_t **results,
799 const char *query, int seek)
800{
801 int ret = 0;
803
805 if (ret != 0) {
806 return ret;
807 }
808
810 if (ret != 0) {
811 return ret;
812 }
813
814 return ret;
815}
816
817static int dbd_oracle_query(apr_dbd_t *sql, int *nrows, const char *query)
818{
819 int ret = 0;
822
823 if (sql->trans && sql->trans->status == TRANS_ERROR) {
824 return 1;
825 }
826
827 /* make our own pool so that APR allocations don't linger and so that
828 * both Stmt and LOB handles are cleaned up (LOB handles may be
829 * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs)
830 */
831 apr_pool_create(&pool, sql->pool);
832
834 if (ret == 0) {
836 if (ret == 0) {
837 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT,
839 sql->err);
840 }
841 }
842
844
845 return ret;
846}
847
848static const char *dbd_oracle_escape(apr_pool_t *pool, const char *arg,
849 apr_dbd_t *sql)
850{
851 return arg; /* OCI has no concept of string escape */
852}
853
855 const char *query, const char *label,
856 int nargs, int nvals, apr_dbd_type_e *types,
858{
859 int ret = 0;
860 int i;
862
863 if (*statement == NULL) {
865 }
866 stmt = *statement;
867 stmt->handle = sql;
868 stmt->pool = pool;
869 stmt->nargs = nargs;
870 stmt->nvals = nvals;
871
872 /* populate our own args, if any */
873 if (nargs > 0) {
874 stmt->args = apr_pcalloc(pool, nargs*sizeof(bind_arg));
875 for (i = 0; i < nargs; i++) {
876 stmt->args[i].type = types[i];
877 }
878 }
879
880 sql->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**) &stmt->stmt,
881 OCI_HTYPE_STMT, 0, NULL);
882 if (sql->status != OCI_SUCCESS) {
883 return 1;
884 }
885
886 sql->status = OCIStmtPrepare(stmt->stmt, sql->err, (text*) query,
888 if (sql->status != OCI_SUCCESS) {
890 return 1;
891 }
892
895
896 /* Perl gets statement type here */
897 sql->status = OCIAttrGet(stmt->stmt, OCI_HTYPE_STMT, &stmt->type, 0,
898 OCI_ATTR_STMT_TYPE, sql->err);
899 if (sql->status != OCI_SUCCESS) {
900 return 1;
901 }
902
903/* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */
904#if 0
907 sql->err);
908 if (sql->status != OCI_SUCCESS) {
909 return 1;
910 }
911#endif
912
913 if (stmt->type == OCI_STMT_SELECT) {
915 }
916 return ret;
917}
918
919static void dbd_oracle_bind(apr_dbd_prepared_t *statement, const char **values)
920{
921 OCIStmt *stmt = statement->stmt;
922 apr_dbd_t *sql = statement->handle;
923 int i, j;
924 sb2 null_ind = -1;
925
926 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
927 if (values[j] == NULL) {
928 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
929 sql->err, i + 1,
930 NULL, 0, SQLT_STR,
931 &null_ind, NULL,
932 (ub2) 0, (ub4) 0,
933 (ub4 *) 0, OCI_DEFAULT);
934 }
935 else {
936 switch (statement->args[i].type) {
938 {
939 char *data = (char *)values[j];
940 int size = atoi((char*)values[++j]);
941
942 /* skip table and column for now */
943 j += 2;
944
945 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
946 sql->err, i + 1,
948 &statement->args[i].ind,
949 NULL,
950 (ub2) 0, (ub4) 0,
951 (ub4 *) 0, OCI_DEFAULT);
952 }
953 break;
955 {
956 char *data = (char *)values[j];
957 int size = atoi((char*)values[++j]);
958
959 /* skip table and column for now */
960 j += 2;
961
962 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
963 sql->err, i + 1,
965 &statement->args[i].ind,
966 NULL,
967 (ub2) 0, (ub4) 0,
968 (ub4 *) 0, OCI_DEFAULT);
969 }
970 break;
971 default:
972 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
973 sql->err, i + 1,
974 (dvoid*) values[j],
975 strlen(values[j]) + 1,
976 SQLT_STR,
977 &statement->args[i].ind,
978 NULL,
979 (ub2) 0, (ub4) 0,
980 (ub4 *) 0, OCI_DEFAULT);
981 break;
982 }
983 }
984
985 if (sql->status != OCI_SUCCESS) {
986 return;
987 }
988 }
989
990 return;
991}
992
994{
996 int i;
1002
1003 /* Perl uses 0 where we used 1 */
1004 sql->status = OCIStmtExecute(sql->svc, stmt->stmt, sql->err, 0, 0,
1006 switch (sql->status) {
1007 case OCI_SUCCESS:
1009 break;
1010 case OCI_ERROR:
1011#ifdef DEBUG
1012 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1013 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1014 printf("Describing prepared statement: %s\n", sql->buf);
1015#endif
1016 default:
1017 return 1;
1018 }
1019 while (sql->status == OCI_SUCCESS) {
1020 sql->status = OCIParamGet(stmt->stmt, OCI_HTYPE_STMT,
1021 sql->err, (dvoid**)&parms, stmt->nout+1);
1022 switch (sql->status) {
1023 case OCI_SUCCESS:
1025 &paramtype[stmt->nout],
1026 0, OCI_ATTR_DATA_TYPE, sql->err);
1028 &paramsize[stmt->nout],
1029 0, OCI_ATTR_DATA_SIZE, sql->err);
1031 &paramname[stmt->nout],
1032 &paramnamelen[stmt->nout],
1033 OCI_ATTR_NAME, sql->err);
1034 ++stmt->nout;
1035 }
1036 }
1037 switch (sql->status) {
1038 case OCI_SUCCESS:
1039 break;
1040 case OCI_ERROR:
1041 break; /* this is what we expect at end-of-loop */
1042 default:
1043 return 1;
1044 }
1045
1046 /* OK, the above works. We have the params; now OCIDefine them */
1047 stmt->out = apr_palloc(stmt->pool, stmt->nout*sizeof(define_arg));
1048 for (i=0; i<stmt->nout; ++i) {
1049 stmt->out[i].type = paramtype[i];
1050 stmt->out[i].len = stmt->out[i].sz = paramsize[i];
1051 stmt->out[i].name = apr_pstrmemdup(stmt->pool,
1053 switch (stmt->out[i].type) {
1054 default:
1055 switch (stmt->out[i].type) {
1056 case SQLT_NUM: /* 2: numeric, Perl worst case=130+38+3 */
1057 stmt->out[i].sz = 171;
1058 break;
1059 case SQLT_CHR: /* 1: char */
1060 case SQLT_AFC: /* 96: ANSI fixed char */
1061 stmt->out[i].sz *= 4; /* ugh, wasteful UCS-4 handling */
1062 break;
1063 case SQLT_DAT: /* 12: date, depends on NLS date format */
1064 stmt->out[i].sz = 75;
1065 break;
1066 case SQLT_BIN: /* 23: raw binary, perhaps UTF-16? */
1067 stmt->out[i].sz *= 2;
1068 break;
1069 case SQLT_RID: /* 11: rowid */
1070 case SQLT_RDD: /* 104: rowid descriptor */
1071 stmt->out[i].sz = 20;
1072 break;
1073 case SQLT_TIMESTAMP: /* 187: timestamp */
1074 case SQLT_TIMESTAMP_TZ: /* 188: timestamp with time zone */
1075 case SQLT_INTERVAL_YM: /* 189: interval year-to-month */
1076 case SQLT_INTERVAL_DS: /* 190: interval day-to-second */
1077 case SQLT_TIMESTAMP_LTZ: /* 232: timestamp with local time zone */
1078 stmt->out[i].sz = 75;
1079 break;
1080 default:
1081#ifdef DEBUG
1082 printf("Unsupported data type: %d\n", stmt->out[i].type);
1083#endif
1084 break;
1085 }
1086 ++stmt->out[i].sz;
1087 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1088 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1089 sql->err, i+1,
1090 stmt->out[i].buf.sval,
1091 stmt->out[i].sz, SQLT_STR,
1092 &stmt->out[i].ind, &stmt->out[i].len,
1093 0, OCI_DEFAULT);
1094 break;
1095 case SQLT_LNG: /* 8: long */
1096 stmt->out[i].sz = sql->long_size * 4 + 4; /* ugh, UCS-4 handling */
1097 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1098 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1099 sql->err, i+1,
1100 stmt->out[i].buf.raw,
1101 stmt->out[i].sz, SQLT_LVC,
1102 &stmt->out[i].ind, NULL,
1103 0, OCI_DEFAULT);
1104 break;
1105 case SQLT_LBI: /* 24: long binary, perhaps UTF-16? */
1106 stmt->out[i].sz = sql->long_size * 2 + 4; /* room for int prefix */
1107 stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz);
1108 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1109 sql->err, i+1,
1110 stmt->out[i].buf.raw,
1111 stmt->out[i].sz, SQLT_LVB,
1112 &stmt->out[i].ind, NULL,
1113 0, OCI_DEFAULT);
1114 break;
1115 case SQLT_BLOB: /* 113 */
1116 case SQLT_CLOB: /* 112 */
1117/*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/
1119 (dvoid**)&stmt->out[i].buf.lobval,
1120 OCI_DTYPE_LOB, 0, NULL);
1121 apr_pool_cleanup_register(stmt->pool, stmt->out[i].buf.lobval,
1124 sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn,
1125 sql->err, i+1,
1126 (dvoid*) &stmt->out[i].buf.lobval,
1127 -1, stmt->out[i].type,
1128 &stmt->out[i].ind, &stmt->out[i].len,
1129 0, OCI_DEFAULT);
1130 break;
1131 }
1132 switch (sql->status) {
1133 case OCI_SUCCESS:
1134 break;
1135 default:
1136 return 1;
1137 }
1138 }
1139 return 0;
1140}
1141
1144 const char **values)
1145{
1149 int exec_mode;
1151
1152 if (trans) {
1153 switch (trans->status) {
1154 case TRANS_ERROR:
1155 return -1;
1156 case TRANS_NONE:
1157 trans = NULL;
1158 break;
1159 case TRANS_1:
1160 oldsnapshot = trans->snapshot1;
1161 newsnapshot = trans->snapshot2;
1162 trans->status = TRANS_2;
1163 break;
1164 case TRANS_2:
1165 oldsnapshot = trans->snapshot2;
1166 newsnapshot = trans->snapshot1;
1167 trans->status = TRANS_1;
1168 break;
1169 }
1171 }
1172 else {
1174 }
1175
1177
1178 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1180 switch (sql->status) {
1181 case OCI_SUCCESS:
1182 break;
1183 case OCI_ERROR:
1184#ifdef DEBUG
1185 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1186 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1187 printf("Execute error %d: %s\n", sql->status, sql->buf);
1188#endif
1189 /* fallthrough */
1190 default:
1191 if (TXN_NOTICE_ERRORS(trans)) {
1192 trans->status = TRANS_ERROR;
1193 }
1194 return 1;
1195 }
1196
1197 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1198 OCI_ATTR_ROW_COUNT, sql->err);
1199 return 0;
1200}
1201
1204 va_list args)
1205{
1206 const char **values;
1207 int i;
1208
1209 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1210 return -1;
1211 }
1212
1213 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1214
1215 for (i = 0; i < statement->nvals; i++) {
1216 values[i] = va_arg(args, const char*);
1217 }
1218
1220}
1221
1223 apr_dbd_results_t **results,
1225 int seek, const char **values)
1226{
1232
1233 if (trans) {
1234 switch (trans->status) {
1235 case TRANS_ERROR:
1236 return 1;
1237 case TRANS_NONE:
1238 trans = NULL;
1239 break;
1240 case TRANS_1:
1241 oldsnapshot = trans->snapshot1;
1242 newsnapshot = trans->snapshot2;
1243 trans->status = TRANS_2;
1244 break;
1245 case TRANS_2:
1246 oldsnapshot = trans->snapshot2;
1247 newsnapshot = trans->snapshot1;
1248 trans->status = TRANS_1;
1249 break;
1250 }
1251 }
1252
1254
1255 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1257 switch (sql->status) {
1258 case OCI_SUCCESS:
1259 break;
1260 case OCI_ERROR:
1261#ifdef DEBUG
1262 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1263 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1264 printf("Executing prepared statement: %s\n", sql->buf);
1265#endif
1266 /* fallthrough */
1267 default:
1268 if (TXN_NOTICE_ERRORS(trans)) {
1269 trans->status = TRANS_ERROR;
1270 }
1271 return 1;
1272 }
1273
1274 if (!*results) {
1275 *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1276 }
1277 (*results)->handle = sql;
1278 (*results)->statement = statement;
1279 (*results)->seek = seek;
1280 (*results)->rownum = seek ? 0 : -1;
1281 (*results)->pool = pool;
1282
1283 return 0;
1284}
1285
1287 apr_dbd_results_t **results,
1289 int seek, va_list args)
1290{
1291 const char **values;
1292 int i;
1293
1294 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1295 return -1;
1296 }
1297
1298 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1299
1300 for (i = 0; i < statement->nvals; i++) {
1301 values[i] = va_arg(args, const char*);
1302 }
1303
1304 return dbd_oracle_pselect(pool, sql, results, statement, seek, values);
1305}
1306
1308 const void **values)
1309{
1310 OCIStmt *stmt = statement->stmt;
1311 apr_dbd_t *sql = statement->handle;
1312 int i, j;
1313 sb2 null_ind = -1;
1315
1316 for (i = 0, j = 0; i < statement->nargs; i++, j++) {
1318 : statement->args[i].type);
1319
1320 switch (type) {
1321 case APR_DBD_TYPE_TINY:
1322 statement->args[i].value.ival = *(char*)values[j];
1323 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1324 sql->err, i + 1,
1325 &statement->args[i].value.ival,
1326 sizeof(statement->args[i].value.ival),
1327 SQLT_INT,
1328 &statement->args[i].ind, NULL,
1329 (ub2) 0, (ub4) 0,
1330 (ub4 *) 0, OCI_DEFAULT);
1331 break;
1332 case APR_DBD_TYPE_UTINY:
1333 statement->args[i].value.uval = *(unsigned char*)values[j];
1334 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1335 sql->err, i + 1,
1336 &statement->args[i].value.uval,
1337 sizeof(statement->args[i].value.uval),
1338 SQLT_UIN,
1339 &statement->args[i].ind, NULL,
1340 (ub2) 0, (ub4) 0,
1341 (ub4 *) 0, OCI_DEFAULT);
1342 break;
1343 case APR_DBD_TYPE_SHORT:
1344 statement->args[i].value.ival = *(short*)values[j];
1345 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1346 sql->err, i + 1,
1347 &statement->args[i].value.ival,
1348 sizeof(statement->args[i].value.ival),
1349 SQLT_INT,
1350 &statement->args[i].ind, NULL,
1351 (ub2) 0, (ub4) 0,
1352 (ub4 *) 0, OCI_DEFAULT);
1353 break;
1355 statement->args[i].value.uval = *(unsigned short*)values[j];
1356 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1357 sql->err, i + 1,
1358 &statement->args[i].value.uval,
1359 sizeof(statement->args[i].value.uval),
1360 SQLT_UIN,
1361 &statement->args[i].ind, NULL,
1362 (ub2) 0, (ub4) 0,
1363 (ub4 *) 0, OCI_DEFAULT);
1364 break;
1365 case APR_DBD_TYPE_INT:
1366 statement->args[i].value.ival = *(int*)values[j];
1367 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1368 sql->err, i + 1,
1369 &statement->args[i].value.ival,
1370 sizeof(statement->args[i].value.ival),
1371 SQLT_INT,
1372 &statement->args[i].ind, NULL,
1373 (ub2) 0, (ub4) 0,
1374 (ub4 *) 0, OCI_DEFAULT);
1375 break;
1376 case APR_DBD_TYPE_UINT:
1377 statement->args[i].value.uval = *(unsigned int*)values[j];
1378 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1379 sql->err, i + 1,
1380 &statement->args[i].value.uval,
1381 sizeof(statement->args[i].value.uval),
1382 SQLT_UIN,
1383 &statement->args[i].ind, NULL,
1384 (ub2) 0, (ub4) 0,
1385 (ub4 *) 0, OCI_DEFAULT);
1386 break;
1387 case APR_DBD_TYPE_LONG:
1388 statement->args[i].value.sval =
1389 apr_psprintf(statement->pool, "%ld", *(long*)values[j]);
1390 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1391 sql->err, i + 1,
1392 statement->args[i].value.sval,
1393 strlen(statement->args[i].value.sval)+1,
1394 SQLT_STR,
1395 &statement->args[i].ind, NULL,
1396 (ub2) 0, (ub4) 0,
1397 (ub4 *) 0, OCI_DEFAULT);
1398 break;
1399 case APR_DBD_TYPE_ULONG:
1400 statement->args[i].value.sval =
1401 apr_psprintf(statement->pool, "%lu",
1402 *(unsigned long*)values[j]);
1403 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1404 sql->err, i + 1,
1405 statement->args[i].value.sval,
1406 strlen(statement->args[i].value.sval)+1,
1407 SQLT_STR,
1408 &statement->args[i].ind, NULL,
1409 (ub2) 0, (ub4) 0,
1410 (ub4 *) 0, OCI_DEFAULT);
1411 break;
1413 statement->args[i].value.sval =
1415 *(apr_int64_t*)values[j]);
1416 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1417 sql->err, i + 1,
1418 statement->args[i].value.sval,
1419 strlen(statement->args[i].value.sval)+1,
1420 SQLT_STR,
1421 &statement->args[i].ind, NULL,
1422 (ub2) 0, (ub4) 0,
1423 (ub4 *) 0, OCI_DEFAULT);
1424 break;
1426 statement->args[i].value.sval =
1428 *(apr_uint64_t*)values[j]);
1429 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1430 sql->err, i + 1,
1431 statement->args[i].value.sval,
1432 strlen(statement->args[i].value.sval)+1,
1433 SQLT_UIN,
1434 &statement->args[i].ind, NULL,
1435 (ub2) 0, (ub4) 0,
1436 (ub4 *) 0, OCI_DEFAULT);
1437 break;
1438 case APR_DBD_TYPE_FLOAT:
1439 statement->args[i].value.fval = *(float*)values[j];
1440 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1441 sql->err, i + 1,
1442 &statement->args[i].value.fval,
1443 sizeof(statement->args[i].value.fval),
1444 SQLT_FLT,
1445 &statement->args[i].ind, NULL,
1446 (ub2) 0, (ub4) 0,
1447 (ub4 *) 0, OCI_DEFAULT);
1448 break;
1450 statement->args[i].value.fval = *(double*)values[j];
1451 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1452 sql->err, i + 1,
1453 &statement->args[i].value.fval,
1454 sizeof(statement->args[i].value.fval),
1455 SQLT_FLT,
1456 &statement->args[i].ind, NULL,
1457 (ub2) 0, (ub4) 0,
1458 (ub4 *) 0, OCI_DEFAULT);
1459 break;
1461 case APR_DBD_TYPE_TEXT:
1462 case APR_DBD_TYPE_TIME:
1463 case APR_DBD_TYPE_DATE:
1467 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1468 sql->err, i + 1,
1469 (dvoid*) values[j],
1470 strlen(values[j]) + 1,
1471 SQLT_STR,
1472 &statement->args[i].ind, NULL,
1473 (ub2) 0, (ub4) 0,
1474 (ub4 *) 0, OCI_DEFAULT);
1475 break;
1476 case APR_DBD_TYPE_BLOB:
1477 {
1478 char *data = (char *)values[j];
1479 apr_size_t size = *(apr_size_t*)values[++j];
1480
1481 /* skip table and column for now */
1482 j += 2;
1483
1484 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1485 sql->err, i + 1,
1486 data, size, SQLT_LBI,
1487 &statement->args[i].ind,
1488 NULL,
1489 (ub2) 0, (ub4) 0,
1490 (ub4 *) 0, OCI_DEFAULT);
1491 }
1492 break;
1493 case APR_DBD_TYPE_CLOB:
1494 {
1495 char *data = (char *)values[j];
1496 apr_size_t size = *(apr_size_t*)values[++j];
1497
1498 /* skip table and column for now */
1499 j += 2;
1500
1501 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1502 sql->err, i + 1,
1503 data, size, SQLT_LNG,
1504 &statement->args[i].ind,
1505 NULL,
1506 (ub2) 0, (ub4) 0,
1507 (ub4 *) 0, OCI_DEFAULT);
1508 }
1509 break;
1510 case APR_DBD_TYPE_NULL:
1511 default:
1512 sql->status = OCIBindByPos(stmt, &statement->args[i].bind,
1513 sql->err, i + 1,
1514 NULL, 0, SQLT_STR,
1515 &null_ind, NULL,
1516 (ub2) 0, (ub4) 0,
1517 (ub4 *) 0, OCI_DEFAULT);
1518 break;
1519 }
1520
1521 if (sql->status != OCI_SUCCESS) {
1522 return;
1523 }
1524 }
1525
1526 return;
1527}
1528
1531 const void **values)
1532{
1536 int exec_mode;
1538
1539 if (trans) {
1540 switch (trans->status) {
1541 case TRANS_ERROR:
1542 return -1;
1543 case TRANS_NONE:
1544 trans = NULL;
1545 break;
1546 case TRANS_1:
1547 oldsnapshot = trans->snapshot1;
1548 newsnapshot = trans->snapshot2;
1549 trans->status = TRANS_2;
1550 break;
1551 case TRANS_2:
1552 oldsnapshot = trans->snapshot2;
1553 newsnapshot = trans->snapshot1;
1554 trans->status = TRANS_1;
1555 break;
1556 }
1558 }
1559 else {
1561 }
1562
1564
1565 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0,
1567 switch (sql->status) {
1568 case OCI_SUCCESS:
1569 break;
1570 case OCI_ERROR:
1571#ifdef DEBUG
1572 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1573 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1574 printf("Execute error %d: %s\n", sql->status, sql->buf);
1575#endif
1576 /* fallthrough */
1577 default:
1578 if (TXN_NOTICE_ERRORS(trans)) {
1579 trans->status = TRANS_ERROR;
1580 }
1581 return 1;
1582 }
1583
1584 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0,
1585 OCI_ATTR_ROW_COUNT, sql->err);
1586 return 0;
1587}
1588
1591 va_list args)
1592{
1593 const void **values;
1594 int i;
1595
1596 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1597 return -1;
1598 }
1599
1600 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1601
1602 for (i = 0; i < statement->nvals; i++) {
1603 values[i] = va_arg(args, const void*);
1604 }
1605
1607}
1608
1610 apr_dbd_results_t ** results,
1612 int seek, const void **values)
1613{
1619
1620 if (trans) {
1621 switch (trans->status) {
1622 case TRANS_ERROR:
1623 return 1;
1624 case TRANS_NONE:
1625 trans = NULL;
1626 break;
1627 case TRANS_1:
1628 oldsnapshot = trans->snapshot1;
1629 newsnapshot = trans->snapshot2;
1630 trans->status = TRANS_2;
1631 break;
1632 case TRANS_2:
1633 oldsnapshot = trans->snapshot2;
1634 newsnapshot = trans->snapshot1;
1635 trans->status = TRANS_1;
1636 break;
1637 }
1638 }
1639
1641
1642 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0,
1644 switch (sql->status) {
1645 case OCI_SUCCESS:
1646 break;
1647 case OCI_ERROR:
1648#ifdef DEBUG
1649 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1650 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1651 printf("Executing prepared statement: %s\n", sql->buf);
1652#endif
1653 /* fallthrough */
1654 default:
1655 if (TXN_NOTICE_ERRORS(trans)) {
1656 trans->status = TRANS_ERROR;
1657 }
1658 return 1;
1659 }
1660
1661 if (!*results) {
1662 *results = apr_palloc(pool, sizeof(apr_dbd_results_t));
1663 }
1664 (*results)->handle = sql;
1665 (*results)->statement = statement;
1666 (*results)->seek = seek;
1667 (*results)->rownum = seek ? 0 : -1;
1668 (*results)->pool = pool;
1669
1670 return 0;
1671}
1672
1674 apr_dbd_results_t ** results,
1676 va_list args)
1677{
1678 const void **values;
1679 int i;
1680
1681 if (sql->trans && sql->trans->status == TRANS_ERROR) {
1682 return -1;
1683 }
1684
1685 values = apr_palloc(pool, sizeof(*values) * statement->nvals);
1686
1687 for (i = 0; i < statement->nvals; i++) {
1688 values[i] = va_arg(args, const void*);
1689 }
1690
1691 return dbd_oracle_pbselect(pool, sql, results, statement, seek, values);
1692}
1693
1696{
1697 int ret = 0;
1699 if (*trans) {
1701 }
1702 else {
1704 OCIHandleAlloc(dbd_oracle_env, (dvoid**)&(*trans)->trans,
1705 OCI_HTYPE_TRANS, 0, 0);
1706 OCIAttrSet(sql->svc, OCI_HTYPE_SVCCTX, (*trans)->trans, 0,
1707 OCI_ATTR_TRANS, sql->err);
1708 }
1709
1710
1711 sql->status = OCITransStart(sql->svc, sql->err, TRANS_TIMEOUT,
1713 switch (sql->status) {
1714 case OCI_ERROR:
1715#ifdef DEBUG
1716 OCIErrorGet(sql->err, 1, NULL, &errorcode, sql->buf,
1717 sizeof(sql->buf), OCI_HTYPE_ERROR);
1718 printf("Transaction: %s\n", sql->buf);
1719#endif
1720 ret = 1;
1721 break;
1722 case OCI_SUCCESS:
1723 (*trans)->handle = sql;
1724 (*trans)->status = TRANS_1;
1725 sql->trans = *trans;
1727 (dvoid**)&(*trans)->snapshot1,
1728 OCI_DTYPE_SNAP, 0, NULL)) {
1729 case OCI_SUCCESS:
1730 apr_pool_cleanup_register(pool, (*trans)->snapshot1,
1732 break;
1733 case OCI_INVALID_HANDLE:
1734 ret = 1;
1735 break;
1736 }
1738 (dvoid**)&(*trans)->snapshot2,
1739 OCI_DTYPE_SNAP, 0, NULL)) {
1740 case OCI_SUCCESS:
1741 apr_pool_cleanup_register(pool, (*trans)->snapshot2,
1743 break;
1744 case OCI_INVALID_HANDLE:
1745 ret = 1;
1746 break;
1747 }
1748 break;
1749 default:
1750 ret = 1;
1751 break;
1752 }
1753 return ret;
1754}
1755
1757{
1758 int ret = 1; /* no transaction is an error cond */
1759 sword status;
1760 apr_dbd_t *handle = trans->handle;
1761 if (trans) {
1762 switch (trans->status) {
1763 case TRANS_NONE: /* No trans is an error here */
1764 status = OCI_ERROR;
1765 break;
1766 case TRANS_ERROR:
1768 break;
1769 default:
1770 /* rollback on explicit rollback request */
1771 if (TXN_DO_ROLLBACK(trans)) {
1773 } else {
1775 }
1776 break;
1777 }
1778
1779 handle->trans = NULL;
1780
1781 switch (status) {
1782 case OCI_SUCCESS:
1783 ret = 0;
1784 break;
1785 default:
1786 ret = 3;
1787 break;
1788 }
1789 }
1790 return ret;
1791}
1792
1794{
1795 if (!trans)
1797
1798 return trans->mode;
1799}
1800
1802 int mode)
1803{
1804 if (!trans)
1806
1807 return trans->mode = (mode & TXN_MODE_BITS);
1808}
1809
1810/* This doesn't work for BLOB because of NULLs, but it can fake it
1811 * if the BLOB is really a string
1812 */
1813static const char *dbd_oracle_get_entry(const apr_dbd_row_t *row, int n)
1814{
1815 ub4 len = 0;
1816 ub1 csform = 0;
1817 ub2 csid = 0;
1818 apr_size_t buflen = 0;
1819 char *buf = NULL;
1820 define_arg *val = &row->res->statement->out[n];
1821 apr_dbd_t *sql = row->res->handle;
1823
1824 if ((n < 0) || (n >= row->res->statement->nout) || (val->ind == -1)) {
1825 return NULL;
1826 }
1827
1828 switch (val->type) {
1829 case SQLT_BLOB:
1830 case SQLT_CLOB:
1831 sql->status = OCILobGetLength(sql->svc, sql->err, val->buf.lobval,
1832 &len);
1833 switch (sql->status) {
1834 case OCI_SUCCESS:
1836 if (len == 0) {
1837 buf = "";
1838 }
1839 break;
1840 case OCI_ERROR:
1841#ifdef DEBUG
1842 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1843 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1844 printf("Finding LOB length: %s\n", sql->buf);
1845 break;
1846#endif
1847 default:
1848 break;
1849 }
1850
1851 if (len == 0) {
1852 break;
1853 }
1854
1855 if (val->type == APR_DBD_TYPE_CLOB) {
1856#if 1
1857 /* Is this necessary, or can it be defaulted? */
1858 sql->status = OCILobCharSetForm(dbd_oracle_env, sql->err,
1859 val->buf.lobval, &csform);
1860 if (sql->status == OCI_SUCCESS) {
1861 sql->status = OCILobCharSetId(dbd_oracle_env, sql->err,
1862 val->buf.lobval, &csid);
1863 }
1864 switch (sql->status) {
1865 case OCI_SUCCESS:
1867 buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1868 /* zeroise all - where the string ends depends on charset */
1869 buf = apr_pcalloc(row->pool, buflen);
1870 break;
1871#ifdef DEBUG
1872 case OCI_ERROR:
1873 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1874 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1875 printf("Reading LOB character set: %s\n", sql->buf);
1876 break; /*** XXX?? ***/
1877#endif
1878 default:
1879 break; /*** XXX?? ***/
1880 }
1881#else /* ignore charset */
1882 buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */
1883 /* zeroise all - where the string ends depends on charset */
1884 buf = apr_pcalloc(row->pool, buflen);
1885#endif
1886 } else {
1887 /* BUG: this'll only work if the BLOB looks like a string */
1888 buflen = len;
1889 buf = apr_palloc(row->pool, buflen+1);
1890 buf[buflen] = 0;
1891 }
1892
1893 if (!buf) {
1894 break;
1895 }
1896
1897 sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval,
1898 &len, 1, (dvoid*) buf, buflen,
1899 NULL, NULL, csid, csform);
1900 switch (sql->status) {
1901 case OCI_SUCCESS:
1903 break;
1904#ifdef DEBUG
1905 case OCI_ERROR:
1906 OCIErrorGet(sql->err, 1, NULL, &errorcode,
1907 sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR);
1908 printf("Reading LOB: %s\n", sql->buf);
1909 buf = NULL; /*** XXX?? ***/
1910 break;
1911#endif
1912 default:
1913 buf = NULL; /*** XXX?? ***/
1914 break;
1915 }
1916
1917 break;
1918 case SQLT_LNG:
1919 case SQLT_LBI:
1920 /* raw is struct { ub4 len; char *buf; } */
1921 len = *(ub4*) val->buf.raw;
1922 buf = apr_pstrndup(row->pool, val->buf.sval + sizeof(ub4), len);
1923 break;
1924 default:
1925 buf = apr_pstrndup(row->pool, val->buf.sval, val->len);
1926 break;
1927 }
1928 return (const char*) buf;
1929}
1930
1931/* XXX Should this use Oracle proper API instead of calling get_entry()? */
1933 apr_dbd_type_e type, void *data)
1934{
1935 define_arg *val = &row->res->statement->out[n];
1936 const char *entry;
1937
1938 if ((n < 0) || (n >= row->res->statement->nout)) {
1939 return APR_EGENERAL;
1940 }
1941
1942 if(val->ind == -1) {
1943 return APR_ENOENT;
1944 }
1945
1946 switch (type) {
1947 case APR_DBD_TYPE_TINY:
1948 entry = dbd_oracle_get_entry(row, n);
1949 if (entry == NULL) {
1950 return APR_ENOENT;
1951 }
1952 *(char*)data = atoi(entry);
1953 break;
1954 case APR_DBD_TYPE_UTINY:
1955 entry = dbd_oracle_get_entry(row, n);
1956 if (entry == NULL) {
1957 return APR_ENOENT;
1958 }
1959 *(unsigned char*)data = atoi(entry);
1960 break;
1961 case APR_DBD_TYPE_SHORT:
1962 entry = dbd_oracle_get_entry(row, n);
1963 if (entry == NULL) {
1964 return APR_ENOENT;
1965 }
1966 *(short*)data = atoi(entry);
1967 break;
1969 entry = dbd_oracle_get_entry(row, n);
1970 if (entry == NULL) {
1971 return APR_ENOENT;
1972 }
1973 *(unsigned short*)data = atoi(entry);
1974 break;
1975 case APR_DBD_TYPE_INT:
1976 entry = dbd_oracle_get_entry(row, n);
1977 if (entry == NULL) {
1978 return APR_ENOENT;
1979 }
1980 *(int*)data = atoi(entry);
1981 break;
1982 case APR_DBD_TYPE_UINT:
1983 entry = dbd_oracle_get_entry(row, n);
1984 if (entry == NULL) {
1985 return APR_ENOENT;
1986 }
1987 *(unsigned int*)data = atoi(entry);
1988 break;
1989 case APR_DBD_TYPE_LONG:
1990 entry = dbd_oracle_get_entry(row, n);
1991 if (entry == NULL) {
1992 return APR_ENOENT;
1993 }
1994 *(long*)data = atol(entry);
1995 break;
1996 case APR_DBD_TYPE_ULONG:
1997 entry = dbd_oracle_get_entry(row, n);
1998 if (entry == NULL) {
1999 return APR_ENOENT;
2000 }
2001 *(unsigned long*)data = atol(entry);
2002 break;
2004 entry = dbd_oracle_get_entry(row, n);
2005 if (entry == NULL) {
2006 return APR_ENOENT;
2007 }
2008 *(apr_int64_t*)data = apr_atoi64(entry);
2009 break;
2011 entry = dbd_oracle_get_entry(row, n);
2012 if (entry == NULL) {
2013 return APR_ENOENT;
2014 }
2015 *(apr_uint64_t*)data = apr_atoi64(entry);
2016 break;
2017 case APR_DBD_TYPE_FLOAT:
2018 entry = dbd_oracle_get_entry(row, n);
2019 if (entry == NULL) {
2020 return APR_ENOENT;
2021 }
2022 *(float*)data = (float)atof(entry);
2023 break;
2025 entry = dbd_oracle_get_entry(row, n);
2026 if (entry == NULL) {
2027 return APR_ENOENT;
2028 }
2029 *(double*)data = atof(entry);
2030 break;
2032 case APR_DBD_TYPE_TEXT:
2033 case APR_DBD_TYPE_TIME:
2034 case APR_DBD_TYPE_DATE:
2038 entry = dbd_oracle_get_entry(row, n);
2039 if (entry == NULL) {
2040 return APR_ENOENT;
2041 }
2042 *(char**)data = (char*)entry;
2043 break;
2044 case APR_DBD_TYPE_BLOB:
2045 case APR_DBD_TYPE_CLOB:
2046 {
2047 apr_bucket *e;
2049 apr_dbd_t *sql = row->res->handle;
2050 ub4 len = 0;
2051
2052 switch (val->type) {
2053 case SQLT_BLOB:
2054 case SQLT_CLOB:
2055 sql->status = OCILobGetLength(sql->svc, sql->err,
2056 val->buf.lobval, &len);
2057 switch(sql->status) {
2058 case OCI_SUCCESS:
2060 if (len == 0) {
2061 e = apr_bucket_eos_create(b->bucket_alloc);
2062 }
2063 else {
2065 row->pool, b->bucket_alloc);
2066 }
2067 break;
2068 default:
2069 return APR_ENOENT;
2070 }
2071 break;
2072 default:
2073 entry = dbd_oracle_get_entry(row, n);
2074 if (entry == NULL) {
2075 return APR_ENOENT;
2076 }
2077 e = apr_bucket_pool_create(entry, strlen(entry),
2078 row->pool, b->bucket_alloc);
2079 break;
2080 }
2082 }
2083 break;
2084 case APR_DBD_TYPE_NULL:
2085 *(void**)data = NULL;
2086 break;
2087 default:
2088 return APR_EGENERAL;
2089 }
2090
2091 return APR_SUCCESS;
2092}
2093
2095{
2096 /* FIXME: none of the oracle docs/examples say anything about
2097 * closing/releasing handles. Which seems unlikely ...
2098 */
2099
2100 /* OK, let's grab from cdemo again.
2101 * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles
2102 */
2103 switch (OCISessionEnd(handle->svc, handle->err, handle->auth,
2104 (ub4)OCI_DEFAULT)) {
2105 default:
2106 break;
2107 }
2108 switch (OCIServerDetach(handle->svr, handle->err, (ub4) OCI_DEFAULT )) {
2109 default:
2110 break;
2111 }
2112 /* does OCISessionEnd imply this? */
2113 switch (OCIHandleFree((dvoid *) handle->auth, (ub4) OCI_HTYPE_SESSION)) {
2114 default:
2115 break;
2116 }
2117 switch (OCIHandleFree((dvoid *) handle->svr, (ub4) OCI_HTYPE_SERVER)) {
2118 default:
2119 break;
2120 }
2121 switch (OCIHandleFree((dvoid *) handle->svc, (ub4) OCI_HTYPE_SVCCTX)) {
2122 default:
2123 break;
2124 }
2125 switch (OCIHandleFree((dvoid *) handle->err, (ub4) OCI_HTYPE_ERROR)) {
2126 default:
2127 break;
2128 }
2129 return APR_SUCCESS;
2130}
2131
2133{
2136
2137 if(dbd_oracle_pselect(pool, sql, &res, sql->check_conn_stmt,
2138 0, NULL) != 0) {
2139 return APR_EGENERAL;
2140 }
2141
2142 if(dbd_oracle_get_row(pool, res, &row, -1) != 0) {
2143 return APR_EGENERAL;
2144 }
2145
2146 if(dbd_oracle_get_row(pool, res, &row, -1) != -1) {
2147 return APR_EGENERAL;
2148 }
2149
2150 return APR_SUCCESS;
2151}
2152
2154 const char *name)
2155{
2156 /* FIXME: need to find this in the docs */
2157 return APR_ENOTIMPL;
2158}
2159
2160static void *dbd_oracle_native(apr_dbd_t *handle)
2161{
2162 /* FIXME: can we do anything better? Oracle doesn't seem to have
2163 * a concept of a handle in the sense we use it.
2164 */
2165 return dbd_oracle_env;
2166}
2167
2169{
2170 return res->statement->nout;
2171}
2172
2174{
2175 if (!res->seek) {
2176 return -1;
2177 }
2178 if (res->nrows >= 0) {
2179 return res->nrows;
2180 }
2181 res->handle->status = OCIAttrGet(res->statement->stmt, OCI_HTYPE_STMT,
2182 &res->nrows, 0, OCI_ATTR_ROW_COUNT,
2183 res->handle->err);
2184 return res->nrows;
2185}
2186
2188 "oracle",
2213 ":apr%d",
2219};
2220#endif
int n
Definition ap_regex.h:278
const char apr_size_t len
Definition ap_regex.h:187
#define bind
APR-UTIL Buckets/Bucket Brigades.
#define TXN_NOTICE_ERRORS(t)
#define TXN_MODE_BITS
#define TXN_DO_ROLLBACK(t)
#define int_errorcode
APR Hash Tables.
APR general purpose library routines.
APR Strings library.
APR Time Library.
const unsigned char * buf
Definition util_md5.h:50
void const char * arg
Definition http_vhost.h:63
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_ENOENT
Definition apr_errno.h:662
#define APR_BUCKET_INIT(e)
apr_file_t * f
#define APR_BUCKET_INSERT_AFTER(a, b)
#define APR_BRIGADE_INSERT_TAIL(b, e)
apr_read_type_e
Definition apr_buckets.h:57
apr_bucket * e
#define APR_BUCKET_BUFF_SIZE
Definition apr_buckets.h:54
apr_bucket apr_bucket_brigade * a
int apr_off_t * length
apr_pool_t apr_dbd_t const char * query
Definition apr_dbd.h:396
apr_dbd_type_e
Definition apr_dbd.h:55
apr_pool_t const char apr_dbd_t const char ** error
Definition apr_dbd.h:143
struct apr_dbd_prepared_t apr_dbd_prepared_t
Definition apr_dbd.h:87
apr_pool_t apr_dbd_t const char const char * label
Definition apr_dbd.h:397
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
struct apr_dbd_t apr_dbd_t
Definition apr_dbd.h:83
apr_dbd_t int const char * statement
Definition apr_dbd.h:272
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
struct apr_dbd_results_t apr_dbd_results_t
Definition apr_dbd.h:85
apr_pool_t const char apr_dbd_t ** handle
Definition apr_dbd.h:142
apr_pool_t apr_dbd_results_t apr_dbd_row_t int rownum
Definition apr_dbd.h:321
apr_pool_t apr_dbd_t int apr_dbd_prepared_t int nargs
Definition apr_dbd.h:414
struct apr_dbd_transaction_t apr_dbd_transaction_t
Definition apr_dbd.h:84
apr_pool_t apr_dbd_results_t apr_dbd_row_t ** row
Definition apr_dbd.h:320
apr_pool_t const char * params
Definition apr_dbd.h:141
apr_dbd_t int * nrows
Definition apr_dbd.h:272
struct apr_dbd_row_t apr_dbd_row_t
Definition apr_dbd.h:86
apr_dbd_row_t int col
Definition apr_dbd.h:331
#define APR_DBD_TRANSACTION_COMMIT
Definition apr_dbd.h:239
@ APR_DBD_TYPE_SHORT
Definition apr_dbd.h:59
@ APR_DBD_TYPE_FLOAT
Definition apr_dbd.h:67
@ APR_DBD_TYPE_TIME
Definition apr_dbd.h:71
@ APR_DBD_TYPE_ULONG
Definition apr_dbd.h:64
@ APR_DBD_TYPE_STRING
Definition apr_dbd.h:69
@ APR_DBD_TYPE_INT
Definition apr_dbd.h:61
@ APR_DBD_TYPE_UINT
Definition apr_dbd.h:62
@ APR_DBD_TYPE_TIMESTAMP
Definition apr_dbd.h:74
@ APR_DBD_TYPE_BLOB
Definition apr_dbd.h:76
@ APR_DBD_TYPE_NULL
Definition apr_dbd.h:78
@ APR_DBD_TYPE_DATETIME
Definition apr_dbd.h:73
@ APR_DBD_TYPE_DOUBLE
Definition apr_dbd.h:68
@ APR_DBD_TYPE_LONGLONG
Definition apr_dbd.h:65
@ APR_DBD_TYPE_UTINY
Definition apr_dbd.h:58
@ APR_DBD_TYPE_DATE
Definition apr_dbd.h:72
@ APR_DBD_TYPE_TINY
Definition apr_dbd.h:57
@ APR_DBD_TYPE_ULONGLONG
Definition apr_dbd.h:66
@ APR_DBD_TYPE_LONG
Definition apr_dbd.h:63
@ APR_DBD_TYPE_CLOB
Definition apr_dbd.h:77
@ APR_DBD_TYPE_TEXT
Definition apr_dbd.h:70
@ APR_DBD_TYPE_ZTIMESTAMP
Definition apr_dbd.h:75
@ APR_DBD_TYPE_USHORT
Definition apr_dbd.h:60
const char apr_hash_t ** values
apr_text_header const char * text
Definition apr_xml.h:78
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char int apr_pool_t * pool
Definition apr_cstr.h:84
const apr_array_header_t * list
Definition apr_cstr.h:105
#define apr_isspace(c)
Definition apr_lib.h:225
#define apr_isalpha(c)
Definition apr_lib.h:205
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
apr_seek_where_t apr_off_t * offset
void * data
int type
int strncasecmp(const char *a, const char *b, size_t n)
apr_ssize_t * klen
Definition apr_hash.h:71
apr_size_t buflen
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_int32_t apr_int32_t apr_int32_t err
const char const char *const * args
int int status
apr_pool_t * p
Definition md_event.c:32
static apr_file_t * out
Definition mod_info.c:85
static const char *const types[]
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
static const char *const trans[040]
Definition sed1.c:28
char * name
apr_size_t length
apr_off_t start
apr_bucket_alloc_t * list
void * data
#define str