Annotation of parser3/src/sql/oracle/parser3oracle.C, revision 1.2

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, tested with Oracle 7.x.x
                      9: */
1.2     ! parser     10: static const char *RCSId="$Id: parser3oracle.C,v 1.1 2001/08/22 14:02:17 parser Exp $"; 
1.1       parser     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: struct OracleSQL_connection_struct {
                     53:        jmp_buf mark; char error[MAX_STRING];
                     54:        OCIEnv *envhp;
                     55:        OCIServer *srvhp;
                     56:        OCIError *errhp;
                     57:        OCISvcCtx *svchp;
                     58:        OCISession *usrhp;
                     59: };
                     60: 
                     61: struct OracleSQL_query_lobs {
                     62:        struct return_rows {
                     63:                struct return_row {
                     64:                        OCILobLocator *locator; ub4 len;
                     65:                        int ind;                
                     66:                        ub2 rcode;
                     67:                } *row;
                     68:                int count;
                     69:        };
                     70:        struct cbf_context_struct {
                     71:                SQL_Driver_services *services;
                     72:                OracleSQL_connection_struct *cs;
                     73:                return_rows *rows;
                     74:        };
                     75:        struct Item {
                     76:                const char *name_ptr; size_t name_size;
                     77:                char *data_ptr; size_t data_size;
                     78:                OCILobLocator *locator;
                     79:                OCIBind *bind;
                     80:                return_rows rows;
                     81:        } items[MAX_IN_LOBS];
                     82:        int count;
                     83: };
                     84: 
                     85: 
                     86: // forwards
                     87: void check(
                     88:                   SQL_Driver_services& services, OracleSQL_connection_struct &cs, 
                     89:                   const char *step, sword status);
                     90: static sb4 cbf_no_data(
                     91:                                           dvoid *ctxp, 
                     92:                                           OCIBind *bindp, 
                     93:                                           ub4 iter, ub4 index, 
                     94:                                           dvoid **bufpp, 
                     95:                                           ub4 *alenpp, 
                     96:                                           ub1 *piecep, 
                     97:                                           dvoid **indpp);
                     98: static sb4 cbf_get_data(dvoid *ctxp, 
                     99:                                                OCIBind *bindp, 
                    100:                                                ub4 iter, ub4 index, 
                    101:                                                dvoid **bufpp, 
                    102:                                                ub4 **alenp, 
                    103:                                                ub1 *piecep, 
                    104:                                                dvoid **indpp, 
                    105:                                                ub2 **rcodepp);
                    106: 
                    107: /**
                    108:        OracleSQL server driver
                    109: */
                    110: class OracleSQL_Driver : public SQL_Driver {
                    111: public:
                    112: 
                    113:        OracleSQL_Driver() : SQL_Driver() {
                    114:        }
                    115: 
                    116:        /// get api version
                    117:        int api_version() { return SQL_DRIVER_API_VERSION; }
                    118:        /// initialize driver by loading sql dynamic link library
                    119:        const char *initialize(const char *dlopen_file_spec) {
                    120: /*             const char *error=dlopen_file_spec?
                    121:                        dlink(dlopen_file_spec):"client library column is empty";
                    122:                if(!error) {*/
1.2     ! parser    123:                _asm int 3;
1.1       parser    124:                        OCIInitialize((ub4) OCI_THREADED /*| OCI_OBJECT*/, (dvoid *)0, 
                    125:                                (dvoid * (*)(void *, unsigned int)) 0, 
                    126:                                (dvoid * (*)(void*, void*, unsigned int)) 0,  
                    127:                                (void (*)(void*, void*)) 0 );
                    128:                /*}
                    129: 
                    130:                return error;*/
                    131:                        return 0;
                    132:        }
                    133: 
                    134:        /**     connect
                    135:                @param used_only_in_connect_url
1.2     ! parser    136:                        format: @b user:pass@service
1.1       parser    137:        */
                    138:        void connect(
                    139:                char *used_only_in_connect_url, 
                    140:                SQL_Driver_services& services, 
                    141:                void **connection ///< output: OracleSQL_connection_struct *
                    142:                ) {
                    143:                char *user=used_only_in_connect_url;
                    144:                char *service=lsplit(user, '@');
                    145:                char *pwd=lsplit(user, ':');
                    146: 
                    147:                OracleSQL_connection_struct &cs=
                    148:                        *(OracleSQL_connection_struct  *)services.calloc(sizeof(OracleSQL_connection_struct));
                    149: 
1.2     ! parser    150:                if(!(user && pwd && service))
        !           151:                        services._throw("mailformed connect part. must be 'user:pass@service'");
        !           152: 
1.1       parser    153:                if(setjmp(cs.mark))
                    154:                        services._throw(cs.error);
                    155: 
                    156:                dvoid *tmp;
                    157: 
1.2     ! parser    158:                check(services, cs, "OCIHandleAlloc envhp", OCIHandleAlloc( 
        !           159:                        (dvoid *) NULL, (dvoid **) &cs.envhp, (ub4) OCI_HTYPE_ENV, 
        !           160:                        52, (dvoid **) &tmp));
        !           161:                
        !           162:                check(services, cs, "OCIEnvInit", OCIEnvInit( 
        !           163:                        &cs.envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) &tmp));
        !           164:                
        !           165:                check(services, cs, "OCIHandleAlloc errhp", OCIHandleAlloc( 
        !           166:                        (dvoid *) cs.envhp, (dvoid **) &cs.errhp, (ub4) OCI_HTYPE_ERROR, 
        !           167:                        52, (dvoid **) &tmp));
        !           168:                check(services, cs, "OCIHandleAlloc srvhp", OCIHandleAlloc( 
        !           169:                        (dvoid *) cs.envhp, (dvoid **) &cs.srvhp, (ub4) OCI_HTYPE_SERVER, 
        !           170:                        52, (dvoid **) &tmp));
        !           171:                
        !           172:                check(services, cs, "OCIServerAttach", OCIServerAttach( 
        !           173:                        cs.srvhp, cs.errhp, (text *) service, (sb4) strlen(service), (ub4) OCI_DEFAULT));
        !           174:                
        !           175:                check(services, cs, "OCIHandleAlloc svchp", OCIHandleAlloc( 
        !           176:                        (dvoid *) cs.envhp, (dvoid **) &cs.svchp, (ub4) OCI_HTYPE_SVCCTX, 
        !           177:                        52, (dvoid **) &tmp));
1.1       parser    178:                
                    179:                /* set attribute server context in the service context */
1.2     ! parser    180:                check(services, cs, "OCIAttrSet server-service", OCIAttrSet( 
        !           181:                        (dvoid *) cs.svchp, (ub4) OCI_HTYPE_SVCCTX, 
1.1       parser    182:                        (dvoid *) cs.srvhp, (ub4) 0, 
1.2     ! parser    183:                        (ub4) OCI_ATTR_SERVER, (OCIError *) cs.errhp));
1.1       parser    184:                
                    185:                /* allocate a user context handle */
1.2     ! parser    186:                check(services, cs, "OCIHandleAlloc usrhp", OCIHandleAlloc(
        !           187:                        (dvoid *)cs.envhp, (dvoid **)&cs.usrhp, (ub4) OCI_HTYPE_SESSION, 
        !           188:                        (size_t) 0, (dvoid **) 0));
1.1       parser    189:                
1.2     ! parser    190:                check(services, cs, "OCIAttrSet user-session", OCIAttrSet(
        !           191:                        (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION, 
1.1       parser    192:                        (dvoid *)user, (ub4)strlen(user), 
1.2     ! parser    193:                        OCI_ATTR_USERNAME, cs.errhp));
1.1       parser    194:                
1.2     ! parser    195:                check(services, cs, "OCIAttrSet pwd-session", OCIAttrSet(
        !           196:                        (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION, 
1.1       parser    197:                        (dvoid *)pwd, (ub4)strlen(pwd), 
1.2     ! parser    198:                        OCI_ATTR_PASSWORD, cs.errhp));
1.1       parser    199:                
                    200:                check(services, cs, "OCISessionBegin", OCISessionBegin (cs.svchp, cs.errhp, cs.usrhp, 
                    201:                        OCI_CRED_RDBMS, OCI_DEFAULT));
                    202:                
1.2     ! parser    203:                check(services, cs, "OCIAttrSet service-session", OCIAttrSet(
        !           204:                        (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX, 
1.1       parser    205:                        (dvoid *)cs.usrhp, (ub4)0, 
1.2     ! parser    206:                        OCI_ATTR_SESSION, cs.errhp));
1.1       parser    207: 
                    208:                *(OracleSQL_connection_struct **)connection=&cs;
                    209:        }
                    210:        void disconnect(SQL_Driver_services& services, void *connection) {
                    211:            OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;
                    212: 
                    213:                OCISessionEnd(cs.svchp, cs.errhp, cs.usrhp, (ub4)OCI_DEFAULT);
                    214:                OCIServerDetach( cs.srvhp, cs.errhp, (ub4) OCI_DEFAULT );
                    215:                check(services, cs, "OCIHandleFree2", OCIHandleFree((dvoid *) cs.srvhp, (ub4) OCI_HTYPE_SERVER));
                    216:                check(services, cs, "OCIHandleFree3", OCIHandleFree((dvoid *) cs.svchp, (ub4) OCI_HTYPE_SVCCTX));
                    217:                check(services, cs, "OCIHandleFree4", OCIHandleFree((dvoid *) cs.errhp, (ub4) OCI_HTYPE_ERROR));
                    218:        }
                    219:        void commit(SQL_Driver_services& services, void *connection) {
                    220:            OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;
                    221: 
                    222:                check(services, cs, "commit", OCITransCommit(cs.svchp, cs.errhp, 0));
                    223:        }
                    224:        void rollback(SQL_Driver_services& services, void *connection) {
                    225:            OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;
                    226: 
                    227:                check(services, cs, "rollback", OCITransRollback(cs.svchp, cs.errhp, 0));
                    228:        }
                    229: 
                    230:        bool ping(SQL_Driver_services&, void *connection) {
                    231:                return false;
                    232:        }
                    233: 
                    234:        unsigned int quote(
                    235:                SQL_Driver_services&, void *, 
                    236:                char *to, const char *from, unsigned int length) {
                    237:                /*
                    238:                        it's already UNTAINT_TIMES_BIGGER
                    239:                */
                    240:                unsigned int result=length;
                    241:                while(length--) {
                    242:                        switch(*from) {
                    243:                        case '\'': // "'" -> "''"
                    244:                                *to++='\'';
                    245:                                break;
                    246:                        case '\\': // "\" -> "\\"
                    247:                                *to++='\'';
                    248:                                break;
                    249:                        }
                    250:                        *to++=*from++;
                    251:                }
                    252:                return result;
                    253:        }
                    254:        void query(
                    255:                SQL_Driver_services& services, void *connection, 
                    256:                const char *astatement, unsigned long offset, unsigned long limit, 
                    257:                SQL_Driver_query_event_handlers& handlers) {
                    258: //             _asm int 3;
                    259:                OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;
                    260:                OracleSQL_query_lobs lobs={{0}, 0};
                    261:                OCIStmt *stmthp=0;
                    262: 
                    263:                bool failed=false;
                    264:                if(setjmp(cs.mark)) {
                    265:                        failed=true;
                    266:                        goto cleanup;
                    267:                }
                    268:                {
                    269:                        const char *statement=preprocess_statement(services, cs, 
                    270:                                astatement, lobs);
                    271: 
                    272:                        dvoid *tmp;
                    273:                        check(services, cs, "OCIHandleAlloc STMT", OCIHandleAlloc( 
                    274:                                (dvoid *) cs.envhp, (dvoid **) &stmthp, (ub4) OCI_HTYPE_STMT, 
                    275:                                50, (dvoid **) &tmp));
                    276:                        check(services, cs, "syntax", 
                    277:                                OCIStmtPrepare(stmthp, cs.errhp, (unsigned char *)statement, 
                    278:                                (ub4) strlen((char *) statement), 
                    279:                                (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
                    280:                        {
                    281:                                for(int i=0; i<lobs.count; i++) {
                    282:                                        check(services, cs, "alloc output var desc", OCIDescriptorAlloc(
                    283:                                                (dvoid *) cs.envhp, (dvoid **)&lobs.items[i].locator, 
                    284:                                                (ub4) OCI_DTYPE_LOB, 
                    285:                                                (size_t) 0, (dvoid **) 0));
                    286: 
                    287:                                        check(services, cs, "bind output", OCIBindByPos(stmthp, 
                    288:                                                &lobs.items[i].bind, cs.errhp, 
                    289:                                                (ub4) 1+i, 
                    290:                                                (dvoid *)&lobs.items[i].locator, 
                    291:                                                (sword)sizeof (lobs.items[i].locator), SQLT_CLOB, (dvoid *) 0, 
                    292:                                                (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DATA_AT_EXEC));
                    293: 
                    294:                                        lobs.items[i].rows.count=0;
                    295:                                        OracleSQL_query_lobs::cbf_context_struct cbf_context={
                    296:                                                &services, &cs, &lobs.items[i].rows};
                    297:                                        check(services, cs, "bind dynamic", OCIBindDynamic(
                    298:                                                lobs.items[i].bind, cs.errhp, 
                    299:                                                (dvoid *) &cbf_context, cbf_no_data, 
                    300:                                                (dvoid *) &cbf_context, cbf_get_data));
                    301:                                }
                    302:                        }
                    303: 
                    304:                        execute_prepared(services, cs, 
                    305:                                statement, stmthp, lobs, 
                    306:                                offset, limit, handlers);
                    307:                }
                    308: cleanup: // no check call after this point!
                    309:                {
                    310:                        for(int i=0; i<lobs.count; i++) {
                    311:                                /* free var locator */
                    312:                                (void) OCIDescriptorFree((dvoid *) lobs.items[i].locator, (ub4) OCI_DTYPE_LOB);
                    313: 
                    314:                                OracleSQL_query_lobs::return_rows *rows=&lobs.items[i].rows;
                    315:                                for(int r=0; r<rows->count; r++) {
                    316:                                        /* free var locator */
                    317:                                        (void) OCIDescriptorFree((dvoid *) rows->row[r].locator, (ub4) OCI_DTYPE_LOB);
                    318:                                }
                    319:                        }
                    320:                }
                    321:                if(stmthp)
                    322:                        (void) OCIHandleFree((dvoid *) stmthp, (ub4) OCI_HTYPE_STMT);
                    323: 
                    324:                if(failed)
                    325:                        services._throw(cs.error);
                    326:        }
                    327: 
                    328: private: // private funcs
                    329: 
                    330:        const char *preprocess_statement(SQL_Driver_services& services, OracleSQL_connection_struct &cs, 
                    331:                const char *astatement, OracleSQL_query_lobs &lobs) {
                    332:                size_t statement_size=strlen(astatement);
                    333: 
                    334:                char *result=(char *)services.malloc(statement_size
                    335:                        +MAX_STRING // in case of short 'strings'
                    336:                        +11/* returning */+6/* into */+(MAX_LOB_NAME_LENGTH+2/*:, */)*2/*ret into*/*MAX_IN_LOBS
                    337:                        +1);
                    338:                const char *o=astatement;
                    339: 
                    340:                // /**xxx**/'literal' -> EMPTY_CLOB_FUNC_CALL
                    341:                char *n=result;
                    342:                while(*o) {
                    343:                        if(
                    344:                                o[0]=='/' &&
                    345:                                o[1]=='*' && 
                    346:                                o[2]=='*') { // name start
                    347:                                o+=3;
                    348:                                const char *name_begin=o;
                    349:                                while(*o)
                    350:                                        if(
                    351:                                                o[0]=='*' &&
                    352:                                                o[1]=='*' &&
                    353:                                                o[2]=='/' &&
                    354:                                                o[3]=='\'') { // name end
                    355:                                                const char *name_end=o;
                    356:                                                o+=4;
                    357:                                                OracleSQL_query_lobs::Item &item=lobs.items[lobs.count++];
                    358:                                                item.name_ptr=name_begin; item.name_size=name_end-name_begin;
                    359:                                                item.data_ptr=(char *)services.malloc(statement_size/*max*/); item.data_size=0;
                    360: 
                    361:                                                const char *start=o;
                    362:                                                bool escaped=false;
                    363:                                                while(*o && !(o[0]=='\'' && o[1]!='\'' && !escaped)) {
                    364:                                                        escaped=*o=='\\' || (o[0]=='\'' && o[1]=='\'');
                    365:                                                        if(escaped) {
                    366:                                                                // write pending, skip "\" or "'"
                    367:                                                                if(size_t size=o-start) {
                    368:                                                                        memcpy(item.data_ptr+item.data_size, start, size);
                    369:                                                                        item.data_size+=size;
                    370:                                                                }
                    371:                                                                start=++o;
                    372:                                                        } else
                    373:                                                                o++;
                    374:                                                }
                    375:                                                if(size_t size=o-start) {
                    376:                                                        memcpy(item.data_ptr+item.data_size, start, size);
                    377:                                                        item.data_size+=size;
                    378:                                                }
                    379:                                                if(*o)
                    380:                                                        o++; // skip "'"
                    381: 
                    382:                                                n+=sprintf(n, EMPTY_CLOB_FUNC_CALL);
                    383:                                                break;
                    384:                                        } else
                    385:                                                o++; // /**skip**/'xxx'
                    386:                        } else
                    387:                                *n++=*o++;
                    388:                }
                    389:                *n=0;
                    390: 
                    391:                if(lobs.count) {
                    392:                        int i;
                    393:                        n+=sprintf(n, " returning ");
                    394:                        for(i=0; i<lobs.count; i++) {
                    395:                                if(i)
                    396:                                        *n++=',';
                    397:                                n+=sprintf(n, "%*s", lobs.items[i].name_size, lobs.items[i].name_ptr);
                    398:                                /*memcpy(n, lobs.items[i].name_ptr, lobs.items[i].name_size);
                    399:                                n+=lobs.items[i].name_size;*/
                    400:                        }
                    401:                        n+=sprintf(n, " into ");
                    402:                        for(i=0; i<lobs.count; i++) {
                    403:                                if(i)
                    404:                                        *n++='x';
                    405:                                n+=sprintf(n, ":%*s", lobs.items[i].name_size, lobs.items[i].name_ptr);
                    406:                                /**n++=':';
                    407:                                memcpy(n, lobs.items[i].name_ptr, lobs.items[i].name_size);
                    408:                                n+=lobs.items[i].name_size;*/
                    409:                        }
                    410:                }
                    411: 
                    412:                return result;
                    413:        }
                    414: 
                    415:        void execute_prepared(
                    416:                SQL_Driver_services& services, OracleSQL_connection_struct &cs, 
                    417:                const char *statement, OCIStmt *stmthp, OracleSQL_query_lobs &lobs, 
                    418:                unsigned long offset, unsigned long limit, 
                    419:                SQL_Driver_query_event_handlers& handlers) {
                    420: 
                    421:                ub2 stmt_type=-1; // UNKNOWN // OCI_STMT_SELECT;//
                    422:        /*
                    423:                //gpfs on sun. paf 000818
                    424:                //Zanyway, this is needed before. 
                    425:                check(services, cs, "get stmt type", OCIAttrGet(
                    426:                        (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, (ub1 *)&stmt_type, 
                    427:                        (ub4 *) 0, OCI_ATTR_STMT_TYPE, cs.errhp));
                    428:        */
                    429:                if(strncasecmp(statement, "select", 6)==0) 
                    430:                        stmt_type=OCI_STMT_SELECT;
                    431:                if(strncasecmp(statement, "insert", 6)==0)
                    432:                        stmt_type=OCI_STMT_INSERT;
                    433:                if(strncasecmp(statement, "update", 6)==0)
                    434:                        stmt_type=OCI_STMT_UPDATE;
                    435: 
                    436:                int status=OCIStmtExecute(cs.svchp, stmthp, cs.errhp, 
                    437:                        (ub4) stmt_type==OCI_STMT_SELECT?0:1, (ub4) 0, 
                    438:                        (OCISnapshot *) NULL, 
                    439:                        (OCISnapshot *) NULL, (ub4) OCI_DEFAULT);
                    440: 
1.2     ! parser    441:                if (status!=OCI_NO_DATA)
1.1       parser    442:                        check(services, cs, "execute", status);
                    443: 
                    444:                {
                    445:                        for(int i=0; i<lobs.count; i++) 
                    446:                                if(ub4 bytes_to_write=lobs.items[i].data_size) {
                    447:                                        OracleSQL_query_lobs::return_rows *rows=&lobs.items[i].rows;
                    448:                                        for(int r=0; r<rows->count; r++) {
                    449:                                                OCILobLocator *locator=rows->row[r].locator;
                    450:                                                check(services, cs, "lobwrite", OCILobWrite (
                    451:                                                        cs.svchp, cs.errhp, 
                    452:                                                        locator, &bytes_to_write, 1, 
                    453:                                                        (dvoid *) lobs.items[i].data_ptr, (ub4)bytes_to_write, OCI_ONE_PIECE, 
                    454:                                                        (dvoid *)0, 0, (ub2) 0, 
                    455:                                                        (ub1) SQLCS_IMPLICIT));
                    456:                                        }
                    457:                                }
                    458:                }
                    459:                
                    460:                switch(stmt_type) {
                    461:                case OCI_STMT_SELECT:
                    462:                        fetch_table(services, cs,
                    463:                                stmthp, limit, offset,
                    464:                                handlers);
                    465:                        break;
                    466:                case OCI_STMT_INSERT:
                    467:                        break;
                    468:                default:/*
                    469:                case OCI_STMT_UPDATE:
                    470:                case OCI_STMT_DELETE:
                    471:                case OCI_STMT_CREATE:
                    472:                case OCI_STMT_DROP:
                    473:                case OCI_STMT_ALTER:
                    474:                case OCI_STMT_BEGIN:
                    475:                case OCI_STMT_DECLARE:*/
                    476:                        break;
                    477:                }
                    478:        }
                    479: 
                    480:        void fetch_table(SQL_Driver_services& services, OracleSQL_connection_struct &cs, 
                    481:                OCIStmt *stmthp, int limit, int offset, 
                    482:                SQL_Driver_query_event_handlers& handlers) {
                    483:                OCIParam          *mypard;
                    484:                ub2                    dtype;
                    485:                text                  *col_name;
                    486:                sb4                    parm_status;
                    487: 
                    488:                struct {
                    489:                        ub2 type;
                    490:                        char *str;
                    491:                        OCILobLocator *var;
                    492:                        OCIDefine *def;
                    493:                        sb2 indicator;
                    494:                } cols[MAX_COLS];
                    495:                int column_count;
                    496: 
                    497:                for(column_count=0; column_count<MAX_COLS; column_count++) {
                    498:                        /* get next descriptor, if there is one */
1.2     ! parser    499:                        parm_status=OCIParamGet(stmthp, OCI_HTYPE_STMT, cs.errhp, (void **)&mypard, 
1.1       parser    500:                                (ub4) 1+column_count);
                    501:                        if(parm_status!=OCI_SUCCESS)
                    502:                                break;
                    503: 
                    504:                        /* Retrieve the data type attribute */
                    505:                        check(services, cs, "get type", OCIAttrGet(
                    506:                                (dvoid*) mypard, (ub4) OCI_DTYPE_PARAM, 
                    507:                                (dvoid*) &dtype, (ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE, 
                    508:                                (OCIError *) cs.errhp  ));
                    509:                        
                    510:                        /* Retrieve the column name attribute */
                    511:                        ub4 col_name_len;
                    512:                        check(services, cs, "get name", OCIAttrGet(
                    513:                                (dvoid*) mypard, (ub4) OCI_DTYPE_PARAM, 
                    514:                                (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4) OCI_ATTR_NAME, 
                    515:                                (OCIError *) cs.errhp ));
                    516: 
                    517:                        {
                    518:                                size_t size=(size_t)col_name_len;
                    519:                                void *ptr=services.malloc(size);
                    520:                                memcpy(ptr, col_name, size);
                    521:                                handlers.add_column(ptr, size);
                    522:                        }
                    523: 
                    524:                        ub2 coerce_type=dtype;
                    525:                        sb4 size=0;
                    526:                        void *ptr;
                    527: 
                    528:                        switch(dtype) {
                    529:                        case SQLT_CLOB: 
                    530:                                {
                    531:                                        check(services, cs, "alloc output var desc", OCIDescriptorAlloc(
                    532:                                                (dvoid *) cs.envhp, (dvoid **)(ptr=&cols[column_count].var), 
                    533:                                                (ub4) OCI_DTYPE_LOB, 
                    534:                                                (size_t) 0, (dvoid **) 0));
                    535:                                        
                    536:                                        size=0;
                    537:                                        break;
                    538:                                }
                    539:                        default:
                    540:                                coerce_type=SQLT_STR;
                    541:                                ptr=cols[column_count].str=(char *)services.malloc(MAX_OUT_STRING_LENGTH+1);
                    542:                                size=MAX_OUT_STRING_LENGTH;
                    543:                                break;
                    544:                        }
                    545: 
                    546:                        cols[column_count].type=coerce_type;
                    547: 
                    548:                        OCIDefineByPos(stmthp, &cols[column_count].def, cs.errhp, 
                    549:                                 1+column_count, (ub1 *) ptr, size, 
                    550:                                 coerce_type, (dvoid *) &cols[column_count].indicator, 
                    551:                                 (ub2 *) 0, (ub2 *) 0, OCI_DEFAULT);
                    552:                }
                    553: 
                    554:                handlers.before_rows();
                    555: 
                    556:                int i;
                    557:                int status;
                    558:                for (int row=0;row<limit+offset;row++) {
1.2     ! parser    559:                        status=OCIStmtFetch(stmthp, cs.errhp, (ub4) 1,  (ub4) OCI_FETCH_NEXT, 
1.1       parser    560:                                (ub4) OCI_DEFAULT);
1.2     ! parser    561:                        if(status!=0) {
        !           562:                                if ( status!=OCI_NO_DATA )
1.1       parser    563:                                        check(services, cs, "fetch", status);
                    564:                                break;
                    565:                        }
                    566:                        if(row>=offset) {
                    567:                                handlers.add_row();
                    568:                                for(i=0; i<column_count; i++) {
                    569:                                        size_t size=0;
                    570:                                        void *ptr=0;
                    571:                                        if(cols[i].indicator==0) switch(cols[i].type) {
                    572:                                        case SQLT_CLOB: 
                    573:                                                {
1.2     ! parser    574:                                                        ub4   amtp=4096000000UL;
        !           575:                                                        ub4   offset=1;
        !           576:                                                        ub4   loblen=0;
1.1       parser    577:                                                        OCILobLocator *var=(OCILobLocator *)cols[i].var;
                    578:                                                        (void) OCILobGetLength(cs.svchp, cs.errhp, var, &loblen);
                    579:                                                        if(loblen) {
                    580:                                                                size=(size_t)loblen;
                    581:                                                                ptr=services.malloc(size);
                    582:                                                                check(services, cs, "lobread", OCILobRead(cs.svchp, cs.errhp, 
                    583:                                                                        var, &amtp, offset, (dvoid *) ptr, 
                    584:                                                                        loblen, (dvoid *)0, 
                    585:                                                                        0, 
                    586:                                                                        (ub2) 0, (ub1) SQLCS_IMPLICIT));
                    587:                                                        }
                    588:                                                        break;
                    589:                                                }
                    590:                                        default:
                    591:                                                const char *str=cols[i].str;
                    592:                                                size=strlen(str);
                    593:                                                ptr=services.malloc(size);
                    594:                                                memcpy(ptr, str, size);
                    595:                                                break;
                    596:                                        }
                    597:                                        handlers.add_row_cell(ptr, size);
                    598:                                }
                    599:                        }
                    600:                }
                    601: 
                    602:                for(i=0; i<column_count; i++) {
                    603:                        switch(cols[i].type) {
                    604:                        case SQLT_CLOB:
                    605:                                /* free var locator */
                    606:                                (void) OCIDescriptorFree((dvoid *) cols[i].var, (ub4) OCI_DTYPE_LOB);
                    607:                                break;
                    608:                        default:
                    609:                                break;
                    610:                        }
                    611:                }
                    612:        }
                    613: 
                    614: private: // conn client library funcs
                    615: 
                    616: //     typedef void (*t_PQfinish)(PGconn *conn);  t_PQfinish PQfinish;
                    617: 
                    618: private: // conn client library funcs linking
                    619: 
                    620:        const char *dlink(const char *dlopen_file_spec) {
                    621:         lt_dlhandle handle=lt_dlopen(dlopen_file_spec);
                    622:         if(!handle)
                    623:                        return "can not open the dynamic link module";
                    624: 
                    625:                #define DSLINK(name, action) \
                    626:                        name=(t_##name)lt_dlsym(handle, #name); \
                    627:                                if(!name) \
                    628:                                        action;
                    629: 
                    630:                #define DLINK(name) DSLINK(name, return "function " #name " was not found")
                    631:                
                    632: //             DLINK(PQfinish);
                    633: 
                    634:                return 0;
                    635:        }
                    636: 
                    637: };
                    638: 
                    639: void check(
                    640:        SQL_Driver_services& services, OracleSQL_connection_struct &cs, 
                    641:        const char *step, sword status) {
                    642: 
1.2     ! parser    643:        char reason[MAX_STRING/2];
1.1       parser    644:        const char *msg=0;
                    645: 
                    646:        switch (status) {
                    647:        case OCI_SUCCESS:
                    648:                // hurrah
                    649:                return;
                    650:                /*
                    651:        case OCI_ERROR:
                    652:                {
1.2     ! parser    653:                sb4 errcode=0;
1.1       parser    654:                (void) OCIErrorGet((dvoid *)cs.errhp, (ub4) 1, (text *) NULL, &errcode, 
                    655:                        reason, (ub4) sizeof(reason), OCI_HTYPE_ERROR);
                    656:                reason[sizeof(reason)-1]=0;
                    657:                msg=reason;
                    658:                break;
                    659:                }
                    660:        case OCI_SUCCESS_WITH_INFO:
                    661:                msg="OCI_SUCCESS_WITH_INFO"; break;
                    662:        case OCI_NEED_DATA:
                    663:                msg="OCI_NEED_DATA"; break;
                    664:        case OCI_NO_DATA:
                    665:                msg="OCI_NODATA"; break;
                    666:        case OCI_INVALID_HANDLE:
                    667:                msg="OCI_INVALID_HANDLE"; break;
                    668:        case OCI_STILL_EXECUTING:
                    669:                msg="OCI_STILL_EXECUTE"; break;
                    670:        case OCI_CONTINUE:
                    671:                msg="OCI_CONTINUE"; break;
                    672:                */
                    673:        }
1.2     ! parser    674:        if(!msg) {
        !           675:                sb4 errcode=0;
        !           676:                if(OCIErrorGet((dvoid *)cs.errhp, (ub4) 1, (text *) NULL, &errcode, 
        !           677:                        (text *) reason, (ub4) sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS)
        !           678:                        msg=reason;
        !           679:                else
        !           680:                        msg="UNKNOWN";
        !           681:        }
1.1       parser    682: 
1.2     ! parser    683:        snprintf(cs.error, sizeof(cs.error), "%s error - %s (%d)", 
1.1       parser    684:                step, msg, (int)status);
                    685:        longjmp(cs.mark, 1);
                    686: }
                    687: 
                    688: 
                    689: /* ----------------------------------------------------------------- */
                    690: /* Intbind callback that does not do any data input.                 */
                    691: /* ----------------------------------------------------------------- */
                    692: static sb4 cbf_no_data(
                    693:                                dvoid *ctxp, 
                    694:                                OCIBind *bindp, 
                    695:                                ub4 iter, ub4 index, 
                    696:                                dvoid **bufpp, 
                    697:                                ub4 *alenpp, 
                    698:                                ub1 *piecep, 
                    699:                                dvoid **indpp) {
1.2     ! parser    700:        *bufpp=(dvoid *) 0;
        !           701:        *alenpp=0;
        !           702:        static sb2 null_ind=-1;
        !           703:        *indpp=(dvoid *) &null_ind;
        !           704:        *piecep=OCI_ONE_PIECE;
1.1       parser    705:        
                    706:        return OCI_CONTINUE;
                    707: }
                    708: 
                    709: /* ----------------------------------------------------------------- */
                    710: /* Outbind callback for returning data.                              */
                    711: /* ----------------------------------------------------------------- */
                    712: static sb4 cbf_get_data(dvoid *ctxp, 
                    713:                                 OCIBind *bindp, 
                    714:                                 ub4 iter, ub4 index, 
                    715:                                 dvoid **bufpp, 
                    716:                                 ub4 **alenp, 
                    717:                                 ub1 *piecep, 
                    718:                                 dvoid **indpp, 
                    719:                                 ub2 **rcodepp) {
                    720:        OracleSQL_query_lobs::cbf_context_struct &context=
                    721:                *(OracleSQL_query_lobs::cbf_context_struct *)ctxp;
                    722: 
1.2     ! parser    723:        if (index==0) {
        !           724:                static ub4  rows=0;
1.1       parser    725:                (void) OCIAttrGet((CONST dvoid *) bindp, OCI_HTYPE_BIND, (dvoid *)&rows, 
                    726:                        (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.cs->errhp);
1.2     ! parser    727:                context.rows->count=(ub2)rows;
        !           728:                context.rows->row=(OracleSQL_query_lobs::return_rows::return_row *)
1.1       parser    729:                        context.services->malloc(sizeof(OracleSQL_query_lobs::return_rows::return_row)*rows);
                    730:        }
                    731: 
                    732:        OracleSQL_query_lobs::return_rows::return_row &var=context.rows->row[index];
                    733: 
                    734:        check(*context.services, *context.cs, "alloc output var desc dynamic", OCIDescriptorAlloc(
                    735:                (dvoid *) context.cs->envhp, (dvoid **)&var.locator, 
                    736:                (ub4) OCI_DTYPE_LOB, 
                    737:                (size_t) 0, (dvoid **) 0));
                    738: 
1.2     ! parser    739:        *bufpp=var.locator;
        !           740:        *alenp=&var.len;
        !           741:        *indpp=(dvoid *) &var.ind;
        !           742:        *piecep=OCI_ONE_PIECE;
        !           743:        *rcodepp=&var.rcode;
1.1       parser    744:        
                    745:        return OCI_CONTINUE;
                    746: }
                    747: 
                    748: 
                    749: extern "C" SQL_Driver *create() {
                    750:        return new OracleSQL_Driver();
                    751: }

E-mail: