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

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

E-mail: