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#include "apu.h" 18#if APU_HAVE_ODBC 19 20#include "apr.h" 21#include "apr_strings.h" 22#include "apr_buckets.h" 23#include "apr_env.h" 24#include "apr_file_io.h" 25#include "apr_file_info.h" 26#include "apr_dbd_internal.h" 27#include "apr_thread_proc.h" 28#include "apu_version.h" 29#include "apu_config.h" 30 31#include <stdlib.h> 32 33/* If library is ODBC-V2, use macros for limited ODBC-V2 support 34 * No random access in V2. 35 */ 36#ifdef ODBCV2 37#define ODBCVER 0x0200 38#include "apr_dbd_odbc_v2.h" 39#endif 40 41/* standard ODBC include files */ 42#ifdef HAVE_SQL_H 43#include <sql.h> 44#include <sqlext.h> 45#elif defined(HAVE_ODBC_SQL_H) 46#include <odbc/sql.h> 47#include <odbc/sqlext.h> 48#endif 49 50/* Driver name is "odbc" and the entry point is 'apr_dbd_odbc_driver' 51 * unless ODBC_DRIVER_NAME is defined and it is linked with another db library which 52 * is ODBC source-compatible. e.g. DB2, Informix, TimesTen, mysql. 53 */ 54#ifndef ODBC_DRIVER_NAME 55#define ODBC_DRIVER_NAME odbc 56#endif 57#define STRINGIFY(x) #x 58#define NAMIFY2(n) apr_dbd_##n##_driver 59#define NAMIFY1(n) NAMIFY2(n) 60#define ODBC_DRIVER_STRING STRINGIFY(ODBC_DRIVER_NAME) 61#define ODBC_DRIVER_ENTRY NAMIFY1(ODBC_DRIVER_NAME) 62 63/* Required APR version for this driver */ 64#define DRIVER_APU_VERSION_MAJOR APU_MAJOR_VERSION 65#define DRIVER_APU_VERSION_MINOR APU_MINOR_VERSION 66 67static SQLHANDLE henv = NULL; /* ODBC ENV handle is process-wide */ 68 69/* Use a CHECK_ERROR macro so we can grab the source line numbers 70 * for error reports 71 */ 72static void check_error(apr_dbd_t *a, const char *step, SQLRETURN rc, 73 SQLSMALLINT type, SQLHANDLE h, int line); 74#define CHECK_ERROR(a,s,r,t,h) check_error(a,s,r,t,h, __LINE__) 75 76#define SOURCE_FILE __FILE__ /* source file for error messages */ 77#define MAX_ERROR_STRING 1024 /* max length of message in dbc */ 78#define MAX_COLUMN_NAME 256 /* longest column name recognized */ 79#define DEFAULT_BUFFER_SIZE 1024 /* value for defaultBufferSize */ 80 81#define MAX_PARAMS 20 82#define DEFAULTSEPS " \t\r\n,=" 83#define CSINGLEQUOTE '\'' 84#define SSINGLEQUOTE "\'" 85 86#define TEXTMODE 1 /* used for text (APR 1.2) mode params */ 87#define BINARYMODE 0 /* used for binary (APR 1.3+) mode params */ 88 89/* Identify datatypes which are LOBs 90 * - DB2 DRDA driver uses undefined types -98 and -99 for CLOB & BLOB 91 */ 92#define IS_LOB(t) (t == SQL_LONGVARCHAR \ 93 || t == SQL_LONGVARBINARY || t == SQL_VARBINARY \ 94 || t == -98 || t == -99) 95 96/* These types are CLOBs 97 * - DB2 DRDA driver uses undefined type -98 for CLOB 98 */ 99#define IS_CLOB(t) \ 100 (t == SQL_LONGVARCHAR || t == -98) 101 102/* Convert a SQL result to an APR result */ 103#define APR_FROM_SQL_RESULT(rc) \ 104 (SQL_SUCCEEDED(rc) ? APR_SUCCESS : APR_EGENERAL) 105 106/* DBD opaque structures */ 107struct apr_dbd_t 108{ 109 SQLHANDLE dbc; /* SQL connection handle - NULL after close */ 110 apr_pool_t *pool; /* connection lifetime pool */ 111 char *dbname; /* ODBC datasource */ 112 int lasterrorcode; 113 int lineNumber; 114 char lastError[MAX_ERROR_STRING]; 115 int defaultBufferSize; /* used for CLOBs in text mode, 116 * and when fld size is indeterminate */ 117 intptr_t transaction_mode; 118 intptr_t dboptions; /* driver options re SQLGetData */ 119 intptr_t default_transaction_mode; 120 int can_commit; /* controls end_trans behavior */ 121}; 122 123struct apr_dbd_results_t 124{ 125 SQLHANDLE stmt; /* parent sql statement handle */ 126 SQLHANDLE dbc; /* parent sql connection handle */ 127 apr_pool_t *pool; /* pool from query or select */ 128 apr_dbd_t *apr_dbd; /* parent DBD connection handle */ 129 int random; /* random access requested */ 130 int ncols; /* number of columns */ 131 int isclosed; /* cursor has been closed */ 132 char **colnames; /* array of column names (NULL until used) */ 133 SQLPOINTER *colptrs; /* pointers to column data */ 134 SQLINTEGER *colsizes; /* sizes for columns (enough for txt or bin) */ 135 SQLINTEGER *coltextsizes; /* max-sizes if converted to text */ 136 SQLSMALLINT *coltypes; /* array of SQL data types for columns */ 137 SQLLEN *colinds; /* array of SQL data indicator/strlens */ 138 int *colstate; /* array of column states 139 * - avail, bound, present, unavail 140 */ 141 int *all_data_fetched; /* flags data as all fetched, for LOBs */ 142 void *data; /* buffer for all data for one row */ 143}; 144 145enum /* results column states */ 146{ 147 COL_AVAIL, /* data may be retrieved with SQLGetData */ 148 COL_PRESENT, /* data has been retrieved with SQLGetData */ 149 COL_BOUND, /* column is bound to colptr */ 150 COL_RETRIEVED, /* all data from column has been returned */ 151 COL_UNAVAIL /* column is unavailable because ODBC driver 152 * requires that columns be retrieved 153 * in ascending order and a higher col 154 * was accessed 155 */ 156}; 157 158struct apr_dbd_row_t { 159 SQLHANDLE stmt; /* parent ODBC statement handle */ 160 SQLHANDLE dbc; /* parent ODBC connection handle */ 161 apr_pool_t *pool; /* pool from get_row */ 162 apr_dbd_results_t *res; 163}; 164 165struct apr_dbd_transaction_t { 166 SQLHANDLE dbc; /* parent ODBC connection handle */ 167 apr_dbd_t *apr_dbd; /* parent DBD connection handle */ 168}; 169 170struct apr_dbd_prepared_t { 171 SQLHANDLE stmt; /* ODBC statement handle */ 172 SQLHANDLE dbc; /* parent ODBC connection handle */ 173 apr_dbd_t *apr_dbd; 174 int nargs; 175 int nvals; 176 int *types; /* array of DBD data types */ 177}; 178 179static void odbc_lob_bucket_destroy(void *data); 180static apr_status_t odbc_lob_bucket_setaside(apr_bucket *e, apr_pool_t *pool); 181static apr_status_t odbc_lob_bucket_read(apr_bucket *e, const char **str, 182 apr_size_t *len, apr_read_type_e block); 183 184/* the ODBC LOB bucket type */ 185static const apr_bucket_type_t odbc_bucket_type = { 186 "ODBC_LOB", 5, APR_BUCKET_DATA, 187 odbc_lob_bucket_destroy, 188 odbc_lob_bucket_read, 189 odbc_lob_bucket_setaside, 190 apr_bucket_shared_split, 191 apr_bucket_shared_copy 192}; 193 194/* ODBC LOB bucket data */ 195typedef struct { 196 /** Ref count for shared bucket */ 197 apr_bucket_refcount refcount; 198 const apr_dbd_row_t *row; 199 int col; 200 SQLSMALLINT type; 201} odbc_bucket; 202 203/* SQL datatype mappings to DBD datatypes 204 * These tables must correspond *exactly* to the apr_dbd_type_e enum 205 * in apr_dbd.h 206 */ 207 208/* ODBC "C" types to DBD datatypes */ 209static SQLSMALLINT const sqlCtype[] = { 210 SQL_C_DEFAULT, /* APR_DBD_TYPE_NONE */ 211 SQL_C_STINYINT, /* APR_DBD_TYPE_TINY, \%hhd */ 212 SQL_C_UTINYINT, /* APR_DBD_TYPE_UTINY, \%hhu */ 213 SQL_C_SSHORT, /* APR_DBD_TYPE_SHORT, \%hd */ 214 SQL_C_USHORT, /* APR_DBD_TYPE_USHORT, \%hu */ 215 SQL_C_SLONG, /* APR_DBD_TYPE_INT, \%d */ 216 SQL_C_ULONG, /* APR_DBD_TYPE_UINT, \%u */ 217 SQL_C_SLONG, /* APR_DBD_TYPE_LONG, \%ld */ 218 SQL_C_ULONG, /* APR_DBD_TYPE_ULONG, \%lu */ 219 SQL_C_SBIGINT, /* APR_DBD_TYPE_LONGLONG, \%lld */ 220 SQL_C_UBIGINT, /* APR_DBD_TYPE_ULONGLONG, \%llu */ 221 SQL_C_FLOAT, /* APR_DBD_TYPE_FLOAT, \%f */ 222 SQL_C_DOUBLE, /* APR_DBD_TYPE_DOUBLE, \%lf */ 223 SQL_C_CHAR, /* APR_DBD_TYPE_STRING, \%s */ 224 SQL_C_CHAR, /* APR_DBD_TYPE_TEXT, \%pDt */ 225 SQL_C_CHAR, /*SQL_C_TYPE_TIME, APR_DBD_TYPE_TIME, \%pDi */ 226 SQL_C_CHAR, /*SQL_C_TYPE_DATE, APR_DBD_TYPE_DATE, \%pDd */ 227 SQL_C_CHAR, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_DATETIME, \%pDa */ 228 SQL_C_CHAR, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_TIMESTAMP, \%pDs */ 229 SQL_C_CHAR, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_ZTIMESTAMP, \%pDz */ 230 SQL_LONGVARBINARY, /* APR_DBD_TYPE_BLOB, \%pDb */ 231 SQL_LONGVARCHAR, /* APR_DBD_TYPE_CLOB, \%pDc */ 232 SQL_TYPE_NULL /* APR_DBD_TYPE_NULL \%pDn */ 233}; 234#define NUM_APR_DBD_TYPES (sizeof(sqlCtype) / sizeof(sqlCtype[0])) 235 236/* ODBC Base types to DBD datatypes */ 237static SQLSMALLINT const sqlBaseType[] = { 238 SQL_C_DEFAULT, /* APR_DBD_TYPE_NONE */ 239 SQL_TINYINT, /* APR_DBD_TYPE_TINY, \%hhd */ 240 SQL_TINYINT, /* APR_DBD_TYPE_UTINY, \%hhu */ 241 SQL_SMALLINT, /* APR_DBD_TYPE_SHORT, \%hd */ 242 SQL_SMALLINT, /* APR_DBD_TYPE_USHORT, \%hu */ 243 SQL_INTEGER, /* APR_DBD_TYPE_INT, \%d */ 244 SQL_INTEGER, /* APR_DBD_TYPE_UINT, \%u */ 245 SQL_INTEGER, /* APR_DBD_TYPE_LONG, \%ld */ 246 SQL_INTEGER, /* APR_DBD_TYPE_ULONG, \%lu */ 247 SQL_BIGINT, /* APR_DBD_TYPE_LONGLONG, \%lld */ 248 SQL_BIGINT, /* APR_DBD_TYPE_ULONGLONG, \%llu */ 249 SQL_FLOAT, /* APR_DBD_TYPE_FLOAT, \%f */ 250 SQL_DOUBLE, /* APR_DBD_TYPE_DOUBLE, \%lf */ 251 SQL_CHAR, /* APR_DBD_TYPE_STRING, \%s */ 252 SQL_CHAR, /* APR_DBD_TYPE_TEXT, \%pDt */ 253 SQL_CHAR, /*SQL_TIME, APR_DBD_TYPE_TIME, \%pDi */ 254 SQL_CHAR, /*SQL_DATE, APR_DBD_TYPE_DATE, \%pDd */ 255 SQL_CHAR, /*SQL_TIMESTAMP, APR_DBD_TYPE_DATETIME, \%pDa */ 256 SQL_CHAR, /*SQL_TIMESTAMP, APR_DBD_TYPE_TIMESTAMP, \%pDs */ 257 SQL_CHAR, /*SQL_TIMESTAMP, APR_DBD_TYPE_ZTIMESTAMP, \%pDz */ 258 SQL_LONGVARBINARY, /* APR_DBD_TYPE_BLOB, \%pDb */ 259 SQL_LONGVARCHAR, /* APR_DBD_TYPE_CLOB, \%pDc */ 260 SQL_TYPE_NULL /* APR_DBD_TYPE_NULL \%pDn */ 261}; 262 263/* result sizes for DBD datatypes (-1 for null-terminated) */ 264static int const sqlSizes[] = { 265 0, 266 sizeof(char), /**< \%hhd out: char* */ 267 sizeof(unsigned char), /**< \%hhu out: unsigned char* */ 268 sizeof(short), /**< \%hd out: short* */ 269 sizeof(unsigned short), /**< \%hu out: unsigned short* */ 270 sizeof(int), /**< \%d out: int* */ 271 sizeof(unsigned int), /**< \%u out: unsigned int* */ 272 sizeof(long), /**< \%ld out: long* */ 273 sizeof(unsigned long), /**< \%lu out: unsigned long* */ 274 sizeof(apr_int64_t), /**< \%lld out: apr_int64_t* */ 275 sizeof(apr_uint64_t), /**< \%llu out: apr_uint64_t* */ 276 sizeof(float), /**< \%f out: float* */ 277 sizeof(double), /**< \%lf out: double* */ 278 -1, /**< \%s out: char** */ 279 -1, /**< \%pDt out: char** */ 280 -1, /**< \%pDi out: char** */ 281 -1, /**< \%pDd out: char** */ 282 -1, /**< \%pDa out: char** */ 283 -1, /**< \%pDs out: char** */ 284 -1, /**< \%pDz out: char** */ 285 sizeof(apr_bucket_brigade), /**< \%pDb out: apr_bucket_brigade* */ 286 sizeof(apr_bucket_brigade), /**< \%pDc out: apr_bucket_brigade* */ 287 0 /**< \%pDn : in: void*, out: void** */ 288}; 289 290/* 291 * local functions 292 */ 293 294/* close any open results for the connection */ 295static apr_status_t odbc_close_results(void *d) 296{ 297 apr_dbd_results_t *dbr = (apr_dbd_results_t *)d; 298 SQLRETURN rc = SQL_SUCCESS; 299 300 if (dbr && dbr->apr_dbd && dbr->apr_dbd->dbc) { 301 if (!dbr->isclosed) 302 rc = SQLCloseCursor(dbr->stmt); 303 dbr->isclosed = 1; 304 } 305 return APR_FROM_SQL_RESULT(rc); 306} 307 308/* close the ODBC statement handle from a prepare */ 309static apr_status_t odbc_close_pstmt(void *s) 310{ 311 SQLRETURN rc = APR_SUCCESS; 312 apr_dbd_prepared_t *statement = s; 313 314 /* stmt is closed if connection has already been closed */ 315 if (statement) { 316 SQLHANDLE hstmt = statement->stmt; 317 318 if (hstmt && statement->apr_dbd && statement->apr_dbd->dbc) { 319 rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); 320 } 321 statement->stmt = NULL; 322 } 323 return APR_FROM_SQL_RESULT(rc); 324} 325 326/* close: close/release a connection obtained from open() */ 327static apr_status_t odbc_close(apr_dbd_t *handle) 328{ 329 SQLRETURN rc = SQL_SUCCESS; 330 331 if (handle->dbc) { 332 rc = SQLDisconnect(handle->dbc); 333 CHECK_ERROR(handle, "SQLDisconnect", rc, SQL_HANDLE_DBC, handle->dbc); 334 rc = SQLFreeHandle(SQL_HANDLE_DBC, handle->dbc); 335 CHECK_ERROR(handle, "SQLFreeHandle (DBC)", rc, SQL_HANDLE_ENV, henv); 336 handle->dbc = NULL; 337 } 338 return APR_FROM_SQL_RESULT(rc); 339} 340 341/* odbc_close re-defined for passing to pool cleanup */ 342static apr_status_t odbc_close_cleanup(void *handle) 343{ 344 return odbc_close((apr_dbd_t *)handle); 345} 346 347/* close the ODBC environment handle at process termination */ 348static apr_status_t odbc_close_env(SQLHANDLE henv) 349{ 350 SQLRETURN rc; 351 352 rc = SQLFreeHandle(SQL_HANDLE_ENV, henv); 353 henv = NULL; 354 return APR_FROM_SQL_RESULT(rc); 355} 356 357/* setup the arrays in results for all the returned columns */ 358static SQLRETURN odbc_set_result_column(int icol, apr_dbd_results_t *res, 359 SQLHANDLE stmt) 360{ 361 SQLRETURN rc; 362 intptr_t maxsize, textsize, realsize, type, isunsigned = 1; 363 364 /* discover the sql type */ 365 rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_UNSIGNED, NULL, 0, NULL, 366 (SQLPOINTER)&isunsigned); 367 isunsigned = (isunsigned == SQL_TRUE); 368 369 rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_TYPE, NULL, 0, NULL, 370 (SQLPOINTER)&type); 371 if (!SQL_SUCCEEDED(rc) || type == SQL_UNKNOWN_TYPE) { 372 /* MANY ODBC v2 datasources only supply CONCISE_TYPE */ 373 rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_CONCISE_TYPE, NULL, 374 0, NULL, (SQLPOINTER)&type); 375 } 376 377 if (!SQL_SUCCEEDED(rc)) { 378 /* if still unknown make it CHAR */ 379 type = SQL_C_CHAR; 380 } 381 382 switch (type) { 383 case SQL_INTEGER: 384 case SQL_SMALLINT: 385 case SQL_TINYINT: 386 case SQL_BIGINT: 387 /* fix these numeric binary types up as signed/unsigned for C types */ 388 type += (isunsigned) ? SQL_UNSIGNED_OFFSET : SQL_SIGNED_OFFSET; 389 break; 390 /* LOB types are not changed to C types */ 391 case SQL_LONGVARCHAR: 392 type = SQL_LONGVARCHAR; 393 break; 394 case SQL_LONGVARBINARY: 395 type = SQL_LONGVARBINARY; 396 break; 397 case SQL_FLOAT : 398 type = SQL_C_FLOAT; 399 break; 400 case SQL_DOUBLE : 401 type = SQL_C_DOUBLE; 402 break; 403 404 /* DBD wants times as strings */ 405 case SQL_TIMESTAMP: 406 case SQL_DATE: 407 case SQL_TIME: 408 default: 409 type = SQL_C_CHAR; 410 } 411 412 res->coltypes[icol] = (SQLSMALLINT)type; 413 414 /* size if retrieved as text */ 415 rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, 416 NULL, (SQLPOINTER)&textsize); 417 if (!SQL_SUCCEEDED(rc) || textsize < 0) { 418 textsize = res->apr_dbd->defaultBufferSize; 419 } 420 /* for null-term, which sometimes isn't included */ 421 textsize++; 422 423 /* real size */ 424 rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, 425 NULL, (SQLPOINTER)&realsize); 426 if (!SQL_SUCCEEDED(rc)) { 427 realsize = textsize; 428 } 429 430 maxsize = (textsize > realsize) ? textsize : realsize; 431 if (IS_LOB(type) || maxsize <= 0) { 432 /* LOB types are never bound and have a NULL colptr for binary. 433 * Ingore their real (1-2gb) length & use a default - the larger 434 * of defaultBufferSize or APR_BUCKET_BUFF_SIZE. 435 * If not a LOB, but simply unknown length - always use defaultBufferSize. 436 */ 437 maxsize = res->apr_dbd->defaultBufferSize; 438 if (IS_LOB(type) && maxsize < APR_BUCKET_BUFF_SIZE) { 439 maxsize = APR_BUCKET_BUFF_SIZE; 440 } 441 442 res->colptrs[icol] = NULL; 443 res->colstate[icol] = COL_AVAIL; 444 res->colsizes[icol] = (SQLINTEGER)maxsize; 445 rc = SQL_SUCCESS; 446 } 447 else { 448 res->colptrs[icol] = apr_pcalloc(res->pool, maxsize); 449 res->colsizes[icol] = (SQLINTEGER)maxsize; 450 if (res->apr_dbd->dboptions & SQL_GD_BOUND) { 451 /* we are allowed to call SQLGetData if we need to */ 452 rc = SQLBindCol(stmt, icol + 1, res->coltypes[icol], 453 res->colptrs[icol], maxsize, 454 &(res->colinds[icol])); 455 CHECK_ERROR(res->apr_dbd, "SQLBindCol", rc, SQL_HANDLE_STMT, 456 stmt); 457 res->colstate[icol] = SQL_SUCCEEDED(rc) ? COL_BOUND : COL_AVAIL; 458 } 459 else { 460 /* this driver won't allow us to call SQLGetData on bound 461 * columns - so don't bind any 462 */ 463 res->colstate[icol] = COL_AVAIL; 464 rc = SQL_SUCCESS; 465 } 466 } 467 return rc; 468} 469 470/* create and populate an apr_dbd_results_t for a select */ 471static SQLRETURN odbc_create_results(apr_dbd_t *handle, SQLHANDLE hstmt, 472 apr_pool_t *pool, const int random, 473 apr_dbd_results_t **res) 474{ 475 SQLRETURN rc; 476 SQLSMALLINT ncols; 477 478 *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); 479 (*res)->stmt = hstmt; 480 (*res)->dbc = handle->dbc; 481 (*res)->pool = pool; 482 (*res)->random = random; 483 (*res)->apr_dbd = handle; 484 rc = SQLNumResultCols(hstmt, &ncols); 485 CHECK_ERROR(handle, "SQLNumResultCols", rc, SQL_HANDLE_STMT, hstmt); 486 (*res)->ncols = ncols; 487 488 if (SQL_SUCCEEDED(rc)) { 489 int i; 490 491 (*res)->colnames = apr_pcalloc(pool, ncols * sizeof(char *)); 492 (*res)->colptrs = apr_pcalloc(pool, ncols * sizeof(void *)); 493 (*res)->colsizes = apr_pcalloc(pool, ncols * sizeof(SQLINTEGER)); 494 (*res)->coltypes = apr_pcalloc(pool, ncols * sizeof(SQLSMALLINT)); 495 (*res)->colinds = apr_pcalloc(pool, ncols * sizeof(SQLLEN)); 496 (*res)->colstate = apr_pcalloc(pool, ncols * sizeof(int)); 497 (*res)->ncols = ncols; 498 499 for (i = 0; i < ncols; i++) { 500 odbc_set_result_column(i, (*res), hstmt); 501 } 502 } 503 return rc; 504} 505 506 507/* bind a parameter - input params only, does not support output parameters */ 508static SQLRETURN odbc_bind_param(apr_pool_t *pool, 509 apr_dbd_prepared_t *statement, const int narg, 510 const SQLSMALLINT type, int *argp, 511 const void **args, const int textmode) 512{ 513 SQLRETURN rc; 514 SQLSMALLINT baseType, cType; 515 void *ptr; 516 SQLULEN len; 517 SQLLEN *indicator; 518 static SQLLEN nullValue = SQL_NULL_DATA; 519 static SQLSMALLINT inOut = SQL_PARAM_INPUT; /* only input params */ 520 521 /* bind a NULL data value */ 522 if (args[*argp] == NULL || type == APR_DBD_TYPE_NULL) { 523 baseType = SQL_CHAR; 524 cType = SQL_C_CHAR; 525 ptr = &nullValue; 526 len = sizeof(SQLINTEGER); 527 indicator = &nullValue; 528 (*argp)++; 529 } 530 /* bind a non-NULL data value */ 531 else { 532 if (type < 0 || type >= NUM_APR_DBD_TYPES) { 533 return APR_EGENERAL; 534 } 535 536 baseType = sqlBaseType[type]; 537 cType = sqlCtype[type]; 538 indicator = NULL; 539 /* LOBs */ 540 if (IS_LOB(cType)) { 541 ptr = (void *)args[*argp]; 542 len = (SQLULEN) * (apr_size_t *)args[*argp + 1]; 543 cType = (IS_CLOB(cType)) ? SQL_C_CHAR : SQL_C_DEFAULT; 544 (*argp) += 4; /* LOBs consume 4 args (last two are unused) */ 545 } 546 /* non-LOBs */ 547 else { 548 switch (baseType) { 549 case SQL_CHAR: 550 case SQL_DATE: 551 case SQL_TIME: 552 case SQL_TIMESTAMP: 553 ptr = (void *)args[*argp]; 554 len = (SQLULEN)strlen(ptr); 555 break; 556 case SQL_TINYINT: 557 ptr = apr_palloc(pool, sizeof(unsigned char)); 558 len = sizeof(unsigned char); 559 *(unsigned char *)ptr = 560 (textmode ? 561 atoi(args[*argp]) : *(unsigned char *)args[*argp]); 562 break; 563 case SQL_SMALLINT: 564 ptr = apr_palloc(pool, sizeof(short)); 565 len = sizeof(short); 566 *(short *)ptr = 567 (textmode ? atoi(args[*argp]) : *(short *)args[*argp]); 568 break; 569 case SQL_INTEGER: 570 ptr = apr_palloc(pool, sizeof(int)); 571 len = sizeof(int); 572 *(long *)ptr = 573 (textmode ? atol(args[*argp]) : *(long *)args[*argp]); 574 break; 575 case SQL_FLOAT: 576 ptr = apr_palloc(pool, sizeof(float)); 577 len = sizeof(float); 578 *(float *)ptr = 579 (textmode ? 580 (float)atof(args[*argp]) : *(float *)args[*argp]); 581 break; 582 case SQL_DOUBLE: 583 ptr = apr_palloc(pool, sizeof(double)); 584 len = sizeof(double); 585 *(double *)ptr = 586 (textmode ? atof(args[*argp]) : *(double *) 587 args[*argp]); 588 break; 589 case SQL_BIGINT: 590 ptr = apr_palloc(pool, sizeof(apr_int64_t)); 591 len = sizeof(apr_int64_t); 592 *(apr_int64_t *)ptr = 593 (textmode ? 594 apr_atoi64(args[*argp]) : *(apr_int64_t *)args[*argp]); 595 break; 596 default: 597 return APR_EGENERAL; 598 } 599 (*argp)++; /* non LOBs consume one argument */ 600 } 601 } 602 rc = SQLBindParameter(statement->stmt, narg, inOut, cType, 603 baseType, len, 0, ptr, len, indicator); 604 CHECK_ERROR(statement->apr_dbd, "SQLBindParameter", rc, SQL_HANDLE_STMT, 605 statement->stmt); 606 return rc; 607} 608 609/* LOB / Bucket Brigade functions */ 610 611/* bucket type specific destroy */ 612static void odbc_lob_bucket_destroy(void *data) 613{ 614 odbc_bucket *bd = data; 615 616 if (apr_bucket_shared_destroy(bd)) 617 apr_bucket_free(bd); 618} 619 620/* set aside a bucket if possible */ 621static apr_status_t odbc_lob_bucket_setaside(apr_bucket *e, apr_pool_t *pool) 622{ 623 odbc_bucket *bd = (odbc_bucket *)e->data; 624 625 /* Unlikely - but if the row pool is ancestor of this pool then it is OK */ 626 if (apr_pool_is_ancestor(bd->row->pool, pool)) 627 return APR_SUCCESS; 628 629 return apr_bucket_setaside_notimpl(e, pool); 630} 631 632/* split a bucket into a heap bucket followed by a LOB bkt w/remaining data */ 633static apr_status_t odbc_lob_bucket_read(apr_bucket *e, const char **str, 634 apr_size_t *len, apr_read_type_e block) 635{ 636 SQLRETURN rc; 637 SQLLEN len_indicator; 638 SQLSMALLINT type; 639 odbc_bucket *bd = (odbc_bucket *)e->data; 640 apr_bucket *nxt; 641 void *buf; 642 int bufsize = bd->row->res->apr_dbd->defaultBufferSize; 643 int eos; 644 645 /* C type is CHAR for CLOBs, DEFAULT for BLOBs */ 646 type = bd->row->res->coltypes[bd->col]; 647 type = (type == SQL_LONGVARCHAR) ? SQL_C_CHAR : SQL_C_DEFAULT; 648 649 /* LOB buffers are always at least APR_BUCKET_BUFF_SIZE, 650 * but they may be much bigger per the BUFSIZE parameter. 651 */ 652 if (bufsize < APR_BUCKET_BUFF_SIZE) 653 bufsize = APR_BUCKET_BUFF_SIZE; 654 655 buf = apr_bucket_alloc(bufsize, e->list); 656 *str = NULL; 657 *len = 0; 658 659 rc = SQLGetData(bd->row->res->stmt, bd->col + 1, 660 type, buf, bufsize, 661 &len_indicator); 662 663 CHECK_ERROR(bd->row->res->apr_dbd, "SQLGetData", rc, 664 SQL_HANDLE_STMT, bd->row->res->stmt); 665 666 if (rc == SQL_NO_DATA || len_indicator == SQL_NULL_DATA || len_indicator < 0) 667 len_indicator = 0; 668 669 if (SQL_SUCCEEDED(rc) || rc == SQL_NO_DATA) { 670 671 if (rc == SQL_SUCCESS_WITH_INFO 672 && (len_indicator == SQL_NO_TOTAL || len_indicator >= bufsize)) { 673 /* not the last read = a full buffer. CLOBs have a null terminator */ 674 *len = bufsize - (IS_CLOB(bd->type) ? 1 : 0 ); 675 676 eos = 0; 677 } 678 else { 679 /* the last read - len_indicator is supposed to be the length, 680 * but some driver get this wrong and return the total length. 681 * We try to handle both interpretations. 682 */ 683 *len = (len_indicator > bufsize 684 && len_indicator >= (SQLLEN)e->start) 685 ? (len_indicator - (SQLLEN)e->start) : len_indicator; 686 687 eos = 1; 688 } 689 690 if (!eos) { 691 /* Create a new LOB bucket to append and append it */ 692 nxt = apr_bucket_alloc(sizeof(apr_bucket *), e->list); 693 APR_BUCKET_INIT(nxt); 694 nxt->length = -1; 695 nxt->data = e->data; 696 nxt->type = &odbc_bucket_type; 697 nxt->free = apr_bucket_free; 698 nxt->list = e->list; 699 nxt->start = e->start + *len; 700 APR_BUCKET_INSERT_AFTER(e, nxt); 701 } 702 else { 703 odbc_lob_bucket_destroy(e->data); 704 } 705 /* make current bucket into a heap bucket */ 706 apr_bucket_heap_make(e, buf, *len, apr_bucket_free); 707 *str = buf; 708 709 /* No data is success in this context */ 710 rc = SQL_SUCCESS; 711 } 712 return APR_FROM_SQL_RESULT(rc); 713} 714 715/* Create a bucket brigade on the row pool for a LOB column */ 716static apr_status_t odbc_create_bucket(const apr_dbd_row_t *row, const int col, 717 SQLSMALLINT type, apr_bucket_brigade *bb) 718{ 719 apr_bucket_alloc_t *list = bb->bucket_alloc; 720 apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); 721 odbc_bucket *bd = apr_bucket_alloc(sizeof(odbc_bucket), list); 722 apr_bucket *eos = apr_bucket_eos_create(list); 723 724 bd->row = row; 725 bd->col = col; 726 bd->type = type; 727 728 APR_BUCKET_INIT(b); 729 b->type = &odbc_bucket_type; 730 b->free = apr_bucket_free; 731 b->list = list; 732 /* LOB lengths are unknown in ODBC */ 733 b = apr_bucket_shared_make(b, bd, 0, -1); 734 735 APR_BRIGADE_INSERT_TAIL(bb, b); 736 APR_BRIGADE_INSERT_TAIL(bb, eos); 737 738 return APR_SUCCESS; 739} 740 741/* returns a data pointer for a column, returns NULL for NULL value, 742 * return -1 if data not available 743 */ 744static void *odbc_get(const apr_dbd_row_t *row, const int col, 745 const SQLSMALLINT sqltype) 746{ 747 SQLRETURN rc; 748 SQLLEN indicator; 749 int state = row->res->colstate[col]; 750 intptr_t options = row->res->apr_dbd->dboptions; 751 752 switch (state) { 753 case (COL_UNAVAIL): 754 return (void *)-1; 755 case (COL_RETRIEVED): 756 return NULL; 757 758 case (COL_BOUND): 759 case (COL_PRESENT): 760 if (sqltype == row->res->coltypes[col]) { 761 /* same type and we already have the data */ 762 row->res->colstate[col] = COL_RETRIEVED; 763 return (row->res->colinds[col] == SQL_NULL_DATA) ? 764 NULL : row->res->colptrs[col]; 765 } 766 } 767 768 /* we need to get the data now */ 769 if (!(options & SQL_GD_ANY_ORDER)) { 770 /* this ODBC driver requires columns to be retrieved in order, 771 * so we attempt to get every prior un-gotten non-LOB column 772 */ 773 int i; 774 for (i = 0; i < col; i++) { 775 if (row->res->colstate[i] == COL_AVAIL) { 776 if (IS_LOB(row->res->coltypes[i])) 777 row->res->colstate[i] = COL_UNAVAIL; 778 else { 779 odbc_get(row, i, row->res->coltypes[i]); 780 row->res->colstate[i] = COL_PRESENT; 781 } 782 } 783 } 784 } 785 786 if ((state == COL_BOUND && !(options & SQL_GD_BOUND))) 787 /* this driver won't let us re-get bound columns */ 788 return (void *)-1; 789 790 /* a LOB might not have a buffer allocated yet - so create one */ 791 if (!row->res->colptrs[col]) 792 row->res->colptrs[col] = apr_pcalloc(row->pool, row->res->colsizes[col]); 793 794 rc = SQLGetData(row->res->stmt, col + 1, sqltype, row->res->colptrs[col], 795 row->res->colsizes[col], &indicator); 796 CHECK_ERROR(row->res->apr_dbd, "SQLGetData", rc, SQL_HANDLE_STMT, 797 row->res->stmt); 798 if (indicator == SQL_NULL_DATA || rc == SQL_NO_DATA) 799 return NULL; 800 801 if (SQL_SUCCEEDED(rc)) { 802 /* whatever it was originally, it is now this sqltype */ 803 row->res->coltypes[col] = sqltype; 804 /* this allows getting CLOBs in text mode by calling get_entry 805 * until it returns NULL 806 */ 807 row->res->colstate[col] = 808 (rc == SQL_SUCCESS_WITH_INFO) ? COL_AVAIL : COL_RETRIEVED; 809 return row->res->colptrs[col]; 810 } 811 else 812 return (void *)-1; 813} 814 815/* Parse the parameter string for open */ 816static apr_status_t odbc_parse_params(apr_pool_t *pool, const char *params, 817 int *connect, SQLCHAR **datasource, 818 SQLCHAR **user, SQLCHAR **password, 819 int *defaultBufferSize, int *nattrs, 820 int **attrs, intptr_t **attrvals) 821{ 822 char *seps, *last, *next, *name[MAX_PARAMS], *val[MAX_PARAMS]; 823 int nparams = 0, i, j; 824 825 *attrs = apr_pcalloc(pool, MAX_PARAMS * sizeof(char *)); 826 *attrvals = apr_pcalloc(pool, MAX_PARAMS * sizeof(intptr_t)); 827 *nattrs = 0; 828 seps = DEFAULTSEPS; 829 name[nparams] = apr_strtok(apr_pstrdup(pool, params), seps, &last); 830 831 /* no params is OK here - let connect return a more useful error msg */ 832 if (!name[nparams]) 833 return SQL_SUCCESS; 834 835 do { 836 if (last[strspn(last, seps)] == CSINGLEQUOTE) { 837 last += strspn(last, seps); 838 seps=SSINGLEQUOTE; 839 } 840 val[nparams] = apr_strtok(NULL, seps, &last); 841 seps = DEFAULTSEPS; 842 843 ++nparams; 844 next = apr_strtok(NULL, seps, &last); 845 if (!next) { 846 break; 847 } 848 if (nparams >= MAX_PARAMS) { 849 /* too many parameters, no place to store */ 850 return APR_EGENERAL; 851 } 852 name[nparams] = next; 853 } while (1); 854 855 for (j = i = 0; i < nparams; i++) { 856 if (!apr_strnatcasecmp(name[i], "CONNECT")) { 857 *datasource = (SQLCHAR *)apr_pstrdup(pool, val[i]); 858 *connect = 1; 859 } 860 else if (!apr_strnatcasecmp(name[i], "DATASOURCE")) { 861 *datasource = (SQLCHAR *)apr_pstrdup(pool, val[i]); 862 *connect = 0; 863 } 864 else if (!apr_strnatcasecmp(name[i], "USER")) { 865 *user = (SQLCHAR *)apr_pstrdup(pool, val[i]); 866 } 867 else if (!apr_strnatcasecmp(name[i], "PASSWORD")) { 868 *password = (SQLCHAR *)apr_pstrdup(pool, val[i]); 869 } 870 else if (!apr_strnatcasecmp(name[i], "BUFSIZE")) { 871 *defaultBufferSize = atoi(val[i]); 872 } 873 else if (!apr_strnatcasecmp(name[i], "ACCESS")) { 874 if (!apr_strnatcasecmp(val[i], "READ_ONLY")) 875 (*attrvals)[j] = SQL_MODE_READ_ONLY; 876 else if (!apr_strnatcasecmp(val[i], "READ_WRITE")) 877 (*attrvals)[j] = SQL_MODE_READ_WRITE; 878 else 879 return SQL_ERROR; 880 (*attrs)[j++] = SQL_ATTR_ACCESS_MODE; 881 } 882 else if (!apr_strnatcasecmp(name[i], "CTIMEOUT")) { 883 (*attrvals)[j] = atoi(val[i]); 884 (*attrs)[j++] = SQL_ATTR_LOGIN_TIMEOUT; 885 } 886 else if (!apr_strnatcasecmp(name[i], "STIMEOUT")) { 887 (*attrvals)[j] = atoi(val[i]); 888 (*attrs)[j++] = SQL_ATTR_CONNECTION_TIMEOUT; 889 } 890 else if (!apr_strnatcasecmp(name[i], "TXMODE")) { 891 if (!apr_strnatcasecmp(val[i], "READ_UNCOMMITTED")) 892 (*attrvals)[j] = SQL_TXN_READ_UNCOMMITTED; 893 else if (!apr_strnatcasecmp(val[i], "READ_COMMITTED")) 894 (*attrvals)[j] = SQL_TXN_READ_COMMITTED; 895 else if (!apr_strnatcasecmp(val[i], "REPEATABLE_READ")) 896 (*attrvals)[j] = SQL_TXN_REPEATABLE_READ; 897 else if (!apr_strnatcasecmp(val[i], "SERIALIZABLE")) 898 (*attrvals)[j] = SQL_TXN_SERIALIZABLE; 899 else if (!apr_strnatcasecmp(val[i], "DEFAULT")) 900 continue; 901 else 902 return SQL_ERROR; 903 (*attrs)[j++] = SQL_ATTR_TXN_ISOLATION; 904 } 905 else 906 return SQL_ERROR; 907 } 908 *nattrs = j; 909 return (*datasource && *defaultBufferSize) ? APR_SUCCESS : SQL_ERROR; 910} 911 912/* common handling after ODBC calls - save error info (code and text) in dbc */ 913static void check_error(apr_dbd_t *dbc, const char *step, SQLRETURN rc, 914 SQLSMALLINT type, SQLHANDLE h, int line) 915{ 916 SQLCHAR buffer[512]; 917 SQLCHAR sqlstate[128]; 918 SQLINTEGER native; 919 SQLSMALLINT reslength; 920 char *res, *p, *end, *logval = NULL; 921 int i; 922 923 /* set info about last error in dbc - fast return for SQL_SUCCESS */ 924 if (rc == SQL_SUCCESS) { 925 char successMsg[] = "[dbd_odbc] SQL_SUCCESS "; 926 apr_size_t successMsgLen = sizeof successMsg - 1; 927 928 dbc->lasterrorcode = SQL_SUCCESS; 929 apr_cpystrn(dbc->lastError, successMsg, sizeof dbc->lastError); 930 apr_cpystrn(dbc->lastError + successMsgLen, step, 931 sizeof dbc->lastError - successMsgLen); 932 return; 933 } 934 switch (rc) { 935 case SQL_INVALID_HANDLE: 936 res = "SQL_INVALID_HANDLE"; 937 break; 938 case SQL_ERROR: 939 res = "SQL_ERROR"; 940 break; 941 case SQL_SUCCESS_WITH_INFO: 942 res = "SQL_SUCCESS_WITH_INFO"; 943 break; 944 case SQL_STILL_EXECUTING: 945 res = "SQL_STILL_EXECUTING"; 946 break; 947 case SQL_NEED_DATA: 948 res = "SQL_NEED_DATA"; 949 break; 950 case SQL_NO_DATA: 951 res = "SQL_NO_DATA"; 952 break; 953 default: 954 res = "unrecognized SQL return code"; 955 } 956 /* these two returns are expected during normal execution */ 957 if (rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA 958 && dbc->can_commit != APR_DBD_TRANSACTION_IGNORE_ERRORS) { 959 dbc->can_commit = APR_DBD_TRANSACTION_ROLLBACK; 960 } 961 p = dbc->lastError; 962 end = p + sizeof(dbc->lastError); 963 dbc->lasterrorcode = rc; 964 p += sprintf(p, "[dbd_odbc] %.64s returned %.30s (%d) at %.24s:%d ", 965 step, res, rc, SOURCE_FILE, line - 1); 966 for (i = 1, rc = 0; rc == 0; i++) { 967 rc = SQLGetDiagRec(type, h, i, sqlstate, &native, buffer, 968 sizeof(buffer), &reslength); 969 if (SQL_SUCCEEDED(rc) && (p < (end - 280))) 970 p += sprintf(p, "%.256s %.20s ", buffer, sqlstate); 971 } 972 apr_env_get(&logval, "apr_dbd_odbc_log", dbc->pool); 973 /* if env var was set or call was init/open (no dbname) - log to stderr */ 974 if (logval || !dbc->dbname ) { 975 char timestamp[APR_CTIME_LEN]; 976 977 apr_file_t *se; 978 apr_ctime(timestamp, apr_time_now()); 979 apr_file_open_stderr(&se, dbc->pool); 980 apr_file_printf(se, "[%s] %s\n", timestamp, dbc->lastError); 981 } 982} 983 984static APR_INLINE int odbc_check_rollback(apr_dbd_t *handle) 985{ 986 if (handle->can_commit == APR_DBD_TRANSACTION_ROLLBACK) { 987 handle->lasterrorcode = SQL_ERROR; 988 apr_cpystrn(handle->lastError, "[dbd_odbc] Rollback pending ", 989 sizeof handle->lastError); 990 return 1; 991 } 992 return 0; 993} 994 995/* 996 * public functions per DBD driver API 997 */ 998 999/** init: allow driver to perform once-only initialisation. **/ 1000static void odbc_init(apr_pool_t *pool) 1001{ 1002 SQLRETURN rc; 1003 char *step; 1004 apr_version_t apuver; 1005 1006 apu_version(&apuver); 1007 if (apuver.major != DRIVER_APU_VERSION_MAJOR 1008 || apuver.minor != DRIVER_APU_VERSION_MINOR) { 1009 apr_file_t *se; 1010 1011 apr_file_open_stderr(&se, pool); 1012 apr_file_printf(se, "Incorrect " ODBC_DRIVER_STRING " dbd driver version\n" 1013 "Attempt to load APU version %d.%d driver with APU version %d.%d\n", 1014 DRIVER_APU_VERSION_MAJOR, DRIVER_APU_VERSION_MINOR, 1015 apuver.major, apuver.minor); 1016 abort(); 1017 } 1018 1019 if (henv) 1020 return; 1021 1022 step = "SQLAllocHandle (SQL_HANDLE_ENV)"; 1023 rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); 1024 apr_pool_cleanup_register(pool, henv, odbc_close_env, apr_pool_cleanup_null); 1025 if (SQL_SUCCEEDED(rc)) { 1026 step = "SQLSetEnvAttr"; 1027 rc = SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION, 1028 (SQLPOINTER)SQL_OV_ODBC3, 0); 1029 } 1030 else { 1031 apr_dbd_t tmp_dbc; 1032 SQLHANDLE err_h = henv; 1033 1034 tmp_dbc.pool = pool; 1035 tmp_dbc.dbname = NULL; 1036 CHECK_ERROR(&tmp_dbc, step, rc, SQL_HANDLE_ENV, err_h); 1037 } 1038} 1039 1040/** native_handle: return the native database handle of the underlying db **/ 1041static void *odbc_native_handle(apr_dbd_t *handle) 1042{ 1043 return handle->dbc; 1044} 1045 1046/** open: obtain a database connection from the server rec. **/ 1047 1048/* It would be more efficient to allocate a single statement handle 1049 * here - but SQL_ATTR_CURSOR_SCROLLABLE must be set before 1050 * SQLPrepare, and we don't know whether random-access is 1051 * specified until SQLExecute so we cannot. 1052 */ 1053 1054static apr_dbd_t *odbc_open(apr_pool_t *pool, const char *params, const char **error) 1055{ 1056 SQLRETURN rc; 1057 SQLHANDLE hdbc = NULL; 1058 apr_dbd_t *handle; 1059 char *err_step; 1060 int err_htype, i; 1061 int defaultBufferSize = DEFAULT_BUFFER_SIZE; 1062 SQLHANDLE err_h = NULL; 1063 SQLCHAR *datasource = (SQLCHAR *)"", *user = (SQLCHAR *)"", 1064 *password = (SQLCHAR *)""; 1065 int nattrs = 0, *attrs = NULL, connect = 0; 1066 intptr_t *attrvals = NULL; 1067 1068 err_step = "SQLAllocHandle (SQL_HANDLE_DBC)"; 1069 err_htype = SQL_HANDLE_ENV; 1070 err_h = henv; 1071 rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); 1072 if (SQL_SUCCEEDED(rc)) { 1073 err_step = "Invalid DBD Parameters - open"; 1074 err_htype = SQL_HANDLE_DBC; 1075 err_h = hdbc; 1076 rc = odbc_parse_params(pool, params, &connect, &datasource, &user, 1077 &password, &defaultBufferSize, &nattrs, &attrs, 1078 &attrvals); 1079 } 1080 if (SQL_SUCCEEDED(rc)) { 1081 for (i = 0; i < nattrs && SQL_SUCCEEDED(rc); i++) { 1082 err_step = "SQLSetConnectAttr (from DBD Parameters)"; 1083 err_htype = SQL_HANDLE_DBC; 1084 err_h = hdbc; 1085 rc = SQLSetConnectAttr(hdbc, attrs[i], (SQLPOINTER)attrvals[i], 0); 1086 } 1087 } 1088 if (SQL_SUCCEEDED(rc)) { 1089 if (connect) { 1090 SQLCHAR out[1024]; 1091 SQLSMALLINT outlen; 1092 1093 err_step = "SQLDriverConnect"; 1094 err_htype = SQL_HANDLE_DBC; 1095 err_h = hdbc; 1096 rc = SQLDriverConnect(hdbc, NULL, datasource, 1097 (SQLSMALLINT)strlen((char *)datasource), 1098 out, sizeof(out), &outlen, SQL_DRIVER_NOPROMPT); 1099 } 1100 else { 1101 err_step = "SQLConnect"; 1102 err_htype = SQL_HANDLE_DBC; 1103 err_h = hdbc; 1104 rc = SQLConnect(hdbc, datasource, 1105 (SQLSMALLINT)strlen((char *)datasource), 1106 user, (SQLSMALLINT)strlen((char *)user), 1107 password, (SQLSMALLINT)strlen((char *)password)); 1108 } 1109 } 1110 if (SQL_SUCCEEDED(rc)) { 1111 handle = apr_pcalloc(pool, sizeof(apr_dbd_t)); 1112 handle->dbname = apr_pstrdup(pool, (char *)datasource); 1113 handle->dbc = hdbc; 1114 handle->pool = pool; 1115 handle->defaultBufferSize = defaultBufferSize; 1116 CHECK_ERROR(handle, "SQLConnect", rc, SQL_HANDLE_DBC, handle->dbc); 1117 handle->default_transaction_mode = 0; 1118 handle->can_commit = APR_DBD_TRANSACTION_IGNORE_ERRORS; 1119 SQLGetInfo(hdbc, SQL_DEFAULT_TXN_ISOLATION, 1120 &(handle->default_transaction_mode), sizeof(intptr_t), NULL); 1121 handle->transaction_mode = handle->default_transaction_mode; 1122 SQLGetInfo(hdbc, SQL_GETDATA_EXTENSIONS ,&(handle->dboptions), 1123 sizeof(intptr_t), NULL); 1124 apr_pool_cleanup_register(pool, handle, odbc_close_cleanup, apr_pool_cleanup_null); 1125 return handle; 1126 } 1127 else { 1128 apr_dbd_t tmp_dbc; 1129 1130 tmp_dbc.pool = pool; 1131 tmp_dbc.dbname = NULL; 1132 CHECK_ERROR(&tmp_dbc, err_step, rc, err_htype, err_h); 1133 if (error) 1134 *error = apr_pstrdup(pool, tmp_dbc.lastError); 1135 if (hdbc) 1136 SQLFreeHandle(SQL_HANDLE_DBC, hdbc); 1137 return NULL; 1138 } 1139} 1140 1141/** check_conn: check status of a database connection **/ 1142static apr_status_t odbc_check_conn(apr_pool_t *pool, apr_dbd_t *handle) 1143{ 1144 SQLUINTEGER isDead; 1145 SQLRETURN rc; 1146 1147 rc = SQLGetConnectAttr(handle->dbc, SQL_ATTR_CONNECTION_DEAD, &isDead, 1148 sizeof(SQLUINTEGER), NULL); 1149 CHECK_ERROR(handle, "SQLGetConnectAttr (SQL_ATTR_CONNECTION_DEAD)", rc, 1150 SQL_HANDLE_DBC, handle->dbc); 1151 /* if driver cannot check connection, say so */ 1152 if (rc != SQL_SUCCESS) 1153 return APR_ENOTIMPL; 1154 1155 return (isDead == SQL_CD_FALSE) ? APR_SUCCESS : APR_EGENERAL; 1156} 1157 1158/** set_dbname: select database name. May be a no-op if not supported. **/ 1159static int odbc_set_dbname(apr_pool_t*pool, apr_dbd_t *handle, 1160 const char *name) 1161{ 1162 if (apr_strnatcmp(name, handle->dbname)) { 1163 return APR_EGENERAL; /* It's illegal to change dbname in ODBC */ 1164 } 1165 CHECK_ERROR(handle, "set_dbname (no-op)", SQL_SUCCESS, SQL_HANDLE_DBC, 1166 handle->dbc); 1167 return APR_SUCCESS; /* OK if it's the same name */ 1168} 1169 1170/** transaction: start a transaction. May be a no-op. **/ 1171static int odbc_start_transaction(apr_pool_t *pool, apr_dbd_t *handle, 1172 apr_dbd_transaction_t **trans) 1173{ 1174 SQLRETURN rc = SQL_SUCCESS; 1175 1176 if (handle->transaction_mode) { 1177 rc = SQLSetConnectAttr(handle->dbc, SQL_ATTR_TXN_ISOLATION, 1178 (SQLPOINTER)handle->transaction_mode, 0); 1179 CHECK_ERROR(handle, "SQLSetConnectAttr (SQL_ATTR_TXN_ISOLATION)", rc, 1180 SQL_HANDLE_DBC, handle->dbc); 1181 } 1182 if (SQL_SUCCEEDED(rc)) { 1183 /* turn off autocommit for transactions */ 1184 rc = SQLSetConnectAttr(handle->dbc, SQL_ATTR_AUTOCOMMIT, 1185 SQL_AUTOCOMMIT_OFF, 0); 1186 CHECK_ERROR(handle, "SQLSetConnectAttr (SQL_ATTR_AUTOCOMMIT)", rc, 1187 SQL_HANDLE_DBC, handle->dbc); 1188 } 1189 if (SQL_SUCCEEDED(rc)) { 1190 *trans = apr_palloc(pool, sizeof(apr_dbd_transaction_t)); 1191 (*trans)->dbc = handle->dbc; 1192 (*trans)->apr_dbd = handle; 1193 } 1194 handle->can_commit = APR_DBD_TRANSACTION_COMMIT; 1195 return APR_FROM_SQL_RESULT(rc); 1196} 1197 1198/** end_transaction: end a transaction **/ 1199static int odbc_end_transaction(apr_dbd_transaction_t *trans) 1200{ 1201 SQLRETURN rc; 1202 int action = (trans->apr_dbd->can_commit != APR_DBD_TRANSACTION_ROLLBACK) 1203 ? SQL_COMMIT : SQL_ROLLBACK; 1204 1205 rc = SQLEndTran(SQL_HANDLE_DBC, trans->dbc, action); 1206 CHECK_ERROR(trans->apr_dbd, "SQLEndTran", rc, SQL_HANDLE_DBC, trans->dbc); 1207 if (SQL_SUCCEEDED(rc)) { 1208 rc = SQLSetConnectAttr(trans->dbc, SQL_ATTR_AUTOCOMMIT, 1209 (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0); 1210 CHECK_ERROR(trans->apr_dbd, "SQLSetConnectAttr (SQL_ATTR_AUTOCOMMIT)", 1211 rc, SQL_HANDLE_DBC, trans->dbc); 1212 } 1213 trans->apr_dbd->can_commit = APR_DBD_TRANSACTION_IGNORE_ERRORS; 1214 return APR_FROM_SQL_RESULT(rc); 1215} 1216 1217/** query: execute an SQL statement which doesn't return a result set **/ 1218static int odbc_query(apr_dbd_t *handle, int *nrows, const char *statement) 1219{ 1220 SQLRETURN rc; 1221 SQLHANDLE hstmt = NULL; 1222 size_t len = strlen(statement); 1223 1224 if (odbc_check_rollback(handle)) 1225 return APR_EGENERAL; 1226 1227 rc = SQLAllocHandle(SQL_HANDLE_STMT, handle->dbc, &hstmt); 1228 CHECK_ERROR(handle, "SQLAllocHandle (STMT)", rc, SQL_HANDLE_DBC, 1229 handle->dbc); 1230 if (!SQL_SUCCEEDED(rc)) 1231 return APR_FROM_SQL_RESULT(rc); 1232 1233 rc = SQLExecDirect(hstmt, (SQLCHAR *)statement, (SQLINTEGER)len); 1234 CHECK_ERROR(handle, "SQLExecDirect", rc, SQL_HANDLE_STMT, hstmt); 1235 1236 if (SQL_SUCCEEDED(rc)) { 1237 SQLLEN rowcount; 1238 1239 rc = SQLRowCount(hstmt, &rowcount); 1240 *nrows = (int)rowcount; 1241 CHECK_ERROR(handle, "SQLRowCount", rc, SQL_HANDLE_STMT, hstmt); 1242 } 1243 1244 SQLFreeHandle(SQL_HANDLE_STMT, hstmt); 1245 return APR_FROM_SQL_RESULT(rc); 1246} 1247 1248/** select: execute an SQL statement which returns a result set **/ 1249static int odbc_select(apr_pool_t *pool, apr_dbd_t *handle, 1250 apr_dbd_results_t **res, const char *statement, 1251 int random) 1252{ 1253 SQLRETURN rc; 1254 SQLHANDLE hstmt; 1255 apr_dbd_prepared_t *stmt; 1256 size_t len = strlen(statement); 1257 1258 if (odbc_check_rollback(handle)) 1259 return APR_EGENERAL; 1260 1261 rc = SQLAllocHandle(SQL_HANDLE_STMT, handle->dbc, &hstmt); 1262 CHECK_ERROR(handle, "SQLAllocHandle (STMT)", rc, SQL_HANDLE_DBC, 1263 handle->dbc); 1264 if (!SQL_SUCCEEDED(rc)) 1265 return APR_FROM_SQL_RESULT(rc); 1266 /* Prepare an apr_dbd_prepared_t for pool cleanup, even though this 1267 * is not a prepared statement. We want the same cleanup mechanism. 1268 */ 1269 stmt = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t)); 1270 stmt->apr_dbd = handle; 1271 stmt->dbc = handle->dbc; 1272 stmt->stmt = hstmt; 1273 apr_pool_cleanup_register(pool, stmt, odbc_close_pstmt, apr_pool_cleanup_null); 1274 if (random) { 1275 rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_SCROLLABLE, 1276 (SQLPOINTER)SQL_SCROLLABLE, 0); 1277 CHECK_ERROR(handle, "SQLSetStmtAttr (SQL_ATTR_CURSOR_SCROLLABLE)", rc, 1278 SQL_HANDLE_STMT, hstmt); 1279 } 1280 if (SQL_SUCCEEDED(rc)) { 1281 rc = SQLExecDirect(hstmt, (SQLCHAR *)statement, (SQLINTEGER)len); 1282 CHECK_ERROR(handle, "SQLExecDirect", rc, SQL_HANDLE_STMT, hstmt); 1283 } 1284 if (SQL_SUCCEEDED(rc)) { 1285 rc = odbc_create_results(handle, hstmt, pool, random, res); 1286 apr_pool_cleanup_register(pool, *res, 1287 odbc_close_results, apr_pool_cleanup_null); 1288 } 1289 return APR_FROM_SQL_RESULT(rc); 1290} 1291 1292/** num_cols: get the number of columns in a results set **/ 1293static int odbc_num_cols(apr_dbd_results_t *res) 1294{ 1295 return res->ncols; 1296} 1297 1298/** num_tuples: get the number of rows in a results set **/ 1299static int odbc_num_tuples(apr_dbd_results_t *res) 1300{ 1301 SQLRETURN rc; 1302 SQLLEN nrows; 1303 1304 rc = SQLRowCount(res->stmt, &nrows); 1305 CHECK_ERROR(res->apr_dbd, "SQLRowCount", rc, SQL_HANDLE_STMT, res->stmt); 1306 return SQL_SUCCEEDED(rc) ? (int)nrows : -1; 1307} 1308 1309/** get_row: get a row from a result set **/ 1310static int odbc_get_row(apr_pool_t *pool, apr_dbd_results_t *res, 1311 apr_dbd_row_t **row, int rownum) 1312{ 1313 SQLRETURN rc; 1314 char *fetchtype; 1315 int c; 1316 1317 *row = apr_pcalloc(pool, sizeof(apr_dbd_row_t)); 1318 (*row)->stmt = res->stmt; 1319 (*row)->dbc = res->dbc; 1320 (*row)->res = res; 1321 (*row)->pool = res->pool; 1322 1323 /* mark all the columns as needing SQLGetData unless they are bound */ 1324 for (c = 0; c < res->ncols; c++) { 1325 if (res->colstate[c] != COL_BOUND) { 1326 res->colstate[c] = COL_AVAIL; 1327 } 1328 /* some drivers do not null-term zero-len CHAR data */ 1329 if (res->colptrs[c]) 1330 *(char *)res->colptrs[c] = 0; 1331 } 1332 1333 if (res->random && (rownum > 0)) { 1334 fetchtype = "SQLFetchScroll"; 1335 rc = SQLFetchScroll(res->stmt, SQL_FETCH_ABSOLUTE, rownum); 1336 } 1337 else { 1338 fetchtype = "SQLFetch"; 1339 rc = SQLFetch(res->stmt); 1340 } 1341 CHECK_ERROR(res->apr_dbd, fetchtype, rc, SQL_HANDLE_STMT, res->stmt); 1342 (*row)->stmt = res->stmt; 1343 if (!SQL_SUCCEEDED(rc) && !res->random) { 1344 /* early close on any error (usually SQL_NO_DATA) if fetching 1345 * sequentially to release resources ASAP 1346 */ 1347 odbc_close_results(res); 1348 return -1; 1349 } 1350 return SQL_SUCCEEDED(rc) ? 0 : -1; 1351} 1352 1353/** datum_get: get a binary entry from a row **/ 1354static apr_status_t odbc_datum_get(const apr_dbd_row_t *row, int col, 1355 apr_dbd_type_e dbdtype, void *data) 1356{ 1357 SQLSMALLINT sqltype; 1358 void *p; 1359 int len; 1360 1361 if (col >= row->res->ncols) 1362 return APR_EGENERAL; 1363 1364 if (dbdtype < 0 || dbdtype >= NUM_APR_DBD_TYPES) { 1365 data = NULL; /* invalid type */ 1366 return APR_EGENERAL; 1367 } 1368 1369 len = sqlSizes[dbdtype]; 1370 sqltype = sqlCtype[dbdtype]; 1371 1372 /* must not memcpy a brigade, sentinals are relative to orig loc */ 1373 if (IS_LOB(sqltype)) 1374 return odbc_create_bucket(row, col, sqltype, data); 1375 1376 p = odbc_get(row, col, sqltype); 1377 if (p == (void *)-1) 1378 return APR_EGENERAL; 1379 1380 if (p == NULL) 1381 return APR_ENOENT; /* SQL NULL value */ 1382 1383 if (len < 0) 1384 *(char**)data = (char *)p; 1385 else 1386 memcpy(data, p, len); 1387 1388 return APR_SUCCESS; 1389 1390} 1391 1392/** get_entry: get an entry from a row (string data) **/ 1393static const char *odbc_get_entry(const apr_dbd_row_t *row, int col) 1394{ 1395 void *p; 1396 1397 if (col >= row->res->ncols) 1398 return NULL; 1399 1400 p = odbc_get(row, col, SQL_C_CHAR); 1401 1402 /* NULL or invalid (-1) */ 1403 if (p == NULL || p == (void *)-1) 1404 return p; 1405 else 1406 return apr_pstrdup(row->pool, p); 1407} 1408 1409/** error: get current error message (if any) **/ 1410static const char *odbc_error(apr_dbd_t *handle, int errnum) 1411{ 1412 return (handle) ? handle->lastError : "[dbd_odbc]No error message available"; 1413} 1414 1415/** escape: escape a string so it is safe for use in query/select **/ 1416static const char *odbc_escape(apr_pool_t *pool, const char *s, 1417 apr_dbd_t *handle) 1418{ 1419 char *newstr, *src, *dst, *sq; 1420 int qcount; 1421 1422 /* return the original if there are no single-quotes */ 1423 if (!(sq = strchr(s, '\''))) 1424 return (char *)s; 1425 /* count the single-quotes and allocate a new buffer */ 1426 for (qcount = 1; (sq = strchr(sq + 1, '\'')); ) 1427 qcount++; 1428 newstr = apr_palloc(pool, strlen(s) + qcount + 1); 1429 1430 /* move chars, doubling all single-quotes */ 1431 src = (char *)s; 1432 for (dst = newstr; *src; src++) { 1433 if ((*dst++ = *src) == '\'') 1434 *dst++ = '\''; 1435 } 1436 *dst = 0; 1437 return newstr; 1438} 1439 1440/** prepare: prepare a statement **/ 1441static int odbc_prepare(apr_pool_t *pool, apr_dbd_t *handle, 1442 const char *query, const char *label, int nargs, 1443 int nvals, apr_dbd_type_e *types, 1444 apr_dbd_prepared_t **statement) 1445{ 1446 SQLRETURN rc; 1447 size_t len = strlen(query); 1448 1449 if (odbc_check_rollback(handle)) 1450 return APR_EGENERAL; 1451 1452 *statement = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t)); 1453 (*statement)->dbc = handle->dbc; 1454 (*statement)->apr_dbd = handle; 1455 (*statement)->nargs = nargs; 1456 (*statement)->nvals = nvals; 1457 (*statement)->types = 1458 apr_pmemdup(pool, types, nargs * sizeof(apr_dbd_type_e)); 1459 rc = SQLAllocHandle(SQL_HANDLE_STMT, handle->dbc, &((*statement)->stmt)); 1460 apr_pool_cleanup_register(pool, *statement, 1461 odbc_close_pstmt, apr_pool_cleanup_null); 1462 CHECK_ERROR(handle, "SQLAllocHandle (STMT)", rc, 1463 SQL_HANDLE_DBC, handle->dbc); 1464 rc = SQLPrepare((*statement)->stmt, (SQLCHAR *)query, (SQLINTEGER)len); 1465 CHECK_ERROR(handle, "SQLPrepare", rc, SQL_HANDLE_STMT, 1466 (*statement)->stmt); 1467 return APR_FROM_SQL_RESULT(rc); 1468} 1469 1470/** pquery: query using a prepared statement + args **/ 1471static int odbc_pquery(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, 1472 apr_dbd_prepared_t *statement, const char **args) 1473{ 1474 SQLRETURN rc = SQL_SUCCESS; 1475 int i, argp; 1476 1477 if (odbc_check_rollback(handle)) 1478 return APR_EGENERAL; 1479 1480 for (i = argp = 0; i < statement->nargs && SQL_SUCCEEDED(rc); i++) { 1481 rc = odbc_bind_param(pool, statement, i + 1, statement->types[i], 1482 &argp, (const void **)args, TEXTMODE); 1483 } 1484 if (SQL_SUCCEEDED(rc)) { 1485 rc = SQLExecute(statement->stmt); 1486 CHECK_ERROR(handle, "SQLExecute", rc, SQL_HANDLE_STMT, 1487 statement->stmt); 1488 } 1489 if (SQL_SUCCEEDED(rc)) { 1490 SQLLEN rowcount; 1491 1492 rc = SQLRowCount(statement->stmt, &rowcount); 1493 *nrows = (int)rowcount; 1494 CHECK_ERROR(handle, "SQLRowCount", rc, SQL_HANDLE_STMT, 1495 statement->stmt); 1496 } 1497 return APR_FROM_SQL_RESULT(rc); 1498} 1499 1500/** pvquery: query using a prepared statement + args **/ 1501static int odbc_pvquery(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, 1502 apr_dbd_prepared_t *statement, va_list args) 1503{ 1504 const char **values; 1505 int i; 1506 1507 values = apr_palloc(pool, sizeof(*values) * statement->nvals); 1508 for (i = 0; i < statement->nvals; i++) 1509 values[i] = va_arg(args, const char *); 1510 return odbc_pquery(pool, handle, nrows, statement, values); 1511} 1512 1513/** pselect: select using a prepared statement + args **/ 1514static int odbc_pselect(apr_pool_t *pool, apr_dbd_t *handle, 1515 apr_dbd_results_t **res, apr_dbd_prepared_t *statement, 1516 int random, const char **args) 1517{ 1518 SQLRETURN rc = SQL_SUCCESS; 1519 int i, argp; 1520 1521 if (odbc_check_rollback(handle)) 1522 return APR_EGENERAL; 1523 1524 if (random) { 1525 rc = SQLSetStmtAttr(statement->stmt, SQL_ATTR_CURSOR_SCROLLABLE, 1526 (SQLPOINTER)SQL_SCROLLABLE, 0); 1527 CHECK_ERROR(handle, "SQLSetStmtAttr (SQL_ATTR_CURSOR_SCROLLABLE)", 1528 rc, SQL_HANDLE_STMT, statement->stmt); 1529 } 1530 if (SQL_SUCCEEDED(rc)) { 1531 for (i = argp = 0; i < statement->nargs && SQL_SUCCEEDED(rc); i++) { 1532 rc = odbc_bind_param(pool, statement, i + 1, statement->types[i], 1533 &argp, (const void **)args, TEXTMODE); 1534 } 1535 } 1536 if (SQL_SUCCEEDED(rc)) { 1537 rc = SQLExecute(statement->stmt); 1538 CHECK_ERROR(handle, "SQLExecute", rc, SQL_HANDLE_STMT, 1539 statement->stmt); 1540 } 1541 if (SQL_SUCCEEDED(rc)) { 1542 rc = odbc_create_results(handle, statement->stmt, pool, random, res); 1543 apr_pool_cleanup_register(pool, *res, 1544 odbc_close_results, apr_pool_cleanup_null); 1545 } 1546 return APR_FROM_SQL_RESULT(rc); 1547} 1548 1549/** pvselect: select using a prepared statement + args **/ 1550static int odbc_pvselect(apr_pool_t *pool, apr_dbd_t *handle, 1551 apr_dbd_results_t **res, 1552 apr_dbd_prepared_t *statement, int random, 1553 va_list args) 1554{ 1555 const char **values; 1556 int i; 1557 1558 values = apr_palloc(pool, sizeof(*values) * statement->nvals); 1559 for (i = 0; i < statement->nvals; i++) 1560 values[i] = va_arg(args, const char *); 1561 return odbc_pselect(pool, handle, res, statement, random, values); 1562} 1563 1564/** get_name: get a column title from a result set **/ 1565static const char *odbc_get_name(const apr_dbd_results_t *res, int col) 1566{ 1567 SQLRETURN rc; 1568 char buffer[MAX_COLUMN_NAME]; 1569 SQLSMALLINT colnamelength, coltype, coldecimal, colnullable; 1570 SQLULEN colsize; 1571 1572 if (col >= res->ncols) 1573 return NULL; /* bogus column number */ 1574 if (res->colnames[col] != NULL) 1575 return res->colnames[col]; /* we already retrieved it */ 1576 rc = SQLDescribeCol(res->stmt, col + 1, 1577 (SQLCHAR *)buffer, sizeof(buffer), &colnamelength, 1578 &coltype, &colsize, &coldecimal, &colnullable); 1579 CHECK_ERROR(res->apr_dbd, "SQLDescribeCol", rc, 1580 SQL_HANDLE_STMT, res->stmt); 1581 res->colnames[col] = apr_pstrdup(res->pool, buffer); 1582 return res->colnames[col]; 1583} 1584 1585/** transaction_mode_get: get the mode of transaction **/ 1586static int odbc_transaction_mode_get(apr_dbd_transaction_t *trans) 1587{ 1588 return (int)trans->apr_dbd->can_commit; 1589} 1590 1591/** transaction_mode_set: set the mode of transaction **/ 1592static int odbc_transaction_mode_set(apr_dbd_transaction_t *trans, int mode) 1593{ 1594 int legal = ( APR_DBD_TRANSACTION_IGNORE_ERRORS 1595 | APR_DBD_TRANSACTION_COMMIT 1596 | APR_DBD_TRANSACTION_ROLLBACK); 1597 1598 if ((mode & legal) != mode) 1599 return APR_EGENERAL; 1600 1601 trans->apr_dbd->can_commit = mode; 1602 return APR_SUCCESS; 1603} 1604 1605/** pbquery: query using a prepared statement + binary args **/ 1606static int odbc_pbquery(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, 1607 apr_dbd_prepared_t *statement, const void **args) 1608{ 1609 SQLRETURN rc = SQL_SUCCESS; 1610 int i, argp; 1611 1612 if (odbc_check_rollback(handle)) 1613 return APR_EGENERAL; 1614 1615 for (i = argp = 0; i < statement->nargs && SQL_SUCCEEDED(rc); i++) 1616 rc = odbc_bind_param(pool, statement, i + 1, statement->types[i], 1617 &argp, args, BINARYMODE); 1618 1619 if (SQL_SUCCEEDED(rc)) { 1620 rc = SQLExecute(statement->stmt); 1621 CHECK_ERROR(handle, "SQLExecute", rc, SQL_HANDLE_STMT, 1622 statement->stmt); 1623 } 1624 if (SQL_SUCCEEDED(rc)) { 1625 SQLLEN rowcount; 1626 1627 rc = SQLRowCount(statement->stmt, &rowcount); 1628 *nrows = (int)rowcount; 1629 CHECK_ERROR(handle, "SQLRowCount", rc, SQL_HANDLE_STMT, 1630 statement->stmt); 1631 } 1632 return APR_FROM_SQL_RESULT(rc); 1633} 1634 1635/** pbselect: select using a prepared statement + binary args **/ 1636static int odbc_pbselect(apr_pool_t *pool, apr_dbd_t *handle, 1637 apr_dbd_results_t **res, 1638 apr_dbd_prepared_t *statement, 1639 int random, const void **args) 1640{ 1641 SQLRETURN rc = SQL_SUCCESS; 1642 int i, argp; 1643 1644 if (odbc_check_rollback(handle)) 1645 return APR_EGENERAL; 1646 1647 if (random) { 1648 rc = SQLSetStmtAttr(statement->stmt, SQL_ATTR_CURSOR_SCROLLABLE, 1649 (SQLPOINTER)SQL_SCROLLABLE, 0); 1650 CHECK_ERROR(handle, "SQLSetStmtAttr (SQL_ATTR_CURSOR_SCROLLABLE)", 1651 rc, SQL_HANDLE_STMT, statement->stmt); 1652 } 1653 if (SQL_SUCCEEDED(rc)) { 1654 for (i = argp = 0; i < statement->nargs && SQL_SUCCEEDED(rc); i++) { 1655 rc = odbc_bind_param(pool, statement, i + 1, statement->types[i], 1656 &argp, args, BINARYMODE); 1657 } 1658 } 1659 if (SQL_SUCCEEDED(rc)) { 1660 rc = SQLExecute(statement->stmt); 1661 CHECK_ERROR(handle, "SQLExecute", rc, SQL_HANDLE_STMT, 1662 statement->stmt); 1663 } 1664 if (SQL_SUCCEEDED(rc)) { 1665 rc = odbc_create_results(handle, statement->stmt, pool, random, res); 1666 apr_pool_cleanup_register(pool, *res, 1667 odbc_close_results, apr_pool_cleanup_null); 1668 } 1669 1670 return APR_FROM_SQL_RESULT(rc); 1671} 1672 1673/** pvbquery: query using a prepared statement + binary args **/ 1674static int odbc_pvbquery(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, 1675 apr_dbd_prepared_t *statement, va_list args) 1676{ 1677 const char **values; 1678 int i; 1679 1680 values = apr_palloc(pool, sizeof(*values) * statement->nvals); 1681 for (i = 0; i < statement->nvals; i++) 1682 values[i] = va_arg(args, const char *); 1683 return odbc_pbquery(pool, handle, nrows, statement, (const void **)values); 1684} 1685 1686/** pvbselect: select using a prepared statement + binary args **/ 1687static int odbc_pvbselect(apr_pool_t *pool, apr_dbd_t *handle, 1688 apr_dbd_results_t **res, 1689 apr_dbd_prepared_t *statement, 1690 int random, va_list args) 1691{ 1692 const char **values; 1693 int i; 1694 1695 values = apr_palloc(pool, sizeof(*values) * statement->nvals); 1696 for (i = 0; i < statement->nvals; i++) 1697 values[i] = va_arg(args, const char *); 1698 return odbc_pbselect(pool, handle, res, statement, random, (const void **)values); 1699} 1700 1701APU_MODULE_DECLARE_DATA const apr_dbd_driver_t ODBC_DRIVER_ENTRY = { 1702 ODBC_DRIVER_STRING, 1703 odbc_init, 1704 odbc_native_handle, 1705 odbc_open, 1706 odbc_check_conn, 1707 odbc_close, 1708 odbc_set_dbname, 1709 odbc_start_transaction, 1710 odbc_end_transaction, 1711 odbc_query, 1712 odbc_select, 1713 odbc_num_cols, 1714 odbc_num_tuples, 1715 odbc_get_row, 1716 odbc_get_entry, 1717 odbc_error, 1718 odbc_escape, 1719 odbc_prepare, 1720 odbc_pvquery, 1721 odbc_pvselect, 1722 odbc_pquery, 1723 odbc_pselect, 1724 odbc_get_name, 1725 odbc_transaction_mode_get, 1726 odbc_transaction_mode_set, 1727 "?", 1728 odbc_pvbquery, 1729 odbc_pvbselect, 1730 odbc_pbquery, 1731 odbc_pbselect, 1732 odbc_datum_get 1733}; 1734 1735#endif 1736