|
|
| version 1.39, 2003/10/28 15:41:01 | version 1.54, 2004/03/26 13:26:41 |
|---|---|
| Line 38 inline int max(int a, int b) { return a> | Line 38 inline int max(int a, int b) { return a> |
| inline int min(int a, int b){ return a<b?a:b; } | inline int min(int a, int b){ return a<b?a:b; } |
| #endif | #endif |
| #if _MSC_VER | |
| // interaction between '_setjmp' and C++ object destruction is non-portable | |
| // but we forced to do that under HPUX | |
| #pragma warning(disable:4611) | |
| #endif | |
| /// @todo small memory leaks here | /// @todo small memory leaks here |
| static int pa_setenv(const char *name, const char *value, bool do_append) { | static int pa_setenv(const char *name, const char *value, bool do_append) { |
| const char *prev_value=0; | const char *prev_value=0; |
| Line 104 static char *lsplit(char **string_ref, c | Line 110 static char *lsplit(char **string_ref, c |
| return result; | return result; |
| } | } |
| static const char *options2env(char *options, bool* LowerCaseColumnNames) { | |
| while(options) { | |
| if(char *key=lsplit(&options, '&')) { | |
| if(*key) { | |
| if(char *value=lsplit(key, '=')) { | |
| if( strcmp( key, "LowerCaseColumnNames" ) == 0 ) { | |
| if( LowerCaseColumnNames ) | |
| *LowerCaseColumnNames = atoi(value)!=0; | |
| continue; | |
| } | |
| bool do_append=key[strlen(key)-1]=='+'; // PATH+= | |
| if(do_append) | |
| key[strlen(key)-1]=0; // remove trailing + | |
| if(strncmp(key, "ORACLE_", 7)==0 // ORACLE_HOME & co | |
| || strncmp(key, "ORA_", 4)==0 // ORA_ENCRYPT_LOGIN & co | |
| || strncmp(key, "NLS_", 4)==0 // NLS_LANG & co | |
| || do_append | |
| ) { | |
| if(pa_setenv(key, value, do_append)!=0) | |
| return "problem changing process environment" /*key*/; | |
| } else | |
| return "unknown option (option must start with ORACLE_, ORA_ or NLS_)" /*key*/; | |
| } else | |
| return "option without =value" /*key*/; | |
| } | |
| } | |
| } | |
| return 0; | |
| } | |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| struct OracleSQL_connection_struct { | struct Connection { |
| SQL_Driver_services *services; | |
| jmp_buf mark; char error[MAX_STRING]; | jmp_buf mark; char error[MAX_STRING]; |
| SQL_Error sql_error; | SQL_Error sql_error; |
| OCIEnv *envhp; | OCIEnv *envhp; |
| Line 145 struct OracleSQL_connection_struct { | Line 122 struct OracleSQL_connection_struct { |
| OCISvcCtx *svchp; | OCISvcCtx *svchp; |
| OCISession *usrhp; | OCISession *usrhp; |
| bool bLowerCaseColumnNames; | char* fetch_buffers[MAX_COLS]; |
| struct Options { | |
| bool bLowerCaseColumnNames; | |
| const char* cstrClientCharset; | |
| } options; | |
| }; | }; |
| struct OracleSQL_query_lobs { | struct OracleSQL_query_lobs { |
| Line 158 struct OracleSQL_query_lobs { | Line 140 struct OracleSQL_query_lobs { |
| int count; | int count; |
| }; | }; |
| struct cbf_context_struct { | struct cbf_context_struct { |
| SQL_Driver_services *services; | Connection *connection; |
| OracleSQL_connection_struct *cs; | |
| return_rows *rows; | return_rows *rows; |
| }; | }; |
| struct Item { | struct Item { |
| Line 174 struct OracleSQL_query_lobs { | Line 155 struct OracleSQL_query_lobs { |
| #endif | #endif |
| // forwards | // forwards |
| void check(OracleSQL_connection_struct &cs, const char *step, sword status); | void check(Connection& connection, const char *step, sword status); |
| void check(OracleSQL_connection_struct &cs, bool error); | void check(Connection& connection, bool error); |
| static sb4 cbf_no_data( | static sb4 cbf_no_data( |
| dvoid *ctxp, | dvoid *ctxp, |
| OCIBind *bindp, | OCIBind *bindp, |
| Line 192 static sb4 cbf_get_data(dvoid *ctxp, | Line 173 static sb4 cbf_get_data(dvoid *ctxp, |
| ub1 *piecep, | ub1 *piecep, |
| dvoid **indpp, | dvoid **indpp, |
| ub2 **rcodepp); | ub2 **rcodepp); |
| void tolower(char *out, const char *in, size_t size); | static void tolower(char *out, const char *in, size_t size); |
| static void toupper(char *out, const char *in, size_t size); | |
| static const char *options2env(char *s, Connection::Options* options) { | |
| while(s) { | |
| if(char *key=lsplit(&s, '&')) { | |
| if(*key) { | |
| if(char *value=lsplit(key, '=')) { | |
| if( strcmp( key, "ClientCharset" ) == 0 ) { | |
| if(options) { | |
| toupper(value, value, strlen(value)); | |
| options->cstrClientCharset = value; | |
| } | |
| continue; | |
| } | |
| if( strcmp( key, "LowerCaseColumnNames" ) == 0 ) { | |
| if(options) | |
| options->bLowerCaseColumnNames = atoi(value)!=0; | |
| continue; | |
| } | |
| bool do_append=key[strlen(key)-1]=='+'; // PATH+= | |
| if(do_append) | |
| key[strlen(key)-1]=0; // remove trailing + | |
| if(strncmp(key, "ORACLE_", 7)==0 // ORACLE_HOME & co | |
| || strncmp(key, "ORA_", 4)==0 // ORA_ENCRYPT_LOGIN & co | |
| || strncmp(key, "NLS_", 4)==0 // NLS_LANG & co | |
| || do_append | |
| ) { | |
| if(pa_setenv(key, value, do_append)!=0) | |
| return "problem changing process environment" /*key*/; | |
| } else | |
| return "unknown option" /*key*/; | |
| } else | |
| return "option without =value" /*key*/; | |
| } | |
| } | |
| } | |
| return 0; | |
| } | |
| /** | /** |
| OracleSQL server driver | OracleSQL server driver |
| Line 240 public: | Line 261 public: |
| void connect( | void connect( |
| char *used_only_in_connect_url, | char *used_only_in_connect_url, |
| SQL_Driver_services& services, | SQL_Driver_services& services, |
| void **connection ///< output: OracleSQL_connection_struct * | void **connection_ref ///< output: Connection * |
| ) { | ) { |
| // connections are cross-request, do not use services._alloc [linked with request] | Connection& connection=*(Connection *)services.malloc(sizeof(Connection)); |
| OracleSQL_connection_struct &cs= | connection.services=&services; |
| *(OracleSQL_connection_struct *)::calloc(sizeof(OracleSQL_connection_struct), 1); | connection.options.bLowerCaseColumnNames = true; |
| cs.bLowerCaseColumnNames = true; | *connection_ref=&connection; |
| char *user=used_only_in_connect_url; | char *user=used_only_in_connect_url; |
| char *service=lsplit(user, '@'); | char *service=lsplit(user, '@'); |
| Line 255 public: | Line 276 public: |
| if(!(user && pwd && service)) | if(!(user && pwd && service)) |
| services._throw("mailformed connect part, must be 'user:pass@service'"); | services._throw("mailformed connect part, must be 'user:pass@service'"); |
| if(const char *error=options2env(options, &cs.bLowerCaseColumnNames)) | if(const char *error=options2env(options, &connection.options)) |
| services._throw(error); | services._throw(error); |
| if(setjmp(cs.mark)) | if(setjmp(connection.mark)) |
| services._throw(cs.error); | services._throw(connection.error); |
| // Allocate and initialize OCIError handle, attempt #1 | // Allocate and initialize OCIError handle, attempt #1 |
| /* | /* |
| Line 277 public: | Line 298 public: |
| think, this is some sort of backward compatibility wonder. | think, this is some sort of backward compatibility wonder. |
| leaving as it is, and without check() | leaving as it is, and without check() |
| */ | */ |
| OCIHandleAlloc((dvoid *)NULL, (dvoid **) &cs.envhp, (ub4)OCI_HTYPE_ENV, 0, 0); | OCIHandleAlloc((dvoid *)NULL, (dvoid **) &connection.envhp, (ub4)OCI_HTYPE_ENV, 0, 0); |
| // Initialize an environment handle, attempt #2 | // Initialize an environment handle, attempt #2 |
| check(cs, "EnvInit", OCIEnvInit( | check(connection, "EnvInit", OCIEnvInit( |
| &cs.envhp, (ub4)OCI_DEFAULT, 0, 0)); | &connection.envhp, (ub4)OCI_DEFAULT, 0, 0)); |
| // Allocate and initialize OCIError handle | // Allocate and initialize OCIError handle |
| check(cs, "HandleAlloc errhp", OCIHandleAlloc( | check(connection, "HandleAlloc errhp", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **) &cs.errhp, (ub4)OCI_HTYPE_ERROR, 0, 0)); | (dvoid *)connection.envhp, (dvoid **) &connection.errhp, (ub4)OCI_HTYPE_ERROR, 0, 0)); |
| // Allocate and initialize OCIServer handle | // Allocate and initialize OCIServer handle |
| check(cs, "HandleAlloc srvhp", OCIHandleAlloc( | check(connection, "HandleAlloc srvhp", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **) &cs.srvhp, (ub4)OCI_HTYPE_SERVER, 0, 0)); | (dvoid *)connection.envhp, (dvoid **) &connection.srvhp, (ub4)OCI_HTYPE_SERVER, 0, 0)); |
| // Attach to a 'service'; initialize server context handle | // Attach to a 'service'; initialize server context handle |
| check(cs, "ServerAttach", OCIServerAttach( | check(connection, "ServerAttach", OCIServerAttach( |
| cs.srvhp, cs.errhp, (text *)service, (sb4)strlen(service), (ub4)OCI_DEFAULT)); | connection.srvhp, connection.errhp, (text *)service, (sb4)strlen(service), (ub4)OCI_DEFAULT)); |
| // Allocate and initialize OCISvcCtx handle | // Allocate and initialize OCISvcCtx handle |
| check(cs, "HandleAlloc svchp", OCIHandleAlloc( | check(connection, "HandleAlloc svchp", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **) &cs.svchp, (ub4)OCI_HTYPE_SVCCTX, 0, 0)); | (dvoid *)connection.envhp, (dvoid **) &connection.svchp, (ub4)OCI_HTYPE_SVCCTX, 0, 0)); |
| // set attribute server context in the service context | // set attribute server context in the service context |
| check(cs, "AttrSet server-service", OCIAttrSet( | check(connection, "AttrSet server-service", OCIAttrSet( |
| (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX, | (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX, |
| (dvoid *)cs.srvhp, (ub4)0, | (dvoid *)connection.srvhp, (ub4)0, |
| (ub4)OCI_ATTR_SERVER, (OCIError *)cs.errhp)); | (ub4)OCI_ATTR_SERVER, (OCIError *)connection.errhp)); |
| // allocate a user context handle | // allocate a user context handle |
| check(cs, "HandleAlloc usrhp", OCIHandleAlloc( | check(connection, "HandleAlloc usrhp", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **)&cs.usrhp, (ub4)OCI_HTYPE_SESSION, 0, 0)); | (dvoid *)connection.envhp, (dvoid **)&connection.usrhp, (ub4)OCI_HTYPE_SESSION, 0, 0)); |
| // set 'user' name | // set 'user' name |
| check(cs, "AttrSet user-session", OCIAttrSet( | check(connection, "AttrSet user-session", OCIAttrSet( |
| (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION, | (dvoid *)connection.usrhp, (ub4)OCI_HTYPE_SESSION, |
| (dvoid *)user, (ub4)strlen(user), | (dvoid *)user, (ub4)strlen(user), |
| OCI_ATTR_USERNAME, cs.errhp)); | OCI_ATTR_USERNAME, connection.errhp)); |
| // set 'pwd' password | // set 'pwd' password |
| check(cs, "AttrSet pwd-session", OCIAttrSet( | check(connection, "AttrSet pwd-session", OCIAttrSet( |
| (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION, | (dvoid *)connection.usrhp, (ub4)OCI_HTYPE_SESSION, |
| (dvoid *)pwd, (ub4)strlen(pwd), | (dvoid *)pwd, (ub4)strlen(pwd), |
| OCI_ATTR_PASSWORD, cs.errhp)); | OCI_ATTR_PASSWORD, connection.errhp)); |
| // Authenticate a user | // Authenticate a user |
| check(cs, "SessionBegin", OCISessionBegin( | check(connection, "SessionBegin", OCISessionBegin( |
| cs.svchp, cs.errhp, cs.usrhp, | connection.svchp, connection.errhp, connection.usrhp, |
| OCI_CRED_RDBMS, OCI_DEFAULT)); | OCI_CRED_RDBMS, OCI_DEFAULT)); |
| // remember connection in session | // remember connection in session |
| check(cs, "AttrSet service-session", OCIAttrSet( | check(connection, "AttrSet service-session", OCIAttrSet( |
| (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX, | (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX, |
| (dvoid *)cs.usrhp, (ub4)0, | (dvoid *)connection.usrhp, (ub4)0, |
| OCI_ATTR_SESSION, cs.errhp)); | OCI_ATTR_SESSION, connection.errhp)); |
| // return created connection | |
| *(OracleSQL_connection_struct **)connection=&cs; | |
| } | } |
| void disconnect(void *connection) { | void disconnect(void *aconnection) { |
| OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; | Connection& connection=*static_cast<Connection *>(aconnection); |
| // free fetch buffers | |
| for(int i=0; i<MAX_COLS; i++) { | |
| if(void* fetch_buffer=connection.fetch_buffers[i]) | |
| ::free(fetch_buffer); | |
| else | |
| break; | |
| } | |
| // Terminate a user session | // Terminate a user session |
| OCISessionEnd( | OCISessionEnd( |
| cs.svchp, cs.errhp, cs.usrhp, (ub4)OCI_DEFAULT); | connection.svchp, connection.errhp, connection.usrhp, (ub4)OCI_DEFAULT); |
| // Detach from a server; uninitialize server context handle | // Detach from a server; uninitialize server context handle |
| OCIServerDetach( | OCIServerDetach( |
| cs.srvhp, cs.errhp, (ub4)OCI_DEFAULT); | connection.srvhp, connection.errhp, (ub4)OCI_DEFAULT); |
| // Free a previously allocated handles | // Free a previously allocated handles |
| /* | /* |
| oci will free them up as belonging to env | oci will free them up as belonging to env |
| OCIHandleFree( | OCIHandleFree( |
| (dvoid *)cs.srvhp, (ub4)OCI_HTYPE_SERVER); | (dvoid *)connection.srvhp, (ub4)OCI_HTYPE_SERVER); |
| OCIHandleFree( | OCIHandleFree( |
| (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX); | (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX); |
| OCIHandleFree( | OCIHandleFree( |
| (dvoid *)cs.errhp, (ub4)OCI_HTYPE_ERROR); | (dvoid *)connection.errhp, (ub4)OCI_HTYPE_ERROR); |
| */ | */ |
| OCIHandleFree( | OCIHandleFree( |
| (dvoid *)cs.envhp, (ub4)OCI_HTYPE_ENV); | (dvoid *)connection.envhp, (ub4)OCI_HTYPE_ENV); |
| // connections are cross-request, do not use services._alloc [linked with request] | // connections are cross-request, do not use services._alloc [linked with request] |
| ::free(&cs); | ::free(&connection); |
| } | } |
| void commit(SQL_Driver_services& services, void *connection) { | void commit(void *aconnection) { |
| OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; | Connection& connection=*static_cast<Connection *>(aconnection); |
| if(setjmp(cs.mark)) | if(setjmp(connection.mark)) |
| services._throw(cs.error); | connection.services->_throw(connection.error); |
| check(cs, "commit", OCITransCommit(cs.svchp, cs.errhp, 0)); | check(connection, "commit", OCITransCommit(connection.svchp, connection.errhp, 0)); |
| } | } |
| void rollback(SQL_Driver_services& services, void *connection) { | void rollback(void *aconnection) { |
| OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; | Connection& connection=*static_cast<Connection *>(aconnection); |
| if(setjmp(cs.mark)) | if(setjmp(connection.mark)) |
| services._throw(cs.error); | connection.services->_throw(connection.error); |
| check(cs, "rollback", OCITransRollback(cs.svchp, cs.errhp, 0)); | // sometimes rollback is done in context when this yields error which masks previous error |
| // consider consequent errors not very important to report, reporting first one | |
| /*check(connection, "rollback", */OCITransRollback(connection.svchp, connection.errhp, 0)/*)*/; | |
| } | } |
| bool ping(SQL_Driver_services&, void *connection) { | bool ping(void* /*connection*/) { |
| // maybe OCIServerVersion? | // maybe OCIServerVersion? |
| // select 0 from dual | // select 0 from dual |
| return true; | return true; |
| } | } |
| const char* quote( | const char* quote(void *aconnection, |
| SQL_Driver_services& services, void *connection, | const char *from, unsigned int length) |
| const char *from, unsigned int length) { | { |
| char *result=(char*)services.malloc_atomic(length*2+1); | Connection& connection=*static_cast<Connection *>(aconnection); |
| char *result=(char*)connection.services->malloc_atomic(length*2+1); | |
| char *to=result; | char *to=result; |
| while(length--) { | while(length--) { |
| switch(*from) { | switch(*from) { |
| Line 385 public: | Line 415 public: |
| *to=0; | *to=0; |
| return result; | return result; |
| } | } |
| void query( | void query(void *aconnection, |
| SQL_Driver_services& services, void *connection, | |
| const char *astatement, unsigned long offset, unsigned long limit, | const char *astatement, unsigned long offset, unsigned long limit, |
| SQL_Driver_query_event_handlers& handlers) { | SQL_Driver_query_event_handlers& handlers) |
| { | |
| OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; | Connection& connection=*static_cast<Connection *>(aconnection); |
| const char* cstrClientCharset=connection.options.cstrClientCharset; | |
| OracleSQL_query_lobs lobs={{0}, 0}; | OracleSQL_query_lobs lobs={{0}, 0}; |
| OCIStmt *stmthp=0; | OCIStmt *stmthp=0; |
| SQL_Driver_services& services=*connection.services; | |
| // transcode from $request:charset to connect-string?client_charset | |
| if(cstrClientCharset) { | |
| size_t transcoded_statement_size; | |
| services.transcode(astatement, strlen(astatement), | |
| astatement, transcoded_statement_size, | |
| services.request_charset(), | |
| cstrClientCharset); | |
| } | |
| bool failed=false; | bool failed=false; |
| if(setjmp(cs.mark)) { | if(setjmp(connection.mark)) { |
| failed=true; | failed=true; |
| goto cleanup; | goto cleanup; |
| } else { | } else { |
| const char *statement=preprocess_statement(services, cs, | const char *statement=preprocess_statement(connection, astatement, lobs); |
| astatement, lobs); | |
| check(cs, "HandleAlloc STMT", OCIHandleAlloc( | check(connection, "HandleAlloc STMT", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0)); | (dvoid *)connection.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0)); |
| check(cs, "syntax", | check(connection, "syntax", |
| OCIStmtPrepare(stmthp, cs.errhp, (unsigned char *)statement, | OCIStmtPrepare(stmthp, connection.errhp, (unsigned char *)statement, |
| (ub4)strlen((char *)statement), | (ub4)strlen((char *)statement), |
| (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)); | (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)); |
| { | { |
| for(int i=0; i<lobs.count; i++) { | for(int i=0; i<lobs.count; i++) { |
| check(cs, "alloc output var desc", OCIDescriptorAlloc( | check(connection, "alloc output var desc", OCIDescriptorAlloc( |
| (dvoid *)cs.envhp, (dvoid **)&lobs.items[i].locator, (ub4)OCI_DTYPE_LOB, 0, 0)); | (dvoid *)connection.envhp, (dvoid **)&lobs.items[i].locator, (ub4)OCI_DTYPE_LOB, 0, 0)); |
| check(cs, "bind output", OCIBindByPos(stmthp, | check(connection, "bind output", OCIBindByPos(stmthp, |
| &lobs.items[i].bind, cs.errhp, | &lobs.items[i].bind, connection.errhp, |
| (ub4)1+i, | (ub4)1+i, |
| (dvoid *)&lobs.items[i].locator, | (dvoid *)&lobs.items[i].locator, |
| (sword)sizeof (lobs.items[i].locator), SQLT_CLOB, (dvoid *)0, | (sword)sizeof (lobs.items[i].locator), SQLT_CLOB, (dvoid *)0, |
| (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DATA_AT_EXEC)); | (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DATA_AT_EXEC)); |
| lobs.items[i].rows.count=0; | lobs.items[i].rows.count=0; |
| OracleSQL_query_lobs::cbf_context_struct cbf_context={ | OracleSQL_query_lobs::cbf_context_struct cbf_context={&connection, &lobs.items[i].rows}; |
| &services, &cs, &lobs.items[i].rows}; | check(connection, "bind dynamic", OCIBindDynamic( |
| check(cs, "bind dynamic", OCIBindDynamic( | lobs.items[i].bind, connection.errhp, |
| lobs.items[i].bind, cs.errhp, | |
| (dvoid *) &cbf_context, cbf_no_data, | (dvoid *) &cbf_context, cbf_no_data, |
| (dvoid *) &cbf_context, cbf_get_data)); | (dvoid *) &cbf_context, cbf_get_data)); |
| } | } |
| } | } |
| execute_prepared(services, cs, | execute_prepared(connection, |
| statement, stmthp, lobs, | statement, stmthp, lobs, |
| offset, limit, handlers); | offset, limit, handlers); |
| } | } |
| Line 451 cleanup: // no check call after this poi | Line 490 cleanup: // no check call after this poi |
| OCIHandleFree((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT); | OCIHandleFree((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT); |
| if(failed) { | if(failed) { |
| if(cs.sql_error.defined()) | if(connection.sql_error.defined()) |
| services._throw(cs.sql_error); | services._throw(connection.sql_error); |
| services._throw(cs.error); | services._throw(connection.error); |
| } | } |
| } | } |
| private: // private funcs | private: // private funcs |
| const char *preprocess_statement(SQL_Driver_services& services, OracleSQL_connection_struct &cs, | const char *preprocess_statement(Connection& connection, |
| const char *astatement, OracleSQL_query_lobs &lobs) { | const char *astatement, OracleSQL_query_lobs &lobs) { |
| size_t statement_size=strlen(astatement); | size_t statement_size=strlen(astatement); |
| SQL_Driver_services& services=*connection.services; | |
| char *result=(char *)services.malloc_atomic(statement_size | char *result=(char *)services.malloc_atomic(statement_size |
| +MAX_STRING // in case of short 'strings' | +MAX_STRING // in case of short 'strings' |
| Line 533 private: // private funcs | Line 573 private: // private funcs |
| if(i) | if(i) |
| *n++=','; | *n++=','; |
| n+=sprintf(n, "%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr); | n+=sprintf(n, "%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr); |
| /*memcpy(n, lobs.items[i].name_ptr, lobs.items[i].name_size); | |
| n+=lobs.items[i].name_size;*/ | |
| } | } |
| n+=sprintf(n, " into "); | n+=sprintf(n, " into "); |
| for(i=0; i<lobs.count; i++) { | for(i=0; i<lobs.count; i++) { |
| if(i) | if(i) |
| *n++='x'; | *n++=','; |
| n+=sprintf(n, ":%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr); | n+=sprintf(n, ":%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr); |
| /**n++=':'; | |
| memcpy(n, lobs.items[i].name_ptr, lobs.items[i].name_size); | |
| n+=lobs.items[i].name_size;*/ | |
| } | } |
| } | } |
| Line 551 private: // private funcs | Line 586 private: // private funcs |
| } | } |
| void execute_prepared( | void execute_prepared( |
| SQL_Driver_services& services, OracleSQL_connection_struct &cs, | Connection& connection, |
| const char *statement, OCIStmt *stmthp, OracleSQL_query_lobs &lobs, | const char *statement, OCIStmt *stmthp, OracleSQL_query_lobs &lobs, |
| unsigned long offset, unsigned long limit, | unsigned long offset, unsigned long limit, |
| SQL_Driver_query_event_handlers& handlers) { | SQL_Driver_query_event_handlers& handlers) { |
| Line 560 private: // private funcs | Line 595 private: // private funcs |
| /* | /* |
| //gpfs on sun. paf 000818 | //gpfs on sun. paf 000818 |
| //Zanyway, this is needed before. | //Zanyway, this is needed before. |
| check(cs, "get stmt type", OCIAttrGet( | check(connection, "get stmt type", OCIAttrGet( |
| (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, (ub1 *)&stmt_type, | (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, (ub1 *)&stmt_type, |
| (ub4 *)0, OCI_ATTR_STMT_TYPE, cs.errhp)); | (ub4 *)0, OCI_ATTR_STMT_TYPE, connection.errhp)); |
| */ | */ |
| while(isspace(*statement)) | while(isspace(*statement)) |
| Line 574 private: // private funcs | Line 609 private: // private funcs |
| else if(strncasecmp(statement, "update", 6)==0) | else if(strncasecmp(statement, "update", 6)==0) |
| stmt_type=OCI_STMT_UPDATE; | stmt_type=OCI_STMT_UPDATE; |
| sword status=OCIStmtExecute(cs.svchp, stmthp, cs.errhp, | sword status=OCIStmtExecute(connection.svchp, stmthp, connection.errhp, |
| (ub4)stmt_type==OCI_STMT_SELECT?0:1, (ub4)0, | (ub4)stmt_type==OCI_STMT_SELECT?0:1, (ub4)0, |
| (OCISnapshot *)NULL, | (OCISnapshot *)NULL, |
| (OCISnapshot *)NULL, (ub4)OCI_DEFAULT); | (OCISnapshot *)NULL, (ub4)OCI_DEFAULT); |
| if(status!=OCI_NO_DATA) | if(status!=OCI_NO_DATA) |
| check(cs, "execute", status); | check(connection, "execute", status); |
| { | { |
| for(int i=0; i<lobs.count; i++) | for(int i=0; i<lobs.count; i++) |
| Line 588 private: // private funcs | Line 623 private: // private funcs |
| OracleSQL_query_lobs::return_rows *rows=&lobs.items[i].rows; | OracleSQL_query_lobs::return_rows *rows=&lobs.items[i].rows; |
| for(int r=0; r<rows->count; r++) { | for(int r=0; r<rows->count; r++) { |
| OCILobLocator *locator=rows->row[r].locator; | OCILobLocator *locator=rows->row[r].locator; |
| check(cs, "lobwrite", OCILobWrite ( | check(connection, "lobwrite", OCILobWrite ( |
| cs.svchp, cs.errhp, | connection.svchp, connection.errhp, |
| locator, &bytes_to_write, 1, | locator, &bytes_to_write, 1, |
| (dvoid *)lobs.items[i].data_ptr, (ub4)bytes_to_write, OCI_ONE_PIECE, | (dvoid *)lobs.items[i].data_ptr, (ub4)bytes_to_write, OCI_ONE_PIECE, |
| (dvoid *)0, 0, (ub2)0, | (dvoid *)0, 0, (ub2)0, |
| Line 600 private: // private funcs | Line 635 private: // private funcs |
| switch(stmt_type) { | switch(stmt_type) { |
| case OCI_STMT_SELECT: | case OCI_STMT_SELECT: |
| fetch_table(services, cs, | fetch_table(connection, |
| stmthp, offset, limit, | stmthp, offset, limit, |
| handlers); | handlers); |
| break; | break; |
| Line 613 private: // private funcs | Line 648 private: // private funcs |
| } | } |
| } | } |
| void fetch_table(SQL_Driver_services& services, OracleSQL_connection_struct &cs, | void fetch_table(Connection& connection, |
| OCIStmt *stmthp, unsigned long offset, unsigned long limit, | OCIStmt *stmthp, unsigned long offset, unsigned long limit, |
| SQL_Driver_query_event_handlers& handlers) { | SQL_Driver_query_event_handlers& handlers) |
| { | |
| const char* cstrClientCharset=connection.options.cstrClientCharset; | |
| SQL_Driver_services& services=*connection.services; | |
| ub4 prefetch_rows=100; | ub4 prefetch_rows=100; |
| check(cs, "AttrSet prefetch-rows", OCIAttrSet( | check(connection, "AttrSet prefetch-rows", OCIAttrSet( |
| (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, | (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, |
| (dvoid *)&prefetch_rows, (ub4)0, | (dvoid *)&prefetch_rows, (ub4)0, |
| (ub4)OCI_ATTR_PREFETCH_ROWS, (OCIError *)cs.errhp)); | (ub4)OCI_ATTR_PREFETCH_ROWS, (OCIError *)connection.errhp)); |
| ub4 prefetch_mem_size=100*0x400; | ub4 prefetch_mem_size=100*0x400; |
| check(cs, "AttrSet prefetch-memory", OCIAttrSet( | check(connection, "AttrSet prefetch-memory", OCIAttrSet( |
| (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, | (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, |
| (dvoid *)&prefetch_mem_size, (ub4)0, | (dvoid *)&prefetch_mem_size, (ub4)0, |
| (ub4)OCI_ATTR_PREFETCH_MEMORY, (OCIError *)cs.errhp)); | (ub4)OCI_ATTR_PREFETCH_MEMORY, (OCIError *)connection.errhp)); |
| OCIParam *mypard; | OCIParam *mypard; |
| ub2 dtype; | ub2 dtype; |
| text *col_name; | const char* col_name; |
| struct { | struct Col { |
| ub2 type; | ub2 type; |
| char *str; | char *str; |
| OCILobLocator *var; | OCILobLocator *var; |
| Line 643 private: // private funcs | Line 681 private: // private funcs |
| int column_count=0; | int column_count=0; |
| bool failed=false; | bool failed=false; |
| jmp_buf saved_mark; memcpy(saved_mark, cs.mark, sizeof(jmp_buf)); | jmp_buf saved_mark; memcpy(saved_mark, connection.mark, sizeof(jmp_buf)); |
| if(setjmp(cs.mark)) { | if(setjmp(connection.mark)) { |
| failed=true; | failed=true; |
| goto cleanup; | goto cleanup; |
| } else { | } else { |
| // idea of preincrementing is that at error time all handles would free up | // idea of preincrementing is that at error time all handles would free up |
| while(++column_count<=MAX_COLS) { | while(++column_count<=MAX_COLS) { |
| /* get next descriptor, if there is one */ | /* get next descriptor, if there is one */ |
| if(OCIParamGet(stmthp, OCI_HTYPE_STMT, cs.errhp, (void **)&mypard, | if(OCIParamGet(stmthp, OCI_HTYPE_STMT, connection.errhp, (void **)&mypard, |
| (ub4) column_count)!=OCI_SUCCESS) { | (ub4) column_count)!=OCI_SUCCESS) { |
| --column_count; | --column_count; |
| break; | break; |
| } | } |
| /* Retrieve the data type attribute */ | /* Retrieve the data type attribute */ |
| check(cs, "get type", OCIAttrGet( | check(connection, "get type", OCIAttrGet( |
| (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, | (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, |
| (dvoid*) &dtype, (ub4 *)0, (ub4)OCI_ATTR_DATA_TYPE, | (dvoid*) &dtype, (ub4 *)0, (ub4)OCI_ATTR_DATA_TYPE, |
| (OCIError *)cs.errhp)); | (OCIError *)connection.errhp)); |
| /* Retrieve the column name attribute */ | /* Retrieve the column name attribute */ |
| ub4 col_name_len; | ub4 col_name_len; |
| check(cs, "get name", OCIAttrGet( | check(connection, "get name", OCIAttrGet( |
| (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, | (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, |
| (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME, | (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME, |
| (OCIError *)cs.errhp)); | (OCIError *)connection.errhp)); |
| // transcode to $request:charset from connect-string?client_charset | |
| if(cstrClientCharset) { | |
| services.transcode(col_name, col_name_len, | |
| col_name, col_name_len, | |
| cstrClientCharset, | |
| services.request_charset()); | |
| } | |
| Col& col=cols[column_count-1]; | |
| { | { |
| size_t length=(size_t)col_name_len; | size_t length=(size_t)col_name_len; |
| char *ptr=(char *)services.malloc_atomic(length+1); | char *ptr=(char *)services.malloc_atomic(length+1); |
| if( cs.bLowerCaseColumnNames ) | if( connection.options.bLowerCaseColumnNames ) |
| tolower(ptr, (char *)col_name, length); | tolower(ptr, col_name, length); |
| else | else |
| memcpy(ptr, col_name, length); | memcpy(ptr, col_name, length); |
| ptr[length]=0; | ptr[length]=0; |
| check(cs, handlers.add_column(cs.sql_error, ptr, length)); | check(connection, handlers.add_column(connection.sql_error, ptr, length)); |
| } | } |
| ub2 coerce_type=dtype; | ub2 coerce_type=dtype; |
| Line 688 private: // private funcs | Line 734 private: // private funcs |
| switch(dtype) { | switch(dtype) { |
| case SQLT_CLOB: | case SQLT_CLOB: |
| { | { |
| check(cs, "alloc output var desc", OCIDescriptorAlloc( | check(connection, "alloc output var desc", OCIDescriptorAlloc( |
| (dvoid *)cs.envhp, (dvoid **)(ptr=&cols[column_count-1].var), | (dvoid *)connection.envhp, (dvoid **)(ptr=&col.var), |
| (ub4)OCI_DTYPE_LOB, | (ub4)OCI_DTYPE_LOB, |
| 0, (dvoid **)0)); | 0, (dvoid **)0)); |
| Line 698 private: // private funcs | Line 744 private: // private funcs |
| } | } |
| default: | default: |
| coerce_type=SQLT_STR; | coerce_type=SQLT_STR; |
| ptr=cols[column_count-1].str=(char *)services.malloc_atomic(MAX_OUT_STRING_LENGTH+1); | char*& buf=connection.fetch_buffers[column_count-1]; |
| ptr=buf; // get cached buffer | |
| if(!ptr) // allocate if needed, caching it | |
| ptr=buf=(char *)::/*see disconnect*/malloc(MAX_OUT_STRING_LENGTH+1/*terminator*/); | |
| col.str=(char*)ptr; | |
| size=MAX_OUT_STRING_LENGTH; | size=MAX_OUT_STRING_LENGTH; |
| break; | break; |
| } | } |
| cols[column_count-1].type=coerce_type; | col.type=coerce_type; |
| check(cs, "DefineByPos", OCIDefineByPos( | // http://i/docs/oracle/server.804/a58234/oci_func.htm#449680 |
| stmthp, &cols[column_count-1].def, cs.errhp, | // this call implicitly allocates the define handle |
| // http://sunsite.eunnet.net/documentation/oracle.8.0.4/server.804/a58234/basics.htm | |
| // when a statement handle is freed, any bind and define handles associated with it | |
| // are also freed | |
| col.def=0; check(connection, "DefineByPos", OCIDefineByPos( | |
| stmthp, &col.def, connection.errhp, | |
| column_count, (ub1 *) ptr, size, | column_count, (ub1 *) ptr, size, |
| coerce_type, (dvoid *) &cols[column_count-1].indicator, | coerce_type, (dvoid *) &col.indicator, |
| (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); | (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); |
| } | } |
| check(cs, handlers.before_rows(cs.sql_error)); | check(connection, handlers.before_rows(connection.sql_error)); |
| for(unsigned long row=0; !limit||row<offset+limit; row++) { | for(unsigned long row=0; !limit||row<offset+limit; row++) { |
| sword status=OCIStmtFetch(stmthp, cs.errhp, (ub4)1, (ub4)OCI_FETCH_NEXT, | sword status=OCIStmtFetch(stmthp, connection.errhp, (ub4)1, (ub4)OCI_FETCH_NEXT, |
| (ub4)OCI_DEFAULT); | (ub4)OCI_DEFAULT); |
| if(status==OCI_NO_DATA) | if(status==OCI_NO_DATA) |
| break; | break; |
| check(cs, "fetch", status); | check(connection, "fetch", status); |
| if(row>=offset) { | if(row>=offset) { |
| check(cs, handlers.add_row(cs.sql_error)); | check(connection, handlers.add_row(connection.sql_error)); |
| for(int i=0; i<column_count; i++) { | for(int i=0; i<column_count; i++) { |
| size_t length=0; | size_t length=0; |
| char* str=0; | char* strm=0; |
| if(!cols[i].indicator) // not NULL | if(!cols[i].indicator) // not NULL |
| switch(cols[i].type) { | switch(cols[i].type) { |
| case SQLT_CLOB: | case SQLT_CLOB: |
| { | { |
| ub4 amtp=4096000000UL; | |
| ub4 offset=1; | ub4 offset=1; |
| ub4 loblen=0; | |
| OCILobLocator *var=(OCILobLocator *)cols[i].var; | OCILobLocator *var=(OCILobLocator *)cols[i].var; |
| OCILobGetLength(cs.svchp, cs.errhp, var, &loblen); | size_t read_size=0; |
| if(loblen) { | strm=(char*)services.malloc_atomic(1/*for terminator*/); // set type of memory block |
| length=(size_t)loblen; | do { |
| str=(char*)services.malloc_atomic(length+1); | char buf[MAX_STRING*10]; |
| check(cs, "lobread", OCILobRead(cs.svchp, cs.errhp, | ub4 amtp=0/*to be read in stream mode*/; |
| var, &amtp, offset, (dvoid *) str, | // http://i/docs/oracle/server.804/a58234/oci_func.htm#427818 |
| loblen, (dvoid *)0, | status=OCILobRead(connection.svchp, connection.errhp, |
| 0, | var, &amtp, offset, (dvoid *)buf, |
| (ub2)0, (ub1) SQLCS_IMPLICIT)); | sizeof(buf), |
| str[length]=0; | (dvoid *)0, 0, |
| } | (ub2)0, (ub1)SQLCS_IMPLICIT); |
| if(status!=OCI_SUCCESS && status!=OCI_NEED_DATA) | |
| check(connection, "lobread", status); | |
| strm=(char*)services.realloc(strm, read_size+amtp+1/*for termintator*/); | |
| memcpy(strm+read_size, buf, amtp); | |
| read_size+=amtp; | |
| offset+=amtp; | |
| } while(status==OCI_NEED_DATA); | |
| length=(size_t)read_size; | |
| strm[length]=0; | |
| break; | break; |
| } | } |
| default: | default: |
| if(const char *value=cols[i].str) { | if(const char *value=cols[i].str) { |
| length=strlen(value); | length=strlen(value); |
| str=(char*)services.malloc_atomic(length+1); | strm=(char*)services.malloc_atomic(length+1); |
| memcpy(str, value, length+1); | memcpy(strm, value, length+1); |
| } else { | } else { |
| length=0; | length=0; |
| str=0; | strm=0; |
| } | } |
| break; | break; |
| } | } |
| check(cs, handlers.add_row_cell(cs.sql_error, str, length)); | |
| const char* str=strm; | |
| if(str && length) | |
| { | |
| // transcode to $request:charset from connect-string?client_charset | |
| if(cstrClientCharset) | |
| services.transcode(str, length, | |
| str, length, | |
| cstrClientCharset, | |
| services.request_charset()); | |
| } | |
| check(connection, handlers.add_row_cell(connection.sql_error, str, length)); | |
| } | } |
| } | } |
| } | } |
| Line 782 cleanup: // no check call after this poi | Line 858 cleanup: // no check call after this poi |
| private: // conn client library funcs | private: // conn client library funcs |
| friend void check(OracleSQL_connection_struct &cs, const char *step, sword status); | friend void check(Connection& connection, const char *step, sword status); |
| friend sb4 cbf_get_data(dvoid *ctxp, | friend sb4 cbf_get_data(dvoid *ctxp, |
| OCIBind *bindp, | OCIBind *bindp, |
| ub4 iter, ub4 index, | ub4 iter, ub4 index, |
| Line 925 private: // conn client library funcs li | Line 1001 private: // conn client library funcs li |
| } *OracleSQL_driver; | } *OracleSQL_driver; |
| void check(OracleSQL_connection_struct &cs, const char *step, sword status) { | void check(Connection& connection, const char *step, sword status) { |
| const char *msg; | const char *msg; |
| char reason[MAX_STRING/2]; | char reason[MAX_STRING/2]; |
| const char *prefix="ERROR"; | |
| switch (status) { | switch (status) { |
| case OCI_SUCCESS: // hurrah | case OCI_SUCCESS: // hurrah |
| case OCI_SUCCESS_WITH_INFO: // ignoring. example: count(column) when column contains NULLs, | case OCI_SUCCESS_WITH_INFO: // ignoring. example: count(column) when column contains NULLs, |
| Line 938 void check(OracleSQL_connection_struct & | Line 1013 void check(OracleSQL_connection_struct & |
| return; | return; |
| case OCI_ERROR: | case OCI_ERROR: |
| { | { |
| sb4 errcode; | sb4 errcode; |
| if(OracleSQL_driver->OCIErrorGet((dvoid *)cs.errhp, (ub4)1, (text *)NULL, &errcode, | if(OracleSQL_driver->OCIErrorGet((dvoid *)connection.errhp, (ub4)1, (text *)NULL, &errcode, |
| (text *)reason, (ub4)sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS) | (text *)reason, (ub4)sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS) { |
| msg=reason; | msg=reason; |
| else | |
| msg="[can not get error description]"; | // transcode to $request:charset from connect-string?client_charset |
| break; | if(const char* cstrClientCharset=connection.options.cstrClientCharset) { |
| if(msg) { | |
| if(size_t msg_length=strlen(msg)) { | |
| connection.services->transcode(msg, msg_length, | |
| msg, msg_length, | |
| cstrClientCharset, | |
| connection.services->request_charset()); | |
| } | |
| } | |
| } | |
| } else | |
| msg="[can not get error description]"; | |
| break; | |
| } | } |
| case OCI_NEED_DATA: | case OCI_NEED_DATA: |
| msg="NEED_DATA"; break; | msg="NEED_DATA"; break; |
| Line 960 void check(OracleSQL_connection_struct & | Line 1047 void check(OracleSQL_connection_struct & |
| msg="unknown"; break; | msg="unknown"; break; |
| } | } |
| snprintf(cs.error, sizeof(cs.error), "%s (%s, %d)", | snprintf(connection.error, sizeof(connection.error), "%s (%s, %d)", |
| msg, step, (int)status); | msg, step, (int)status); |
| longjmp(cs.mark, 1); | longjmp(connection.mark, 1); |
| } | } |
| void check(OracleSQL_connection_struct &cs, bool error) { | void check(Connection& connection, bool error) { |
| if(error) | if(error) |
| longjmp(cs.mark, 1); | longjmp(connection.mark, 1); |
| } | } |
| /* ----------------------------------------------------------------- */ | /* ----------------------------------------------------------------- */ |
| /* Intbind callback that does not do any data input. */ | /* Intbind callback that does not do any data input. */ |
| /* ----------------------------------------------------------------- */ | /* ----------------------------------------------------------------- */ |
| static sb4 cbf_no_data( | static sb4 cbf_no_data( |
| dvoid *ctxp, | dvoid* /*ctxp*/, |
| OCIBind *bindp, | OCIBind* /*bindp*/, |
| ub4 iter, ub4 index, | ub4 /*iter*/, ub4 /*index*/, |
| dvoid **bufpp, | dvoid **bufpp, |
| ub4 *alenpp, | ub4 *alenpp, |
| ub1 *piecep, | ub1 *piecep, |
| Line 995 static sb4 cbf_no_data( | Line 1082 static sb4 cbf_no_data( |
| /* ----------------------------------------------------------------- */ | /* ----------------------------------------------------------------- */ |
| static sb4 cbf_get_data(dvoid *ctxp, | static sb4 cbf_get_data(dvoid *ctxp, |
| OCIBind *bindp, | OCIBind *bindp, |
| ub4 iter, ub4 index, | ub4 /*iter*/, ub4 index, |
| dvoid **bufpp, | dvoid **bufpp, |
| ub4 **alenp, | ub4 **alenp, |
| ub1 *piecep, | ub1 *piecep, |
| Line 1006 static sb4 cbf_get_data(dvoid *ctxp, | Line 1093 static sb4 cbf_get_data(dvoid *ctxp, |
| if(index==0) { | if(index==0) { |
| static ub4 rows; | static ub4 rows; |
| check(*context.cs, "AttrGet cbf_get_data ROWS_RETURNED", | check(*context.connection, "AttrGet cbf_get_data ROWS_RETURNED", |
| OracleSQL_driver->OCIAttrGet( | OracleSQL_driver->OCIAttrGet( |
| (CONST dvoid *) bindp, OCI_HTYPE_BIND, (dvoid *)&rows, | (CONST dvoid *) bindp, OCI_HTYPE_BIND, (dvoid *)&rows, |
| (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.cs->errhp)) ; | (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.connection->errhp)) ; |
| context.rows->count=(ub2)rows; | context.rows->count=(ub2)rows; |
| context.rows->row=(OracleSQL_query_lobs::return_rows::return_row *) | context.rows->row=(OracleSQL_query_lobs::return_rows::return_row *) |
| context.services->malloc_atomic(sizeof(OracleSQL_query_lobs::return_rows::return_row)*rows); | context.connection->services->malloc_atomic(sizeof(OracleSQL_query_lobs::return_rows::return_row)*rows); |
| } | } |
| OracleSQL_query_lobs::return_rows::return_row &var=context.rows->row[index]; | OracleSQL_query_lobs::return_rows::return_row &var=context.rows->row[index]; |
| check(*context.cs, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc( | check(*context.connection, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc( |
| (dvoid *) context.cs->envhp, (dvoid **)&var.locator, | (dvoid *) context.connection->envhp, (dvoid **)&var.locator, |
| (ub4)OCI_DTYPE_LOB, | (ub4)OCI_DTYPE_LOB, |
| 0, (dvoid **)0)); | 0, (dvoid **)0)); |
| Line 1031 static sb4 cbf_get_data(dvoid *ctxp, | Line 1118 static sb4 cbf_get_data(dvoid *ctxp, |
| return OCI_CONTINUE; | return OCI_CONTINUE; |
| } | } |
| void tolower(char *out, const char *in, size_t size) { | static void tolower(char *out, const char *in, size_t size) { |
| while(size--) | while(size--) |
| *out++=tolower(*in++); | *out++=(char)tolower(*in++); |
| } | } |
| static void toupper(char *out, const char *in, size_t size) { | |
| while(size--) | |
| *out++=(char)toupper(*in++); | |
| } | |
| extern "C" SQL_Driver *SQL_DRIVER_CREATE() { | extern "C" SQL_Driver *SQL_DRIVER_CREATE() { |
| return OracleSQL_driver=new OracleSQL_Driver(); | return OracleSQL_driver=new OracleSQL_Driver(); |