Annotation of sql/oracle/parser3oracle.C, revision 1.1
1.1 ! parser 1: /** @file
! 2: Parser Oracle driver.
! 3:
! 4: Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
! 5:
! 6: Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)
! 7:
! 8: 2001.07.30 using Oracle 8.1.6 [@test tested with Oracle 7.x.x]
! 9: */
! 10: static const char *RCSId="$Id: parser3oracle.C,v 1.19 2001/09/14 15:41:59 parser Exp $";
! 11:
! 12: #include "config_includes.h"
! 13:
! 14: #include "pa_sql_driver.h"
! 15:
! 16: #include <oci.h>
! 17:
! 18: #define MAX_COLS 500
! 19: #define MAX_IN_LOBS 5
! 20: #define MAX_LOB_NAME_LENGTH 100
! 21: #define MAX_OUT_STRING_LENGTH 4000
! 22:
! 23: #define EMPTY_CLOB_FUNC_CALL "empty_clob()"
! 24:
! 25: #include "ltdl.h"
! 26:
! 27: #define MAX_STRING 0x400
! 28: #define MAX_NUMBER 20
! 29:
! 30: #if _MSC_VER
! 31: # define snprintf _snprintf
! 32: # define strcasecmp _stricmp
! 33: # define strncasecmp _strnicmp
! 34: #endif
! 35:
! 36: #ifndef max
! 37: inline int max(int a, int b) { return a>b?a:b; }
! 38: inline int min(int a, int b){ return a<b?a:b; }
! 39: #endif
! 40:
! 41: static char *lsplit(char *string, char delim) {
! 42: if(string) {
! 43: char *v=strchr(string, delim);
! 44: if(v) {
! 45: *v=0;
! 46: return v+1;
! 47: }
! 48: }
! 49: return 0;
! 50: }
! 51:
! 52: #ifndef DOXYGEN
! 53: struct OracleSQL_connection_struct {
! 54: jmp_buf mark; char error[MAX_STRING];
! 55: OCIEnv *envhp;
! 56: OCIServer *srvhp;
! 57: OCIError *errhp;
! 58: OCISvcCtx *svchp;
! 59: OCISession *usrhp;
! 60: };
! 61:
! 62: struct OracleSQL_query_lobs {
! 63: struct return_rows {
! 64: struct return_row {
! 65: OCILobLocator *locator; ub4 len;
! 66: int ind;
! 67: ub2 rcode;
! 68: } *row;
! 69: int count;
! 70: };
! 71: struct cbf_context_struct {
! 72: SQL_Driver_services *services;
! 73: OracleSQL_connection_struct *cs;
! 74: return_rows *rows;
! 75: };
! 76: struct Item {
! 77: const char *name_ptr; size_t name_size;
! 78: char *data_ptr; size_t data_size;
! 79: OCILobLocator *locator;
! 80: OCIBind *bind;
! 81: return_rows rows;
! 82: } items[MAX_IN_LOBS];
! 83: int count;
! 84: };
! 85: #endif
! 86:
! 87: // forwards
! 88: void check(
! 89: SQL_Driver_services& services, OracleSQL_connection_struct &cs,
! 90: const char *step, sword status);
! 91: static sb4 cbf_no_data(
! 92: dvoid *ctxp,
! 93: OCIBind *bindp,
! 94: ub4 iter, ub4 index,
! 95: dvoid **bufpp,
! 96: ub4 *alenpp,
! 97: ub1 *piecep,
! 98: dvoid **indpp);
! 99: static sb4 cbf_get_data(dvoid *ctxp,
! 100: OCIBind *bindp,
! 101: ub4 iter, ub4 index,
! 102: dvoid **bufpp,
! 103: ub4 **alenp,
! 104: ub1 *piecep,
! 105: dvoid **indpp,
! 106: ub2 **rcodepp);
! 107: void tolower(char *out, const char *in, size_t size);
! 108:
! 109: /**
! 110: OracleSQL server driver
! 111: @test NLS_LANG=AMERICAN_AMERICA.CL8MSWIN1251
! 112: */
! 113: class OracleSQL_Driver : public SQL_Driver {
! 114: public:
! 115:
! 116: OracleSQL_Driver() : SQL_Driver() {
! 117: }
! 118:
! 119: /// get api version
! 120: int api_version() { return SQL_DRIVER_API_VERSION; }
! 121: /// initialize driver by loading sql dynamic link library
! 122: const char *initialize(const char *dlopen_file_spec) {
! 123:
! 124: const char *error=dlopen_file_spec?
! 125: dlink(dlopen_file_spec):"client library column is empty";
! 126: if(!error) {
! 127:
! 128: // error="OCIInitialize replacer";/*
! 129: OCIInitialize((ub4)OCI_THREADED, (dvoid *)0,
! 130: (dvoid * (*)(void *, unsigned int))0,
! 131: (dvoid * (*)(void*, void*, unsigned int))0,
! 132: (void (*)(void*, void*))0 );
! 133:
! 134: // */
! 135: }
! 136:
! 137: return error;
! 138: }
! 139:
! 140: /** connect
! 141: @param used_only_in_connect_url
! 142: format: @b user:pass@service
! 143: */
! 144: void connect(
! 145: char *used_only_in_connect_url,
! 146: SQL_Driver_services& services,
! 147: void **connection ///< output: OracleSQL_connection_struct *
! 148: ) {
! 149: // connections are cross-request, do not use services._alloc [linked with request]
! 150: OracleSQL_connection_struct &cs=
! 151: *(OracleSQL_connection_struct *)::calloc(sizeof(OracleSQL_connection_struct), 1);
! 152:
! 153: char *user=used_only_in_connect_url;
! 154: char *service=lsplit(user, '@');
! 155: char *pwd=lsplit(user, ':');
! 156:
! 157: if(!(user && pwd && service))
! 158: services._throw("mailformed connect part, must be 'user:pass@service'");
! 159:
! 160: if(setjmp(cs.mark))
! 161: services._throw(cs.error);
! 162:
! 163: // Allocate and initialize OCIError handle, attempt #1
! 164: /*
! 165: grabbed from sample
! 166: /server.804/a58234/oci_func.htm#446192
! 167: but doc
! 168: /server.804/a58234/oci_func.htm#446100
! 169: doesnt have this param listed as allowed
! 170: 8.1.6 client library barks as OCI_INVALID_HANDLE
! 171: and debugging revealed that OCI_HTYPE_ENV param value is invalid
! 172: later in doc
! 173: /server.804/a58234/oci_func.htm#446192
! 174: on OCIEnvInit thay say
! 175: "No changes are done to an already initialized handle"
! 176: think, this is some sort of backward compatibility wonder.
! 177: leaving as it is, and without check()
! 178: */
! 179: OCIHandleAlloc((dvoid *)NULL, (dvoid **) &cs.envhp, (ub4)OCI_HTYPE_ENV, 0, 0);
! 180: // Initialize an environment handle, attempt #2
! 181: check(services, cs, "EnvInit", OCIEnvInit(
! 182: &cs.envhp, (ub4)OCI_DEFAULT, 0, 0));
! 183: // Allocate and initialize OCIError handle
! 184: check(services, cs, "HandleAlloc errhp", OCIHandleAlloc(
! 185: (dvoid *)cs.envhp, (dvoid **) &cs.errhp, (ub4)OCI_HTYPE_ERROR, 0, 0));
! 186: // Allocate and initialize OCIServer handle
! 187: check(services, cs, "HandleAlloc srvhp", OCIHandleAlloc(
! 188: (dvoid *)cs.envhp, (dvoid **) &cs.srvhp, (ub4)OCI_HTYPE_SERVER, 0, 0));
! 189: // Attach to a 'service'; initialize server context handle
! 190: check(services, cs, "ServerAttach", OCIServerAttach(
! 191: cs.srvhp, cs.errhp, (text *)service, (sb4)strlen(service), (ub4)OCI_DEFAULT));
! 192: // Allocate and initialize OCISvcCtx handle
! 193: check(services, cs, "HandleAlloc svchp", OCIHandleAlloc(
! 194: (dvoid *)cs.envhp, (dvoid **) &cs.svchp, (ub4)OCI_HTYPE_SVCCTX, 0, 0));
! 195: // set attribute server context in the service context
! 196: check(services, cs, "AttrSet server-service", OCIAttrSet(
! 197: (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX,
! 198: (dvoid *)cs.srvhp, (ub4)0,
! 199: (ub4)OCI_ATTR_SERVER, (OCIError *)cs.errhp));
! 200: // allocate a user context handle
! 201: check(services, cs, "HandleAlloc usrhp", OCIHandleAlloc(
! 202: (dvoid *)cs.envhp, (dvoid **)&cs.usrhp, (ub4)OCI_HTYPE_SESSION, 0, 0));
! 203: // set 'user' name
! 204: check(services, cs, "AttrSet user-session", OCIAttrSet(
! 205: (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION,
! 206: (dvoid *)user, (ub4)strlen(user),
! 207: OCI_ATTR_USERNAME, cs.errhp));
! 208: // set 'pwd' password
! 209: check(services, cs, "AttrSet pwd-session", OCIAttrSet(
! 210: (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION,
! 211: (dvoid *)pwd, (ub4)strlen(pwd),
! 212: OCI_ATTR_PASSWORD, cs.errhp));
! 213: // Authenticate a user
! 214: check(services, cs, "SessionBegin", OCISessionBegin(
! 215: cs.svchp, cs.errhp, cs.usrhp,
! 216: OCI_CRED_RDBMS, OCI_DEFAULT));
! 217: // remember connection in session
! 218: check(services, cs, "AttrSet service-session", OCIAttrSet(
! 219: (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX,
! 220: (dvoid *)cs.usrhp, (ub4)0,
! 221: OCI_ATTR_SESSION, cs.errhp));
! 222:
! 223: // return created connection
! 224: *(OracleSQL_connection_struct **)connection=&cs;
! 225: }
! 226: void disconnect(void *connection) {
! 227:
! 228: return;
! 229:
! 230:
! 231: OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;
! 232: // Terminate a user session
! 233: OCISessionEnd(
! 234: cs.svchp, cs.errhp, cs.usrhp, (ub4)OCI_DEFAULT);
! 235: // Detach from a server; uninitialize server context handle
! 236: OCIServerDetach(
! 237: cs.srvhp, cs.errhp, (ub4)OCI_DEFAULT);
! 238: // Free a previously allocated handles
! 239: /*
! 240: oci will free them up as belonging to env
! 241: OCIHandleFree(
! 242: (dvoid *)cs.srvhp, (ub4)OCI_HTYPE_SERVER);
! 243: OCIHandleFree(
! 244: (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX);
! 245: OCIHandleFree(
! 246: (dvoid *)cs.errhp, (ub4)OCI_HTYPE_ERROR);
! 247: */
! 248: OCIHandleFree(
! 249: (dvoid *)cs.envhp, (ub4)OCI_HTYPE_ENV);
! 250:
! 251: // connections are cross-request, do not use services._alloc [linked with request]
! 252: ::free(&cs);
! 253: }
! 254: void commit(SQL_Driver_services& services, void *connection) {
! 255: OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;
! 256: if(setjmp(cs.mark))
! 257: services._throw(cs.error);
! 258:
! 259: check(services, cs, "commit", OCITransCommit(cs.svchp, cs.errhp, 0));
! 260: }
! 261: void rollback(SQL_Driver_services& services, void *connection) {
! 262: OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;
! 263: if(setjmp(cs.mark))
! 264: services._throw(cs.error);
! 265:
! 266: check(services, cs, "rollback", OCITransRollback(cs.svchp, cs.errhp, 0));
! 267: }
! 268:
! 269: bool ping(SQL_Driver_services&, void *connection) {
! 270: // maybe OCIServerVersion?
! 271: return true;
! 272: }
! 273:
! 274: unsigned int quote(
! 275: SQL_Driver_services&, void *,
! 276: char *to, const char *from, unsigned int length) {
! 277: /*
! 278: it's already UNTAINT_TIMES_BIGGER
! 279: */
! 280: unsigned int result=length;
! 281: while(length--) {
! 282: switch(*from) {
! 283: case '\'': // "'" -> "''"
! 284: *to++='\'';
! 285: break;
! 286: case '\\': // "\" -> "\\"
! 287: *to++='\'';
! 288: break;
! 289: }
! 290: *to++=*from++;
! 291: }
! 292: return result;
! 293: }
! 294: void query(
! 295: SQL_Driver_services& services, void *connection,
! 296: const char *astatement, unsigned long offset, unsigned long limit,
! 297: SQL_Driver_query_event_handlers& handlers) {
! 298:
! 299: OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;
! 300: OracleSQL_query_lobs lobs={{0}, 0};
! 301: OCIStmt *stmthp=0;
! 302:
! 303: bool failed=false;
! 304: if(setjmp(cs.mark)) {
! 305: failed=true;
! 306: goto cleanup;
! 307: } else {
! 308: const char *statement=preprocess_statement(services, cs,
! 309: astatement, lobs);
! 310:
! 311: check(services, cs, "HandleAlloc STMT", OCIHandleAlloc(
! 312: (dvoid *)cs.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0));
! 313: check(services, cs, "syntax",
! 314: OCIStmtPrepare(stmthp, cs.errhp, (unsigned char *)statement,
! 315: (ub4)strlen((char *)statement),
! 316: (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT));
! 317: {
! 318: for(int i=0; i<lobs.count; i++) {
! 319: check(services, cs, "alloc output var desc", OCIDescriptorAlloc(
! 320: (dvoid *)cs.envhp, (dvoid **)&lobs.items[i].locator, (ub4)OCI_DTYPE_LOB, 0, 0));
! 321:
! 322: check(services, cs, "bind output", OCIBindByPos(stmthp,
! 323: &lobs.items[i].bind, cs.errhp,
! 324: (ub4)1+i,
! 325: (dvoid *)&lobs.items[i].locator,
! 326: (sword)sizeof (lobs.items[i].locator), SQLT_CLOB, (dvoid *)0,
! 327: (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DATA_AT_EXEC));
! 328:
! 329: lobs.items[i].rows.count=0;
! 330: OracleSQL_query_lobs::cbf_context_struct cbf_context={
! 331: &services, &cs, &lobs.items[i].rows};
! 332: check(services, cs, "bind dynamic", OCIBindDynamic(
! 333: lobs.items[i].bind, cs.errhp,
! 334: (dvoid *) &cbf_context, cbf_no_data,
! 335: (dvoid *) &cbf_context, cbf_get_data));
! 336: }
! 337: }
! 338:
! 339: execute_prepared(services, cs,
! 340: statement, stmthp, lobs,
! 341: offset, limit, handlers);
! 342: }
! 343: cleanup: // no check call after this point!
! 344: {
! 345: for(int i=0; i<lobs.count; i++) {
! 346: /* free var locator */
! 347: if(OCILobLocator *locator=lobs.items[i].locator)
! 348: OCIDescriptorFree((dvoid *)locator, (ub4)OCI_DTYPE_LOB);
! 349:
! 350: /* free rows descriptors */
! 351: OracleSQL_query_lobs::return_rows &rows=lobs.items[i].rows;
! 352: for(int r=0; r<rows.count; r++)
! 353: OCIDescriptorFree((dvoid *)rows.row[r].locator, (ub4)OCI_DTYPE_LOB);
! 354: }
! 355: }
! 356: if(stmthp)
! 357: OCIHandleFree((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT);
! 358:
! 359: if(failed)
! 360: services._throw(cs.error);
! 361: }
! 362:
! 363: private: // private funcs
! 364:
! 365: const char *preprocess_statement(SQL_Driver_services& services, OracleSQL_connection_struct &cs,
! 366: const char *astatement, OracleSQL_query_lobs &lobs) {
! 367: size_t statement_size=strlen(astatement);
! 368:
! 369: char *result=(char *)services.malloc(statement_size
! 370: +MAX_STRING // in case of short 'strings'
! 371: +11/* returning */+6/* into */+(MAX_LOB_NAME_LENGTH+2/*:, */)*2/*ret into*/*MAX_IN_LOBS
! 372: +1);
! 373: const char *o=astatement;
! 374:
! 375: // /**xxx**/'literal' -> EMPTY_CLOB_FUNC_CALL
! 376: char *n=result;
! 377: while(*o) {
! 378: if(
! 379: o[0]=='/' &&
! 380: o[1]=='*' &&
! 381: o[2]=='*') { // name start
! 382: o+=3;
! 383: const char *name_begin=o;
! 384: while(*o)
! 385: if(
! 386: o[0]=='*' &&
! 387: o[1]=='*' &&
! 388: o[2]=='/' &&
! 389: o[3]=='\'') { // name end
! 390: const char *name_end=o;
! 391: o+=4;
! 392: OracleSQL_query_lobs::Item &item=lobs.items[lobs.count++];
! 393: item.name_ptr=name_begin; item.name_size=name_end-name_begin;
! 394: item.data_ptr=(char *)services.malloc(statement_size/*max*/); item.data_size=0;
! 395:
! 396: const char *start=o;
! 397: bool escaped=false;
! 398: while(*o && !(o[0]=='\'' && o[1]!='\'' && !escaped)) {
! 399: escaped=*o=='\\' || (o[0]=='\'' && o[1]=='\'');
! 400: if(escaped) {
! 401: // write pending, skip "\" or "'"
! 402: if(size_t size=o-start) {
! 403: memcpy(item.data_ptr+item.data_size, start, size);
! 404: item.data_size+=size;
! 405: }
! 406: start=++o;
! 407: } else
! 408: o++;
! 409: }
! 410: if(size_t size=o-start) {
! 411: memcpy(item.data_ptr+item.data_size, start, size);
! 412: item.data_size+=size;
! 413: }
! 414: if(*o)
! 415: o++; // skip "'"
! 416:
! 417: n+=sprintf(n, EMPTY_CLOB_FUNC_CALL);
! 418: break;
! 419: } else
! 420: o++; // /**skip**/'xxx'
! 421: } else
! 422: *n++=*o++;
! 423: }
! 424: *n=0;
! 425:
! 426: if(lobs.count) {
! 427: int i;
! 428: n+=sprintf(n, " returning ");
! 429: for(i=0; i<lobs.count; i++) {
! 430: if(i)
! 431: *n++=',';
! 432: n+=sprintf(n, "%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr);
! 433: /*memcpy(n, lobs.items[i].name_ptr, lobs.items[i].name_size);
! 434: n+=lobs.items[i].name_size;*/
! 435: }
! 436: n+=sprintf(n, " into ");
! 437: for(i=0; i<lobs.count; i++) {
! 438: if(i)
! 439: *n++='x';
! 440: n+=sprintf(n, ":%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr);
! 441: /**n++=':';
! 442: memcpy(n, lobs.items[i].name_ptr, lobs.items[i].name_size);
! 443: n+=lobs.items[i].name_size;*/
! 444: }
! 445: }
! 446:
! 447: return result;
! 448: }
! 449:
! 450: void execute_prepared(
! 451: SQL_Driver_services& services, OracleSQL_connection_struct &cs,
! 452: const char *statement, OCIStmt *stmthp, OracleSQL_query_lobs &lobs,
! 453: unsigned long offset, unsigned long limit,
! 454: SQL_Driver_query_event_handlers& handlers) {
! 455:
! 456: ub2 stmt_type=0; // UNKNOWN
! 457: /*
! 458: //gpfs on sun. paf 000818
! 459: //Zanyway, this is needed before.
! 460: check(services, cs, "get stmt type", OCIAttrGet(
! 461: (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, (ub1 *)&stmt_type,
! 462: (ub4 *)0, OCI_ATTR_STMT_TYPE, cs.errhp));
! 463: */
! 464: if(strncasecmp(statement, "select", 6)==0)
! 465: stmt_type=OCI_STMT_SELECT;
! 466: else if(strncasecmp(statement, "insert", 6)==0)
! 467: stmt_type=OCI_STMT_INSERT;
! 468: else if(strncasecmp(statement, "update", 6)==0)
! 469: stmt_type=OCI_STMT_UPDATE;
! 470:
! 471: sword status=OCIStmtExecute(cs.svchp, stmthp, cs.errhp,
! 472: (ub4)stmt_type==OCI_STMT_SELECT?0:1, (ub4)0,
! 473: (OCISnapshot *)NULL,
! 474: (OCISnapshot *)NULL, (ub4)OCI_DEFAULT);
! 475:
! 476: if(status!=OCI_NO_DATA)
! 477: check(services, cs, "execute", status);
! 478:
! 479: {
! 480: for(int i=0; i<lobs.count; i++)
! 481: if(ub4 bytes_to_write=lobs.items[i].data_size) {
! 482: OracleSQL_query_lobs::return_rows *rows=&lobs.items[i].rows;
! 483: for(int r=0; r<rows->count; r++) {
! 484: OCILobLocator *locator=rows->row[r].locator;
! 485: check(services, cs, "lobwrite", OCILobWrite (
! 486: cs.svchp, cs.errhp,
! 487: locator, &bytes_to_write, 1,
! 488: (dvoid *)lobs.items[i].data_ptr, (ub4)bytes_to_write, OCI_ONE_PIECE,
! 489: (dvoid *)0, 0, (ub2)0,
! 490: (ub1) SQLCS_IMPLICIT));
! 491: }
! 492: }
! 493: }
! 494:
! 495: switch(stmt_type) {
! 496: case OCI_STMT_SELECT:
! 497: fetch_table(services, cs,
! 498: stmthp, offset, limit,
! 499: handlers);
! 500: break;
! 501: default:
! 502: /*
! 503: case OCI_STMT_INSERT:
! 504: case OCI_STMT_UPDATE:
! 505: */
! 506: break;
! 507: }
! 508: }
! 509:
! 510: void fetch_table(SQL_Driver_services& services, OracleSQL_connection_struct &cs,
! 511: OCIStmt *stmthp, unsigned long offset, unsigned long limit,
! 512: SQL_Driver_query_event_handlers& handlers) {
! 513:
! 514: OCIParam *mypard;
! 515: ub2 dtype;
! 516: text *col_name;
! 517:
! 518: struct {
! 519: ub2 type;
! 520: char *str;
! 521: OCILobLocator *var;
! 522: OCIDefine *def;
! 523: sb2 indicator;
! 524: } cols[MAX_COLS]={0};
! 525: int column_count=0;
! 526:
! 527: bool failed=false;
! 528: jmp_buf saved_mark; memcpy(saved_mark, cs.mark, sizeof(jmp_buf));
! 529: if(setjmp(cs.mark)) {
! 530: failed=true;
! 531: goto cleanup;
! 532: } else {
! 533: // idea of preincrementing is that at error time all handles would free up
! 534: while(++column_count<=MAX_COLS) {
! 535: /* get next descriptor, if there is one */
! 536: if(OCIParamGet(stmthp, OCI_HTYPE_STMT, cs.errhp, (void **)&mypard,
! 537: (ub4) column_count)!=OCI_SUCCESS)
! 538: break;
! 539:
! 540: /* Retrieve the data type attribute */
! 541: check(services, cs, "get type", OCIAttrGet(
! 542: (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM,
! 543: (dvoid*) &dtype, (ub4 *)0, (ub4)OCI_ATTR_DATA_TYPE,
! 544: (OCIError *)cs.errhp));
! 545:
! 546: /* Retrieve the column name attribute */
! 547: ub4 col_name_len;
! 548: check(services, cs, "get name", OCIAttrGet(
! 549: (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM,
! 550: (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME,
! 551: (OCIError *)cs.errhp));
! 552:
! 553: {
! 554: size_t size=(size_t)col_name_len;
! 555: char *ptr=(char *)services.malloc(size);
! 556: tolower(ptr, (char *)col_name, size);
! 557: handlers.add_column(ptr, size);
! 558: }
! 559:
! 560: ub2 coerce_type=dtype;
! 561: sb4 size=0;
! 562: void *ptr;
! 563:
! 564: switch(dtype) {
! 565: case SQLT_CLOB:
! 566: {
! 567: check(services, cs, "alloc output var desc", OCIDescriptorAlloc(
! 568: (dvoid *)cs.envhp, (dvoid **)(ptr=&cols[column_count-1].var),
! 569: (ub4)OCI_DTYPE_LOB,
! 570: 0, (dvoid **)0));
! 571:
! 572: size=0;
! 573: break;
! 574: }
! 575: default:
! 576: coerce_type=SQLT_STR;
! 577: ptr=cols[column_count-1].str=(char *)services.malloc(MAX_OUT_STRING_LENGTH+1);
! 578: size=MAX_OUT_STRING_LENGTH;
! 579: break;
! 580: }
! 581:
! 582: cols[column_count-1].type=coerce_type;
! 583:
! 584: check(services, cs, "DefineByPos", OCIDefineByPos(
! 585: stmthp, &cols[column_count-1].def, cs.errhp,
! 586: column_count, (ub1 *) ptr, size,
! 587: coerce_type, (dvoid *) &cols[column_count-1].indicator,
! 588: (ub2 *)0, (ub2 *)0, OCI_DEFAULT));
! 589: }
! 590:
! 591: handlers.before_rows();
! 592:
! 593: for(unsigned long row=0; !limit||row<limit+offset; row++) {
! 594: sword status=OCIStmtFetch(stmthp, cs.errhp, (ub4)1, (ub4)OCI_FETCH_NEXT,
! 595: (ub4)OCI_DEFAULT);
! 596: if(status!=OCI_SUCCESS) {
! 597: if(status!=OCI_NO_DATA)
! 598: check(services, cs, "fetch", status);
! 599: break;
! 600: }
! 601: if(row>=offset) {
! 602: handlers.add_row();
! 603: for(int i=0; i<column_count; i++) {
! 604: size_t size;
! 605: void *ptr;
! 606: if(cols[i].indicator) { // NULL?
! 607: size=0;
! 608: ptr=0;
! 609: } else // not NULL
! 610: switch(cols[i].type) {
! 611: case SQLT_CLOB:
! 612: {
! 613: ub4 amtp=4096000000UL;
! 614: ub4 offset=1;
! 615: ub4 loblen=0;
! 616: OCILobLocator *var=(OCILobLocator *)cols[i].var;
! 617: OCILobGetLength(cs.svchp, cs.errhp, var, &loblen);
! 618: if(loblen) {
! 619: size=(size_t)loblen;
! 620: ptr=services.malloc(size);
! 621: check(services, cs, "lobread", OCILobRead(cs.svchp, cs.errhp,
! 622: var, &amtp, offset, (dvoid *) ptr,
! 623: loblen, (dvoid *)0,
! 624: 0,
! 625: (ub2)0, (ub1) SQLCS_IMPLICIT));
! 626: }
! 627: break;
! 628: }
! 629: default:
! 630: if(const char *str=cols[i].str) {
! 631: size=strlen(str);
! 632: ptr=services.malloc(size);
! 633: memcpy(ptr, str, size);
! 634: } else {
! 635: size=0;
! 636: ptr=0;
! 637: }
! 638: break;
! 639: }
! 640: handlers.add_row_cell(ptr, size);
! 641: }
! 642: }
! 643: }
! 644: }
! 645:
! 646: cleanup: // no check call after this point!
! 647: for(int i=0; i<column_count; i++) {
! 648: switch(cols[i].type) {
! 649: case SQLT_CLOB:
! 650: /* free var locator */
! 651: OCIDescriptorFree((dvoid *) cols[i].var, (ub4)OCI_DTYPE_LOB);
! 652: break;
! 653: default:
! 654: break;
! 655: }
! 656: }
! 657:
! 658: if(failed) // need rethrow?
! 659: longjmp(saved_mark, 1);
! 660: }
! 661:
! 662: private: // conn client library funcs
! 663:
! 664: friend void check(
! 665: SQL_Driver_services& services, OracleSQL_connection_struct &cs,
! 666: const char *step, sword status);
! 667: friend sb4 cbf_get_data(dvoid *ctxp,
! 668: OCIBind *bindp,
! 669: ub4 iter, ub4 index,
! 670: dvoid **bufpp,
! 671: ub4 **alenp,
! 672: ub1 *piecep,
! 673: dvoid **indpp,
! 674: ub2 **rcodepp);
! 675:
! 676:
! 677: #define OCI_DECL(name, params) \
! 678: typedef sword (*t_OCI##name)params; t_OCI##name OCI##name
! 679:
! 680: OCI_DECL(Initialize, (ub4 mode, dvoid *ctxp,
! 681: dvoid * (*malocfp)(dvoid *ctxp, size_t size),
! 682: dvoid * (*ralocfp)(dvoid *ctxp, dvoid *memptr, size_t newsize),
! 683: void (*mfreefp)(dvoid *ctxp, dvoid *memptr) ));
! 684:
! 685: OCI_DECL(EnvInit, (OCIEnv **envp, ub4 mode,
! 686: size_t xtramem_sz, dvoid **usrmempp));
! 687:
! 688: OCI_DECL(AttrGet, (CONST dvoid *trgthndlp, ub4 trghndltyp,
! 689: dvoid *attributep, ub4 *sizep, ub4 attrtype,
! 690: OCIError *errhp));
! 691:
! 692: OCI_DECL(AttrSet, (dvoid *trgthndlp, ub4 trghndltyp, dvoid *attributep,
! 693: ub4 size, ub4 attrtype, OCIError *errhp));
! 694:
! 695: OCI_DECL(BindByPos, (OCIStmt *stmtp, OCIBind **bindp, OCIError *errhp,
! 696: ub4 position, dvoid *valuep, sb4 value_sz,
! 697: ub2 dty, dvoid *indp, ub2 *alenp, ub2 *rcodep,
! 698: ub4 maxarr_len, ub4 *curelep, ub4 mode));
! 699:
! 700: OCI_DECL(BindDynamic, (OCIBind *bindp, OCIError *errhp, dvoid *ictxp,
! 701: OCICallbackInBind icbfp, dvoid *octxp,
! 702: OCICallbackOutBind ocbfp));
! 703:
! 704: OCI_DECL(DefineByPos, (OCIStmt *stmtp, OCIDefine **defnp, OCIError *errhp,
! 705: ub4 position, dvoid *valuep, sb4 value_sz, ub2 dty,
! 706: dvoid *indp, ub2 *rlenp, ub2 *rcodep, ub4 mode));
! 707:
! 708: OCI_DECL(DescriptorAlloc, (CONST dvoid *parenth, dvoid **descpp,
! 709: CONST ub4 type, CONST size_t xtramem_sz,
! 710: dvoid **usrmempp));
! 711:
! 712: OCI_DECL(DescriptorFree, (dvoid *descp, CONST ub4 type));
! 713:
! 714:
! 715: OCI_DECL(ErrorGet, (dvoid *hndlp, ub4 recordno, OraText *sqlstate,
! 716: sb4 *errcodep, OraText *bufp, ub4 bufsiz, ub4 type));
! 717:
! 718: OCI_DECL(HandleAlloc, (CONST dvoid *parenth, dvoid **hndlpp, CONST ub4 type,
! 719: CONST size_t xtramem_sz, dvoid **usrmempp));
! 720:
! 721: OCI_DECL(HandleFree, (dvoid *hndlp, CONST ub4 type));
! 722:
! 723: OCI_DECL(LobGetLength, (OCISvcCtx *svchp, OCIError *errhp,
! 724: OCILobLocator *locp,
! 725: ub4 *lenp));
! 726:
! 727: OCI_DECL(LobRead, (OCISvcCtx *svchp, OCIError *errhp, OCILobLocator *locp,
! 728: ub4 *amtp, ub4 offset, dvoid *bufp, ub4 bufl,
! 729: dvoid *ctxp, sb4 (*cbfp)(dvoid *ctxp,
! 730: CONST dvoid *bufp,
! 731: ub4 len,
! 732: ub1 piece),
! 733: ub2 csid, ub1 csfrm));
! 734:
! 735: OCI_DECL(LobWrite, (OCISvcCtx *svchp, OCIError *errhp, OCILobLocator *locp,
! 736: ub4 *amtp, ub4 offset, dvoid *bufp, ub4 buflen,
! 737: ub1 piece, dvoid *ctxp,
! 738: sb4 (*cbfp)(dvoid *ctxp,
! 739: dvoid *bufp,
! 740: ub4 *len,
! 741: ub1 *piece),
! 742: ub2 csid, ub1 csfrm));
! 743:
! 744: OCI_DECL(ParamGet, (CONST dvoid *hndlp, ub4 htype, OCIError *errhp,
! 745: dvoid **parmdpp, ub4 pos));
! 746:
! 747: OCI_DECL(ServerAttach, (OCIServer *srvhp, OCIError *errhp,
! 748: CONST OraText *dblink, sb4 dblink_len, ub4 mode));
! 749:
! 750: OCI_DECL(ServerDetach, (OCIServer *srvhp, OCIError *errhp, ub4 mode));
! 751:
! 752: OCI_DECL(SessionBegin, (OCISvcCtx *svchp, OCIError *errhp, OCISession *usrhp,
! 753: ub4 credt, ub4 mode));
! 754:
! 755: OCI_DECL(SessionEnd, (OCISvcCtx *svchp, OCIError *errhp, OCISession *usrhp,
! 756: ub4 mode));
! 757:
! 758: OCI_DECL(StmtExecute, (OCISvcCtx *svchp, OCIStmt *stmtp, OCIError *errhp,
! 759: ub4 iters, ub4 rowoff, CONST OCISnapshot *snap_in,
! 760: OCISnapshot *snap_out, ub4 mode));
! 761:
! 762: OCI_DECL(StmtFetch, (OCIStmt *stmtp, OCIError *errhp, ub4 nrows,
! 763: ub2 orientation, ub4 mode));
! 764:
! 765: OCI_DECL(StmtPrepare, (OCIStmt *stmtp, OCIError *errhp, CONST OraText *stmt,
! 766: ub4 stmt_len, ub4 language, ub4 mode));
! 767:
! 768: OCI_DECL(TransCommit, (OCISvcCtx *svchp, OCIError *errhp, ub4 flags));
! 769:
! 770: OCI_DECL(TransRollback, (OCISvcCtx *svchp, OCIError *errhp, ub4 flags));
! 771:
! 772: private: // conn client library funcs linking
! 773:
! 774: const char *dlink(const char *dlopen_file_spec) {
! 775: if(lt_dlinit())
! 776:
! 777: return lt_dlerror();
! 778:
! 779:
! 780:
! 781: lt_dlhandle handle=lt_dlopen(dlopen_file_spec);
! 782:
! 783: //return "hren31";
! 784:
! 785: if(!handle)
! 786: return lt_dlerror(); //"can not open the dynamic link module";
! 787:
! 788: #define DSLINK(name, action) \
! 789: name=(t_##name)lt_dlsym(handle, #name); \
! 790: if(!name) \
! 791: action;
! 792:
! 793: #define OCI_LINK(name) DSLINK(OCI##name, return "function OCI" #name " was not found")
! 794:
! 795: OCI_LINK(Initialize);
! 796: OCI_LINK(EnvInit);
! 797: OCI_LINK(AttrGet); OCI_LINK(AttrSet);
! 798: OCI_LINK(BindByPos); OCI_LINK(BindDynamic);
! 799: OCI_LINK(DefineByPos);
! 800: OCI_LINK(DescriptorAlloc); OCI_LINK(DescriptorFree);
! 801: OCI_LINK(ErrorGet);
! 802: OCI_LINK(HandleAlloc); OCI_LINK(HandleFree);
! 803: OCI_LINK(LobGetLength);
! 804: OCI_LINK(LobRead); OCI_LINK(LobWrite);
! 805: OCI_LINK(ParamGet);
! 806: OCI_LINK(ServerAttach); OCI_LINK(ServerDetach);
! 807: OCI_LINK(SessionBegin); OCI_LINK(SessionEnd);
! 808: OCI_LINK(StmtExecute); OCI_LINK(StmtFetch); OCI_LINK(StmtPrepare);
! 809: OCI_LINK(TransCommit); OCI_LINK(TransRollback);
! 810:
! 811: return 0;
! 812: }
! 813:
! 814: } *OracleSQL_driver;
! 815:
! 816: void check(
! 817: SQL_Driver_services& services, OracleSQL_connection_struct &cs,
! 818: const char *step, sword status) {
! 819:
! 820: const char *msg;
! 821: char reason[MAX_STRING/2];
! 822:
! 823: switch (status) {
! 824: case OCI_SUCCESS:
! 825: return; // hurrah
! 826: case OCI_ERROR:
! 827: {
! 828: sb4 errcode;
! 829: if(OracleSQL_driver->OCIErrorGet((dvoid *)cs.errhp, (ub4)1, (text *)NULL, &errcode,
! 830: (text *)reason, (ub4)sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS)
! 831: msg=reason;
! 832: else
! 833: msg="[can not get error description]";
! 834: break;
! 835: }
! 836: case OCI_SUCCESS_WITH_INFO:
! 837: msg="SUCCESS_WITH_INFO"; break;
! 838: case OCI_NEED_DATA:
! 839: msg="NEED_DATA"; break;
! 840: case OCI_NO_DATA:
! 841: msg="NODATA"; break;
! 842: case OCI_INVALID_HANDLE:
! 843: msg="INVALID_HANDLE"; break;
! 844: case OCI_STILL_EXECUTING:
! 845: msg="STILL_EXECUTE"; break;
! 846: case OCI_CONTINUE:
! 847: msg="CONTINUE"; break;
! 848: default:
! 849: msg="unknown"; break;
! 850: }
! 851:
! 852: snprintf(cs.error, sizeof(cs.error), "%s (%s, %d)",
! 853: msg, step, (int)status);
! 854: longjmp(cs.mark, 1);
! 855: }
! 856:
! 857:
! 858: /* ----------------------------------------------------------------- */
! 859: /* Intbind callback that does not do any data input. */
! 860: /* ----------------------------------------------------------------- */
! 861: static sb4 cbf_no_data(
! 862: dvoid *ctxp,
! 863: OCIBind *bindp,
! 864: ub4 iter, ub4 index,
! 865: dvoid **bufpp,
! 866: ub4 *alenpp,
! 867: ub1 *piecep,
! 868: dvoid **indpp) {
! 869: *bufpp=(dvoid *)0;
! 870: *alenpp=0;
! 871: static sb2 null_ind=-1;
! 872: *indpp=(dvoid *) &null_ind;
! 873: *piecep=OCI_ONE_PIECE;
! 874:
! 875: return OCI_CONTINUE;
! 876: }
! 877:
! 878: /* ----------------------------------------------------------------- */
! 879: /* Outbind callback for returning data. */
! 880: /* ----------------------------------------------------------------- */
! 881: static sb4 cbf_get_data(dvoid *ctxp,
! 882: OCIBind *bindp,
! 883: ub4 iter, ub4 index,
! 884: dvoid **bufpp,
! 885: ub4 **alenp,
! 886: ub1 *piecep,
! 887: dvoid **indpp,
! 888: ub2 **rcodepp) {
! 889: OracleSQL_query_lobs::cbf_context_struct &context=
! 890: *(OracleSQL_query_lobs::cbf_context_struct *)ctxp;
! 891:
! 892: if(index==0) {
! 893: static ub4 rows;
! 894: check(*context.services, *context.cs, "AttrGet cbf_get_data ROWS_RETURNED",
! 895: OracleSQL_driver->OCIAttrGet(
! 896: (CONST dvoid *) bindp, OCI_HTYPE_BIND, (dvoid *)&rows,
! 897: (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.cs->errhp)) ;
! 898: context.rows->count=(ub2)rows;
! 899: context.rows->row=(OracleSQL_query_lobs::return_rows::return_row *)
! 900: context.services->malloc(sizeof(OracleSQL_query_lobs::return_rows::return_row)*rows);
! 901: }
! 902:
! 903: OracleSQL_query_lobs::return_rows::return_row &var=context.rows->row[index];
! 904:
! 905: check(*context.services, *context.cs, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc(
! 906: (dvoid *) context.cs->envhp, (dvoid **)&var.locator,
! 907: (ub4)OCI_DTYPE_LOB,
! 908: 0, (dvoid **)0));
! 909:
! 910: *bufpp=var.locator;
! 911: *alenp=&var.len;
! 912: *indpp=(dvoid *) &var.ind;
! 913: *piecep=OCI_ONE_PIECE;
! 914: *rcodepp=&var.rcode;
! 915:
! 916: return OCI_CONTINUE;
! 917: }
! 918:
! 919: void tolower(char *out, const char *in, size_t size) {
! 920: while(size--)
! 921: *out++=tolower(*in++);
! 922: }
! 923:
! 924: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
! 925: //_asm int 3;
! 926: return OracleSQL_driver=new OracleSQL_Driver();
! 927: }
E-mail: