--- sql/oracle/parser3oracle.C 2003/09/29 06:15:27 1.35 +++ sql/oracle/parser3oracle.C 2003/12/23 11:52:37 1.44 @@ -7,7 +7,7 @@ 2001.07.30 using Oracle 8.1.6 [@test tested with Oracle 7.x.x] */ -static const char *RCSId="$Id: parser3oracle.C,v 1.35 2003/09/29 06:15:27 paf Exp $"; +static const char *RCSId="$Id: parser3oracle.C,v 1.44 2003/12/23 11:52:37 paf Exp $"; #include "config_includes.h" @@ -104,33 +104,10 @@ static char *lsplit(char **string_ref, c 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 struct OracleSQL_connection_struct { + SQL_Driver_services *services; + jmp_buf mark; char error[MAX_STRING]; SQL_Error sql_error; OCIEnv *envhp; @@ -138,6 +115,11 @@ struct OracleSQL_connection_struct { OCIError *errhp; OCISvcCtx *svchp; OCISession *usrhp; + + struct Options { + bool bLowerCaseColumnNames; + const char* cstrClientCharset; + } options; }; struct OracleSQL_query_lobs { @@ -150,7 +132,6 @@ struct OracleSQL_query_lobs { int count; }; struct cbf_context_struct { - SQL_Driver_services *services; OracleSQL_connection_struct *cs; return_rows *rows; }; @@ -185,6 +166,46 @@ static sb4 cbf_get_data(dvoid *ctxp, dvoid **indpp, ub2 **rcodepp); 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 @@ -206,7 +227,7 @@ public: const char *error=dlopen_file_spec? dlink(dlopen_file_spec):"client library column is empty"; if(!error) { - error=options2env(options); + error=options2env(options, 0); if(!error) OCIInitialize((ub4)OCI_THREADED/*| OCI_OBJECT*/, (dvoid *)0, @@ -237,6 +258,8 @@ public: // connections are cross-request, do not use services._alloc [linked with request] OracleSQL_connection_struct &cs= *(OracleSQL_connection_struct *)::calloc(sizeof(OracleSQL_connection_struct), 1); + cs.services=&services; + cs.options.bLowerCaseColumnNames = true; char *user=used_only_in_connect_url; char *service=lsplit(user, '@'); @@ -246,7 +269,7 @@ public: if(!(user && pwd && 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); if(setjmp(cs.mark)) @@ -339,31 +362,34 @@ public: // connections are cross-request, do not use services._alloc [linked with request] ::free(&cs); } - void commit(SQL_Driver_services& services, void *connection) { + void commit(void *connection) { OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; if(setjmp(cs.mark)) - services._throw(cs.error); + cs.services->_throw(cs.error); 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; 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? // select 0 from dual return true; } - const char* quote( - SQL_Driver_services& services, void *connection, - const char *from, unsigned int length) { - char *result=(char*)services.malloc_atomic(length*2+1); + const char* quote(void *connection, + const char *from, unsigned int length) + { + OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; + char *result=(char*)cs.services->malloc_atomic(length*2+1); char *to=result; while(length--) { switch(*from) { @@ -376,22 +402,30 @@ public: *to=0; return result; } - void query( - SQL_Driver_services& services, void *connection, + void query(void *connection, 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_query_lobs lobs={{0}, 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; if(setjmp(cs.mark)) { failed=true; goto cleanup; } else { - const char *statement=preprocess_statement(services, cs, - astatement, lobs); + const char *statement=preprocess_statement(cs, astatement, lobs); check(cs, "HandleAlloc STMT", OCIHandleAlloc( (dvoid *)cs.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0)); @@ -412,8 +446,7 @@ public: (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DATA_AT_EXEC)); lobs.items[i].rows.count=0; - OracleSQL_query_lobs::cbf_context_struct cbf_context={ - &services, &cs, &lobs.items[i].rows}; + OracleSQL_query_lobs::cbf_context_struct cbf_context={&cs, &lobs.items[i].rows}; check(cs, "bind dynamic", OCIBindDynamic( lobs.items[i].bind, cs.errhp, (dvoid *) &cbf_context, cbf_no_data, @@ -450,9 +483,10 @@ cleanup: // no check call after this poi 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) { size_t statement_size=strlen(astatement); + SQL_Driver_services& services=*cs.services; char *result=(char *)services.malloc_atomic(statement_size +MAX_STRING // in case of short 'strings' @@ -524,17 +558,12 @@ private: // private funcs if(i) *n++=','; 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 "); for(i=0; i=offset) { check(cs, handlers.add_row(cs.sql_error)); for(int i=0; iOCIErrorGet((dvoid *)cs.errhp, (ub4)1, (text *)NULL, &errcode, (text *)reason, (ub4)sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS) msg=reason; + + // transcode to $request:charset from connect-string?client_charset + 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; @@ -999,7 +1072,7 @@ static sb4 cbf_get_data(dvoid *ctxp, (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.cs->errhp)) ; context.rows->count=(ub2)rows; 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]; @@ -1022,8 +1095,12 @@ void tolower(char *out, const char *in, while(size--) *out++=tolower(*in++); } +void toupper(char *out, const char *in, size_t size) { + while(size--) + *out++=toupper(*in++); +} + extern "C" SQL_Driver *SQL_DRIVER_CREATE() { - //_asm int 3; return OracleSQL_driver=new OracleSQL_Driver(); }