|
|
| version 1.32.4.1, 2003/10/02 09:38:19 | version 1.48, 2003/12/24 12:47:36 |
|---|---|
| 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 |
| /// @test setenv version memory. maybe key/value needs ::malloc_atomic? | #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 | |
| 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; |
| if(do_append) | if(do_append) |
| Line 70 static int pa_setenv(const char *name, c | Line 76 static int pa_setenv(const char *name, c |
| if(value) { | if(value) { |
| if(prev_value) { | if(prev_value) { |
| // MEM_LEAK_HERE | // MEM_LEAK_HERE |
| char *buf=(char *)::malloc_atomic(strlen(prev_value) | char *buf=(char *)::malloc(strlen(prev_value) |
| +strlen(value) | +strlen(value) |
| +1); | +1); |
| strcpy(buf, prev_value); | strcpy(buf, prev_value); |
| 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) { | |
| while(options) { | |
| if(char *key=lsplit(&options, '&')) { | |
| if(*key) { | |
| if(char *value=lsplit(key, '=')) { | |
| 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 OracleSQL_connection_struct { |
| 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 138 struct OracleSQL_connection_struct { | Line 121 struct OracleSQL_connection_struct { |
| OCIError *errhp; | OCIError *errhp; |
| OCISvcCtx *svchp; | OCISvcCtx *svchp; |
| OCISession *usrhp; | OCISession *usrhp; |
| char* fetch_buffers[MAX_COLS]; | |
| struct Options { | |
| bool bLowerCaseColumnNames; | |
| const char* cstrClientCharset; | |
| } options; | |
| }; | }; |
| struct OracleSQL_query_lobs { | struct OracleSQL_query_lobs { |
| Line 150 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; | |
| OracleSQL_connection_struct *cs; | OracleSQL_connection_struct *cs; |
| return_rows *rows; | return_rows *rows; |
| }; | }; |
| Line 185 static sb4 cbf_get_data(dvoid *ctxp, | Line 174 static sb4 cbf_get_data(dvoid *ctxp, |
| dvoid **indpp, | dvoid **indpp, |
| ub2 **rcodepp); | ub2 **rcodepp); |
| void tolower(char *out, const char *in, size_t size); | void tolower(char *out, const char *in, size_t size); |
| void toupper(char *out, const char *in, size_t size); | |
| static const char *options2env(char *s, OracleSQL_connection_struct::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 206 public: | Line 235 public: |
| const char *error=dlopen_file_spec? | const char *error=dlopen_file_spec? |
| dlink(dlopen_file_spec):"client library column is empty"; | dlink(dlopen_file_spec):"client library column is empty"; |
| if(!error) { | if(!error) { |
| error=options2env(options); | error=options2env(options, 0); |
| if(!error) | if(!error) |
| OCIInitialize((ub4)OCI_THREADED/*| OCI_OBJECT*/, (dvoid *)0, | OCIInitialize((ub4)OCI_THREADED/*| OCI_OBJECT*/, (dvoid *)0, |
| Line 237 public: | Line 266 public: |
| // connections are cross-request, do not use services._alloc [linked with request] | // connections are cross-request, do not use services._alloc [linked with request] |
| OracleSQL_connection_struct &cs= | OracleSQL_connection_struct &cs= |
| *(OracleSQL_connection_struct *)::calloc(sizeof(OracleSQL_connection_struct), 1); | *(OracleSQL_connection_struct *)::calloc(sizeof(OracleSQL_connection_struct), 1); |
| cs.services=&services; | |
| cs.options.bLowerCaseColumnNames = true; | |
| char *user=used_only_in_connect_url; | char *user=used_only_in_connect_url; |
| char *service=lsplit(user, '@'); | char *service=lsplit(user, '@'); |
| Line 246 public: | Line 277 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)) | if(const char *error=options2env(options, &cs.options)) |
| services._throw(error); | services._throw(error); |
| if(setjmp(cs.mark)) | if(setjmp(cs.mark)) |
| Line 317 public: | Line 348 public: |
| } | } |
| void disconnect(void *connection) { | void disconnect(void *connection) { |
| OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; | OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; |
| // free fetch buffers | |
| for(int i=0; i<MAX_COLS; i++) { | |
| if(void* fetch_buffer=cs.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); | cs.svchp, cs.errhp, cs.usrhp, (ub4)OCI_DEFAULT); |
| Line 339 public: | Line 379 public: |
| // 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(&cs); |
| } | } |
| void commit(SQL_Driver_services& services, void *connection) { | void commit(void *connection) { |
| OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; | OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; |
| if(setjmp(cs.mark)) | if(setjmp(cs.mark)) |
| services._throw(cs.error); | cs.services->_throw(cs.error); |
| check(cs, "commit", OCITransCommit(cs.svchp, cs.errhp, 0)); | check(cs, "commit", OCITransCommit(cs.svchp, cs.errhp, 0)); |
| } | } |
| void rollback(SQL_Driver_services& services, void *connection) { | void rollback(void *connection) { |
| OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; | OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; |
| if(setjmp(cs.mark)) | if(setjmp(cs.mark)) |
| services._throw(cs.error); | cs.services->_throw(cs.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(cs, "rollback", */OCITransRollback(cs.svchp, cs.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 *connection, |
| 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); | OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; |
| char *result=(char*)cs.services->malloc_atomic(length*2+1); | |
| char *to=result; | char *to=result; |
| while(length--) { | while(length--) { |
| switch(*from) { | switch(*from) { |
| case '\'': // "'" -> "''" | case '\'': // "'" -> "''" |
| *to++='\''; result++; | *to++='\''; |
| break; | break; |
| } | } |
| *to++=*from++; | *to++=*from++; |
| Line 376 public: | Line 419 public: |
| *to=0; | *to=0; |
| return result; | return result; |
| } | } |
| void query( | void query(void *connection, |
| 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; | OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; |
| OracleSQL_query_lobs lobs={{0}, 0}; | OracleSQL_query_lobs lobs={{0}, 0}; |
| OCIStmt *stmthp=0; | OCIStmt *stmthp=0; |
| SQL_Driver_services& services=*cs.services; | |
| // transcode from $request:charset to connect-string?client_charset | |
| size_t transcoded_statement_size; | |
| if(const char* cstrClientCharset=cs.options.cstrClientCharset) | |
| 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(cs.mark)) { |
| failed=true; | failed=true; |
| goto cleanup; | goto cleanup; |
| } else { | } else { |
| const char *statement=preprocess_statement(services, cs, | const char *statement=preprocess_statement(cs, astatement, lobs); |
| astatement, lobs); | |
| check(cs, "HandleAlloc STMT", OCIHandleAlloc( | check(cs, "HandleAlloc STMT", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0)); | (dvoid *)cs.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0)); |
| Line 412 public: | Line 463 public: |
| (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={&cs, &lobs.items[i].rows}; |
| &services, &cs, &lobs.items[i].rows}; | |
| check(cs, "bind dynamic", OCIBindDynamic( | check(cs, "bind dynamic", OCIBindDynamic( |
| lobs.items[i].bind, cs.errhp, | lobs.items[i].bind, cs.errhp, |
| (dvoid *) &cbf_context, cbf_no_data, | (dvoid *) &cbf_context, cbf_no_data, |
| Line 421 public: | Line 471 public: |
| } | } |
| } | } |
| execute_prepared(services, cs, | execute_prepared(cs, |
| statement, stmthp, lobs, | statement, stmthp, lobs, |
| offset, limit, handlers); | offset, limit, handlers); |
| } | } |
| Line 450 cleanup: // no check call after this poi | Line 500 cleanup: // no check call after this poi |
| private: // private funcs | private: // private funcs |
| const char *preprocess_statement(SQL_Driver_services& services, OracleSQL_connection_struct &cs, | const char *preprocess_statement(OracleSQL_connection_struct &cs, |
| 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=*cs.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 467 private: // private funcs | Line 518 private: // private funcs |
| o[0]=='/' && | o[0]=='/' && |
| o[1]=='*' && | o[1]=='*' && |
| o[2]=='*') { // name start | o[2]=='*') { // name start |
| const char* saved_o=o; | |
| o+=3; | o+=3; |
| const char *name_begin=o; | const char *name_begin=o; |
| while(*o) | while(*o) |
| Line 475 private: // private funcs | Line 527 private: // private funcs |
| o[1]=='*' && | o[1]=='*' && |
| o[2]=='/' && | o[2]=='/' && |
| o[3]=='\'') { // name end | o[3]=='\'') { // name end |
| saved_o=0; // found, marking that | |
| const char *name_end=o; | const char *name_end=o; |
| o+=4; | o+=4; |
| OracleSQL_query_lobs::Item &item=lobs.items[lobs.count++]; | OracleSQL_query_lobs::Item &item=lobs.items[lobs.count++]; |
| Line 506 private: // private funcs | Line 559 private: // private funcs |
| break; | break; |
| } else | } else |
| o++; // /**skip**/'xxx' | o++; // /**skip**/'xxx' |
| if(saved_o) { | |
| o=saved_o; | |
| *n++=*o++; | |
| } | |
| } else | } else |
| *n++=*o++; | *n++=*o++; |
| } | } |
| Line 518 private: // private funcs | Line 575 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 536 private: // private funcs | Line 588 private: // private funcs |
| } | } |
| void execute_prepared( | void execute_prepared( |
| SQL_Driver_services& services, OracleSQL_connection_struct &cs, | OracleSQL_connection_struct &cs, |
| 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 585 private: // private funcs | Line 637 private: // private funcs |
| switch(stmt_type) { | switch(stmt_type) { |
| case OCI_STMT_SELECT: | case OCI_STMT_SELECT: |
| fetch_table(services, cs, | fetch_table(cs, |
| stmthp, offset, limit, | stmthp, offset, limit, |
| handlers); | handlers); |
| break; | break; |
| Line 598 private: // private funcs | Line 650 private: // private funcs |
| } | } |
| } | } |
| void fetch_table(SQL_Driver_services& services, OracleSQL_connection_struct &cs, | void fetch_table(OracleSQL_connection_struct &cs, |
| 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) |
| { | |
| SQL_Driver_services& services=*cs.services; | |
| ub4 prefetch_rows=100; | ub4 prefetch_rows=100; |
| check(cs, "AttrSet prefetch-rows", OCIAttrSet( | check(cs, "AttrSet prefetch-rows", OCIAttrSet( |
| Line 618 private: // private funcs | Line 672 private: // private funcs |
| ub2 dtype; | ub2 dtype; |
| text *col_name; | text *col_name; |
| struct { | struct Col { |
| ub2 type; | ub2 type; |
| char *str; | char *str; |
| OCILobLocator *var; | OCILobLocator *var; |
| Line 655 private: // private funcs | Line 709 private: // private funcs |
| (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 *)cs.errhp)); |
| Col& col=cols[column_count-1]; | |
| { | { |
| size_t size=(size_t)col_name_len; | size_t length=(size_t)col_name_len; |
| char *ptr=(char *)services.malloc_atomic(size+1); | char *ptr=(char *)services.malloc_atomic(length+1); |
| tolower(ptr, (char *)col_name, size); | if( cs.options.bLowerCaseColumnNames ) |
| ptr[size]=0; | tolower(ptr, (char *)col_name, length); |
| check(cs, handlers.add_column(cs.sql_error, ptr, size)); | else |
| memcpy(ptr, col_name, length); | |
| ptr[length]=0; | |
| check(cs, handlers.add_column(cs.sql_error, ptr, length)); | |
| } | } |
| ub2 coerce_type=dtype; | ub2 coerce_type=dtype; |
| Line 671 private: // private funcs | Line 729 private: // private funcs |
| case SQLT_CLOB: | case SQLT_CLOB: |
| { | { |
| check(cs, "alloc output var desc", OCIDescriptorAlloc( | check(cs, "alloc output var desc", OCIDescriptorAlloc( |
| (dvoid *)cs.envhp, (dvoid **)(ptr=&cols[column_count-1].var), | (dvoid *)cs.envhp, (dvoid **)(ptr=&col.var), |
| (ub4)OCI_DTYPE_LOB, | (ub4)OCI_DTYPE_LOB, |
| 0, (dvoid **)0)); | 0, (dvoid **)0)); |
| Line 680 private: // private funcs | Line 738 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=cs.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(cs, "DefineByPos", OCIDefineByPos( | |
| stmthp, &col.def, cs.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)); |
| } | } |
| Line 706 private: // private funcs | Line 773 private: // private funcs |
| if(row>=offset) { | if(row>=offset) { |
| check(cs, handlers.add_row(cs.sql_error)); | check(cs, handlers.add_row(cs.sql_error)); |
| for(int i=0; i<column_count; i++) { | for(int i=0; i<column_count; i++) { |
| size_t size=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 |
| size=(size_t)loblen; | do { |
| str=(char*)services.malloc_atomic(size+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(cs.svchp, cs.errhp, |
| 0, | var, &amtp, offset, (dvoid *)buf, |
| (ub2)0, (ub1) SQLCS_IMPLICIT)); | sizeof(buf), |
| str[size]=0; | (dvoid *)0, 0, |
| } | (ub2)0, (ub1)SQLCS_IMPLICIT); |
| if(status!=OCI_SUCCESS && status!=OCI_NEED_DATA) | |
| check(cs, "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) { |
| size=strlen(value); | length=strlen(value); |
| str=(char*)services.malloc_atomic(size+1); | strm=(char*)services.malloc_atomic(length+1); |
| memcpy(str, value, size+1); | memcpy(strm, value, length+1); |
| } else { | } else { |
| size=0; | length=0; |
| str=0; | strm=0; |
| } | } |
| break; | break; |
| } | } |
| check(cs, handlers.add_row_cell(cs.sql_error, str, size)); | |
| const char* str=strm; | |
| if(str && length) | |
| { | |
| // transcode to $request:charset from connect-string?client_charset | |
| if(const char* cstrClientCharset=cs.options.cstrClientCharset) { | |
| const char* dest; | |
| size_t dest_length; | |
| services.transcode(str, length, | |
| dest, dest_length, | |
| cstrClientCharset, | |
| services.request_charset()); | |
| str=dest; | |
| length=dest_length; | |
| } | |
| } | |
| check(cs, handlers.add_row_cell(cs.sql_error, str, length)); | |
| } | } |
| } | } |
| } | } |
| Line 912 void check(OracleSQL_connection_struct & | Line 1005 void check(OracleSQL_connection_struct & |
| 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 920 void check(OracleSQL_connection_struct & | Line 1012 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 *)cs.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=cs.options.cstrClientCharset) { |
| if(msg) { | |
| if(size_t msg_length=strlen(msg)) { | |
| cs.services->transcode(msg, msg_length, | |
| msg, msg_length, | |
| cstrClientCharset, | |
| cs.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 956 void check(OracleSQL_connection_struct & | Line 1060 void check(OracleSQL_connection_struct & |
| /* 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 977 static sb4 cbf_no_data( | Line 1081 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 994 static sb4 cbf_get_data(dvoid *ctxp, | Line 1098 static sb4 cbf_get_data(dvoid *ctxp, |
| (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.cs->errhp)) ; | (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.cs->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.cs->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]; |
| Line 1015 static sb4 cbf_get_data(dvoid *ctxp, | Line 1119 static sb4 cbf_get_data(dvoid *ctxp, |
| void tolower(char *out, const char *in, size_t size) { | void tolower(char *out, const char *in, size_t size) { |
| while(size--) | while(size--) |
| *out++=tolower(*in++); | *out++=(char)tolower(*in++); |
| } | |
| 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() { |
| //_asm int 3; | |
| return OracleSQL_driver=new OracleSQL_Driver(); | return OracleSQL_driver=new OracleSQL_Driver(); |
| } | } |