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

1.1       parser      1: /** @file
                      2:        Parser Oracle driver.
                      3: 
1.29      paf         4:        Copyright(c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com)
1.1       parser      5: 
1.19      paf         6:        Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1       parser      7: 
                      8:        2001.07.30 using Oracle 8.1.6 [@test tested with Oracle 7.x.x]
                      9: */
1.60    ! paf        10: static const char *RCSId="$Id: parser3oracle.C,v 1.59 2004/06/18 11:29:55 paf 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: 
1.45      paf        41: #if _MSC_VER
                     42: // interaction between '_setjmp' and C++ object destruction is non-portable
                     43: // but we forced to do that under HPUX
                     44: #pragma warning(disable:4611)   
                     45: #endif
                     46: 
1.33      paf        47: /// @todo small memory leaks here
1.10      paf        48: static int pa_setenv(const char *name, const char *value, bool do_append) {
                     49:        const char *prev_value=0;
                     50:        if(do_append)
                     51:                prev_value=getenv(name);
1.4       paf        52: #ifdef HAVE_PUTENV
                     53:     // MEM_LEAK_HERE. refer to EOF man putenv
1.10      paf        54:        char *buf=(char *)::malloc(strlen(name)
                     55:                +1
                     56:                +(prev_value?strlen(prev_value):0)
                     57:                +strlen(value)
                     58:                +1);
1.4       paf        59:        strcpy(buf, name);
                     60:        strcat(buf, "=");
1.10      paf        61:        if(prev_value)
                     62:                strcat(buf, prev_value);
1.4       paf        63:        strcat(buf, value);
1.5       paf        64: /*
                     65:        if(FILE *f=fopen("f", "at")) {
                     66:                fprintf(f, "****************************%s\n", buf);
                     67: //             for (char **env = environ; env != NULL && *env != NULL; env++)
                     68: //                     fputs(*env, f);
                     69:        
                     70:                fclose(f);
                     71:        }
                     72: */     
1.4       paf        73:        return putenv(buf);
                     74: #else 
                     75:        //#ifdef HAVE_SETENV
1.10      paf        76:        if(value) {
                     77:                if(prev_value) {
                     78:                        // MEM_LEAK_HERE
1.33      paf        79:                        char *buf=(char *)::malloc(strlen(prev_value)
1.10      paf        80:                                +strlen(value)
                     81:                                +1);
                     82:                        strcpy(buf, prev_value);
                     83:                        strcat(buf, value);
1.24      paf        84:                        value=buf;
                     85:                }
                     86:                return setenv(name, value, 1/*overwrite*/); 
1.10      paf        87:        } else {
1.4       paf        88:                unsetenv(name);
                     89:                return 0;
                     90:        }
                     91: #endif
                     92: }
                     93: 
1.1       parser     94: static char *lsplit(char *string, char delim) {
                     95:     if(string) {
                     96:                char *v=strchr(string, delim);
                     97:                if(v) {
                     98:                        *v=0;
                     99:                        return v+1;
                    100:                }
                    101:     }
                    102:     return 0;
                    103: }
                    104: 
1.4       paf       105: static char *lsplit(char **string_ref, char delim) {
                    106:     char *result=*string_ref;
                    107:        char *next=lsplit(*string_ref, delim);
                    108:     *string_ref=next;
                    109:     return result;
                    110: }
                    111: 
1.1       parser    112: #ifndef DOXYGEN
1.49      paf       113: struct Connection {
1.42      paf       114:        SQL_Driver_services *services;
                    115: 
1.1       parser    116:        jmp_buf mark; char error[MAX_STRING];
1.27      paf       117:        SQL_Error sql_error;
1.1       parser    118:        OCIEnv *envhp;
                    119:        OCIServer *srvhp;
                    120:        OCIError *errhp;
                    121:        OCISvcCtx *svchp;
                    122:        OCISession *usrhp;
1.39      paf       123: 
1.46      paf       124:        char* fetch_buffers[MAX_COLS];
                    125: 
1.42      paf       126:        struct Options {
                    127:                bool bLowerCaseColumnNames;
                    128:                const char* cstrClientCharset;
                    129:        } options;
1.1       parser    130: };
                    131: 
1.60    ! paf       132: struct Query_lobs {
1.1       parser    133:        struct return_rows {
                    134:                struct return_row {
                    135:                        OCILobLocator *locator; ub4 len;
                    136:                        int ind;                
                    137:                        ub2 rcode;
                    138:                } *row;
                    139:                int count;
                    140:        };
                    141:        struct Item {
                    142:                const char *name_ptr; size_t name_size;
                    143:                char *data_ptr; size_t data_size;
                    144:                OCILobLocator *locator;
                    145:                OCIBind *bind;
                    146:                return_rows rows;
1.57      paf       147:                Connection *connection;
1.1       parser    148:        } items[MAX_IN_LOBS];
                    149:        int count;
                    150: };
1.60    ! paf       151: 
1.1       parser    152: #endif
                    153: 
                    154: // forwards
1.60    ! paf       155: static void faile(Connection& connection, const char *msg);
        !           156: static void check(Connection& connection, const char *step, sword status);
        !           157: static void check(Connection& connection, bool error);
1.1       parser    158: static sb4 cbf_no_data(
                    159:                                           dvoid *ctxp, 
                    160:                                           OCIBind *bindp, 
                    161:                                           ub4 iter, ub4 index, 
                    162:                                           dvoid **bufpp, 
                    163:                                           ub4 *alenpp, 
                    164:                                           ub1 *piecep, 
                    165:                                           dvoid **indpp);
                    166: static sb4 cbf_get_data(dvoid *ctxp, 
                    167:                                                OCIBind *bindp, 
                    168:                                                ub4 iter, ub4 index, 
                    169:                                                dvoid **bufpp, 
                    170:                                                ub4 **alenp, 
                    171:                                                ub1 *piecep, 
                    172:                                                dvoid **indpp, 
                    173:                                                ub2 **rcodepp);
1.55      paf       174: static void tolower_str(char *out, const char *in, size_t size);
                    175: static void toupper_str(char *out, const char *in, size_t size);
1.1       parser    176: 
1.49      paf       177: static const char *options2env(char *s, Connection::Options* options) {
1.42      paf       178:        while(s) {
                    179:                if(char *key=lsplit(&s, '&')) {
                    180:                        if(*key) {
                    181:                                if(char *value=lsplit(key, '=')) {
                    182:                                        if( strcmp( key, "ClientCharset" ) == 0 ) {
1.44      paf       183:                                                if(options) {
1.55      paf       184:                                                        toupper_str(value, value, strlen(value));
1.42      paf       185:                                                        options->cstrClientCharset = value;
1.44      paf       186:                                                }
1.42      paf       187:                                                continue;
                    188:                                        }
                    189: 
                    190:                                        if( strcmp( key, "LowerCaseColumnNames" ) == 0 ) {
                    191:                                                if(options)
                    192:                                                        options->bLowerCaseColumnNames = atoi(value)!=0;
                    193:                                                continue;
                    194:                                        }
                    195: 
                    196:                                        bool do_append=key[strlen(key)-1]=='+'; // PATH+=
                    197:                                        if(do_append)
                    198:                                                key[strlen(key)-1]=0; // remove trailing +
                    199:                                        if(strncmp(key, "ORACLE_", 7)==0  // ORACLE_HOME & co
                    200:                                                || strncmp(key, "ORA_", 4)==0 // ORA_ENCRYPT_LOGIN & co
                    201:                                                || strncmp(key, "NLS_", 4)==0 // NLS_LANG & co
                    202:                                                || do_append
                    203:                                                ) {
                    204:                                                if(pa_setenv(key, value, do_append)!=0)
                    205:                                                        return "problem changing process environment" /*key*/;
                    206:                                        } else
                    207:                                                return "unknown option" /*key*/;
                    208:                                } else 
                    209:                                        return "option without =value" /*key*/;
                    210:                        }
                    211:                }
                    212:        }
                    213:        return 0;
                    214: }
                    215: 
