Annotation of sql/oracle/parser3oracle.C, revision 1.1

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

E-mail: