--- sql/oracle/parser3oracle.C 2004/03/30 08:18:24 1.55 +++ sql/oracle/parser3oracle.C 2008/06/30 15:22:28 1.69 @@ -7,7 +7,8 @@ 2001.07.30 using Oracle 8.1.6 [@test tested with Oracle 7.x.x] */ -static const char *RCSId="$Id: parser3oracle.C,v 1.55 2004/03/30 08:18:24 paf Exp $"; + +static const char *RCSId="$Id: parser3oracle.C,v 1.69 2008/06/30 15:22:28 misha Exp $"; #include "config_includes.h" @@ -19,6 +20,7 @@ static const char *RCSId="$Id: parser3or #define MAX_IN_LOBS 5 #define MAX_LOB_NAME_LENGTH 100 #define MAX_OUT_STRING_LENGTH 4000 +#define MAX_BINDS 100 #define EMPTY_CLOB_FUNC_CALL "empty_clob()" @@ -44,6 +46,8 @@ inline int min(int a, int b){ return a(aconnection); - // free fetch buffers + // free fetch buffers. leave that to GC [no such services func. yet?] + /* for(int i=0; ifree(fetch_buffer); else break; - } + } + */ // Terminate a user session OCISessionEnd( @@ -372,9 +400,10 @@ public: OCIHandleFree( (dvoid *)connection.envhp, (ub4)OCI_HTYPE_ENV); - // connections are cross-request, do not use services._alloc [linked with request] - ::free(&connection); + // 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)) @@ -382,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)) @@ -415,24 +445,29 @@ public: *to=0; return result; } - void query(void *aconnection, - const char *astatement, unsigned long offset, unsigned long limit, - SQL_Driver_query_event_handlers& handlers) - { + + 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 + ){ + Connection& connection=*static_cast(aconnection); - const char* cstrClientCharset=connection.options.cstrClientCharset; - OracleSQL_query_lobs lobs={{0}, 0}; + 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) { - size_t transcoded_statement_size; + 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_statement_size, + astatement, transcoded_xxx_size, services.request_charset(), - cstrClientCharset); + connection.options.client_charset); } bool failed=false; @@ -440,6 +475,9 @@ public: failed=true; goto cleanup; } else { + if(placeholders_count>MAX_BINDS) + fail(connection, "too many bind variables"); + const char *statement=preprocess_statement(connection, astatement, lobs); check(connection, "HandleAlloc STMT", OCIHandleAlloc( @@ -448,30 +486,129 @@ public: OCIStmtPrepare(stmthp, connection.errhp, (unsigned char *)statement, (ub4)strlen((char *)statement), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)); + + struct Bind_info { + OCIBind *bind; + sb2 indicator; + }; + + int binds_size=sizeof(Bind_info) * placeholders_count; + // we DO store OCIBind* into ATOMIC gc memory, + // but we do not allocate/free it, that's done automatically from oracle [using environment handles] + // so we don't have to bother with that + Bind_info* binds=static_cast(services.malloc_atomic(binds_size)); { + for(size_t i=0; icount; r++) { OCILobLocator *locator=rows->row[r].locator; check(connection, "lobwrite", OCILobWrite ( @@ -652,7 +789,8 @@ private: // private funcs OCIStmt *stmthp, unsigned long offset, unsigned long limit, SQL_Driver_query_event_handlers& handlers) { - const char* cstrClientCharset=connection.options.cstrClientCharset; + bool transcode_needed=_transcode_required(connection); + SQL_Driver_services& services=*connection.services; ub4 prefetch_rows=100; @@ -667,9 +805,9 @@ private: // private funcs (dvoid *)&prefetch_mem_size, (ub4)0, (ub4)OCI_ATTR_PREFETCH_MEMORY, (OCIError *)connection.errhp)); - OCIParam *mypard; - ub2 dtype; - const char* col_name; + OCIParam *mypard; + ub2 dtype; + const char* col_name; struct Col { ub2 type; @@ -707,11 +845,12 @@ private: // private funcs (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME, (OCIError *)connection.errhp)); - // transcode to $request:charset from connect-string?client_charset - if(cstrClientCharset) { + + if(transcode_needed){ + // transcode column name from ?ClientCharset to $request:charset services.transcode(col_name, col_name_len, col_name, col_name_len, - cstrClientCharset, + connection.options.client_charset, services.request_charset()); } @@ -732,25 +871,25 @@ private: // private funcs void *ptr; switch(dtype) { - case SQLT_CLOB: - { - check(connection, "alloc output var desc", OCIDescriptorAlloc( - (dvoid *)connection.envhp, (dvoid **)(ptr=&col.var), - (ub4)OCI_DTYPE_LOB, - 0, (dvoid **)0)); - - size=0; + case SQLT_CLOB: + { + check(connection, "alloc output var desc", OCIDescriptorAlloc( + (dvoid *)connection.envhp, (dvoid **)(ptr=&col.var), + (ub4)OCI_DTYPE_LOB, + 0, (dvoid **)0)); + + size=0; + break; + } + default: + coerce_type=SQLT_STR; + char*& buf=connection.fetch_buffers[column_count-1]; + ptr=buf; // get cached buffer + if(!ptr) // allocate if needed, caching it + ptr=buf=(char *)services.malloc_atomic(MAX_OUT_STRING_LENGTH+1/*terminator*/); + col.str=(char*)ptr; + size=MAX_OUT_STRING_LENGTH; break; - } - default: - coerce_type=SQLT_STR; - 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; - break; } col.type=coerce_type; @@ -769,7 +908,7 @@ private: // private funcs check(connection, handlers.before_rows(connection.sql_error)); - for(unsigned long row=0; !limit||rowrequest_charset())!=0); + } + private: // conn client library funcs + friend void fail(Connection& connection, const char *msg); friend void check(Connection& connection, const char *step, sword status); friend sb4 cbf_get_data(dvoid *ctxp, OCIBind *bindp, @@ -892,6 +1057,11 @@ private: // conn client library funcs ub2 dty, dvoid *indp, ub2 *alenp, ub2 *rcodep, ub4 maxarr_len, ub4 *curelep, ub4 mode)); + OCI_DECL(BindByName, (OCIStmt *stmtp, OCIBind **bindp, OCIError *errhp, + text* placeholder, sb4 placeh_len, dvoid *valuep, sb4 value_sz, + ub2 dty, dvoid *indp, ub2 *alenp, ub2 *rcodep, + ub4 maxarr_len, ub4 *curelep, ub4 mode)); + OCI_DECL(BindDynamic, (OCIBind *bindp, OCIError *errhp, dvoid *ictxp, OCICallbackInBind icbfp, dvoid *octxp, OCICallbackOutBind ocbfp)); @@ -983,7 +1153,7 @@ private: // conn client library funcs li OCI_LINK(Initialize); OCI_LINK(EnvInit); OCI_LINK(AttrGet); OCI_LINK(AttrSet); - OCI_LINK(BindByPos); OCI_LINK(BindDynamic); + OCI_LINK(BindByPos); OCI_LINK(BindByName); OCI_LINK(BindDynamic); OCI_LINK(DefineByPos); OCI_LINK(DescriptorAlloc); OCI_LINK(DescriptorFree); OCI_LINK(ErrorGet); @@ -1018,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 @@ -1052,6 +1220,11 @@ void check(Connection& connection, const longjmp(connection.mark, 1); } +void fail(Connection& connection, const char* msg) { + snprintf(connection.error, sizeof(connection.error), "%s", msg); + longjmp(connection.mark, 1); +} + void check(Connection& connection, bool error) { if(error) longjmp(connection.mark, 1); @@ -1060,7 +1233,7 @@ void check(Connection& connection, bool /* ----------------------------------------------------------------- */ /* Intbind callback that does not do any data input. */ /* ----------------------------------------------------------------- */ -static sb4 cbf_no_data( +sb4 cbf_no_data( dvoid* /*ctxp*/, OCIBind* /*bindp*/, ub4 /*iter*/, ub4 /*index*/, @@ -1088,8 +1261,7 @@ static sb4 cbf_get_data(dvoid *ctxp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp) { - OracleSQL_query_lobs::cbf_context_struct &context= - *(OracleSQL_query_lobs::cbf_context_struct *)ctxp; + Query_lobs::Item& context=*static_cast(ctxp); if(index==0) { static ub4 rows; @@ -1097,12 +1269,12 @@ static sb4 cbf_get_data(dvoid *ctxp, OracleSQL_driver->OCIAttrGet( (CONST dvoid *) bindp, OCI_HTYPE_BIND, (dvoid *)&rows, (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.connection->errhp)) ; - context.rows->count=(ub2)rows; - context.rows->row=(OracleSQL_query_lobs::return_rows::return_row *) - context.connection->services->malloc_atomic(sizeof(OracleSQL_query_lobs::return_rows::return_row)*rows); + context.rows.count=(ub2)rows; + context.rows.row=(Query_lobs::return_rows::return_row *) + context.connection->services->malloc_atomic(sizeof(Query_lobs::return_rows::return_row)*rows); } - OracleSQL_query_lobs::return_rows::return_row &var=context.rows->row[index]; + Query_lobs::return_rows::return_row &var=context.rows.row[index]; check(*context.connection, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc( (dvoid *) context.connection->envhp, (dvoid **)&var.locator, @@ -1118,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(); }