1.1       parser    216: /**
                    217:        OracleSQL server driver
                    218: */
                    219: class OracleSQL_Driver : public SQL_Driver {
                    220: public:
                    221: 
                    222:        OracleSQL_Driver() : SQL_Driver() {
                    223:        }
                    224: 
                    225:        /// get api version
                    226:        int api_version() { return SQL_DRIVER_API_VERSION; }
1.6       paf       227:        /** initialize driver by loading sql dynamic link library
                    228:                @todo ?objects=1 which would turn on OCI_OBJECT init flag
                    229:        */
1.5       paf       230:        const char *initialize(char *dlopen_file_spec) {
                    231:                char *options=lsplit(dlopen_file_spec, '?');
1.1       parser    232: 
                    233:                const char *error=dlopen_file_spec?
                    234:                        dlink(dlopen_file_spec):"client library column is empty";
                    235:                if(!error) {
1.39      paf       236:                        error=options2env(options, 0);
1.1       parser    237: 
1.5       paf       238:                        if(!error)
                    239:                                OCIInitialize((ub4)OCI_THREADED/*| OCI_OBJECT*/, (dvoid *)0, 
                    240:                                        (dvoid * (*)(void *, unsigned int))0, 
                    241:                                        (dvoid * (*)(void*, void*, unsigned int))0,  
                    242:                                        (void (*)(void*, void*))0 
                    243:                                );
1.1       parser    244:                }
                    245: 
                    246:                return error;
                    247:        }
                    248: 
                    249:        /**     connect
1.58      paf       250:                @param url
1.4       paf       251:                        format: @b user:pass@service?
                    252:                           ORACLE_HOME=/u01/app/oracle/product/8.1.5&
1.5       paf       253:                           ORA_NLS33=/u01/app/oracle/product/8.1.5/ocommon/nls/admin/data&
1.4       paf       254:                           NLS_LANG=RUSSIAN_AMERICA.CL8MSWIN1251&
                    255:                           ORA_ENCRYPT_LOGIN=TRUE
                    256: 
                    257:                @todo environment manupulation doesnt look thread safe
1.58      paf       258:                @todo allocate 'aused_only_in_connect_url' on gc heap, so it can be manipulated directly
1.1       parser    259:        */
                    260:        void connect(
1.58      paf       261:                char *url, 
1.1       parser    262:                SQL_Driver_services& services, 
1.50      paf       263:                void **connection_ref ///< output: Connection *
1.56      paf       264:                ) 
                    265:        {
                    266:                // connections are cross-request, do not use services._alloc [linked with request]
1.58      paf       267:                Connection& connection=*(Connection  *)services.malloc(sizeof(Connection));
1.49      paf       268:                connection.services=&services;
                    269:                connection.options.bLowerCaseColumnNames = true;
1.50      paf       270:                *connection_ref=&connection;
1.1       parser    271: 
1.58      paf       272:                char *user=url;
1.1       parser    273:                char *service=lsplit(user, '@');
                    274:                char *pwd=lsplit(user, ':');
1.4       paf       275:                char *options=lsplit(service, '?');
1.1       parser    276: 
                    277:                if(!(user && pwd && service))
                    278:                        services._throw("mailformed connect part, must be 'user:pass@service'");
                    279: 
1.49      paf       280:                if(const char *error=options2env(options, &connection.options))
1.5       paf       281:                        services._throw(error);
1.4       paf       282: 
1.49      paf       283:                if(setjmp(connection.mark))
                    284:                        services._throw(connection.error);
1.1       parser    285: 
                    286:                // Allocate and initialize OCIError handle, attempt #1
                    287:                /*
                    288:                        grabbed from sample 
                    289:                        /server.804/a58234/oci_func.htm#446192
                    290:                        but doc 
                    291:                        /server.804/a58234/oci_func.htm#446100
                    292:                        doesnt have this param listed as allowed
                    293:                        8.1.6 client library barks as OCI_INVALID_HANDLE
                    294:                        and debugging revealed that OCI_HTYPE_ENV param value is invalid
                    295:                        later in doc 
                    296:                        /server.804/a58234/oci_func.htm#446192
                    297:                        on OCIEnvInit thay say
                    298:                        "No changes are done to an already initialized handle"
                    299:                        think, this is some sort of backward compatibility wonder.
                    300:                        leaving as it is, and without check()
                    301:                */
1.49      paf       302:                OCIHandleAlloc((dvoid *)NULL, (dvoid **) &connection.envhp, (ub4)OCI_HTYPE_ENV, 0, 0);
1.1       parser    303:                // Initialize an environment handle, attempt #2
1.49      paf       304:                check(connection, "EnvInit", OCIEnvInit(
                    305:                        &connection.envhp, (ub4)OCI_DEFAULT, 0, 0));            
1.1       parser    306:                // Allocate and initialize OCIError handle
1.49      paf       307:                check(connection, "HandleAlloc errhp", OCIHandleAlloc( 
                    308:                        (dvoid *)connection.envhp, (dvoid **) &connection.errhp, (ub4)OCI_HTYPE_ERROR, 0, 0));
1.1       parser    309:                // Allocate and initialize OCIServer handle
1.49      paf       310:                check(connection, "HandleAlloc srvhp", OCIHandleAlloc( 
                    311:                        (dvoid *)connection.envhp, (dvoid **) &connection.srvhp, (ub4)OCI_HTYPE_SERVER, 0, 0));         
1.1       parser    312:                // Attach to a 'service'; initialize server context handle  
1.49      paf       313:                check(connection, "ServerAttach", OCIServerAttach( 
                    314:                        connection.srvhp, connection.errhp, (text *)service, (sb4)strlen(service), (ub4)OCI_DEFAULT));
1.1       parser    315:                // Allocate and initialize OCISvcCtx handle
1.49      paf       316:                check(connection, "HandleAlloc svchp", OCIHandleAlloc( 
                    317:                        (dvoid *)connection.envhp, (dvoid **) &connection.svchp, (ub4)OCI_HTYPE_SVCCTX, 0, 0));         
1.1       parser    318:                // set attribute server context in the service context
1.49      paf       319:                check(connection, "AttrSet server-service", OCIAttrSet( 
                    320:                        (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX, 
                    321:                        (dvoid *)connection.srvhp, (ub4)0, 
                    322:                        (ub4)OCI_ATTR_SERVER, (OCIError *)connection.errhp));           
1.1       parser    323:                // allocate a user context handle
1.49      paf       324:                check(connection, "HandleAlloc usrhp", OCIHandleAlloc(
                    325:                        (dvoid *)connection.envhp, (dvoid **)&connection.usrhp, (ub4)OCI_HTYPE_SESSION, 0, 0));
1.1       parser    326:                // set 'user' name
1.49      paf       327:                check(connection, "AttrSet user-session", OCIAttrSet(
                    328:                        (dvoid *)connection.usrhp, (ub4)OCI_HTYPE_SESSION, 
1.1       parser    329:                        (dvoid *)user, (ub4)strlen(user), 
1.49      paf       330:                        OCI_ATTR_USERNAME, connection.errhp));          
1.1       parser    331:                // set 'pwd' password
1.49      paf       332:                check(connection, "AttrSet pwd-session", OCIAttrSet(
                    333:                        (dvoid *)connection.usrhp, (ub4)OCI_HTYPE_SESSION, 
1.1       parser    334:                        (dvoid *)pwd, (ub4)strlen(pwd), 
1.49      paf       335:                        OCI_ATTR_PASSWORD, connection.errhp));
1.1       parser    336:                // Authenticate a user  
1.49      paf       337:                check(connection, "SessionBegin", OCISessionBegin(
                    338:                        connection.svchp, connection.errhp, connection.usrhp, 
1.1       parser    339:                        OCI_CRED_RDBMS, OCI_DEFAULT));
                    340:                // remember connection in session
1.49      paf       341:                check(connection, "AttrSet service-session", OCIAttrSet(
                    342:                        (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX, 
                    343:                        (dvoid *)connection.usrhp, (ub4)0, 
                    344:                        OCI_ATTR_SESSION, connection.errhp));
1.1       parser    345:        }
1.49      paf       346:        void disconnect(void *aconnection) {
                    347:            Connection& connection=*static_cast<Connection *>(aconnection);
1.47      paf       348: 
1.58      paf       349:                // free fetch buffers. leave that to GC [no such services func. yet?]
                    350:                /*
1.47      paf       351:                for(int i=0; i<MAX_COLS; i++) {
1.49      paf       352:                        if(void* fetch_buffer=connection.fetch_buffers[i])
1.58      paf       353:                                connection.services->free(fetch_buffer);
1.47      paf       354:                        else
                    355:                                break;
1.58      paf       356:                }
                    357:                */
1.47      paf       358: 
1.1       parser    359:                // Terminate a user session
                    360:                OCISessionEnd(
1.49      paf       361:                        connection.svchp, connection.errhp, connection.usrhp, (ub4)OCI_DEFAULT);
1.1       parser    362:                // Detach from a server; uninitialize server context handle
                    363:                OCIServerDetach(
1.49      paf       364:                        connection.srvhp, connection.errhp, (ub4)OCI_DEFAULT);
1.1       parser    365:                // Free a previously allocated handles
                    366:                /* 
                    367:                oci will free them up as belonging to env
                    368:                OCIHandleFree(
1.49      paf       369:                        (dvoid *)connection.srvhp, (ub4)OCI_HTYPE_SERVER);
1.1       parser    370:                OCIHandleFree(
1.49      paf       371:                        (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX);
1.1       parser    372:                OCIHandleFree(
1.49      paf       373:                        (dvoid *)connection.errhp, (ub4)OCI_HTYPE_ERROR);
1.1       parser    374:                */
                    375:                OCIHandleFree(
1.49      paf       376:                        (dvoid *)connection.envhp, (ub4)OCI_HTYPE_ENV);
1.1       parser    377: 
1.58      paf       378:                // free connection. leave that to GC [no such services func. yet?]
                    379:                // connection.services->free(&connection);
1.1       parser    380:        }
1.49      paf       381:        void commit(void *aconnection) {
                    382:            Connection& connection=*static_cast<Connection *>(aconnection);
                    383:                if(setjmp(connection.mark))
                    384:                        connection.services->_throw(connection.error);
1.1       parser    385: 
1.49      paf       386:                check(connection, "commit", OCITransCommit(connection.svchp, connection.errhp, 0));
1.1       parser    387:        }
1.49      paf       388:        void rollback(void *aconnection) {
                    389:            Connection& connection=*static_cast<Connection *>(aconnection);
                    390:                if(setjmp(connection.mark))
                    391:                        connection.services->_throw(connection.error);
1.1       parser    392: 
1.42      paf       393:                // sometimes rollback is done in context when this yields error which masks previous error
                    394:                // consider consequent errors not very important to report, reporting first one
1.49      paf       395:                /*check(connection, "rollback", */OCITransRollback(connection.svchp, connection.errhp, 0)/*)*/;
1.1       parser    396:        }
                    397: 
1.45      paf       398:        bool ping(void* /*connection*/) {
1.1       parser    399:                // maybe OCIServerVersion?
1.4       paf       400:                // select 0 from dual
1.1       parser    401:                return true;
                    402:        }
                    403: 
1.49      paf       404:        const char* quote(void *aconnection,
1.42      paf       405:                const char *from, unsigned int length) 
                    406:        {
1.49      paf       407:                Connection& connection=*static_cast<Connection *>(aconnection);
                    408:                char *result=(char*)connection.services->malloc_atomic(length*2+1);
1.32      paf       409:                char *to=result;
                    410:                while(length--) {
                    411:                        switch(*from) {
                    412:                        case '\'': // "'" -> "''"
1.35      paf       413:                                *to++='\'';
1.32      paf       414:                                break;
1.1       parser    415:                        }
1.32      paf       416:                        *to++=*from++;
                    417:                }
                    418:                *to=0;
                    419:                return result;
1.1       parser    420:        }
1.60    ! paf       421:        void query(void* aconnection, 
        !           422:                const char* astatement, 
        !           423:                size_t placeholders_count, Placeholder* placeholders, 
        !           424:                unsigned long offset, unsigned long limit,
1.42      paf       425:                SQL_Driver_query_event_handlers& handlers) 
                    426:        {
1.49      paf       427:                Connection& connection=*static_cast<Connection *>(aconnection);
1.54      paf       428:                const char* cstrClientCharset=connection.options.cstrClientCharset;
1.60    ! paf       429:                Query_lobs lobs={{0}, 0};
1.1       parser    430:                OCIStmt *stmthp=0;
                    431: 
1.49      paf       432:                SQL_Driver_services& services=*connection.services;
1.42      paf       433: 
                    434:                // transcode from $request:charset to connect-string?client_charset
1.54      paf       435:                if(cstrClientCharset) {
1.60    ! paf       436:                        size_t transcoded_xxx_size;
1.42      paf       437:                        services.transcode(astatement, strlen(astatement),
1.60    ! paf       438:                                astatement, transcoded_xxx_size,
1.42      paf       439:                                services.request_charset(),
                    440:                                cstrClientCharset);
1.53      paf       441:                }
1.42      paf       442: 
1.1       parser    443:                bool failed=false;
1.49      paf       444:                if(setjmp(connection.mark)) {
1.1       parser    445:                        failed=true;
                    446:                        goto cleanup;
                    447:                } else {
1.49      paf       448:                        const char *statement=preprocess_statement(connection, astatement, lobs);
1.1       parser    449: 
1.49      paf       450:                        check(connection, "HandleAlloc STMT", OCIHandleAlloc( 
                    451:                                (dvoid *)connection.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0));
                    452:                        check(connection, "syntax", 
                    453:                                OCIStmtPrepare(stmthp, connection.errhp, (unsigned char *)statement, 
1.1       parser    454:                                (ub4)strlen((char *)statement), 
                    455:                                (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT));
1.60    ! paf       456: 
        !           457:                        struct Bind_info {
        !           458:                                        OCIBind *bind;
        !           459:                                        sb2 indicator;
        !           460:                        };
        !           461: 
        !           462:                        int binds_size=sizeof(Bind_info) * placeholders_count;
        !           463:                        Bind_info* binds=static_cast<Bind_info*>(services.malloc_atomic(binds_size));
1.1       parser    464:                        {
1.60    ! paf       465:                                for(size_t i=0; i<placeholders_count; i++) {
        !           466:                                        Placeholder& ph=placeholders[i];
        !           467:                                        Bind_info& bi=binds[i];
        !           468:                                        bi.bind=0;
        !           469:                                        bi.indicator=ph.is_null? -1: 0/*9999*/;
        !           470: 
        !           471:                                        size_t value_length;
        !           472: 
        !           473:                                        if(cstrClientCharset) {
        !           474:                                                size_t name_length;
        !           475:                                                services.transcode(ph.name, strlen(ph.name),
        !           476:                                                        ph.name, name_length,
        !           477:                                                        services.request_charset(),
        !           478:                                                        cstrClientCharset);
        !           479: 
        !           480:                                                if(ph.value)
        !           481:                                                        services.transcode(ph.value, strlen(ph.value),
        !           482:                                                                ph.value, value_length,
        !           483:                                                                services.request_charset(),
        !           484:                                                                cstrClientCharset);
        !           485:                                        } else {
        !           486:                                                value_length=ph.value? strlen(ph.value): 0;
        !           487:                                        }
        !           488: 
        !           489:                                        char placeholder_buf[MAX_STRING];
        !           490:                                        sb4 placeh_len=snprintf(placeholder_buf, sizeof(placeholder_buf), ":%s", ph.name);
        !           491:                                        check(connection, "bind name", OCIBindByName(stmthp, 
        !           492:                                                &bi.bind, connection.errhp, 
        !           493:                                                (text*)placeholder_buf, placeh_len,
        !           494:                                                (dvoid *)ph.value, (sword)value_length, SQLT_CHR/*SQLT_STR*/, (dvoid *)&bi.indicator, 
        !           495:                                                (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT));
        !           496:                                }
        !           497: 
1.1       parser    498:                                for(int i=0; i<lobs.count; i++) {
1.60    ! paf       499:                                        Query_lobs::Item &item=lobs.items[i];
1.49      paf       500:                                        check(connection, "alloc output var desc", OCIDescriptorAlloc(
1.57      paf       501:                                                (dvoid *)connection.envhp, (dvoid **)&item.locator, (ub4)OCI_DTYPE_LOB, 0, 0));
1.1       parser    502: 
1.59      paf       503:                                        char placeholder_buf[MAX_STRING];
                    504:                                        sb4 placeh_len=snprintf(placeholder_buf, sizeof(placeholder_buf), 
                    505:                                                ":%.*s", item.name_size, item.name_ptr);
                    506:                                        check(connection, "bind lob", OCIBindByName(stmthp, 
1.57      paf       507:                                                &item.bind, connection.errhp, 
1.59      paf       508:                                                (text*)placeholder_buf, placeh_len,
1.57      paf       509:                                                (dvoid *)&item.locator, 
                    510:                                                (sword)sizeof (item.locator), SQLT_CLOB, (dvoid *)0, 
1.1       parser    511:                                                (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DATA_AT_EXEC));
                    512: 
1.57      paf       513:                                        item.rows.count=0;
                    514:                                        item.connection=&connection;
1.49      paf       515:                                        check(connection, "bind dynamic", OCIBindDynamic(
1.57      paf       516:                                                item.bind, connection.errhp, 
                    517:                                                (dvoid *) &item, cbf_no_data, 
                    518:                                                (dvoid *) &item, cbf_get_data));
1.1       parser    519:                                }
                    520:                        }
                    521: 
1.49      paf       522:                        execute_prepared(connection, 
1.26      paf       523:                                statement, stmthp, lobs, 
                    524:                                offset, limit, handlers);
1.60    ! paf       525: 
        !           526:                        {
        !           527:                                for(size_t i=0; i<placeholders_count; i++) {
        !           528:                                        Placeholder& ph=placeholders[i];
        !           529:                                        Bind_info& bi=binds[i];
        !           530: 
        !           531:                                        if(bi.indicator==9999 /*unchanged*/)
        !           532:                                                continue;
        !           533: 
        !           534:                                        if(bi.indicator==-1)
        !           535:                                                ph.is_null=true;
        !           536:                                        else
        !           537:                                                if(bi.indicator==0)
        !           538:                                                        ph.is_null=false;
        !           539:                                                else
        !           540:                                                        fail(connection, bi.indicator<0?
        !           541:                                                                "column return buffer overflow, additionally size too big to be returned in 'indicator'"
        !           542:                                                                : "column return buffer overflow");
        !           543: 
        !           544:                                        ph.were_updated=true;
        !           545: 
        !           546:                                        if(cstrClientCharset) {
        !           547:                                                if(ph.value) {
        !           548:                                                        size_t value_length;
        !           549:                                                        services.transcode(ph.value, strlen(ph.value),
        !           550:                                                                ph.value, value_length,
        !           551:                                                                cstrClientCharset,
        !           552:                                                                services.request_charset());
        !           553:                                                }
        !           554:                                        }
        !           555:                                }
        !           556:                        }
1.1       parser    557:                }
                    558: cleanup: // no check call after this point!
                    559:                {
                    560:                        for(int i=0; i<lobs.count; i++) {
                    561:                                /* free var locator */
                    562:                                if(OCILobLocator *locator=lobs.items[i].locator)
                    563:                                        OCIDescriptorFree((dvoid *)locator, (ub4)OCI_DTYPE_LOB);
                    564: 
                    565:                                /* free rows descriptors */
1.60    ! paf       566:                                Query_lobs::return_rows &rows=lobs.items[i].rows;
1.1       parser    567:                                for(int r=0; r<rows.count; r++)
                    568:                                        OCIDescriptorFree((dvoid *)rows.row[r].locator, (ub4)OCI_DTYPE_LOB);
                    569:                        }
                    570:                }
                    571:                if(stmthp)
                    572:                        OCIHandleFree((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT);
                    573: 
1.26      paf       574:                if(failed) {
1.49      paf       575:                        if(connection.sql_error.defined())
                    576:                                services._throw(connection.sql_error);
                    577:                        services._throw(connection.error);
1.26      paf       578:                }
1.1       parser    579:        }
                    580: 
                    581: private: // private funcs
                    582: 
1.49      paf       583:        const char *preprocess_statement(Connection& connection, 
1.60    ! paf       584:                const char *astatement, Query_lobs &lobs) {
1.1       parser    585:                size_t statement_size=strlen(astatement);
1.49      paf       586:                SQL_Driver_services& services=*connection.services;
1.1       parser    587: 
1.32      paf       588:                char *result=(char *)services.malloc_atomic(statement_size
1.1       parser    589:                        +MAX_STRING // in case of short 'strings'
                    590:                        +11/* returning */+6/* into */+(MAX_LOB_NAME_LENGTH+2/*:, */)*2/*ret into*/*MAX_IN_LOBS
                    591:                        +1);
                    592:                const char *o=astatement;
                    593: 
                    594:                // /**xxx**/'literal' -> EMPTY_CLOB_FUNC_CALL
                    595:                char *n=result;
                    596:                while(*o) {
                    597:                        if(
                    598:                                o[0]=='/' &&
                    599:                                o[1]=='*' && 
                    600:                                o[2]=='*') { // name start
1.34      paf       601:                                const char* saved_o=o;
1.1       parser    602:                                o+=3;
                    603:                                const char *name_begin=o;
                    604:                                while(*o)
                    605:                                        if(
                    606:                                                o[0]=='*' &&
                    607:                                                o[1]=='*' &&
                    608:                                                o[2]=='/' &&
                    609:                                                o[3]=='\'') { // name end
1.34      paf       610:                                                saved_o=0; // found, marking that
1.1       parser    611:                                                const char *name_end=o;
                    612:                                                o+=4;
1.60    ! paf       613:                                                Query_lobs::Item &item=lobs.items[lobs.count++];
1.1       parser    614:                                                item.name_ptr=name_begin; item.name_size=name_end-name_begin;
1.32      paf       615:                                                item.data_ptr=(char *)services.malloc_atomic(statement_size/*max*/); item.data_size=0;
1.1       parser    616: 
                    617:                                                const char *start=o;
                    618:                                                bool escaped=false;
                    619:                                                while(*o && !(o[0]=='\'' && o[1]!='\'' && !escaped)) {
1.14      paf       620:                                                        escaped=o[0]=='\'' && o[1]=='\'';
1.1       parser    621:                                                        if(escaped) {
                    622:                                                                // write pending, skip "\" or "'"
                    623:                                                                if(size_t size=o-start) {
                    624:                                                                        memcpy(item.data_ptr+item.data_size, start, size);
                    625:                                                                        item.data_size+=size;
                    626:                                                                }
                    627:                                                                start=++o;
                    628:                                                        } else
                    629:                                                                o++;
                    630:                                                }
                    631:                                                if(size_t size=o-start) {
                    632:                                                        memcpy(item.data_ptr+item.data_size, start, size);
                    633:                                                        item.data_size+=size;
                    634:                                                }
                    635:                                                if(*o)
                    636:                                                        o++; // skip "'"
                    637: 
                    638:                                                n+=sprintf(n, EMPTY_CLOB_FUNC_CALL);
                    639:                                                break;
                    640:                                        } else
                    641:                                                o++; // /**skip**/'xxx'
1.34      paf       642:                                if(saved_o) {
                    643:                                        o=saved_o;
                    644:                                        *n++=*o++;
                    645:                                }
1.1       parser    646:                        } else
                    647:                                *n++=*o++;
                    648:                }
                    649:                *n=0;
                    650: 
                    651:                if(lobs.count) {
                    652:                        int i;
                    653:                        n+=sprintf(n, " returning ");
                    654:                        for(i=0; i<lobs.count; i++) {
                    655:                                if(i)
                    656:                                        *n++=',';
                    657:                                n+=sprintf(n, "%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr);
                    658:                        }
                    659:                        n+=sprintf(n, " into ");
                    660:                        for(i=0; i<lobs.count; i++) {
                    661:                                if(i)
1.41      paf       662:                                        *n++=',';
1.1       parser    663:                                n+=sprintf(n, ":%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr);
                    664:                        }
                    665:                }
                    666: 
                    667:                return result;
                    668:        }
                    669: 
                    670:        void execute_prepared(
1.49      paf       671:                Connection& connection, 
1.60    ! paf       672:                const char *statement, OCIStmt *stmthp, Query_lobs &lobs, 
1.1       parser    673:                unsigned long offset, unsigned long limit, 
                    674:                SQL_Driver_query_event_handlers& handlers) {
                    675: 
                    676:                ub2 stmt_type=0; // UNKNOWN
                    677:        /*
                    678:                //gpfs on sun. paf 000818
                    679:                //Zanyway, this is needed before. 
1.49      paf       680:                check(connection, "get stmt type", OCIAttrGet(
1.1       parser    681:                        (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, (ub1 *)&stmt_type, 
1.49      paf       682:                        (ub4 *)0, OCI_ATTR_STMT_TYPE, connection.errhp));
1.1       parser    683:        */
1.16      paf       684: 
1.17      paf       685:                while(isspace(*statement)) 
1.16      paf       686:                        statement++;
1.1       parser    687:                if(strncasecmp(statement, "select", 6)==0) 
                    688:                        stmt_type=OCI_STMT_SELECT;
                    689:                else if(strncasecmp(statement, "insert", 6)==0)
                    690:                        stmt_type=OCI_STMT_INSERT;
                    691:                else if(strncasecmp(statement, "update", 6)==0)
                    692:                        stmt_type=OCI_STMT_UPDATE;
                    693: 
1.49      paf       694:                sword status=OCIStmtExecute(connection.svchp, stmthp, connection.errhp, 
1.1       parser    695:                        (ub4)stmt_type==OCI_STMT_SELECT?0:1, (ub4)0, 
                    696:                        (OCISnapshot *)NULL, 
                    697:                        (OCISnapshot *)NULL, (ub4)OCI_DEFAULT);
                    698: 
                    699:                if(status!=OCI_NO_DATA)
1.49      paf       700:                        check(connection, "execute", status);
1.1       parser    701: 
                    702:                {
                    703:                        for(int i=0; i<lobs.count; i++) 
                    704:                                if(ub4 bytes_to_write=lobs.items[i].data_size) {
1.60    ! paf       705:                                        Query_lobs::return_rows *rows=&lobs.items[i].rows;
1.1       parser    706:                                        for(int r=0; r<rows->count; r++) {
                    707:                                                OCILobLocator *locator=rows->row[r].locator;
1.49      paf       708:                                                check(connection, "lobwrite", OCILobWrite (
                    709:                                                        connection.svchp, connection.errhp, 
1.1       parser    710:                                                        locator, &bytes_to_write, 1, 
                    711:                                                        (dvoid *)lobs.items[i].data_ptr, (ub4)bytes_to_write, OCI_ONE_PIECE, 
                    712:                                                        (dvoid *)0, 0, (ub2)0, 
                    713:                                                        (ub1) SQLCS_IMPLICIT));
                    714:                                        }
                    715:                                }
                    716:                }
                    717:                
                    718:                switch(stmt_type) {
                    719:                case OCI_STMT_SELECT:
1.49      paf       720:                        fetch_table(connection,
1.1       parser    721:                                stmthp, offset, limit, 
                    722:                                handlers);
                    723:                        break;
                    724:                default:
                    725:                /*
                    726:                case OCI_STMT_INSERT:
                    727:                case OCI_STMT_UPDATE:
                    728:                */
                    729:                        break;
                    730:                }
                    731:        }
                    732: 
1.49      paf       733:        void fetch_table(Connection& connection, 
1.1       parser    734:                OCIStmt *stmthp, unsigned long offset, unsigned long limit, 
1.42      paf       735:                SQL_Driver_query_event_handlers& handlers) 
                    736:        {
1.54      paf       737:                const char* cstrClientCharset=connection.options.cstrClientCharset;
1.49      paf       738:                SQL_Driver_services& services=*connection.services;
1.12      paf       739: 
1.10      paf       740:                ub4 prefetch_rows=100;
1.49      paf       741:                check(connection, "AttrSet prefetch-rows", OCIAttrSet( 
1.9       paf       742:                        (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, 
                    743:                        (dvoid *)&prefetch_rows, (ub4)0, 
1.49      paf       744:                        (ub4)OCI_ATTR_PREFETCH_ROWS, (OCIError *)connection.errhp));
1.9       paf       745: 
1.20      paf       746:                ub4 prefetch_mem_size=100*0x400;
1.49      paf       747:                check(connection, "AttrSet prefetch-memory", OCIAttrSet( 
1.9       paf       748:                        (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, 
                    749:                        (dvoid *)&prefetch_mem_size, (ub4)0, 
1.49      paf       750:                        (ub4)OCI_ATTR_PREFETCH_MEMORY, (OCIError *)connection.errhp));
1.1       parser    751: 
                    752:                OCIParam          *mypard;
                    753:                ub2                    dtype;
1.51      paf       754:                const char*           col_name;
1.1       parser    755: 
1.40      paf       756:                struct Col {
1.1       parser    757:                        ub2 type;
                    758:                        char *str;
                    759:                        OCILobLocator *var;
                    760:                        OCIDefine *def;
                    761:                        sb2 indicator;
                    762:                } cols[MAX_COLS]={0};
                    763:                int column_count=0;
                    764: 
                    765:                bool failed=false;
1.49      paf       766:                jmp_buf saved_mark; memcpy(saved_mark, connection.mark, sizeof(jmp_buf));
                    767:                if(setjmp(connection.mark)) {
1.1       parser    768:                        failed=true;
                    769:                        goto cleanup;
                    770:                } else {
1.27      paf       771:                        // idea of preincrementing is that at error time all handles would free up
                    772:                        while(++column_count<=MAX_COLS) {
                    773:                                /* get next descriptor, if there is one */
1.49      paf       774:                                if(OCIParamGet(stmthp, OCI_HTYPE_STMT, connection.errhp, (void **)&mypard, 
1.27      paf       775:                                        (ub4) column_count)!=OCI_SUCCESS) {
                    776:                                        --column_count;
                    777:                                        break;
                    778:                                }
                    779:                                
                    780:                                /* Retrieve the data type attribute */
1.49      paf       781:                                check(connection, "get type", OCIAttrGet(
1.27      paf       782:                                        (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, 
                    783:                                        (dvoid*) &dtype, (ub4 *)0, (ub4)OCI_ATTR_DATA_TYPE, 
1.49      paf       784:                                        (OCIError *)connection.errhp));
1.27      paf       785:                                
                    786:                                /* Retrieve the column name attribute */
                    787:                                ub4 col_name_len;
1.49      paf       788:                                check(connection, "get name", OCIAttrGet(
1.27      paf       789:                                        (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, 
                    790:                                        (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME, 
1.49      paf       791:                                        (OCIError *)connection.errhp));
1.51      paf       792:                                // transcode to $request:charset from connect-string?client_charset
1.54      paf       793:                                if(cstrClientCharset) {
1.51      paf       794:                                        services.transcode(col_name, col_name_len,
                    795:                                                col_name, col_name_len,
                    796:                                                cstrClientCharset,
                    797:                                                services.request_charset());
                    798:                                }
                    799: 
1.40      paf       800:                                Col& col=cols[column_count-1];
1.27      paf       801:                                {
1.38      paf       802:                                        size_t length=(size_t)col_name_len;
                    803:                                        char *ptr=(char *)services.malloc_atomic(length+1);
1.49      paf       804:                                        if( connection.options.bLowerCaseColumnNames ) 
1.55      paf       805:                                                tolower_str(ptr, col_name, length);
1.39      paf       806:                                        else
                    807:                                                memcpy(ptr, col_name, length);                                          
1.38      paf       808:                                        ptr[length]=0;
1.49      paf       809:                                        check(connection, handlers.add_column(connection.sql_error, ptr, length));
1.27      paf       810:                                }
                    811:                                
                    812:                                ub2 coerce_type=dtype;
                    813:                                sb4 size=0;
                    814:                                void *ptr;
                    815:                                
                    816:                                switch(dtype) {
                    817:                                case SQLT_CLOB: 
1.1       parser    818:                                        {
1.49      paf       819:                                                check(connection, "alloc output var desc", OCIDescriptorAlloc(
                    820:                                                        (dvoid *)connection.envhp, (dvoid **)(ptr=&col.var), 
1.27      paf       821:                                                        (ub4)OCI_DTYPE_LOB, 
                    822:                                                        0, (dvoid **)0));
                    823:                                                
                    824:                                                size=0;
1.1       parser    825:                                                break;
                    826:                                        }
1.27      paf       827:                                default:
                    828:                                        coerce_type=SQLT_STR;
1.49      paf       829:                                        char*& buf=connection.fetch_buffers[column_count-1];
1.46      paf       830:                                        ptr=buf; // get cached buffer
                    831:                                        if(!ptr) // allocate if needed, caching it
1.58      paf       832:                                                ptr=buf=(char *)services.malloc_atomic(MAX_OUT_STRING_LENGTH+1/*terminator*/);
1.46      paf       833:                                        col.str=(char*)ptr;
1.27      paf       834:                                        size=MAX_OUT_STRING_LENGTH;
                    835:                                        break;
1.1       parser    836:                                }
                    837:                                
1.40      paf       838:                                col.type=coerce_type;
1.1       parser    839:                                
1.48      paf       840:                                // http://i/docs/oracle/server.804/a58234/oci_func.htm#449680
                    841:                                //   this call implicitly allocates the define handle
                    842:                                // http://sunsite.eunnet.net/documentation/oracle.8.0.4/server.804/a58234/basics.htm
                    843:                                //   when a statement handle is freed, any bind and define handles associated with it 
                    844:                                //   are also freed
1.49      paf       845:                                col.def=0; check(connection, "DefineByPos", OCIDefineByPos(
                    846:                                        stmthp, &col.def, connection.errhp, 
1.27      paf       847:                                        column_count, (ub1 *) ptr, size, 
1.40      paf       848:                                        coerce_type, (dvoid *) &col.indicator, 
1.27      paf       849:                                        (ub2 *)0, (ub2 *)0, OCI_DEFAULT));
                    850:                        }
                    851:                        
1.49      paf       852:                        check(connection, handlers.before_rows(connection.sql_error));
1.27      paf       853:                        
                    854:                        for(unsigned long row=0; !limit||row<offset+limit; row++) {
1.49      paf       855:                                sword status=OCIStmtFetch(stmthp, connection.errhp, (ub4)1,  (ub4)OCI_FETCH_NEXT, 
1.27      paf       856:                                        (ub4)OCI_DEFAULT);
                    857:                                if(status==OCI_NO_DATA)
                    858:                                        break;
1.49      paf       859:                                check(connection, "fetch", status);
1.3       paf       860: 
1.27      paf       861:                                if(row>=offset) {
1.49      paf       862:                                        check(connection, handlers.add_row(connection.sql_error));
1.27      paf       863:                                        for(int i=0; i<column_count; i++) {
1.37      paf       864:                                                size_t length=0;
1.42      paf       865:                                                char* strm=0;
1.60    ! paf       866: 
        !           867:                                                sb2 indicator=cols[i].indicator;
        !           868:                                                if(indicator!=-1) { // not NULL
        !           869:                                                        if(indicator!=0)
        !           870:                                                                fail(connection, indicator<0?
        !           871:                                                                        "column return buffer overflow, additionally size too big to be returned in 'indicator'"
        !           872:                                                                        : "column return buffer overflow");
        !           873: 
1.27      paf       874:                                                        switch(cols[i].type) {
                    875:                                                        case SQLT_CLOB: 
                    876:                                                                {
                    877:                                                                        ub4   offset=1;
                    878:                                                                        OCILobLocator *var=(OCILobLocator *)cols[i].var;
1.42      paf       879:                                                                        size_t read_size=0;
1.45      paf       880:                                                                        strm=(char*)services.malloc_atomic(1/*for terminator*/); // set type of memory block
1.42      paf       881:                                                                        do {
                    882:                                                                                char buf[MAX_STRING*10];
1.45      paf       883:                                                                                ub4   amtp=0/*to be read in stream mode*/;
                    884:                                                                                // http://i/docs/oracle/server.804/a58234/oci_func.htm#427818
1.49      paf       885:                                                                                status=OCILobRead(connection.svchp, connection.errhp, 
1.42      paf       886:                                                                                        var, &amtp, offset, (dvoid *)buf, 
                    887:                                                                                        sizeof(buf), 
                    888:                                                                                        (dvoid *)0, 0, 
                    889:                                                                                        (ub2)0, (ub1)SQLCS_IMPLICIT);
                    890:                                         if(status!=OCI_SUCCESS && status!=OCI_NEED_DATA)
1.49      paf       891:                                                                                        check(connection, "lobread", status);
1.42      paf       892: 
1.45      paf       893:                                                                                strm=(char*)services.realloc(strm, read_size+amtp+1/*for termintator*/);
1.42      paf       894:                                                                                memcpy(strm+read_size, buf, amtp);
                    895:                                                                                read_size+=amtp;
                    896:                                                                                offset+=amtp;
                    897:                                                                        } while(status==OCI_NEED_DATA);
                    898: 
                    899:                                                                        length=(size_t)read_size;
                    900:                                                                        strm[length]=0;
1.1       parser    901:                                                                        break;
                    902:                                                                }
1.27      paf       903:                                                        default:
1.32      paf       904:                                                                if(const char *value=cols[i].str) {
1.37      paf       905:                                                                        length=strlen(value);
1.42      paf       906:                                                                        strm=(char*)services.malloc_atomic(length+1);
                    907:                                                                        memcpy(strm, value, length+1);
1.27      paf       908:                                                                } else {
1.37      paf       909:                                                                        length=0;
1.42      paf       910:                                                                        strm=0;
1.27      paf       911:                                                                }
                    912:                                                                break;
                    913:                                                        }
1.60    ! paf       914:                                                }
1.42      paf       915: 
                    916:                                                const char* str=strm;
                    917:                                                if(str && length)
                    918:                                                {
                    919:                                                        // transcode to $request:charset from connect-string?client_charset
1.54      paf       920:                                                        if(cstrClientCharset)
1.42      paf       921:                                                                services.transcode(str, length,
1.53      paf       922:                                                                        str, length,
1.42      paf       923:                                                                        cstrClientCharset,
                    924:                                                                        services.request_charset());
                    925:                                                }
                    926: 
1.49      paf       927:                                                check(connection, handlers.add_row_cell(connection.sql_error, str, length));
1.1       parser    928:                                        }
                    929:                                }
                    930:                        }
                    931:                }
                    932: 
                    933: cleanup: // no check call after this point!
                    934:                for(int i=0; i<column_count; i++) {
                    935:                        switch(cols[i].type) {
                    936:                        case SQLT_CLOB:
                    937:                                /* free var locator */
                    938:                                OCIDescriptorFree((dvoid *) cols[i].var, (ub4)OCI_DTYPE_LOB);
                    939:                                break;
                    940:                        default:
                    941:                                break;
                    942:                        }
                    943:                }
                    944: 
                    945:                if(failed) // need rethrow?
                    946:                        longjmp(saved_mark, 1);
                    947:        }
                    948: 
                    949: private: // conn client library funcs
                    950:        
1.60    ! paf       951:        friend void fail(Connection& connection, const char *msg);
1.49      paf       952:        friend void check(Connection& connection, const char *step, sword status);
1.1       parser    953:        friend sb4 cbf_get_data(dvoid *ctxp, 
                    954:                OCIBind *bindp, 
                    955:                ub4 iter, ub4 index, 
                    956:                dvoid **bufpp, 
                    957:                ub4 **alenp, 
                    958:                ub1 *piecep, 
                    959:                dvoid **indpp, 
                    960:                ub2 **rcodepp);
                    961: 
                    962: 
                    963: #define OCI_DECL(name, params) \
                    964:        typedef sword (*t_OCI##name)params; t_OCI##name OCI##name
                    965: 
                    966:        OCI_DECL(Initialize, (ub4 mode, dvoid *ctxp, 
                    967:                dvoid * (*malocfp)(dvoid *ctxp, size_t size),
                    968:                dvoid * (*ralocfp)(dvoid *ctxp, dvoid *memptr, size_t newsize),
                    969:                void (*mfreefp)(dvoid *ctxp, dvoid *memptr) ));
                    970: 
                    971:        OCI_DECL(EnvInit, (OCIEnv **envp, ub4 mode, 
                    972:                size_t xtramem_sz, dvoid **usrmempp)); 
                    973:                
                    974:        OCI_DECL(AttrGet, (CONST dvoid *trgthndlp, ub4 trghndltyp, 
                    975:                dvoid *attributep, ub4 *sizep, ub4 attrtype, 
                    976:                OCIError *errhp));
                    977:        
                    978:        OCI_DECL(AttrSet, (dvoid *trgthndlp, ub4 trghndltyp, dvoid *attributep,
                    979:                                                                ub4 size, ub4 attrtype, OCIError *errhp));
                    980: 
                    981:        OCI_DECL(BindByPos, (OCIStmt *stmtp, OCIBind **bindp, OCIError *errhp,
                    982:                ub4 position, dvoid *valuep, sb4 value_sz,
                    983:                ub2 dty, dvoid *indp, ub2 *alenp, ub2 *rcodep,
                    984:                ub4 maxarr_len, ub4 *curelep, ub4 mode));
                    985: 
1.59      paf       986:        OCI_DECL(BindByName, (OCIStmt *stmtp, OCIBind **bindp, OCIError *errhp,
                    987:                text* placeholder, sb4 placeh_len, dvoid *valuep, sb4 value_sz,
                    988:                ub2 dty, dvoid *indp, ub2 *alenp, ub2 *rcodep,
                    989:                ub4 maxarr_len, ub4 *curelep, ub4 mode));
                    990: 
1.1       parser    991:        OCI_DECL(BindDynamic, (OCIBind *bindp, OCIError *errhp, dvoid *ictxp,
                    992:                OCICallbackInBind icbfp, dvoid *octxp,
                    993:                OCICallbackOutBind ocbfp));
                    994:        
                    995:        OCI_DECL(DefineByPos, (OCIStmt *stmtp, OCIDefine **defnp, OCIError *errhp,
                    996:                ub4 position, dvoid *valuep, sb4 value_sz, ub2 dty,
                    997:                dvoid *indp, ub2 *rlenp, ub2 *rcodep, ub4 mode));
                    998:        
                    999:        OCI_DECL(DescriptorAlloc, (CONST dvoid *parenth, dvoid **descpp, 
                   1000:                CONST ub4 type, CONST size_t xtramem_sz, 
                   1001:                dvoid **usrmempp));
                   1002:        
                   1003:        OCI_DECL(DescriptorFree, (dvoid *descp, CONST ub4 type));
                   1004: 
                   1005:        
                   1006:        OCI_DECL(ErrorGet, (dvoid *hndlp, ub4 recordno, OraText *sqlstate,
                   1007:                        sb4 *errcodep, OraText *bufp, ub4 bufsiz, ub4 type));
                   1008: 
                   1009:        OCI_DECL(HandleAlloc, (CONST dvoid *parenth, dvoid **hndlpp, CONST ub4 type, 
                   1010:                        CONST size_t xtramem_sz, dvoid **usrmempp));
                   1011: 
                   1012:        OCI_DECL(HandleFree, (dvoid *hndlp, CONST ub4 type));
                   1013:                                           
                   1014:        OCI_DECL(LobGetLength, (OCISvcCtx *svchp, OCIError *errhp, 
                   1015:                           OCILobLocator *locp,
                   1016:                           ub4 *lenp));
                   1017: 
                   1018:        OCI_DECL(LobRead, (OCISvcCtx *svchp, OCIError *errhp, OCILobLocator *locp,
                   1019:                      ub4 *amtp, ub4 offset, dvoid *bufp, ub4 bufl, 
                   1020:                      dvoid *ctxp, sb4 (*cbfp)(dvoid *ctxp, 
                   1021:                                               CONST dvoid *bufp, 
                   1022:                                               ub4 len, 
                   1023:                                               ub1 piece),
                   1024:                      ub2 csid, ub1 csfrm));
                   1025: 
                   1026:        OCI_DECL(LobWrite, (OCISvcCtx *svchp, OCIError *errhp, OCILobLocator *locp,
                   1027:                       ub4 *amtp, ub4 offset, dvoid *bufp, ub4 buflen, 
                   1028:                       ub1 piece, dvoid *ctxp, 
                   1029:                       sb4 (*cbfp)(dvoid *ctxp, 
                   1030:                                   dvoid *bufp, 
                   1031:                                   ub4 *len, 
                   1032:                                   ub1 *piece),
                   1033:                       ub2 csid, ub1 csfrm));
                   1034: 
                   1035:        OCI_DECL(ParamGet, (CONST dvoid *hndlp, ub4 htype, OCIError *errhp, 
                   1036:                      dvoid **parmdpp, ub4 pos));
                   1037: 
                   1038:        OCI_DECL(ServerAttach, (OCIServer *srvhp, OCIError *errhp,
                   1039:                           CONST OraText *dblink, sb4 dblink_len, ub4 mode));
                   1040: 
                   1041:        OCI_DECL(ServerDetach, (OCIServer *srvhp, OCIError *errhp, ub4 mode));
                   1042: 
                   1043:        OCI_DECL(SessionBegin, (OCISvcCtx *svchp, OCIError *errhp, OCISession *usrhp,
                   1044:                           ub4 credt, ub4 mode));
                   1045: 
                   1046:        OCI_DECL(SessionEnd, (OCISvcCtx *svchp, OCIError *errhp, OCISession *usrhp, 
                   1047:                          ub4 mode));
                   1048: 
                   1049:        OCI_DECL(StmtExecute, (OCISvcCtx *svchp, OCIStmt *stmtp, OCIError *errhp, 
                   1050:                          ub4 iters, ub4 rowoff, CONST OCISnapshot *snap_in, 
                   1051:                          OCISnapshot *snap_out, ub4 mode));
                   1052: 
                   1053:        OCI_DECL(StmtFetch, (OCIStmt *stmtp, OCIError *errhp, ub4 nrows, 
                   1054:                         ub2 orientation, ub4 mode));
                   1055: 
                   1056:        OCI_DECL(StmtPrepare, (OCIStmt *stmtp, OCIError *errhp, CONST OraText *stmt,
                   1057:                           ub4 stmt_len, ub4 language, ub4 mode));
                   1058: 
                   1059:        OCI_DECL(TransCommit, (OCISvcCtx *svchp, OCIError *errhp, ub4 flags));
                   1060: 
                   1061:        OCI_DECL(TransRollback, (OCISvcCtx *svchp, OCIError *errhp, ub4 flags));
                   1062: 
                   1063: private: // conn client library funcs linking
                   1064: 
                   1065:        const char *dlink(const char *dlopen_file_spec) {
                   1066:                if(lt_dlinit())
                   1067:                        return lt_dlerror();
                   1068:         lt_dlhandle handle=lt_dlopen(dlopen_file_spec);
                   1069:         if(!handle)
                   1070:                        return lt_dlerror(); //"can not open the dynamic link module";
                   1071: 
                   1072:                #define DSLINK(name, action) \
                   1073:                        name=(t_##name)lt_dlsym(handle, #name); \
                   1074:                                if(!name) \
                   1075:                                        action;
                   1076: 
                   1077:                #define OCI_LINK(name) DSLINK(OCI##name, return "function OCI" #name " was not found")
                   1078:                
                   1079:                OCI_LINK(Initialize);
                   1080:                OCI_LINK(EnvInit);
                   1081:                OCI_LINK(AttrGet);              OCI_LINK(AttrSet);
1.59      paf      1082:                OCI_LINK(BindByPos);            OCI_LINK(BindByName);   OCI_LINK(BindDynamic);
1.1       parser   1083:                OCI_LINK(DefineByPos);
                   1084:                OCI_LINK(DescriptorAlloc);              OCI_LINK(DescriptorFree);
                   1085:                OCI_LINK(ErrorGet);
                   1086:                OCI_LINK(HandleAlloc);          OCI_LINK(HandleFree);
                   1087:                OCI_LINK(LobGetLength);
                   1088:                OCI_LINK(LobRead);              OCI_LINK(LobWrite);
                   1089:                OCI_LINK(ParamGet);
                   1090:                OCI_LINK(ServerAttach);         OCI_LINK(ServerDetach);
                   1091:                OCI_LINK(SessionBegin);         OCI_LINK(SessionEnd);
                   1092:                OCI_LINK(StmtExecute);          OCI_LINK(StmtFetch);            OCI_LINK(StmtPrepare);
                   1093:                OCI_LINK(TransCommit);          OCI_LINK(TransRollback);
                   1094: 
                   1095:                return 0;
                   1096:        }
                   1097: 
                   1098: } *OracleSQL_driver;
                   1099: 
1.49      paf      1100: void check(Connection& connection, const char *step, sword status) {
1.1       parser   1101: 
                   1102:        const char *msg;
                   1103:        char reason[MAX_STRING/2];
                   1104: 
                   1105:        switch (status) {
1.22      paf      1106:        case OCI_SUCCESS: // hurrah
                   1107:        case OCI_SUCCESS_WITH_INFO:             // ignoring. example: count(column) when column contains NULLs, 
                   1108:                                                                                                                // count() not counting them and gives that status
                   1109:                return;
1.1       parser   1110:        case OCI_ERROR:
                   1111:                {
1.45      paf      1112:                        sb4 errcode;
1.49      paf      1113:                        if(OracleSQL_driver->OCIErrorGet((dvoid *)connection.errhp, (ub4)1, (text *)NULL, &errcode, 
1.45      paf      1114:                                (text *)reason, (ub4)sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS) {
                   1115:                                msg=reason;
                   1116: 
                   1117:                                // transcode to $request:charset from connect-string?client_charset
1.49      paf      1118:                                if(const char* cstrClientCharset=connection.options.cstrClientCharset) {
1.45      paf      1119:                                        if(msg) {
                   1120:                                                if(size_t msg_length=strlen(msg)) {
1.49      paf      1121:                                                        connection.services->transcode(msg, msg_length,
1.45      paf      1122:                                                                msg, msg_length,
                   1123:                                                                cstrClientCharset,
1.49      paf      1124:                                                                connection.services->request_charset());
1.45      paf      1125:                                                }
1.42      paf      1126:                                        }
                   1127:                                }
1.45      paf      1128:                        } else
                   1129:                                msg="[can not get error description]";
                   1130:                        break;
1.1       parser   1131:                }
                   1132:        case OCI_NEED_DATA:
                   1133:                msg="NEED_DATA"; break;
                   1134:        case OCI_NO_DATA:
                   1135:                msg="NODATA"; break;
                   1136:        case OCI_INVALID_HANDLE:
                   1137:                msg="INVALID_HANDLE"; break;
                   1138:        case OCI_STILL_EXECUTING:
                   1139:                msg="STILL_EXECUTE"; break;
                   1140:        case OCI_CONTINUE:
                   1141:                msg="CONTINUE"; break;
                   1142:        default:
                   1143:                msg="unknown"; break;
                   1144:        }
                   1145: 
1.49      paf      1146:        snprintf(connection.error, sizeof(connection.error), "%s (%s, %d)", 
1.22      paf      1147:                msg, step, (int)status);
1.49      paf      1148:        longjmp(connection.mark, 1);
1.1       parser   1149: }
                   1150: 
1.60    ! paf      1151: void fail(Connection& connection, const char* msg) {
        !          1152:        snprintf(connection.error, sizeof(connection.error), "%s", msg);
        !          1153:        longjmp(connection.mark, 1);
        !          1154: }
        !          1155: 
1.49      paf      1156: void check(Connection& connection, bool error) {
1.27      paf      1157:        if(error)
1.49      paf      1158:                longjmp(connection.mark, 1);
1.27      paf      1159: }
1.1       parser   1160: 
                   1161: /* ----------------------------------------------------------------- */
                   1162: /* Intbind callback that does not do any data input.                 */
                   1163: /* ----------------------------------------------------------------- */
1.60    ! paf      1164: sb4 cbf_no_data(
1.45      paf      1165:                                dvoid* /*ctxp*/, 
                   1166:                                OCIBind* /*bindp*/, 
                   1167:                                ub4 /*iter*/, ub4 /*index*/, 
1.1       parser   1168:                                dvoid **bufpp, 
                   1169:                                ub4 *alenpp, 
                   1170:                                ub1 *piecep, 
                   1171:                                dvoid **indpp) {
                   1172:        *bufpp=(dvoid *)0;
                   1173:        *alenpp=0;
                   1174:        static sb2 null_ind=-1;
                   1175:        *indpp=(dvoid *) &null_ind;
                   1176:        *piecep=OCI_ONE_PIECE;
                   1177:        
                   1178:        return OCI_CONTINUE;
                   1179: }
                   1180: 
                   1181: /* ----------------------------------------------------------------- */
                   1182: /* Outbind callback for returning data.                              */
                   1183: /* ----------------------------------------------------------------- */
                   1184: static sb4 cbf_get_data(dvoid *ctxp, 
                   1185:                                 OCIBind *bindp, 
1.45      paf      1186:                                 ub4 /*iter*/, ub4 index, 
1.1       parser   1187:                                 dvoid **bufpp, 
                   1188:                                 ub4 **alenp, 
                   1189:                                 ub1 *piecep, 
                   1190:                                 dvoid **indpp, 
                   1191:                                 ub2 **rcodepp) {
1.60    ! paf      1192:        Query_lobs::Item& context=*static_cast<Query_lobs::Item*>(ctxp);
1.1       parser   1193: 
                   1194:        if(index==0) {
                   1195:                static ub4  rows;
1.49      paf      1196:                check(*context.connection, "AttrGet cbf_get_data ROWS_RETURNED", 
1.1       parser   1197:                        OracleSQL_driver->OCIAttrGet(
                   1198:                                (CONST dvoid *) bindp, OCI_HTYPE_BIND, (dvoid *)&rows, 
1.49      paf      1199:                                (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.connection->errhp)) ;
1.57      paf      1200:                context.rows.count=(ub2)rows;
1.60    ! paf      1201:                context.rows.row=(Query_lobs::return_rows::return_row *)
        !          1202:                        context.connection->services->malloc_atomic(sizeof(Query_lobs::return_rows::return_row)*rows);
1.1       parser   1203:        }
                   1204: 
1.60    ! paf      1205:        Query_lobs::return_rows::return_row &var=context.rows.row[index];
1.1       parser   1206: 
1.49      paf      1207:        check(*context.connection, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc(
                   1208:                (dvoid *) context.connection->envhp, (dvoid **)&var.locator, 
1.1       parser   1209:                (ub4)OCI_DTYPE_LOB, 
                   1210:                0, (dvoid **)0));
                   1211: 
                   1212:        *bufpp=var.locator;
                   1213:        *alenp=&var.len;
                   1214:        *indpp=(dvoid *) &var.ind;
                   1215:        *piecep=OCI_ONE_PIECE;
                   1216:        *rcodepp=&var.rcode;
                   1217:        
                   1218:        return OCI_CONTINUE;
                   1219: }
                   1220: 
1.55      paf      1221: static void tolower_str(char *out, const char *in, size_t size) {
1.38      paf      1222:        while(size--)
1.45      paf      1223:                *out++=(char)tolower(*in++);
1.1       parser   1224: }
1.55      paf      1225: static void toupper_str(char *out, const char *in, size_t size) {
1.44      paf      1226:        while(size--)
1.45      paf      1227:                *out++=(char)toupper(*in++);
1.44      paf      1228: }
                   1229: 
1.1       parser   1230: 
                   1231: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
                   1232:        return OracleSQL_driver=new OracleSQL_Driver();
                   1233: }

E-mail: