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); 89static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql, 90 const char *query, const char *label, 91 int nargs, int nvals, apr_dbd_type_e *types, 92 apr_dbd_prepared_t **statement); 93static int outputParams(apr_dbd_t*, apr_dbd_prepared_t*); 94static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql, 95 apr_dbd_results_t **results, 96 apr_dbd_prepared_t *statement, 97 int seek, const char **values); 98static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql, 99 int *nrows, apr_dbd_prepared_t *statement, 100 const char **values); 101static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql, 102 apr_dbd_transaction_t **trans); 103static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans); 104 105struct apr_dbd_transaction_t { 106 int mode; 107 enum { TRANS_NONE, TRANS_ERROR, TRANS_1, TRANS_2 } status; 108 apr_dbd_t *handle; 109 OCITrans *trans; 110 OCISnapshot *snapshot1; 111 OCISnapshot *snapshot2; 112}; 113 114struct apr_dbd_results_t { 115 apr_pool_t *pool; 116 apr_dbd_t* handle; 117 unsigned int rownum; 118 int seek; 119 int nrows; 120 apr_dbd_prepared_t *statement; 121}; 122 123struct apr_dbd_t { 124 sword status; 125 OCIError *err; 126 OCIServer *svr; 127 OCISvcCtx *svc; 128 OCISession *auth; 129 apr_dbd_transaction_t* trans; 130 apr_pool_t *pool; 131 char buf[ERR_BUF_SIZE]; /* for error messages */ 132 apr_size_t long_size; 133 apr_dbd_prepared_t *check_conn_stmt; 134}; 135 136struct apr_dbd_row_t { 137 int n; 138 apr_dbd_results_t *res; 139 apr_pool_t *pool; 140}; 141 142typedef struct { 143 apr_dbd_type_e type; 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; 153 OCILobLocator *lobval; 154 } value; 155} bind_arg; 156 157typedef struct { 158 int type; 159 sb2 ind; 160 ub2 len; /* length of actual output */ 161 OCIDefine *defn; 162 apr_size_t sz; /* length of buf for output */ 163 union { 164 void *raw; 165 char *sval; 166 OCILobLocator *lobval; 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; 177 define_arg *out; 178 apr_dbd_t *handle; 179 apr_pool_t *pool; 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; 196/** 197 * A bucket referring to a Oracle BLOB/CLOB 198 */ 199struct apr_bucket_lob { 200 /** Number of buckets using this memory */ 201 apr_bucket_refcount refcount; 202 /** The row this bucket refers to */ 203 const apr_dbd_row_t *row; 204 /** The column this bucket refers to */ 205 int col; 206 /** The pool into which any needed structures should 207 * be created while reading from this bucket */ 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, 213 apr_size_t *len, apr_read_type_e block); 214static apr_bucket *apr_bucket_lob_make(apr_bucket *b, 215 const apr_dbd_row_t *row, int col, 216 apr_off_t offset, apr_size_t len, 217 apr_pool_t *p); 218static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col, 219 apr_off_t offset, 220 apr_size_t len, apr_pool_t *p, 221 apr_bucket_alloc_t *list); 222 223static const apr_bucket_type_t apr_bucket_type_lob = { 224 "LOB", 5, APR_BUCKET_DATA, 225 lob_bucket_destroy, 226 lob_bucket_read, 227 apr_bucket_setaside_notimpl, 228 apr_bucket_shared_split, 229 apr_bucket_shared_copy 230}; 231 232static void lob_bucket_destroy(void *data) 233{ 234 apr_bucket_lob *f = data; 235 236 if (apr_bucket_shared_destroy(f)) { 237 /* no need to destroy database objects here; it will get 238 * done automatically when the pool gets cleaned up */ 239 apr_bucket_free(f); 240 } 241} 242 243static apr_status_t lob_bucket_read(apr_bucket *e, const char **str, 244 apr_size_t *len, apr_read_type_e block) 245{ 246 apr_bucket_lob *a = e->data; 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 */ 252 apr_off_t boffset = e->start; 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*/ 258 ub4 length = APR_BUCKET_BUFF_SIZE; 259 char *buf = NULL; 260 261 *str = NULL; /* in case we die prematurely */ 262 263 /* fetch from offset if not at the beginning */ 264 buf = apr_palloc(row->pool, APR_BUCKET_BUFF_SIZE); 265 sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval, 266 &length, 1 + (size_t)boffset, 267 (dvoid*) buf, APR_BUCKET_BUFF_SIZE, 268 NULL, NULL, 0, SQLCS_IMPLICIT); 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; 299 APR_BUCKET_INSERT_AFTER(e, b); 300 } 301 else { 302 lob_bucket_destroy(a); 303 } 304 305 return APR_SUCCESS; 306} 307 308static apr_bucket *apr_bucket_lob_make(apr_bucket *b, 309 const apr_dbd_row_t *row, int col, 310 apr_off_t offset, apr_size_t len, 311 apr_pool_t *p) 312{ 313 apr_bucket_lob *f; 314 315 f = apr_bucket_alloc(sizeof(*f), b->list); 316 f->row = row; 317 f->col = col; 318 f->readpool = p; 319 320 b = apr_bucket_shared_make(b, f, offset, len); 321 b->type = &apr_bucket_type_lob; 322 323 return b; 324} 325 326static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col, 327 apr_off_t offset, 328 apr_size_t len, apr_pool_t *p, 329 apr_bucket_alloc_t *list) 330{ 331 apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); 332 333 APR_BUCKET_INIT(b); 334 b->free = apr_bucket_free; 335 b->list = list; 336 return apr_bucket_lob_make(b, row, col, offset, len, p); 337} 338 339static apr_status_t dbd_free_lobdesc(void *lob) 340{ 341 switch (OCIDescriptorFree(lob, OCI_DTYPE_LOB)) { 342 case OCI_SUCCESS: 343 return APR_SUCCESS; 344 default: 345 return APR_EGENERAL; 346 } 347} 348 349static apr_status_t dbd_free_snapshot(void *snap) 350{ 351 switch (OCIDescriptorFree(snap, OCI_DTYPE_SNAP)) { 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 367 OCIEnvCreate(&dbd_oracle_env, OCI_THREADED|OCI_NEW_LENGTH_SEMANTICS, 368 NULL, NULL, NULL, NULL, 0, NULL); 369#else 370 OCIEnvCreate(&dbd_oracle_env, OCI_THREADED, 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{ 379 apr_dbd_t *ret = apr_pcalloc(pool, sizeof(apr_dbd_t)); 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); 425 vlen = strcspn(value, delims); 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, 436 OCI_HTYPE_ERROR, 0, NULL); 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, 450 OCI_HTYPE_SERVER, 0, NULL); 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) { 460 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 461 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 462 ERR_BUF_SIZE, OCI_HTYPE_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, 471 OCI_HTYPE_SVCCTX, 0, NULL); 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) { 481 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 482 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 483 ERR_BUF_SIZE, OCI_HTYPE_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) { 506 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 507 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 508 ERR_BUF_SIZE, OCI_HTYPE_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) { 527 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 528 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 529 ERR_BUF_SIZE, OCI_HTYPE_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) { 547 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 548 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 549 ERR_BUF_SIZE, OCI_HTYPE_ERROR); 550 } 551 return NULL; 552#endif 553 case OCI_SUCCESS: 554 break; 555 } 556 ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->auth, 557 OCI_HTYPE_SESSION, 0, NULL); 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) { 567 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 568 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 569 ERR_BUF_SIZE, OCI_HTYPE_ERROR); 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) { 587 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 588 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 589 ERR_BUF_SIZE, OCI_HTYPE_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) { 607 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 608 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 609 ERR_BUF_SIZE, OCI_HTYPE_ERROR); 610 } 611 return NULL; 612#endif 613 case OCI_SUCCESS: 614 break; 615 } 616 ret->status = OCISessionBegin(ret->svc, ret->err, ret->auth, 617 OCI_CRED_RDBMS, OCI_DEFAULT); 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) { 627 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 628 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 629 ERR_BUF_SIZE, OCI_HTYPE_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) { 646 *error = apr_pcalloc(pool, ERR_BUF_SIZE); 647 OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), 648 ERR_BUF_SIZE, OCI_HTYPE_ERROR); 649 } 650 return NULL; 651#endif 652 break; 653 case OCI_SUCCESS: 654 break; 655 } 656#endif 657 658 if(dbd_oracle_prepare(pool, ret, CHECK_CONN_QUERY, NULL, 0, 0, NULL, 659 &ret->check_conn_stmt) != 0) { 660 return NULL; 661 } 662 663 return ret; 664} 665 666#ifdef EXPORT_NATIVE_FUNCS 667static apr_size_t dbd_oracle_long_size_set(apr_dbd_t *sql, 668 apr_size_t long_size) 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 686static int dbd_oracle_get_row(apr_pool_t *pool, apr_dbd_results_t *res, 687 apr_dbd_row_t **rowp, int rownum) 688{ 689 apr_dbd_row_t *row = *rowp; 690 apr_dbd_t *sql = res->handle; 691 int_errorcode; 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, 712 OCI_FETCH_ABSOLUTE, row->n, OCI_DEFAULT); 713 } 714 else { 715 sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1, 716 OCI_FETCH_NEXT, 0, OCI_DEFAULT); 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 */ 742 sb4 errorcode; 743 744 switch (sql->status) { 745 case OCI_SUCCESS: 746 return "OCI_SUCCESS"; 747 case OCI_SUCCESS_WITH_INFO: 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"; 753 case OCI_INVALID_HANDLE: 754 return "OCI_INVALID_HANDLE"; 755 case OCI_STILL_EXECUTING: 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 770static apr_status_t freeStatement(void *statement) 771{ 772 int rv = APR_SUCCESS; 773 OCIStmt *stmt = ((apr_dbd_prepared_t*)statement)->stmt; 774 775#ifdef PREPARE2 776 OCIError *err; 777 778 if (OCIHandleAlloc(dbd_oracle_env, (dvoid**)&err, OCI_HTYPE_ERROR, 779 0, NULL) != OCI_SUCCESS) { 780 return APR_EGENERAL; 781 } 782 if (OCIStmtRelease(stmt, err, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS) { 783 rv = APR_EGENERAL; 784 } 785 if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) { 786 rv = APR_EGENERAL; 787 } 788#else 789 if (OCIHandleFree(stmt, OCI_HTYPE_STMT) != OCI_SUCCESS) { 790 rv = APR_EGENERAL; 791 } 792#endif 793 794 return rv; 795} 796 797static int dbd_oracle_select(apr_pool_t *pool, apr_dbd_t *sql, 798 apr_dbd_results_t **results, 799 const char *query, int seek) 800{ 801 int ret = 0; 802 apr_dbd_prepared_t *statement = NULL; 803 804 ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement); 805 if (ret != 0) { 806 return ret; 807 } 808 809 ret = dbd_oracle_pselect(pool, sql, results, statement, seek, NULL); 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; 820 apr_pool_t *pool; 821 apr_dbd_prepared_t *statement = NULL; 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 833 ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement); 834 if (ret == 0) { 835 ret = dbd_oracle_pquery(pool, sql, nrows, statement, NULL); 836 if (ret == 0) { 837 sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, 838 nrows, 0, OCI_ATTR_ROW_COUNT, 839 sql->err); 840 } 841 } 842 843 apr_pool_destroy(pool); 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 854static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql, 855 const char *query, const char *label, 856 int nargs, int nvals, apr_dbd_type_e *types, 857 apr_dbd_prepared_t **statement) 858{ 859 int ret = 0; 860 int i; 861 apr_dbd_prepared_t *stmt ; 862 863 if (*statement == NULL) { 864 *statement = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t)); 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, 887 strlen(query), OCI_NTV_SYNTAX, OCI_DEFAULT); 888 if (sql->status != OCI_SUCCESS) { 889 OCIHandleFree(stmt->stmt, OCI_HTYPE_STMT); 890 return 1; 891 } 892 893 apr_pool_cleanup_register(pool, stmt, freeStatement, 894 apr_pool_cleanup_null); 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 905 sql->status = OCIAttrSet(stmt->stmt, OCI_HTYPE_STMT, &prefetch_size, 906 sizeof(prefetch_size), OCI_ATTR_PREFETCH_MEMORY, 907 sql->err); 908 if (sql->status != OCI_SUCCESS) { 909 return 1; 910 } 911#endif 912 913 if (stmt->type == OCI_STMT_SELECT) { 914 ret = outputParams(sql, stmt); 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) { 937 case APR_DBD_TYPE_BLOB: 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, 947 data, size, SQLT_LBI, 948 &statement->args[i].ind, 949 NULL, 950 (ub2) 0, (ub4) 0, 951 (ub4 *) 0, OCI_DEFAULT); 952 } 953 break; 954 case APR_DBD_TYPE_CLOB: 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, 964 data, size, SQLT_LNG, 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 993static int outputParams(apr_dbd_t *sql, apr_dbd_prepared_t *stmt) 994{ 995 OCIParam *parms; 996 int i; 997 ub2 paramtype[DBD_ORACLE_MAX_COLUMNS]; 998 ub2 paramsize[DBD_ORACLE_MAX_COLUMNS]; 999 char *paramname[DBD_ORACLE_MAX_COLUMNS]; 1000 ub4 paramnamelen[DBD_ORACLE_MAX_COLUMNS]; 1001 int_errorcode; 1002 1003 /* Perl uses 0 where we used 1 */ 1004 sql->status = OCIStmtExecute(sql->svc, stmt->stmt, sql->err, 0, 0, 1005 NULL, NULL, OCI_DESCRIBE_ONLY); 1006 switch (sql->status) { 1007 case OCI_SUCCESS: 1008 case OCI_SUCCESS_WITH_INFO: 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: 1024 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM, 1025 ¶mtype[stmt->nout], 1026 0, OCI_ATTR_DATA_TYPE, sql->err); 1027 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM, 1028 ¶msize[stmt->nout], 1029 0, OCI_ATTR_DATA_SIZE, sql->err); 1030 sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM, 1031 ¶mname[stmt->nout], 1032 ¶mnamelen[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, 1052 paramname[i], paramnamelen[i]); 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*/ 1118 sql->status = OCIDescriptorAlloc(dbd_oracle_env, 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, 1122 dbd_free_lobdesc, 1123 apr_pool_cleanup_null); 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 1142static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql, 1143 int *nrows, apr_dbd_prepared_t *statement, 1144 const char **values) 1145{ 1146 OCISnapshot *oldsnapshot = NULL; 1147 OCISnapshot *newsnapshot = NULL; 1148 apr_dbd_transaction_t* trans = sql->trans; 1149 int exec_mode; 1150 int_errorcode; 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 } 1170 exec_mode = OCI_DEFAULT; 1171 } 1172 else { 1173 exec_mode = OCI_COMMIT_ON_SUCCESS; 1174 } 1175 1176 dbd_oracle_bind(statement, values); 1177 1178 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0, 1179 oldsnapshot, newsnapshot, exec_mode); 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 1202static int dbd_oracle_pvquery(apr_pool_t *pool, apr_dbd_t *sql, 1203 int *nrows, apr_dbd_prepared_t *statement, 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 1219 return dbd_oracle_pquery(pool, sql, nrows, statement, values); 1220} 1221 1222static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql, 1223 apr_dbd_results_t **results, 1224 apr_dbd_prepared_t *statement, 1225 int seek, const char **values) 1226{ 1227 int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT; 1228 OCISnapshot *oldsnapshot = NULL; 1229 OCISnapshot *newsnapshot = NULL; 1230 apr_dbd_transaction_t* trans = sql->trans; 1231 int_errorcode; 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 1253 dbd_oracle_bind(statement, values); 1254 1255 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0, 1256 oldsnapshot, newsnapshot, exec_mode); 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 1286static int dbd_oracle_pvselect(apr_pool_t *pool, apr_dbd_t *sql, 1287 apr_dbd_results_t **results, 1288 apr_dbd_prepared_t *statement, 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 1307static void dbd_oracle_bbind(apr_dbd_prepared_t * statement, 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; 1314 apr_dbd_type_e type; 1315 1316 for (i = 0, j = 0; i < statement->nargs; i++, j++) { 1317 type = (values[j] == NULL ? APR_DBD_TYPE_NULL 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; 1354 case APR_DBD_TYPE_USHORT: 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; 1412 case APR_DBD_TYPE_LONGLONG: 1413 statement->args[i].value.sval = 1414 apr_psprintf(statement->pool, "%" APR_INT64_T_FMT, 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; 1425 case APR_DBD_TYPE_ULONGLONG: 1426 statement->args[i].value.sval = 1427 apr_psprintf(statement->pool, "%" APR_UINT64_T_FMT, 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; 1449 case APR_DBD_TYPE_DOUBLE: 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; 1460 case APR_DBD_TYPE_STRING: 1461 case APR_DBD_TYPE_TEXT: 1462 case APR_DBD_TYPE_TIME: 1463 case APR_DBD_TYPE_DATE: 1464 case APR_DBD_TYPE_DATETIME: 1465 case APR_DBD_TYPE_TIMESTAMP: 1466 case APR_DBD_TYPE_ZTIMESTAMP: 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 1529static int dbd_oracle_pbquery(apr_pool_t * pool, apr_dbd_t * sql, 1530 int *nrows, apr_dbd_prepared_t * statement, 1531 const void **values) 1532{ 1533 OCISnapshot *oldsnapshot = NULL; 1534 OCISnapshot *newsnapshot = NULL; 1535 apr_dbd_transaction_t* trans = sql->trans; 1536 int exec_mode; 1537 int_errorcode; 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 } 1557 exec_mode = OCI_DEFAULT; 1558 } 1559 else { 1560 exec_mode = OCI_COMMIT_ON_SUCCESS; 1561 } 1562 1563 dbd_oracle_bbind(statement, values); 1564 1565 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0, 1566 oldsnapshot, newsnapshot, exec_mode); 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 1589static int dbd_oracle_pvbquery(apr_pool_t * pool, apr_dbd_t * sql, 1590 int *nrows, apr_dbd_prepared_t * statement, 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 1606 return dbd_oracle_pbquery(pool, sql, nrows, statement, values); 1607} 1608 1609static int dbd_oracle_pbselect(apr_pool_t * pool, apr_dbd_t * sql, 1610 apr_dbd_results_t ** results, 1611 apr_dbd_prepared_t * statement, 1612 int seek, const void **values) 1613{ 1614 int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT; 1615 OCISnapshot *oldsnapshot = NULL; 1616 OCISnapshot *newsnapshot = NULL; 1617 apr_dbd_transaction_t* trans = sql->trans; 1618 int_errorcode; 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 1640 dbd_oracle_bbind(statement, values); 1641 1642 sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0, 1643 oldsnapshot, newsnapshot, exec_mode); 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 1673static int dbd_oracle_pvbselect(apr_pool_t * pool, apr_dbd_t * sql, 1674 apr_dbd_results_t ** results, 1675 apr_dbd_prepared_t * statement, int seek, 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 1694static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql, 1695 apr_dbd_transaction_t **trans) 1696{ 1697 int ret = 0; 1698 int_errorcode; 1699 if (*trans) { 1700 dbd_oracle_end_transaction(*trans); 1701 } 1702 else { 1703 *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); 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, 1712 OCI_TRANS_NEW); 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; 1726 switch (OCIDescriptorAlloc(dbd_oracle_env, 1727 (dvoid**)&(*trans)->snapshot1, 1728 OCI_DTYPE_SNAP, 0, NULL)) { 1729 case OCI_SUCCESS: 1730 apr_pool_cleanup_register(pool, (*trans)->snapshot1, 1731 dbd_free_snapshot, apr_pool_cleanup_null); 1732 break; 1733 case OCI_INVALID_HANDLE: 1734 ret = 1; 1735 break; 1736 } 1737 switch (OCIDescriptorAlloc(dbd_oracle_env, 1738 (dvoid**)&(*trans)->snapshot2, 1739 OCI_DTYPE_SNAP, 0, NULL)) { 1740 case OCI_SUCCESS: 1741 apr_pool_cleanup_register(pool, (*trans)->snapshot2, 1742 dbd_free_snapshot, apr_pool_cleanup_null); 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 1756static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans) 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: 1767 status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT); 1768 break; 1769 default: 1770 /* rollback on explicit rollback request */ 1771 if (TXN_DO_ROLLBACK(trans)) { 1772 status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT); 1773 } else { 1774 status = OCITransCommit(handle->svc, handle->err, OCI_DEFAULT); 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 1793static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t *trans) 1794{ 1795 if (!trans) 1796 return APR_DBD_TRANSACTION_COMMIT; 1797 1798 return trans->mode; 1799} 1800 1801static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t *trans, 1802 int mode) 1803{ 1804 if (!trans) 1805 return APR_DBD_TRANSACTION_COMMIT; 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; 1822 int_errorcode; 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: 1835 case OCI_SUCCESS_WITH_INFO: 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: 1866 case OCI_SUCCESS_WITH_INFO: 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: 1902 case OCI_SUCCESS_WITH_INFO: 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()? */ 1932static apr_status_t dbd_oracle_datum_get(const apr_dbd_row_t *row, int n, 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; 1968 case APR_DBD_TYPE_USHORT: 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; 2003 case APR_DBD_TYPE_LONGLONG: 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; 2010 case APR_DBD_TYPE_ULONGLONG: 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; 2024 case APR_DBD_TYPE_DOUBLE: 2025 entry = dbd_oracle_get_entry(row, n); 2026 if (entry == NULL) { 2027 return APR_ENOENT; 2028 } 2029 *(double*)data = atof(entry); 2030 break; 2031 case APR_DBD_TYPE_STRING: 2032 case APR_DBD_TYPE_TEXT: 2033 case APR_DBD_TYPE_TIME: 2034 case APR_DBD_TYPE_DATE: 2035 case APR_DBD_TYPE_DATETIME: 2036 case APR_DBD_TYPE_TIMESTAMP: 2037 case APR_DBD_TYPE_ZTIMESTAMP: 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; 2048 apr_bucket_brigade *b = (apr_bucket_brigade*)data; 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: 2059 case OCI_SUCCESS_WITH_INFO: 2060 if (len == 0) { 2061 e = apr_bucket_eos_create(b->bucket_alloc); 2062 } 2063 else { 2064 e = apr_bucket_lob_create(row, n, 0, len, 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 } 2081 APR_BRIGADE_INSERT_TAIL(b, e); 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 2094static apr_status_t dbd_oracle_close(apr_dbd_t *handle) 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 2132static apr_status_t dbd_oracle_check_conn(apr_pool_t *pool, apr_dbd_t *sql) 2133{ 2134 apr_dbd_results_t *res = NULL; 2135 apr_dbd_row_t *row = NULL; 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 2153static int dbd_oracle_select_db(apr_pool_t *pool, apr_dbd_t *handle, 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 2168static int dbd_oracle_num_cols(apr_dbd_results_t* res) 2169{ 2170 return res->statement->nout; 2171} 2172 2173static int dbd_oracle_num_tuples(apr_dbd_results_t* res) 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 2187APU_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_oracle_driver = { 2188 "oracle", 2189 dbd_oracle_init, 2190 dbd_oracle_native, 2191 dbd_oracle_open, 2192 dbd_oracle_check_conn, 2193 dbd_oracle_close, 2194 dbd_oracle_select_db, 2195 dbd_oracle_start_transaction, 2196 dbd_oracle_end_transaction, 2197 dbd_oracle_query, 2198 dbd_oracle_select, 2199 dbd_oracle_num_cols, 2200 dbd_oracle_num_tuples, 2201 dbd_oracle_get_row, 2202 dbd_oracle_get_entry, 2203 dbd_oracle_error, 2204 dbd_oracle_escape, 2205 dbd_oracle_prepare, 2206 dbd_oracle_pvquery, 2207 dbd_oracle_pvselect, 2208 dbd_oracle_pquery, 2209 dbd_oracle_pselect, 2210 dbd_oracle_get_name, 2211 dbd_oracle_transaction_mode_get, 2212 dbd_oracle_transaction_mode_set, 2213 ":apr%d", 2214 dbd_oracle_pvbquery, 2215 dbd_oracle_pvbselect, 2216 dbd_oracle_pbquery, 2217 dbd_oracle_pbselect, 2218 dbd_oracle_datum_get 2219}; 2220#endif 2221