--- sql/oracle/parser3oracle.C 2002/12/09 11:43:08 1.26 +++ sql/oracle/parser3oracle.C 2003/12/24 08:39:09 1.45 @@ -1,13 +1,13 @@ /** @file Parser Oracle driver. - Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) + Copyright(c) 2001, 2003 ArtLebedev Group (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 $"; +static const char *RCSId="$Id: parser3oracle.C,v 1.45 2003/12/24 08:39:09 paf Exp $"; #include "config_includes.h" @@ -38,7 +38,13 @@ inline int max(int a, int b) { return a> inline int min(int a, int b){ return a_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(void *connection) { OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection; if(setjmp(cs.mark)) - services._throw(cs.error); + cs.services->_throw(cs.error); - check(services, 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; } - 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++; + 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) { + case '\'': // "'" -> "''" + *to++='\''; + break; } - return result; - } else // estimate mode - return length*2; + *to++=*from++; + } + *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(services, cs, "HandleAlloc STMT", OCIHandleAlloc( + check(cs, "HandleAlloc STMT", OCIHandleAlloc( (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, (ub4)strlen((char *)statement), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)); { for(int i=0; icount; r++) { OCILobLocator *locator=rows->row[r].locator; - check(services, cs, "lobwrite", OCILobWrite ( + check(cs, "lobwrite", OCILobWrite ( cs.svchp, cs.errhp, locator, &bytes_to_write, 1, (dvoid *)lobs.items[i].data_ptr, (ub4)bytes_to_write, OCI_ONE_PIECE, @@ -587,7 +626,7 @@ private: // private funcs switch(stmt_type) { case OCI_STMT_SELECT: - fetch_table(services, cs, + fetch_table(cs, stmthp, offset, limit, handlers); break; @@ -600,18 +639,20 @@ private: // private funcs } } - void fetch_table(SQL_Driver_services& services, OracleSQL_connection_struct &cs, + void fetch_table(OracleSQL_connection_struct &cs, OCIStmt *stmthp, unsigned long offset, unsigned long limit, - SQL_Driver_query_event_handlers& handlers) { + SQL_Driver_query_event_handlers& handlers) + { + SQL_Driver_services& services=*cs.services; ub4 prefetch_rows=100; - check(services, cs, "AttrSet prefetch-rows", OCIAttrSet( + 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(services, cs, "AttrSet prefetch-memory", OCIAttrSet( + 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)); @@ -620,7 +661,7 @@ private: // private funcs ub2 dtype; text *col_name; - struct { + struct Col { ub2 type; char *str; OCILobLocator *var; @@ -635,125 +676,146 @@ private: // private funcs failed=true; goto cleanup; } else { - try { - - // 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)); - + // 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(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(cs, "get name", OCIAttrGet( + (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, + (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME, + (OCIError *)cs.errhp)); + + Col& col=cols[column_count-1]; + { + size_t length=(size_t)col_name_len; + char *ptr=(char *)services.malloc_atomic(length+1); + if( cs.options.bLowerCaseColumnNames ) + tolower(ptr, (char *)col_name, length); + else + memcpy(ptr, col_name, length); + ptr[length]=0; + check(cs, handlers.add_column(cs.sql_error, ptr, length)); + } + + ub2 coerce_type=dtype; + sb4 size=0; + void *ptr; + + switch(dtype) { + case SQLT_CLOB: { - 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) { - case SQLT_CLOB: - { - check(services, cs, "alloc output var desc", OCIDescriptorAlloc( - (dvoid *)cs.envhp, (dvoid **)(ptr=&cols[column_count-1].var), - (ub4)OCI_DTYPE_LOB, - 0, (dvoid **)0)); - - size=0; - break; - } - default: - coerce_type=SQLT_STR; - ptr=cols[column_count-1].str=(char *)services.malloc(MAX_OUT_STRING_LENGTH+1); - size=MAX_OUT_STRING_LENGTH; + check(cs, "alloc output var desc", OCIDescriptorAlloc( + (dvoid *)cs.envhp, (dvoid **)(ptr=&col.var), + (ub4)OCI_DTYPE_LOB, + 0, (dvoid **)0)); + + size=0; 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)); + default: + coerce_type=SQLT_STR; + ptr=col.str=(char *)services.malloc_atomic(MAX_OUT_STRING_LENGTH+1); + size=MAX_OUT_STRING_LENGTH; + break; } - handlers.before_rows(); + col.type=coerce_type; - for(unsigned long row=0; !limit||row=offset) { + check(cs, handlers.add_row(cs.sql_error)); + for(int i=0; i=offset) { - handlers.add_row(); - 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; - else - msg="[can not get error description]"; - break; + 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; + + // 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; } case OCI_NEED_DATA: msg="NEED_DATA"; break; @@ -969,14 +1031,18 @@ void check( 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. */ /* ----------------------------------------------------------------- */ static sb4 cbf_no_data( - dvoid *ctxp, - OCIBind *bindp, - ub4 iter, ub4 index, + dvoid* /*ctxp*/, + OCIBind* /*bindp*/, + ub4 /*iter*/, ub4 /*index*/, dvoid **bufpp, ub4 *alenpp, ub1 *piecep, @@ -995,7 +1061,7 @@ 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, @@ -1006,18 +1072,18 @@ static sb4 cbf_get_data(dvoid *ctxp, if(index==0) { 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( (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); + 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]; - 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, (ub4)OCI_DTYPE_LOB, 0, (dvoid **)0)); @@ -1033,10 +1099,14 @@ static sb4 cbf_get_data(dvoid *ctxp, void tolower(char *out, const char *in, size_t size) { while(size--) - *out++=tolower(*in++); + *out++=(char)tolower(*in++); } +void toupper(char *out, const char *in, size_t size) { + while(size--) + *out++=(char)toupper(*in++); +} + extern "C" SQL_Driver *SQL_DRIVER_CREATE() { - //_asm int 3; return OracleSQL_driver=new OracleSQL_Driver(); }