--- sql/oracle/parser3oracle.C 2002/12/09 11:43:08 1.26 +++ sql/oracle/parser3oracle.C 2013/05/27 20:10:14 1.78 @@ -1,13 +1,12 @@ /** @file Parser Oracle driver. - Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) 2001.07.30 using Oracle 8.1.6 [@test tested with Oracle 7.x.x] */ -static const char *RCSId="$Id: parser3oracle.C,v 1.26 2002/12/09 11:43:08 paf Exp $"; #include "config_includes.h" @@ -15,10 +14,13 @@ static const char *RCSId="$Id: parser3or #include +volatile const char * IDENT_PARSER3ORACLE_C="$Id: parser3oracle.C,v 1.78 2013/05/27 20:10:14 moko Exp $" IDENT_PA_SQL_DRIVER_H; + #define MAX_COLS 500 #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()" @@ -38,7 +40,15 @@ inline int max(int a, int b) { return a> inline int min(int a, int b){ return a(aconnection); + + // 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( - cs.svchp, cs.errhp, cs.usrhp, (ub4)OCI_DEFAULT); + connection.svchp, connection.errhp, connection.usrhp, (ub4)OCI_DEFAULT); // Detach from a server; uninitialize server context handle OCIServerDetach( - cs.srvhp, cs.errhp, (ub4)OCI_DEFAULT); + connection.srvhp, connection.errhp, (ub4)OCI_DEFAULT); // Free a previously allocated handles /* oci will free them up as belonging to env OCIHandleFree( - (dvoid *)cs.srvhp, (ub4)OCI_HTYPE_SERVER); + (dvoid *)connection.srvhp, (ub4)OCI_HTYPE_SERVER); OCIHandleFree( - (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX); + (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX); OCIHandleFree( - (dvoid *)cs.errhp, (ub4)OCI_HTYPE_ERROR); + (dvoid *)connection.errhp, (ub4)OCI_HTYPE_ERROR); */ OCIHandleFree( - (dvoid *)cs.envhp, (ub4)OCI_HTYPE_ENV); + (dvoid *)connection.envhp, (ub4)OCI_HTYPE_ENV); - // connections are cross-request, do not use services._alloc [linked with request] - ::free(&cs); + // free connection. leave that to GC [no such services func. yet?] + // connection.services->free(&connection); } - void commit(SQL_Driver_services& services, void *connection) { - OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; - if(setjmp(cs.mark)) - services._throw(cs.error); - check(services, cs, "commit", OCITransCommit(cs.svchp, cs.errhp, 0)); + void commit(void *aconnection) { + Connection& connection=*static_cast(aconnection); + if(setjmp(connection.mark)) + connection.services->_throw(connection.error); + + check(connection, "commit", OCITransCommit(connection.svchp, connection.errhp, 0)); } - void rollback(SQL_Driver_services& services, void *connection) { - OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; - if(setjmp(cs.mark)) - services._throw(cs.error); - check(services, cs, "rollback", OCITransRollback(cs.svchp, cs.errhp, 0)); + void rollback(void *aconnection) { + Connection& connection=*static_cast(aconnection); + if(setjmp(connection.mark)) + connection.services->_throw(connection.error); + + // 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(connection, "rollback", */OCITransRollback(connection.svchp, connection.errhp, 0)/*)*/; } - bool ping(SQL_Driver_services&, void *connection) { + bool ping(void* /*connection*/) { // maybe OCIServerVersion? // select 0 from dual return true; } - unsigned int quote( - SQL_Driver_services&, void *, - char *to, const char *from, unsigned int length) { - if(to) { // store mode - unsigned int result=length; - while(length--) { - switch(*from) { - case '\'': // "'" -> "''" - *to++='\''; result++; - break; - } - *to++=*from++; - } - return result; - } else // estimate mode - return length*2; - } - void query( - SQL_Driver_services& services, void *connection, - const char *astatement, unsigned long offset, unsigned long limit, - SQL_Driver_query_event_handlers& handlers) { + // charset here is services.request_charset(), not connection.client_charset + // thus we can't use the sql server quoting support + const char* quote(void *aconnection, const char *str, unsigned int length) + { + const char* from; + const char* from_end=str+length; + + size_t quoted=0; + + for(from=str; from(aconnection); + char *result=(char*)connection.services->malloc_atomic(length + quoted + 1); + char *to = result; + + for(from=str; from '' + *to++=*from; + } - OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; - OracleSQL_query_lobs lobs={{0}, 0}; + *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 + ){ + + Connection& connection=*static_cast(aconnection); + Query_lobs lobs={{0}, 0}; OCIStmt *stmthp=0; + SQL_Driver_services& services=*connection.services; + bool failed=false; - if(setjmp(cs.mark)) { + if(setjmp(connection.mark)) { failed=true; goto cleanup; } else { - const char *statement=preprocess_statement(services, cs, - astatement, lobs); + if(placeholders_count>MAX_BINDS) + fail(connection, "too many bind variables"); + + while(isspace((unsigned char)*astatement)) + astatement++; + + const char* client_charset=connection.options.client_charset; + const char* request_charset=services.request_charset(); + 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, + request_charset, + client_charset); + } + + const char *statement=_preprocess_statement_lobs(connection, astatement, lobs); + + modified_statement mstatement=_preprocess_statement_limit(connection, statement, offset, limit); + statement=mstatement.statement; - check(services, cs, "HandleAlloc STMT", OCIHandleAlloc( - (dvoid *)cs.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0)); - check(services, cs, "syntax", - OCIStmtPrepare(stmthp, cs.errhp, (unsigned char *)statement, + if(mstatement.limit) // limit was added in statement + limit=SQL_NO_LIMIT; + if(mstatement.offset) // limit was added in statement + offset=0; + + check(connection, "HandleAlloc STMT", OCIHandleAlloc( + (dvoid *)connection.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0)); + check(connection, "syntax", + 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(int i=0; i EMPTY_CLOB_FUNC_CALL char *n=result; @@ -469,6 +699,7 @@ private: // private funcs o[0]=='/' && o[1]=='*' && o[2]=='*') { // name start + const char* saved_o=o; o+=3; const char *name_begin=o; while(*o) @@ -477,16 +708,17 @@ private: // private funcs o[1]=='*' && o[2]=='/' && o[3]=='\'') { // name end + saved_o=0; // found, marking that const char *name_end=o; o+=4; - OracleSQL_query_lobs::Item &item=lobs.items[lobs.count++]; + Query_lobs::Item &item=lobs.items[lobs.count++]; 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; bool escaped=false; while(*o && !(o[0]=='\'' && o[1]!='\'' && !escaped)) { - escaped=o[0]=='\'' && o[1]=='\''; + escaped=!escaped && (o[0]=='\'' && o[1]=='\''); if(escaped) { // write pending, skip "\" or "'" if(size_t size=o-start) { @@ -508,6 +740,10 @@ private: // private funcs break; } else o++; // /**skip**/'xxx' + if(saved_o) { + o=saved_o; + *n++=*o++; + } } else *n++=*o++; } @@ -520,17 +756,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; icount; r++) { OCILobLocator *locator=rows->row[r].locator; - check(services, cs, "lobwrite", OCILobWrite ( - cs.svchp, cs.errhp, + check(connection, "lobwrite", OCILobWrite ( + connection.svchp, connection.errhp, locator, &bytes_to_write, 1, (dvoid *)lobs.items[i].data_ptr, (ub4)bytes_to_write, OCI_ONE_PIECE, (dvoid *)0, 0, (ub2)0, @@ -587,9 +816,9 @@ private: // private funcs switch(stmt_type) { case OCI_STMT_SELECT: - fetch_table(services, cs, + fetch_table(connection, stmthp, offset, limit, - handlers); + handlers, skip_rownum_column); break; default: /* @@ -600,27 +829,29 @@ private: // private funcs } } - void fetch_table(SQL_Driver_services& services, OracleSQL_connection_struct &cs, - OCIStmt *stmthp, unsigned long offset, unsigned long limit, - SQL_Driver_query_event_handlers& handlers) { + void fetch_table(Connection& connection, + OCIStmt *stmthp, unsigned long offset, unsigned long limit, + SQL_Driver_query_event_handlers& handlers, bool skip_rownum_column) + { + SQL_Driver_services& services=*connection.services; ub4 prefetch_rows=100; - check(services, cs, "AttrSet prefetch-rows", OCIAttrSet( + check(connection, "AttrSet prefetch-rows", OCIAttrSet( (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, (dvoid *)&prefetch_rows, (ub4)0, - (ub4)OCI_ATTR_PREFETCH_ROWS, (OCIError *)cs.errhp)); + (ub4)OCI_ATTR_PREFETCH_ROWS, (OCIError *)connection.errhp)); ub4 prefetch_mem_size=100*0x400; - check(services, cs, "AttrSet prefetch-memory", OCIAttrSet( + check(connection, "AttrSet prefetch-memory", OCIAttrSet( (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, (dvoid *)&prefetch_mem_size, (ub4)0, - (ub4)OCI_ATTR_PREFETCH_MEMORY, (OCIError *)cs.errhp)); + (ub4)OCI_ATTR_PREFETCH_MEMORY, (OCIError *)connection.errhp)); - OCIParam *mypard; - ub2 dtype; - text *col_name; + OCIParam *mypard; + ub2 dtype; + const char* col_name; - struct { + struct Col { ub2 type; char *str; OCILobLocator *var; @@ -630,51 +861,69 @@ private: // private funcs int column_count=0; bool failed=false; - jmp_buf saved_mark; memcpy(saved_mark, cs.mark, sizeof(jmp_buf)); - if(setjmp(cs.mark)) { + jmp_buf saved_mark; memcpy(saved_mark, connection.mark, sizeof(jmp_buf)); + if(setjmp(connection.mark)) { failed=true; goto cleanup; } else { - try { + bool transcode_needed=transcode_required(connection); + const char* client_charset=connection.options.client_charset; + const char* request_charset=services.request_charset(); + + // idea of preincrementing is that at error time all handles would free up + while(++column_count<=MAX_COLS) { + /* get next descriptor, if there is one */ + if(OCIParamGet(stmthp, OCI_HTYPE_STMT, connection.errhp, (void **)&mypard, + (ub4) column_count)!=OCI_SUCCESS) { + --column_count; + break; + } - // idea of preincrementing is that at error time all handles would free up - while(++column_count<=MAX_COLS) { - /* get next descriptor, if there is one */ - if(OCIParamGet(stmthp, OCI_HTYPE_STMT, cs.errhp, (void **)&mypard, - (ub4) column_count)!=OCI_SUCCESS) { - --column_count; - break; - } - - /* Retrieve the data type attribute */ - check(services, cs, "get type", OCIAttrGet( - (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, - (dvoid*) &dtype, (ub4 *)0, (ub4)OCI_ATTR_DATA_TYPE, - (OCIError *)cs.errhp)); - - /* Retrieve the column name attribute */ - ub4 col_name_len; - check(services, cs, "get name", OCIAttrGet( - (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, - (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME, - (OCIError *)cs.errhp)); - - { - size_t size=(size_t)col_name_len; - char *ptr=(char *)services.malloc(size); - tolower(ptr, (char *)col_name, size); - handlers.add_column(ptr, size); - } - - ub2 coerce_type=dtype; - sb4 size=0; - void *ptr; - - switch(dtype) { + if(skip_rownum_column && column_count==1) + continue; + + /* Retrieve the data type attribute */ + check(connection, "get type", OCIAttrGet( + (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, + (dvoid*) &dtype, (ub4 *)0, (ub4)OCI_ATTR_DATA_TYPE, + (OCIError *)connection.errhp)); + + /* Retrieve the column name attribute */ + ub4 col_name_len; + check(connection, "get name", OCIAttrGet( + (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, + (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME, + (OCIError *)connection.errhp)); + + size_t length=(size_t)col_name_len; + if(transcode_needed){ + // transcode column name from ?ClientCharset to $request:charset + services.transcode(col_name, col_name_len, + col_name, length, + client_charset, + request_charset); + } + + Col& col=cols[column_count-1]; + { + char *ptr=(char *)services.malloc_atomic(length+1); + if( connection.options.bLowerCaseColumnNames ) + tolower_str(ptr, col_name, length); + else + memcpy(ptr, col_name, length); + ptr[length]=0; + check(connection, handlers.add_column(connection.sql_error, ptr, length)); + } + + ub2 coerce_type=dtype; + sb4 size=0; + void *ptr; + + switch(dtype) { case SQLT_CLOB: { - check(services, cs, "alloc output var desc", OCIDescriptorAlloc( - (dvoid *)cs.envhp, (dvoid **)(ptr=&cols[column_count-1].var), + check(connection, "alloc output var desc", OCIDescriptorAlloc( + (dvoid *)connection.envhp, (dvoid **)(ptr=&col.var), (ub4)OCI_DTYPE_LOB, 0, (dvoid **)0)); @@ -683,77 +932,119 @@ private: // private funcs } default: coerce_type=SQLT_STR; - ptr=cols[column_count-1].str=(char *)services.malloc(MAX_OUT_STRING_LENGTH+1); + 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; - } - - cols[column_count-1].type=coerce_type; - - check(services, cs, "DefineByPos", OCIDefineByPos( - stmthp, &cols[column_count-1].def, cs.errhp, - column_count, (ub1 *) ptr, size, - coerce_type, (dvoid *) &cols[column_count-1].indicator, - (ub2 *)0, (ub2 *)0, OCI_DEFAULT)); } - handlers.before_rows(); + col.type=coerce_type; - for(unsigned long row=0; !limit||row=offset) { - handlers.add_row(); - for(int i=0; i=offset) { + check(connection, handlers.add_row(connection.sql_error)); + for(int i=0; ioffset + statement_limited=(char *)connection.services->malloc_atomic( + statement_size + +64/*SELECT * FROM (SELECT ROWNUM r__, z__.* FROM () z__) WHERE r__<=*/ + +MAX_NUMBER + +9/* AND r__>*/ + +MAX_NUMBER + +1/*terminator*/ + ); + + result.statement=statement_limited; + + strcpy(statement_limited, "SELECT * FROM (SELECT ROWNUM r__, z__.* FROM ("); + strcat(statement_limited, astatement); + + statement_limited+=46+statement_size; + statement_limited+=snprintf(statement_limited, 18+MAX_NUMBER, ") z__) WHERE r__<=%lu", limit+offset); + statement_limited+=snprintf(statement_limited, 9+MAX_NUMBER, " AND r__>%lu", offset); + + } else { + + // SELECT * FROM (user_query) WHERE ROWNUM<=limit + // this statement can be easy for the sql server but we can't use it with offset + + statement_limited=(char *)connection.services->malloc_atomic( + statement_size + +31/*SELECT * FROM () WHERE ROWNUM<=*/ + +MAX_NUMBER + +1/*terminator*/ + ); + + result.statement=statement_limited; + + strcpy(statement_limited, "SELECT * FROM ("); + strcat(statement_limited, astatement); + + statement_limited+=15+statement_size; + statement_limited+=snprintf(statement_limited, 16+MAX_NUMBER, ") WHERE ROWNUM<=%lu", limit); + + } + *statement_limited=0; + + //connection.services->_throw(result.statement); + } + return result; + } + private: // conn client library funcs - friend void check( - SQL_Driver_services& services, OracleSQL_connection_struct &cs, - const char *step, sword status); + 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, ub4 iter, ub4 index, @@ -811,6 +1167,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)); @@ -886,18 +1247,19 @@ private: // conn client library funcs private: // conn client library funcs linking const char *dlink(const char *dlopen_file_spec) { - if(lt_dlinit()) - - return lt_dlerror(); - - - - lt_dlhandle handle=lt_dlopen(dlopen_file_spec); + if(lt_dlinit()){ + if(const char* result=lt_dlerror()) + return result; + return "can not prepare to dynamic loading"; + } - //return "hren31"; + lt_dlhandle handle=lt_dlopen(dlopen_file_spec); - if(!handle) - return lt_dlerror(); //"can not open the dynamic link module"; + if(!handle){ + if(const char* result=lt_dlerror()) + return result; + return "can not open the dynamic link module"; + } #define DSLINK(name, action) \ name=(t_##name)lt_dlsym(handle, #name); \ @@ -909,7 +1271,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); @@ -927,14 +1289,11 @@ private: // conn client library funcs li } *OracleSQL_driver; -void check( - SQL_Driver_services& services, OracleSQL_connection_struct &cs, - const char *step, sword status) { +void check(Connection& connection, const char *step, sword status) { const char *msg; char reason[MAX_STRING/2]; - const char *prefix="ERROR"; switch (status) { case OCI_SUCCESS: // hurrah case OCI_SUCCESS_WITH_INFO: // ignoring. example: count(column) when column contains NULLs, @@ -942,13 +1301,23 @@ void check( return; case OCI_ERROR: { - sb4 errcode; - if(OracleSQL_driver->OCIErrorGet((dvoid *)cs.errhp, (ub4)1, (text *)NULL, &errcode, - (text *)reason, (ub4)sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS) - msg=reason; - else - msg="[can not get error description]"; - break; + sb4 errcode; + if(OracleSQL_driver->OCIErrorGet((dvoid *)connection.errhp, (ub4)1, (text *)NULL, &errcode, + (text *)reason, (ub4)sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS) { + msg=reason; + + if(msg && transcode_required(connection)){ + // transcode server error message from ?ClientCharset to $request:charset + 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 + msg="[can not get error description]"; + break; } case OCI_NEED_DATA: msg="NEED_DATA"; break; @@ -964,19 +1333,32 @@ void check( msg="unknown"; break; } - snprintf(cs.error, sizeof(cs.error), "%s (%s, %d)", + snprintf(connection.error, sizeof(connection.error), "%s (%s, %d)", msg, step, (int)status); - longjmp(cs.mark, 1); + longjmp(connection.mark, 1); +} + +bool transcode_required(Connection& connection){ + return (connection.options.client_charset && strcmp(connection.options.client_charset, connection.services->request_charset())!=0); +} + +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); +} /* ----------------------------------------------------------------- */ /* Intbind callback that does not do any data input. */ /* ----------------------------------------------------------------- */ -static sb4 cbf_no_data( - dvoid *ctxp, - OCIBind *bindp, - ub4 iter, ub4 index, +sb4 cbf_no_data( + dvoid* /*ctxp*/, + OCIBind* /*bindp*/, + ub4 /*iter*/, ub4 /*index*/, dvoid **bufpp, ub4 *alenpp, ub1 *piecep, @@ -995,30 +1377,29 @@ static sb4 cbf_no_data( /* ----------------------------------------------------------------- */ static sb4 cbf_get_data(dvoid *ctxp, OCIBind *bindp, - ub4 iter, ub4 index, + ub4 /*iter*/, ub4 index, dvoid **bufpp, ub4 **alenp, 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; - check(*context.services, *context.cs, "AttrGet cbf_get_data ROWS_RETURNED", + check(*context.connection, "AttrGet cbf_get_data ROWS_RETURNED", OracleSQL_driver->OCIAttrGet( (CONST dvoid *) bindp, OCI_HTYPE_BIND, (dvoid *)&rows, - (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(sizeof(OracleSQL_query_lobs::return_rows::return_row)*rows); + (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.connection->errhp)) ; + 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.services, *context.cs, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc( - (dvoid *) context.cs->envhp, (dvoid **)&var.locator, + check(*context.connection, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc( + (dvoid *) context.connection->envhp, (dvoid **)&var.locator, (ub4)OCI_DTYPE_LOB, 0, (dvoid **)0)); @@ -1031,12 +1412,6 @@ static sb4 cbf_get_data(dvoid *ctxp, return OCI_CONTINUE; } -void tolower(char *out, const char *in, size_t size) { - while(size--) - *out++=tolower(*in++); -} - extern "C" SQL_Driver *SQL_DRIVER_CREATE() { - //_asm int 3; return OracleSQL_driver=new OracleSQL_Driver(); }