|
|
| version 1.7, 2001/11/13 11:30:11 | version 1.33, 2003/08/19 10:33:10 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser Oracle driver. | Parser Oracle driver. |
| Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com) | Copyright(c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| 2001.07.30 using Oracle 8.1.6 [@test tested with Oracle 7.x.x] | 2001.07.30 using Oracle 8.1.6 [@test tested with Oracle 7.x.x] |
| */ | */ |
| 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? | /// @todo small memory leaks here |
| static int pa_setenv(const char *name, const char *value) { | static int pa_setenv(const char *name, const char *value, bool do_append) { |
| const char *prev_value=0; | |
| if(do_append) | |
| prev_value=getenv(name); | |
| #ifdef HAVE_PUTENV | #ifdef HAVE_PUTENV |
| // MEM_LEAK_HERE. refer to EOF man putenv | // MEM_LEAK_HERE. refer to EOF man putenv |
| char *buf=(char *)::malloc(strlen(name)+1+strlen(value)+1); | char *buf=(char *)::malloc(strlen(name) |
| +1 | |
| +(prev_value?strlen(prev_value):0) | |
| +strlen(value) | |
| +1); | |
| strcpy(buf, name); | strcpy(buf, name); |
| strcat(buf, "="); | strcat(buf, "="); |
| if(prev_value) | |
| strcat(buf, prev_value); | |
| strcat(buf, value); | strcat(buf, value); |
| /* | /* |
| if(FILE *f=fopen("f", "at")) { | if(FILE *f=fopen("f", "at")) { |
| Line 58 static int pa_setenv(const char *name, c | Line 67 static int pa_setenv(const char *name, c |
| return putenv(buf); | return putenv(buf); |
| #else | #else |
| //#ifdef HAVE_SETENV | //#ifdef HAVE_SETENV |
| if(value) | if(value) { |
| if(prev_value) { | |
| // MEM_LEAK_HERE | |
| char *buf=(char *)::malloc(strlen(prev_value) | |
| +strlen(value) | |
| +1); | |
| strcpy(buf, prev_value); | |
| strcat(buf, value); | |
| value=buf; | |
| } | |
| return setenv(name, value, 1/*overwrite*/); | return setenv(name, value, 1/*overwrite*/); |
| else { | } else { |
| unsetenv(name); | unsetenv(name); |
| return 0; | return 0; |
| } | } |
| Line 85 static char *lsplit(char **string_ref, c | Line 104 static char *lsplit(char **string_ref, c |
| return result; | return result; |
| } | } |
| static const char *pa_setenv(char *options) { | static const char *options2env(char *options) { |
| while(options) { | while(options) { |
| if(char *key=lsplit(&options, '&')) { | if(char *key=lsplit(&options, '&')) { |
| if(*key) { | if(*key) { |
| if(char *value=lsplit(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 | if(strncmp(key, "ORACLE_", 7)==0 // ORACLE_HOME & co |
| || strncmp(key, "ORA_", 4)==0 // ORA_ENCRYPT_LOGIN & co | || strncmp(key, "ORA_", 4)==0 // ORA_ENCRYPT_LOGIN & co |
| || strncmp(key, "NLS_", 4)==0 // NLS_LANG & co | || strncmp(key, "NLS_", 4)==0 // NLS_LANG & co |
| || do_append | |
| ) { | ) { |
| if(pa_setenv(key, value)!=0) | if(pa_setenv(key, value, do_append)!=0) |
| return "problem changing process environment" /*key*/; | return "problem changing process environment" /*key*/; |
| } else | } else |
| return "unknown connect option (option must start with ORACLE_, ORA_ or NLS_)" /*key*/; | return "unknown option (option must start with ORACLE_, ORA_ or NLS_)" /*key*/; |
| } else | } else |
| return "connect option without =value" /*key*/; | return "option without =value" /*key*/; |
| } | } |
| } | } |
| } | } |
| Line 109 static const char *pa_setenv(char *optio | Line 132 static const char *pa_setenv(char *optio |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| struct OracleSQL_connection_struct { | struct OracleSQL_connection_struct { |
| jmp_buf mark; char error[MAX_STRING]; | jmp_buf mark; char error[MAX_STRING]; |
| SQL_Error sql_error; | |
| OCIEnv *envhp; | OCIEnv *envhp; |
| OCIServer *srvhp; | OCIServer *srvhp; |
| OCIError *errhp; | OCIError *errhp; |
| Line 142 struct OracleSQL_query_lobs { | Line 166 struct OracleSQL_query_lobs { |
| #endif | #endif |
| // forwards | // forwards |
| void check( | void check(OracleSQL_connection_struct &cs, const char *step, sword status); |
| SQL_Driver_services& services, OracleSQL_connection_struct &cs, | void check(OracleSQL_connection_struct &cs, bool error); |
| const char *step, sword status); | |
| static sb4 cbf_no_data( | static sb4 cbf_no_data( |
| dvoid *ctxp, | dvoid *ctxp, |
| OCIBind *bindp, | OCIBind *bindp, |
| Line 165 void tolower(char *out, const char *in, | Line 188 void tolower(char *out, const char *in, |
| /** | /** |
| OracleSQL server driver | OracleSQL server driver |
| @test NLS_LANG=AMERICAN_AMERICA.CL8MSWIN1251 | |
| */ | */ |
| class OracleSQL_Driver : public SQL_Driver { | class OracleSQL_Driver : public SQL_Driver { |
| public: | public: |
| Line 184 public: | Line 206 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=pa_setenv(options); | error=options2env(options); |
| if(!error) | if(!error) |
| OCIInitialize((ub4)OCI_THREADED/*| OCI_OBJECT*/, (dvoid *)0, | OCIInitialize((ub4)OCI_THREADED/*| OCI_OBJECT*/, (dvoid *)0, |
| Line 224 public: | Line 246 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=pa_setenv(options)) | if(const char *error=options2env(options)) |
| services._throw(error); | services._throw(error); |
| if(setjmp(cs.mark)) | if(setjmp(cs.mark)) |
| Line 248 public: | Line 270 public: |
| */ | */ |
| OCIHandleAlloc((dvoid *)NULL, (dvoid **) &cs.envhp, (ub4)OCI_HTYPE_ENV, 0, 0); | OCIHandleAlloc((dvoid *)NULL, (dvoid **) &cs.envhp, (ub4)OCI_HTYPE_ENV, 0, 0); |
| // Initialize an environment handle, attempt #2 | // Initialize an environment handle, attempt #2 |
| check(services, cs, "EnvInit", OCIEnvInit( | check(cs, "EnvInit", OCIEnvInit( |
| &cs.envhp, (ub4)OCI_DEFAULT, 0, 0)); | &cs.envhp, (ub4)OCI_DEFAULT, 0, 0)); |
| // Allocate and initialize OCIError handle | // Allocate and initialize OCIError handle |
| check(services, cs, "HandleAlloc errhp", OCIHandleAlloc( | check(cs, "HandleAlloc errhp", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **) &cs.errhp, (ub4)OCI_HTYPE_ERROR, 0, 0)); | (dvoid *)cs.envhp, (dvoid **) &cs.errhp, (ub4)OCI_HTYPE_ERROR, 0, 0)); |
| // Allocate and initialize OCIServer handle | // Allocate and initialize OCIServer handle |
| check(services, cs, "HandleAlloc srvhp", OCIHandleAlloc( | check(cs, "HandleAlloc srvhp", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **) &cs.srvhp, (ub4)OCI_HTYPE_SERVER, 0, 0)); | (dvoid *)cs.envhp, (dvoid **) &cs.srvhp, (ub4)OCI_HTYPE_SERVER, 0, 0)); |
| // Attach to a 'service'; initialize server context handle | // Attach to a 'service'; initialize server context handle |
| check(services, cs, "ServerAttach", OCIServerAttach( | check(cs, "ServerAttach", OCIServerAttach( |
| cs.srvhp, cs.errhp, (text *)service, (sb4)strlen(service), (ub4)OCI_DEFAULT)); | cs.srvhp, cs.errhp, (text *)service, (sb4)strlen(service), (ub4)OCI_DEFAULT)); |
| // Allocate and initialize OCISvcCtx handle | // Allocate and initialize OCISvcCtx handle |
| check(services, cs, "HandleAlloc svchp", OCIHandleAlloc( | check(cs, "HandleAlloc svchp", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **) &cs.svchp, (ub4)OCI_HTYPE_SVCCTX, 0, 0)); | (dvoid *)cs.envhp, (dvoid **) &cs.svchp, (ub4)OCI_HTYPE_SVCCTX, 0, 0)); |
| // set attribute server context in the service context | // set attribute server context in the service context |
| check(services, cs, "AttrSet server-service", OCIAttrSet( | check(cs, "AttrSet server-service", OCIAttrSet( |
| (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX, | (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX, |
| (dvoid *)cs.srvhp, (ub4)0, | (dvoid *)cs.srvhp, (ub4)0, |
| (ub4)OCI_ATTR_SERVER, (OCIError *)cs.errhp)); | (ub4)OCI_ATTR_SERVER, (OCIError *)cs.errhp)); |
| // allocate a user context handle | // allocate a user context handle |
| check(services, cs, "HandleAlloc usrhp", OCIHandleAlloc( | check(cs, "HandleAlloc usrhp", OCIHandleAlloc( |
| (dvoid *)cs.envhp, (dvoid **)&cs.usrhp, (ub4)OCI_HTYPE_SESSION, 0, 0)); | (dvoid *)cs.envhp, (dvoid **)&cs.usrhp, (ub4)OCI_HTYPE_SESSION, 0, 0)); |
| // set 'user' name | // set 'user' name |
| check(services, cs, "AttrSet user-session", OCIAttrSet( | check(cs, "AttrSet user-session", OCIAttrSet( |
| (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION, | (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION, |
| (dvoid *)user, (ub4)strlen(user), | (dvoid *)user, (ub4)strlen(user), |
| OCI_ATTR_USERNAME, cs.errhp)); | OCI_ATTR_USERNAME, cs.errhp)); |
| // set 'pwd' password | // set 'pwd' password |
| check(services, cs, "AttrSet pwd-session", OCIAttrSet( | check(cs, "AttrSet pwd-session", OCIAttrSet( |
| (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION, | (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION, |
| (dvoid *)pwd, (ub4)strlen(pwd), | (dvoid *)pwd, (ub4)strlen(pwd), |
| OCI_ATTR_PASSWORD, cs.errhp)); | OCI_ATTR_PASSWORD, cs.errhp)); |
| // Authenticate a user | // Authenticate a user |
| check(services, cs, "SessionBegin", OCISessionBegin( | check(cs, "SessionBegin", OCISessionBegin( |
| cs.svchp, cs.errhp, cs.usrhp, | cs.svchp, cs.errhp, cs.usrhp, |
| OCI_CRED_RDBMS, OCI_DEFAULT)); | OCI_CRED_RDBMS, OCI_DEFAULT)); |
| // remember connection in session | // remember connection in session |
| check(services, cs, "AttrSet service-session", OCIAttrSet( | check(cs, "AttrSet service-session", OCIAttrSet( |
| (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX, | (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX, |
| (dvoid *)cs.usrhp, (ub4)0, | (dvoid *)cs.usrhp, (ub4)0, |
| OCI_ATTR_SESSION, cs.errhp)); | OCI_ATTR_SESSION, cs.errhp)); |
| Line 293 public: | Line 315 public: |
| // return created connection | // return created connection |
| *(OracleSQL_connection_struct **)connection=&cs; | *(OracleSQL_connection_struct **)connection=&cs; |
| } | } |
| /// @test remove return | |
| void disconnect(void *connection) { | void disconnect(void *connection) { |
| return; | |
| OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; | OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; |
| // Terminate a user session | // Terminate a user session |
| OCISessionEnd( | OCISessionEnd( |
| Line 327 public: | Line 344 public: |
| if(setjmp(cs.mark)) | if(setjmp(cs.mark)) |
| services._throw(cs.error); | services._throw(cs.error); |
| check(services, 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(SQL_Driver_services& services, 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); | services._throw(cs.error); |
| check(services, cs, "rollback", OCITransRollback(cs.svchp, cs.errhp, 0)); | check(cs, "rollback", OCITransRollback(cs.svchp, cs.errhp, 0)); |
| } | } |
| bool ping(SQL_Driver_services&, void *connection) { | bool ping(SQL_Driver_services&, void *connection) { |
| Line 343 public: | Line 360 public: |
| return true; | return true; |
| } | } |
| unsigned int quote( | const char* quote( |
| SQL_Driver_services&, void *, | SQL_Driver_services& services, void *connection, |
| char *to, const char *from, unsigned int length) { | const char *from, unsigned int length) { |
| /* | char *result=(char*)services.malloc_atomic(length*2+1); |
| it's already UNTAINT_TIMES_BIGGER | char *to=result; |
| */ | |
| unsigned int result=length; | |
| while(length--) { | while(length--) { |
| switch(*from) { | switch(*from) { |
| case '\'': // "'" -> "''" | case '\'': // "'" -> "''" |
| *to++='\''; | *to++='\''; result++; |
| break; | |
| case '\\': // "\" -> "\\" | |
| *to++='\''; | |
| break; | break; |
| } | } |
| *to++=*from++; | *to++=*from++; |
| } | } |
| *to=0; | |
| return result; | return result; |
| } | } |
| void query( | void query( |
| Line 380 public: | Line 393 public: |
| const char *statement=preprocess_statement(services, cs, | const char *statement=preprocess_statement(services, cs, |
| astatement, lobs); | astatement, lobs); |
| check(services, 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)); |
| check(services, cs, "syntax", | check(cs, "syntax", |
| OCIStmtPrepare(stmthp, cs.errhp, (unsigned char *)statement, | OCIStmtPrepare(stmthp, cs.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(services, cs, "alloc output var desc", OCIDescriptorAlloc( | check(cs, "alloc output var desc", OCIDescriptorAlloc( |
| (dvoid *)cs.envhp, (dvoid **)&lobs.items[i].locator, (ub4)OCI_DTYPE_LOB, 0, 0)); | (dvoid *)cs.envhp, (dvoid **)&lobs.items[i].locator, (ub4)OCI_DTYPE_LOB, 0, 0)); |
| check(services, cs, "bind output", OCIBindByPos(stmthp, | check(cs, "bind output", OCIBindByPos(stmthp, |
| &lobs.items[i].bind, cs.errhp, | &lobs.items[i].bind, cs.errhp, |
| (ub4)1+i, | (ub4)1+i, |
| (dvoid *)&lobs.items[i].locator, | (dvoid *)&lobs.items[i].locator, |
| Line 401 public: | Line 414 public: |
| 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={ |
| &services, &cs, &lobs.items[i].rows}; | &services, &cs, &lobs.items[i].rows}; |
| check(services, 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, |
| (dvoid *) &cbf_context, cbf_get_data)); | (dvoid *) &cbf_context, cbf_get_data)); |
| Line 428 cleanup: // no check call after this poi | Line 441 cleanup: // no check call after this poi |
| if(stmthp) | if(stmthp) |
| OCIHandleFree((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT); | OCIHandleFree((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT); |
| if(failed) | if(failed) { |
| if(cs.sql_error.defined()) | |
| services._throw(cs.sql_error); | |
| services._throw(cs.error); | services._throw(cs.error); |
| } | |
| } | } |
| private: // private funcs | private: // private funcs |
| Line 438 private: // private funcs | Line 454 private: // private funcs |
| 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); |
| char *result=(char *)services.malloc(statement_size | char *result=(char *)services.malloc_atomic(statement_size |
| +MAX_STRING // in case of short 'strings' | +MAX_STRING // in case of short 'strings' |
| +11/* returning */+6/* into */+(MAX_LOB_NAME_LENGTH+2/*:, */)*2/*ret into*/*MAX_IN_LOBS | +11/* returning */+6/* into */+(MAX_LOB_NAME_LENGTH+2/*:, */)*2/*ret into*/*MAX_IN_LOBS |
| +1); | +1); |
| Line 463 private: // private funcs | Line 479 private: // private funcs |
| o+=4; | o+=4; |
| OracleSQL_query_lobs::Item &item=lobs.items[lobs.count++]; | OracleSQL_query_lobs::Item &item=lobs.items[lobs.count++]; |
| item.name_ptr=name_begin; item.name_size=name_end-name_begin; | item.name_ptr=name_begin; item.name_size=name_end-name_begin; |
| item.data_ptr=(char *)services.malloc(statement_size/*max*/); item.data_size=0; | item.data_ptr=(char *)services.malloc_atomic(statement_size/*max*/); item.data_size=0; |
| const char *start=o; | const char *start=o; |
| bool escaped=false; | bool escaped=false; |
| while(*o && !(o[0]=='\'' && o[1]!='\'' && !escaped)) { | while(*o && !(o[0]=='\'' && o[1]!='\'' && !escaped)) { |
| escaped=*o=='\\' || (o[0]=='\'' && o[1]=='\''); | escaped=o[0]=='\'' && o[1]=='\''; |
| if(escaped) { | if(escaped) { |
| // write pending, skip "\" or "'" | // write pending, skip "\" or "'" |
| if(size_t size=o-start) { | if(size_t size=o-start) { |
| Line 529 private: // private funcs | Line 545 private: // private funcs |
| /* | /* |
| //gpfs on sun. paf 000818 | //gpfs on sun. paf 000818 |
| //Zanyway, this is needed before. | //Zanyway, this is needed before. |
| check(services, cs, "get stmt type", OCIAttrGet( | check(cs, "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, cs.errhp)); |
| */ | */ |
| while(isspace(*statement)) | |
| statement++; | |
| if(strncasecmp(statement, "select", 6)==0) | if(strncasecmp(statement, "select", 6)==0) |
| stmt_type=OCI_STMT_SELECT; | stmt_type=OCI_STMT_SELECT; |
| else if(strncasecmp(statement, "insert", 6)==0) | else if(strncasecmp(statement, "insert", 6)==0) |
| Line 546 private: // private funcs | Line 565 private: // private funcs |
| (OCISnapshot *)NULL, (ub4)OCI_DEFAULT); | (OCISnapshot *)NULL, (ub4)OCI_DEFAULT); |
| if(status!=OCI_NO_DATA) | if(status!=OCI_NO_DATA) |
| check(services, cs, "execute", status); | check(cs, "execute", status); |
| { | { |
| for(int i=0; i<lobs.count; i++) | for(int i=0; i<lobs.count; i++) |
| Line 554 private: // private funcs | Line 573 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(services, cs, "lobwrite", OCILobWrite ( | check(cs, "lobwrite", OCILobWrite ( |
| cs.svchp, cs.errhp, | cs.svchp, cs.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, |
| Line 583 private: // private funcs | Line 602 private: // private funcs |
| 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) { |
| ub4 prefetch_rows=100; | |
| check(cs, "AttrSet prefetch-rows", OCIAttrSet( | |
| (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, | |
| (dvoid *)&prefetch_rows, (ub4)0, | |
| (ub4)OCI_ATTR_PREFETCH_ROWS, (OCIError *)cs.errhp)); | |
| ub4 prefetch_mem_size=100*0x400; | |
| check(cs, "AttrSet prefetch-memory", OCIAttrSet( | |
| (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, | |
| (dvoid *)&prefetch_mem_size, (ub4)0, | |
| (ub4)OCI_ATTR_PREFETCH_MEMORY, (OCIError *)cs.errhp)); | |
| OCIParam *mypard; | OCIParam *mypard; |
| ub2 dtype; | ub2 dtype; |
| text *col_name; | text *col_name; |
| Line 612 private: // private funcs | Line 643 private: // private funcs |
| } | } |
| /* Retrieve the data type attribute */ | /* Retrieve the data type attribute */ |
| check(services, cs, "get type", OCIAttrGet( | check(cs, "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 *)cs.errhp)); |
| /* Retrieve the column name attribute */ | /* Retrieve the column name attribute */ |
| ub4 col_name_len; | ub4 col_name_len; |
| check(services, cs, "get name", OCIAttrGet( | check(cs, "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 *)cs.errhp)); |
| { | { |
| size_t size=(size_t)col_name_len; | size_t size=(size_t)col_name_len; |
| char *ptr=(char *)services.malloc(size); | char *ptr=(char *)services.malloc_atomic(size); |
| tolower(ptr, (char *)col_name, size); | tolower(ptr, (char *)col_name, size); |
| handlers.add_column(ptr, size); | check(cs, handlers.add_column(cs.sql_error, ptr, size)); |
| } | } |
| ub2 coerce_type=dtype; | ub2 coerce_type=dtype; |
| Line 638 private: // private funcs | Line 669 private: // private funcs |
| switch(dtype) { | switch(dtype) { |
| case SQLT_CLOB: | case SQLT_CLOB: |
| { | { |
| check(services, 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=&cols[column_count-1].var), |
| (ub4)OCI_DTYPE_LOB, | (ub4)OCI_DTYPE_LOB, |
| 0, (dvoid **)0)); | 0, (dvoid **)0)); |
| Line 648 private: // private funcs | Line 679 private: // private funcs |
| } | } |
| default: | default: |
| coerce_type=SQLT_STR; | coerce_type=SQLT_STR; |
| ptr=cols[column_count-1].str=(char *)services.malloc(MAX_OUT_STRING_LENGTH+1); | ptr=cols[column_count-1].str=(char *)services.malloc_atomic(MAX_OUT_STRING_LENGTH+1); |
| size=MAX_OUT_STRING_LENGTH; | size=MAX_OUT_STRING_LENGTH; |
| break; | break; |
| } | } |
| cols[column_count-1].type=coerce_type; | cols[column_count-1].type=coerce_type; |
| check(services, cs, "DefineByPos", OCIDefineByPos( | check(cs, "DefineByPos", OCIDefineByPos( |
| stmthp, &cols[column_count-1].def, cs.errhp, | stmthp, &cols[column_count-1].def, cs.errhp, |
| column_count, (ub1 *) ptr, size, | column_count, (ub1 *) ptr, size, |
| coerce_type, (dvoid *) &cols[column_count-1].indicator, | coerce_type, (dvoid *) &cols[column_count-1].indicator, |
| (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); | (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); |
| } | } |
| handlers.before_rows(); | check(cs, handlers.before_rows(cs.sql_error)); |
| for(unsigned long row=0; !limit||row<limit+offset; 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, cs.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(services, cs, "fetch", status); | check(cs, "fetch", status); |
| if(row>=offset) { | if(row>=offset) { |
| handlers.add_row(); | 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 size=0; |
| void *ptr=0; | char* str=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: |
| { | { |
| Line 687 private: // private funcs | Line 718 private: // private funcs |
| OCILobGetLength(cs.svchp, cs.errhp, var, &loblen); | OCILobGetLength(cs.svchp, cs.errhp, var, &loblen); |
| if(loblen) { | if(loblen) { |
| size=(size_t)loblen; | size=(size_t)loblen; |
| ptr=services.malloc(size); | str=(char*)services.malloc_atomic(size+1); |
| check(services, cs, "lobread", OCILobRead(cs.svchp, cs.errhp, | check(cs, "lobread", OCILobRead(cs.svchp, cs.errhp, |
| var, &amtp, offset, (dvoid *) ptr, | var, &amtp, offset, (dvoid *) str, |
| loblen, (dvoid *)0, | loblen, (dvoid *)0, |
| 0, | 0, |
| (ub2)0, (ub1) SQLCS_IMPLICIT)); | (ub2)0, (ub1) SQLCS_IMPLICIT)); |
| str[size]=0; | |
| } | } |
| break; | break; |
| } | } |
| default: | default: |
| if(const char *str=cols[i].str) { | if(const char *value=cols[i].str) { |
| size=strlen(str); | size=strlen(str); |
| ptr=services.malloc(size); | str=(char*)services.malloc_atomic(size+1); |
| memcpy(ptr, str, size); | memcpy(str, value, size+1); |
| } else { | } else { |
| size=0; | size=0; |
| ptr=0; | str=0; |
| } | } |
| break; | break; |
| } | } |
| handlers.add_row_cell(ptr, size); | check(cs, handlers.add_row_cell(cs.sql_error, str, size)); |
| } | } |
| } | } |
| } | } |
| Line 731 cleanup: // no check call after this poi | Line 763 cleanup: // no check call after this poi |
| private: // conn client library funcs | private: // conn client library funcs |
| friend void check( | friend void check(OracleSQL_connection_struct &cs, const char *step, sword status); |
| SQL_Driver_services& services, OracleSQL_connection_struct &cs, | |
| 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 843 private: // conn client library funcs li | Line 873 private: // conn client library funcs li |
| const char *dlink(const char *dlopen_file_spec) { | const char *dlink(const char *dlopen_file_spec) { |
| if(lt_dlinit()) | if(lt_dlinit()) |
| return lt_dlerror(); | return lt_dlerror(); |
| lt_dlhandle handle=lt_dlopen(dlopen_file_spec); | lt_dlhandle handle=lt_dlopen(dlopen_file_spec); |
| //return "hren31"; | |
| if(!handle) | if(!handle) |
| return lt_dlerror(); //"can not open the dynamic link module"; | return lt_dlerror(); //"can not open the dynamic link module"; |
| Line 883 private: // conn client library funcs li | Line 906 private: // conn client library funcs li |
| } *OracleSQL_driver; | } *OracleSQL_driver; |
| void check( | void check(OracleSQL_connection_struct &cs, const char *step, sword status) { |
| SQL_Driver_services& services, OracleSQL_connection_struct &cs, | |
| 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: | case OCI_SUCCESS: // hurrah |
| return; // hurrah | case OCI_SUCCESS_WITH_INFO: // ignoring. example: count(column) when column contains NULLs, |
| // count() not counting them and gives that status | |
| return; | |
| case OCI_ERROR: | case OCI_ERROR: |
| { | { |
| sb4 errcode; | sb4 errcode; |
| Line 903 void check( | Line 927 void check( |
| msg="[can not get error description]"; | msg="[can not get error description]"; |
| break; | break; |
| } | } |
| case OCI_SUCCESS_WITH_INFO: | |
| msg="SUCCESS_WITH_INFO"; break; | |
| case OCI_NEED_DATA: | case OCI_NEED_DATA: |
| msg="NEED_DATA"; break; | msg="NEED_DATA"; break; |
| case OCI_NO_DATA: | case OCI_NO_DATA: |
| Line 924 void check( | Line 946 void check( |
| longjmp(cs.mark, 1); | longjmp(cs.mark, 1); |
| } | } |
| void check(OracleSQL_connection_struct &cs, bool error) { | |
| if(error) | |
| longjmp(cs.mark, 1); | |
| } | |
| /* ----------------------------------------------------------------- */ | /* ----------------------------------------------------------------- */ |
| /* Intbind callback that does not do any data input. */ | /* Intbind callback that does not do any data input. */ |
| Line 961 static sb4 cbf_get_data(dvoid *ctxp, | Line 987 static sb4 cbf_get_data(dvoid *ctxp, |
| if(index==0) { | if(index==0) { |
| static ub4 rows; | static ub4 rows; |
| check(*context.services, *context.cs, "AttrGet cbf_get_data ROWS_RETURNED", | check(*context.cs, "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.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(sizeof(OracleSQL_query_lobs::return_rows::return_row)*rows); | context.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.services, *context.cs, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc( | check(*context.cs, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc( |
| (dvoid *) context.cs->envhp, (dvoid **)&var.locator, | (dvoid *) context.cs->envhp, (dvoid **)&var.locator, |
| (ub4)OCI_DTYPE_LOB, | (ub4)OCI_DTYPE_LOB, |
| 0, (dvoid **)0)); | 0, (dvoid **)0)); |