--- sql/oracle/parser3oracle.C 2004/10/07 09:27:02 1.65 +++ sql/oracle/parser3oracle.C 2008/06/30 15:22:28 1.69 @@ -8,7 +8,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.65 2004/10/07 09:27:02 paf Exp $"; +static const char *RCSId="$Id: parser3oracle.C,v 1.69 2008/06/30 15:22:28 misha Exp $"; #include "config_includes.h" @@ -95,22 +95,40 @@ static int pa_setenv(const char *name, c #endif } -static char *lsplit(char *string, char delim) { - if(string) { - char *v=strchr(string, delim); - if(v) { +static char *lsplit(char *string, char delim){ + if(string){ + if(char* v=strchr(string, delim)){ *v=0; return v+1; } - } - return 0; + } + return 0; } -static char *lsplit(char **string_ref, char delim) { - char *result=*string_ref; +static char *lsplit(char **string_ref, char delim){ + char *result=*string_ref; char *next=lsplit(*string_ref, delim); - *string_ref=next; - return result; + *string_ref=next; + return result; +} + +static char* rsplit(char* string, char delim){ + if(string){ + if(char* v=strrchr(string, delim)){ + *v=0; + return v+1; + } + } + return NULL; +} + +static void tolower_str(char *out, const char *in, size_t size) { + while(size--) + *out++=(char)tolower(*in++); +} +static void toupper_str(char *out, const char *in, size_t size) { + while(size--) + *out++=(char)toupper(*in++); } #ifndef DOXYGEN @@ -130,7 +148,7 @@ struct Connection { struct Options { bool bLowerCaseColumnNames; - const char* cstrClientCharset; + const char* client_charset; } options; }; @@ -176,25 +194,23 @@ static sb4 cbf_get_data(dvoid *ctxp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp); -static void tolower_str(char *out, const char *in, size_t size); -static void toupper_str(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) { + while(s){ + if(char *key=lsplit(&s, '&')){ + if(*key){ + if(char *value=lsplit(key, '=')){ + if(strcmp(key, "ClientCharset")== 0){ + if(options){ toupper_str(value, value, strlen(value)); - options->cstrClientCharset = value; + options->client_charset=value; } continue; } - if( strcmp( key, "LowerCaseColumnNames" ) == 0 ) { + if(strcmp(key, "LowerCaseColumnNames")==0){ if(options) - options->bLowerCaseColumnNames = atoi(value)!=0; + options->bLowerCaseColumnNames=atoi(value)!=0; continue; } @@ -229,6 +245,7 @@ public: /// get api version int api_version() { return SQL_DRIVER_API_VERSION; } + /** initialize driver by loading sql dynamic link library @todo ?objects=1 which would turn on OCI_OBJECT init flag */ @@ -254,28 +271,30 @@ public: /** connect @param url format: @b user:pass@service? - ORACLE_HOME=/u01/app/oracle/product/8.1.5& - ORA_NLS33=/u01/app/oracle/product/8.1.5/ocommon/nls/admin/data& - NLS_LANG=RUSSIAN_AMERICA.CL8MSWIN1251& - ORA_ENCRYPT_LOGIN=TRUE + ORACLE_HOME=/u01/app/oracle/product/8.1.5& + ORA_NLS33=/u01/app/oracle/product/8.1.5/ocommon/nls/admin/data& + NLS_LANG=RUSSIAN_AMERICA.CL8MSWIN1251& + ORA_ENCRYPT_LOGIN=TRUE& + ClientCharset=charset& + LowerCaseColumnNames=0 @todo environment manupulation doesnt look thread safe @todo allocate 'aused_only_in_connect_url' on gc heap, so it can be manipulated directly */ void connect( - char *url, - SQL_Driver_services& services, - void **connection_ref ///< output: Connection * + char *url, + SQL_Driver_services& services, + void **connection_ref ///< output: Connection * ) { // connections are cross-request, do not use services._alloc [linked with request] - Connection& connection=*(Connection *)services.malloc(sizeof(Connection)); + Connection& connection=*(Connection *)services.malloc(sizeof(Connection)); connection.services=&services; - connection.options.bLowerCaseColumnNames = true; + connection.options.bLowerCaseColumnNames=true; *connection_ref=&connection; char *user=url; - char *service=lsplit(user, '@'); + char *service=rsplit(user, '@'); char *pwd=lsplit(user, ':'); char *options=lsplit(service, '?'); @@ -348,6 +367,7 @@ public: (dvoid *)connection.usrhp, (ub4)0, OCI_ATTR_SESSION, connection.errhp)); } + void disconnect(void *aconnection) { Connection& connection=*static_cast(aconnection); @@ -383,6 +403,7 @@ public: // free connection. leave that to GC [no such services func. yet?] // connection.services->free(&connection); } + void commit(void *aconnection) { Connection& connection=*static_cast(aconnection); if(setjmp(connection.mark)) @@ -390,6 +411,7 @@ public: check(connection, "commit", OCITransCommit(connection.svchp, connection.errhp, 0)); } + void rollback(void *aconnection) { Connection& connection=*static_cast(aconnection); if(setjmp(connection.mark)) @@ -423,27 +445,29 @@ public: *to=0; return result; } + void query(void* aconnection, - const char* astatement, - size_t placeholders_count, Placeholder* placeholders, - unsigned long offset, unsigned long limit, - SQL_Driver_query_event_handlers& handlers) - { + const char* astatement, + size_t placeholders_count, Placeholder* placeholders, + unsigned long offset, unsigned long limit, + SQL_Driver_query_event_handlers& handlers + ){ Connection& connection=*static_cast(aconnection); - const char* cstrClientCharset=connection.options.cstrClientCharset; Query_lobs lobs={{0}, 0}; OCIStmt *stmthp=0; SQL_Driver_services& services=*connection.services; - // transcode from $request:charset to connect-string?client_charset - if(cstrClientCharset) { + bool transcode_needed=_transcode_required(connection); + + if(transcode_needed){ + // transcode query from $request:charset to ?ClientCharset size_t transcoded_xxx_size; services.transcode(astatement, strlen(astatement), astatement, transcoded_xxx_size, services.request_charset(), - cstrClientCharset); + connection.options.client_charset); } bool failed=false; @@ -483,18 +507,19 @@ public: size_t value_length; - if(cstrClientCharset) { + if(transcode_needed){ + // transcode bind variables names and their values from $request:charset to ?ClientCharset size_t name_length; services.transcode(ph.name, strlen(ph.name), ph.name, name_length, services.request_charset(), - cstrClientCharset); + connection.options.client_charset); if(ph.value) services.transcode(ph.value, strlen(ph.value), ph.value, value_length, services.request_charset(), - cstrClientCharset); + connection.options.client_charset); } else { value_length=ph.value? strlen(ph.value): 0; } @@ -506,6 +531,8 @@ public: value_buf=(char *)services.malloc_atomic(MAX_OUT_STRING_LENGTH+1/*terminator*/); if(value_length) memcpy(value_buf, ph.value, value_length+1); + else + value_buf[0]=0; char name_buf[MAX_STRING]; sb4 placeh_len=snprintf(name_buf, sizeof(name_buf), ":%s", ph.name); @@ -570,10 +597,11 @@ public: memcpy(returned_value, bind_buffer, value_length+1 ); ph.value=returned_value; - if(cstrClientCharset) { + if(transcode_needed){ + // transcode bind variable output from ?ClientCharset to $request:charset services.transcode(ph.value, value_length, ph.value, value_length/*request_charset())!=0); + } + private: // conn client library funcs friend void fail(Connection& connection, const char *msg); @@ -1141,15 +1188,13 @@ void check(Connection& connection, const (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=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()); - } + // transcode server error message from ?ClientCharset to $request:charset + if(msg && connection.options.client_charset && strcmp(connection.options.client_charset, connection.services->request_charset())!=0){ + if(size_t msg_length=strlen(msg)){ + connection.services->transcode(msg, msg_length, + msg, msg_length, + connection.options.client_charset, + connection.services->request_charset()); } } } else @@ -1245,16 +1290,6 @@ static sb4 cbf_get_data(dvoid *ctxp, return OCI_CONTINUE; } -static void tolower_str(char *out, const char *in, size_t size) { - while(size--) - *out++=(char)tolower(*in++); -} -static void toupper_str(char *out, const char *in, size_t size) { - while(size--) - *out++=(char)toupper(*in++); -} - - extern "C" SQL_Driver *SQL_DRIVER_CREATE() { return OracleSQL_driver=new OracleSQL_Driver(); }