// Copyright (c) 1999-2001 David Muse // See the file COPYING for more information #include #include #include #include #include #include #include #include #include #define MAX_BYTES_PER_CHAR 4 oracle8connection::oracle8connection() : sqlrconnection_svr() { statementmode=OCI_DEFAULT; #ifdef OCI_ATTR_PROXY_CREDENTIALS newsession=NULL; #endif } oracle8connection::~oracle8connection() { } uint16_t oracle8connection::getNumberOfConnectStringVars() { return NUM_CONNECT_STRING_VARS; } void oracle8connection::handleConnectString() { setUser(connectStringValue("user")); setPassword(connectStringValue("password")); sid=connectStringValue("oracle_sid"); home=connectStringValue("oracle_home"); nlslang=connectStringValue("nls_lang"); const char *autocom=connectStringValue("autocommit"); setAutoCommitBehavior((autocom && !charstring::compareIgnoringCase(autocom,"yes"))); fetchatonce=charstring::toUnsignedInteger( connectStringValue("fetchatonce")); if (!fetchatonce) { fetchatonce=FETCH_AT_ONCE; } maxselectlistsize=charstring::toUnsignedInteger( connectStringValue("maxselectlistsize")); if (!maxselectlistsize) { maxselectlistsize=MAX_SELECT_LIST_SIZE; } maxitembuffersize=charstring::toUnsignedInteger( connectStringValue("maxitembuffersize")); if (!maxitembuffersize) { maxitembuffersize=MAX_ITEM_BUFFER_SIZE; } if (maxitembuffersizemaxselectlistsize]; columnnames=new char *[oracle8conn->maxselectlistsize]; def=new OCIDefine *[oracle8conn->maxselectlistsize]; def_lob=new OCILobLocator **[oracle8conn->maxselectlistsize]; def_buf=new ub1 *[oracle8conn->maxselectlistsize]; def_indp=new sb2 *[oracle8conn->maxselectlistsize]; def_col_retlen=new ub2 *[oracle8conn->maxselectlistsize]; def_col_retcode=new ub2 *[oracle8conn->maxselectlistsize]; for (uint16_t i=0; imaxselectlistsize; i++) { def_lob[i]=new OCILobLocator *[oracle8conn->fetchatonce]; for (uint32_t j=0; jfetchatonce; j++) { def_lob[i][j]=NULL; } def_buf[i]=new ub1[oracle8conn->fetchatonce* oracle8conn->maxitembuffersize]; def_indp[i]=new sb2[oracle8conn->fetchatonce]; def_col_retlen[i]=new ub2[oracle8conn->fetchatonce]; def_col_retcode[i]=new ub2[oracle8conn->fetchatonce]; def[i]=NULL; } #ifdef HAVE_ORACLE_8i createtemp.compile("(create|CREATE)[ \\t\\n\\r]+(global|GLOBAL)[ \\t\\n\\r]+(temporary|TEMPORARY)[ \\t\\n\\r]+(table|TABLE)[ \\t\\n\\r]+"); preserverows.compile("(on|ON)[ \\t\\n\\r]+(commit|COMMIT)[ \\t\\n\\r]+(preserve|PRESERVE)[ \\t\\n\\r]+(rows|ROWS)"); #endif } oracle8cursor::~oracle8cursor() { delete errormessage; for (uint16_t i=0; imaxselectlistsize; i++) { delete[] def_col_retcode[i]; delete[] def_col_retlen[i]; delete[] def_indp[i]; delete[] def_lob[i]; delete[] def_buf[i]; } for (uint16_t i=0; ienv,(dvoid **)&stmt, OCI_HTYPE_STMT,(size_t)0, (dvoid **)0)!=OCI_SUCCESS) { return false; } // set the number of rows to prefetch if (OCIAttrSet((dvoid *)stmt,OCI_HTYPE_STMT, (dvoid *)&(oracle8conn->fetchatonce),(ub4)0, OCI_ATTR_PREFETCH_ROWS, (OCIError *)oracle8conn->err)!=OCI_SUCCESS) { return false; } return sqlrcursor_svr::openCursor(id); } bool oracle8cursor::closeCursor() { return (OCIHandleFree(stmt,OCI_HTYPE_STMT)==OCI_SUCCESS); } bool oracle8cursor::prepareQuery(const char *query, uint32_t length) { // keep a pointer to the query and length in case it needs to be // reprepared later this->query=(char *)query; this->length=length; // reset the statement type stmttype=0; // prepare the query return (OCIStmtPrepare(stmt,oracle8conn->err, (text *)query,(ub4)length, (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT)==OCI_SUCCESS); } void oracle8cursor::checkRePrepare() { // Oracle8 appears to have a bug. // You can prepare, bind, execute, rebind, re-execute, etc. with // selects, but not with DML, it has to be re-prepared. // What a drag. if (!prepared && stmttype && stmttype!=OCI_STMT_SELECT) { cleanUpData(true,true); prepareQuery(query,length); prepared=true; } } bool oracle8cursor::inputBindString(const char *variable, uint16_t variablesize, const char *value, uint16_t valuesize, int16_t *isnull) { checkRePrepare(); // the size of the value must include the terminating NULL if (charstring::isInteger(variable+1,variablesize-1)) { if (!charstring::toInteger(variable+1)) { return false; } if (OCIBindByPos(stmt,&inbindpp[inbindcount], oracle8conn->err, (ub4)charstring::toInteger(variable+1), (dvoid *)value,(sb4)valuesize+1, SQLT_STR, (dvoid *)isnull,(ub2 *)0, (ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { if (OCIBindByName(stmt,&inbindpp[inbindcount], oracle8conn->err, (text *)variable,(sb4)variablesize, (dvoid *)value,(sb4)valuesize+1, SQLT_STR, (dvoid *)isnull,(ub2 *)0, (ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } inbindcount++; return true; } bool oracle8cursor::inputBindInteger(const char *variable, uint16_t variablesize, int64_t *value) { checkRePrepare(); inintbindstring[inbindcount]=charstring::parseNumber(*value); if (charstring::isInteger(variable+1,variablesize-1)) { if (!charstring::toInteger(variable+1)) { return false; } if (OCIBindByPos(stmt,&inbindpp[inbindcount], oracle8conn->err, (ub4)charstring::toInteger(variable+1), (dvoid *)inintbindstring[inbindcount], (sb4)charstring::length( inintbindstring[inbindcount])+1, SQLT_STR, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { if (OCIBindByName(stmt,&inbindpp[inbindcount], oracle8conn->err, (text *)variable,(sb4)variablesize, (dvoid *)inintbindstring[inbindcount], (sb4)charstring::length( inintbindstring[inbindcount])+1, SQLT_STR, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } inbindcount++; return true; } bool oracle8cursor::inputBindDouble(const char *variable, uint16_t variablesize, double *value, uint32_t precision, uint32_t scale) { checkRePrepare(); if (charstring::isInteger(variable+1,variablesize-1)) { if (!charstring::toInteger(variable+1)) { return false; } if (OCIBindByPos(stmt,&inbindpp[inbindcount], oracle8conn->err, (ub4)charstring::toInteger(variable+1), (dvoid *)value,(sb4)sizeof(double), SQLT_FLT, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { if (OCIBindByName(stmt,&inbindpp[inbindcount], oracle8conn->err, (text *)variable,(sb4)variablesize, (dvoid *)value,(sb4)sizeof(double), SQLT_FLT, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } inbindcount++; return true; } bool oracle8cursor::outputBindString(const char *variable, uint16_t variablesize, char *value, uint16_t valuesize, int16_t *isnull) { checkRePrepare(); outintbindstring[outbindcount]=NULL; if (charstring::isInteger(variable+1,variablesize-1)) { if (!charstring::toInteger(variable+1)) { return false; } if (OCIBindByPos(stmt,&outbindpp[outbindcount], oracle8conn->err, (ub4)charstring::toInteger(variable+1), (dvoid *)value, (sb4)valuesize, SQLT_STR, (dvoid *)isnull,(ub2 *)0, (ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { if (OCIBindByName(stmt,&outbindpp[outbindcount], oracle8conn->err, (text *)variable,(sb4)variablesize, (dvoid *)value, (sb4)valuesize, SQLT_STR, (dvoid *)isnull,(ub2 *)0, (ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } outbindcount++; return true; } bool oracle8cursor::outputBindInteger(const char *variable, uint16_t variablesize, int64_t *value, int16_t *isnull) { checkRePrepare(); outintbindstring[outbindcount]=new char[21]; rawbuffer::zero(outintbindstring[outbindcount],21); outintbind[outbindcount]=value; if (charstring::isInteger(variable+1,variablesize-1)) { if (!charstring::toInteger(variable+1)) { return false; } if (OCIBindByPos(stmt,&outbindpp[outbindcount], oracle8conn->err, (ub4)charstring::toInteger(variable+1), (dvoid *)outintbindstring[outbindcount], (sb4)21, SQLT_STR, (dvoid *)isnull,(ub2 *)0, (ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { if (OCIBindByName(stmt,&outbindpp[outbindcount], oracle8conn->err, (text *)variable,(sb4)variablesize, (dvoid *)outintbindstring[outbindcount], (sb4)21, SQLT_STR, (dvoid *)isnull,(ub2 *)0, (ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } outbindcount++; return true; } bool oracle8cursor::outputBindDouble(const char *variable, uint16_t variablesize, double *value, uint32_t *precision, uint32_t *scale, int16_t *isnull) { checkRePrepare(); outintbindstring[outbindcount]=NULL; if (charstring::isInteger(variable+1,variablesize-1)) { if (!charstring::toInteger(variable+1)) { return false; } if (OCIBindByPos(stmt,&outbindpp[outbindcount], oracle8conn->err, (ub4)charstring::toInteger(variable+1), (dvoid *)value,(sb4)sizeof(double), SQLT_FLT, (dvoid *)isnull,(ub2 *)0, (ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { if (OCIBindByName(stmt,&outbindpp[outbindcount], oracle8conn->err, (text *)variable,(sb4)variablesize, (dvoid *)value,(sb4)sizeof(double), SQLT_FLT, (dvoid *)isnull,(ub2 *)0, (ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } outbindcount++; return true; } #ifdef HAVE_ORACLE_8i bool oracle8cursor::inputBindBlob(const char *variable, uint16_t variablesize, const char *value, uint32_t valuesize, int16_t *isnull) { return inputBindGenericLob(variable,variablesize, value,valuesize,isnull, OCI_TEMP_BLOB,SQLT_BLOB); } bool oracle8cursor::inputBindClob(const char *variable, uint16_t variablesize, const char *value, uint32_t valuesize, int16_t *isnull) { return inputBindGenericLob(variable,variablesize, value,valuesize,isnull, OCI_TEMP_CLOB,SQLT_CLOB); } bool oracle8cursor::inputBindGenericLob(const char *variable, uint16_t variablesize, const char *value, uint32_t valuesize, int16_t *isnull, ub1 temptype, ub2 type) { checkRePrepare(); // create a temporary lob, write the value to it if (OCIDescriptorAlloc((dvoid *)oracle8conn->env, (dvoid **)&inbind_lob[inbindlobcount], (ub4)OCI_DTYPE_LOB, (size_t)0,(dvoid **)0)!=OCI_SUCCESS) { return false; } if (OCILobCreateTemporary(oracle8conn->svc,oracle8conn->err, inbind_lob[inbindlobcount], //(ub2)0,SQLCS_IMPLICIT, (ub2)OCI_DEFAULT,OCI_DEFAULT, temptype,OCI_ATTR_NOCACHE, OCI_DURATION_SESSION)!=OCI_SUCCESS) { OCIDescriptorFree(inbind_lob[inbindlobcount],OCI_DTYPE_LOB); return false; } if (OCILobOpen(oracle8conn->svc,oracle8conn->err, inbind_lob[inbindlobcount], OCI_LOB_READWRITE)!=OCI_SUCCESS) { OCILobFreeTemporary(oracle8conn->svc,oracle8conn->err, inbind_lob[inbindlobcount]); OCIDescriptorFree(inbind_lob[inbindlobcount],OCI_DTYPE_LOB); return false; } ub4 size=valuesize; if (OCILobWrite(oracle8conn->svc,oracle8conn->err, inbind_lob[inbindlobcount],&size,1, (void *)value,valuesize, OCI_ONE_PIECE,(dvoid *)0, (sb4 (*)(dvoid*,dvoid*,ub4*,ub1 *))0, 0,SQLCS_IMPLICIT)!=OCI_SUCCESS) { OCILobClose(oracle8conn->svc,oracle8conn->err, inbind_lob[inbindlobcount]); OCILobFreeTemporary(oracle8conn->svc,oracle8conn->err, inbind_lob[inbindlobcount]); OCIDescriptorFree(inbind_lob[inbindlobcount],OCI_DTYPE_LOB); return false; } // bind the temporary lob if (charstring::isInteger(variable+1,variablesize-1)) { if (!charstring::toInteger(variable+1)) { return false; } if (OCIBindByPos(stmt,&inbindpp[inbindcount], oracle8conn->err, (ub4)charstring::toInteger(variable+1), (dvoid *)&inbind_lob[inbindlobcount],(sb4)0, type, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { if (OCIBindByName(stmt,&inbindpp[inbindcount], oracle8conn->err, (text *)variable,(sb4)variablesize, (dvoid *)&inbind_lob[inbindlobcount],(sb4)0, type, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } inbindlobcount++; inbindcount++; return true; } bool oracle8cursor::outputBindBlob(const char *variable, uint16_t variablesize, uint16_t index, int16_t *isnull) { return outputBindGenericLob(variable,variablesize,index, isnull,SQLT_BLOB); } bool oracle8cursor::outputBindClob(const char *variable, uint16_t variablesize, uint16_t index, int16_t *isnull) { return outputBindGenericLob(variable,variablesize,index, isnull,SQLT_CLOB); } bool oracle8cursor::outputBindGenericLob(const char *variable, uint16_t variablesize, uint16_t index, int16_t *isnull, ub2 type) { checkRePrepare(); // allocate a lob descriptor if (OCIDescriptorAlloc((dvoid *)oracle8conn->env, (dvoid **)&outbind_lob[index],(ub4)OCI_DTYPE_LOB, (size_t)0,(dvoid **)0)!=OCI_SUCCESS) { return false; } outbindlobcount=index+1; // bind the lob descriptor if (charstring::isInteger(variable+1,variablesize-1)) { if (!charstring::toInteger(variable+1)) { return false; } if (OCIBindByPos(stmt,&outbindpp[outbindcount], oracle8conn->err, (ub4)charstring::toInteger(variable+1), (dvoid *)&outbind_lob[index], (sb4)sizeof(OCILobLocator *), type, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { if (OCIBindByName(stmt,&outbindpp[outbindcount], oracle8conn->err, (text *)variable,(sb4)variablesize, (dvoid *)&outbind_lob[index], (sb4)sizeof(OCILobLocator *), type, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } outbindcount++; return true; } bool oracle8cursor::outputBindCursor(const char *variable, uint16_t variablesize, sqlrcursor_svr *cursor) { checkRePrepare(); if (charstring::isInteger(variable+1,variablesize-1)) { if (!charstring::toInteger(variable+1)) { return false; } if (OCIBindByPos(stmt,&curbindpp[curbindcount], oracle8conn->err, (ub4)charstring::toInteger(variable+1), (dvoid *)&(((oracle8cursor *)cursor)->stmt), (sb4)0, SQLT_RSET, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { if (OCIBindByName(stmt,&curbindpp[curbindcount], oracle8conn->err, (text *)variable,(sb4)variablesize, (dvoid *)&(((oracle8cursor *)cursor)->stmt), (sb4)0, SQLT_RSET, (dvoid *)0,(ub2 *)0,(ub2 *)0,0,(ub4 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } curbindcount++; return true; } void oracle8cursor::returnOutputBindBlob(uint16_t index) { // FIXME: call OCILobGetChunkSize to determine the size of this buffer // rather than maxitembuffersize, it will improve performance ub1 buf[oracle8conn->maxitembuffersize+1]; sendLob(outbind_lob[index],buf); } void oracle8cursor::returnOutputBindClob(uint16_t index) { // FIXME: call OCILobGetChunkSize to determine the size of this buffer // rather than maxitembuffersize, it will improve performance ub1 buf[oracle8conn->maxitembuffersize+1]; sendLob(outbind_lob[index],buf); } void oracle8cursor::sendLob(OCILobLocator *lob, ub1 *buf) { // When reading from a clob, you have to tell it how // many characters to read, and the offset must be // specified in characters too. But the OCILobRead // returns the number of bytes read, not characters // and there's no good way to convert the number of // bytes read into the number of characters. So, we'll // have to try to read the same number of characters // each time and make sure that we don't try to read // more than will fit in our buffer. That way, we can // be sure that we were able to read them all and will // be able to reliably calculate the next offset. ub4 charstoread=oracle8conn->maxitembuffersize/MAX_BYTES_PER_CHAR; // handle lob datatypes // handle lob datatypes ub4 retlen=charstoread; ub4 offset=1; bool start=true; // Get the length of the lob. If we fail to read the // length, send a NULL field. Unfortunately OCILobGetLength // has no way to express that a LOB is NULL, the result is // "undefined" in that case. ub4 loblength=0; if (OCILobGetLength(oracle8conn->svc, oracle8conn->err, lob,&loblength)!=OCI_SUCCESS) { conn->sendNullField(); return; } // handle empty lob's if (!loblength) { conn->startSendingLong(0); conn->sendLongSegment("",0); conn->endSendingLong(); return; } // We should be able to call OCILobRead over and over, // as long as it returns OCI_NEED_DATA, but OCILobRead // fails to return OCI_NEED_DATA (at least in version // 8.1.7 for Linux), so we have to do this instead. // OCILobRead appears to return OCI_INVALID_HANDLE when // the LOB is NULL, but this is not documented anywhere. while (retlen) { // initialize retlen to the number of characters we want to read retlen=charstoread; // read a segment from the lob sword retval=OCILobRead(oracle8conn->svc, oracle8conn->err, lob, &retlen, offset, (dvoid *)buf, oracle8conn->maxitembuffersize, (dvoid *)NULL, (sb4(*)(dvoid *,CONST dvoid *,ub4,ub1))NULL, (ub2)0, (ub1)SQLCS_IMPLICIT); // OCILobRead returns OCI_INVALID_HANDLE if // the LOB is NULL. In that case, return a // NULL field. // Otherwise, start sending the field (if we // haven't already), send a segment of the LOB, // move to the next segment and reset the // amount to read. if (retval==OCI_INVALID_HANDLE) { conn->sendNullField(); break; } else { if (start) { conn->startSendingLong(loblength); start=false; } conn->sendLongSegment((char *)buf,(int32_t)retlen); offset=offset+charstoread; } } // if we ever started sending a LOB, // finish sending it now if (!start) { conn->endSendingLong(); } } void oracle8cursor::checkForTempTable(const char *query, uint32_t length) { char *ptr=(char *)query; char *endptr=(char *)query+length; // skip any leading comments if (!skipWhitespace(&ptr,endptr) || !skipComment(&ptr,endptr) || !skipWhitespace(&ptr,endptr)) { return; } // look for "create global temporary table " if (createtemp.match(ptr)) { ptr=createtemp.getSubstringEnd(0); } else { return; } // get the table name stringbuffer tablename; while (ptr && *ptr && *ptr!=' ' && *ptr!='\n' && *ptr!=' ' && ptraddSessionTempTableForTrunc(tablename.getString()); } } #endif bool oracle8cursor::executeQuery(const char *query, uint32_t length, bool execute) { // initialize the column count ncols=0; // get the type of the query (select, insert, update, etc...) if (OCIAttrGet(stmt,OCI_HTYPE_STMT, (dvoid *)&stmttype,(ub4 *)NULL, OCI_ATTR_STMT_TYPE,oracle8conn->err)!=OCI_SUCCESS) { return false; } #ifdef HAVE_ORACLE_8i if (stmttype==OCI_STMT_CREATE) { checkForTempTable(query,length); } #endif // set up how many times to iterate; // 0 for selects, 1 for non-selects ub4 iters=1; if (stmttype==OCI_STMT_SELECT) { iters=0; } // initialize row counters row=0; maxrow=0; totalrows=0; // execute the query if (execute) { if (OCIStmtExecute(oracle8conn->svc,stmt, oracle8conn->err,iters, (ub4)0,NULL,NULL, oracle8conn->statementmode)!=OCI_SUCCESS) { return false; } // reset the prepared flag prepared=false; } // if the query is a select, describe/define it if (stmttype==OCI_STMT_SELECT) { // get the column count if (OCIAttrGet((dvoid *)stmt,OCI_HTYPE_STMT, (dvoid *)&ncols,(ub4 *)NULL, OCI_ATTR_PARAM_COUNT, oracle8conn->err)!=OCI_SUCCESS) { return false; } // run through the columns... for (sword i=0; ierr, (dvoid **)&desc[i].paramd, i+1)!=OCI_SUCCESS) { return false; } // get the column name if (OCIAttrGet((dvoid *)desc[i].paramd, OCI_DTYPE_PARAM, (dvoid **)&desc[i].buf, (ub4 *)&desc[i].buflen, (ub4)OCI_ATTR_NAME, oracle8conn->err)!=OCI_SUCCESS) { return false; } // get the column type if (OCIAttrGet((dvoid *)desc[i].paramd, OCI_DTYPE_PARAM, (dvoid *)&desc[i].dbtype,(ub4 *)NULL, (ub4)OCI_ATTR_DATA_TYPE, oracle8conn->err)!=OCI_SUCCESS) { return false; } // get the column precision if (OCIAttrGet((dvoid *)desc[i].paramd, OCI_DTYPE_PARAM, (dvoid *)&desc[i].precision,(ub4 *)NULL, (ub4)OCI_ATTR_PRECISION, oracle8conn->err)!=OCI_SUCCESS) { return false; } // get the column scale if (OCIAttrGet((dvoid *)desc[i].paramd, OCI_DTYPE_PARAM, (dvoid *)&desc[i].scale,(ub4 *)NULL, (ub4)OCI_ATTR_SCALE, oracle8conn->err)!=OCI_SUCCESS) { return false; } // get whether the column is nullable if (OCIAttrGet((dvoid *)desc[i].paramd, OCI_DTYPE_PARAM, (dvoid *)&desc[i].nullok,(ub4 *)NULL, (ub4)OCI_ATTR_IS_NULL, oracle8conn->err)!=OCI_SUCCESS) { return false; } // is the column a LOB? if (desc[i].dbtype==BLOB_TYPE || desc[i].dbtype==CLOB_TYPE || desc[i].dbtype==BFILE_TYPE) { // return 0 for the size of lobs desc[i].dbsize=0; // set the NULL indicators to false rawbuffer::zero(def_indp[i], sizeof(sb2)* oracle8conn->fetchatonce); // allocate a lob descriptor for (uint32_t j=0; jfetchatonce; j++) { if (OCIDescriptorAlloc( (void *)oracle8conn->env, (void **)&def_lob[i][j], OCI_DTYPE_LOB,0,0)) { return false; } } // define the column as a lob if (OCIDefineByPos(stmt,&def[i], oracle8conn->err, i+1, (dvoid *)def_lob[i], (sb4)-1, desc[i].dbtype, (dvoid *)0, 0, (ub2 *)0, OCI_DEFAULT)!=OCI_SUCCESS) { return false; } } else { // get the column size if (OCIAttrGet((dvoid *)desc[i].paramd, OCI_DTYPE_PARAM, (dvoid *)&desc[i].dbsize, (ub4 *)NULL, (ub4)OCI_ATTR_DATA_SIZE, oracle8conn->err)!=OCI_SUCCESS) { return false; } // if the column is not a LOB, define it, // translated to a NULL terminated string if (OCIDefineByPos(stmt,&def[i], oracle8conn->err, i+1, (dvoid *)def_buf[i], (sb4)oracle8conn->maxitembuffersize, SQLT_STR, (dvoid *)def_indp[i], (ub2 *)def_col_retlen[i], def_col_retcode[i], OCI_DEFAULT)!=OCI_SUCCESS) { return false; } // set the lob member to NULL for (uint32_t j=0; jfetchatonce; j++) { def_lob[i][j]=NULL; } } } } // convert integer output binds for (uint16_t i=0; ierr,1, (text *)0,&errcode, message,sizeof(message), OCI_HTYPE_ERROR); message[1023]=(char)NULL; // check for dead connection or shutdown in progress if (errcode==3114 || errcode==3113 || errcode==1089) { *liveconnection=false; } else { *liveconnection=true; } // only return an error message if the error wasn't a dead database delete errormessage; errormessage=new stringbuffer(); if (*liveconnection) { errormessage->append((const char *)message); } return errormessage->getString(); } bool oracle8cursor::knowsRowCount() { return false; } uint64_t oracle8cursor::rowCount() { return 0; } bool oracle8cursor::knowsAffectedRows() { return true; } uint64_t oracle8cursor::affectedRows() { // get the affected row count ub4 rows; if (OCIAttrGet(stmt,OCI_HTYPE_STMT, (dvoid *)&rows,(ub4 *)NULL, OCI_ATTR_ROW_COUNT,oracle8conn->err)==OCI_SUCCESS) { return rows; } return 0; } uint32_t oracle8cursor::colCount() { return ncols; } const char * const * oracle8cursor::columnNames() { for (sword i=0; isendColumnDefinition((char *)desc[i].buf, (uint16_t)desc[i].buflen, type, (uint32_t)desc[i].dbsize, (uint32_t)desc[i].precision, (uint32_t)desc[i].scale, (uint16_t)desc[i].nullok,0,0, 0,0,0,binary,0); } } bool oracle8cursor::noRowsToReturn() { return (stmttype!=OCI_STMT_SELECT); } bool oracle8cursor::skipRow() { if (fetchRow()) { row++; return true; } return false; } bool oracle8cursor::fetchRow() { if (row==oracle8conn->fetchatonce) { row=0; } if (row>0 && row==maxrow) { return false; } if (!row) { OCIStmtFetch(stmt,oracle8conn->err,oracle8conn->fetchatonce, OCI_FETCH_NEXT,OCI_DEFAULT); ub4 currentrow; OCIAttrGet(stmt,OCI_HTYPE_STMT, (dvoid *)¤trow,(ub4 *)NULL, OCI_ATTR_ROW_COUNT,oracle8conn->err); if (currentrow==totalrows) { return false; } maxrow=currentrow-totalrows; totalrows=currentrow; } return true; } void oracle8cursor::returnRow() { for (sword col=0; colsendNullField(); continue; } // in OCI8, longs are just like other datatypes, but LOBS // are different if (desc[col].dbtype==BLOB_TYPE || desc[col].dbtype==CLOB_TYPE || desc[col].dbtype==BFILE_TYPE) { // send the lob sendLob(def_lob[col][row], &def_buf[col][row*oracle8conn-> maxitembuffersize]); #ifdef HAVE_ORACLE_8i // if the lob is temporary, deallocate it boolean templob; if (OCILobIsTemporary(oracle8conn->env, oracle8conn->err, def_lob[col][row], &templob)!=OCI_SUCCESS) { continue; } if (templob) { OCILobFreeTemporary(oracle8conn->svc, oracle8conn->err, def_lob[col][row]); } #endif continue; } // handle normal datatypes conn->sendField((const char *) &def_buf[col] [row*oracle8conn-> maxitembuffersize], (uint32_t)def_col_retlen[col][row]); } // increment the row counter row++; } void oracle8cursor::cleanUpData(bool freeresult, bool freebinds) { // OCI8 version of ocan(), but since it uses OCIStmtFetch we // only want to run it if the statement was a select if (freeresult && stmttype==OCI_STMT_SELECT) { OCIStmtFetch(stmt,oracle8conn->err,0, OCI_FETCH_NEXT,OCI_DEFAULT); } // free row/column resources if (freeresult) { for (ub4 i=0; imaxselectlistsize; i++) { for (uint32_t j=0; jfetchatonce; j++) { if (def_lob[i][j]) { OCIDescriptorFree(def_lob[i][j], OCI_DTYPE_LOB); def_lob[i][j]=NULL; } } if (def[i]) { OCIHandleFree(def[i],OCI_HTYPE_DEFINE); def[i]=NULL; } } } if (freebinds) { // free lob bind resources #ifdef HAVE_ORACLE_8i for (uint16_t i=0; isvc, oracle8conn->err, inbind_lob[i]); OCILobClose(oracle8conn->svc,oracle8conn->err, inbind_lob[i]); OCIDescriptorFree(inbind_lob[i],OCI_DTYPE_LOB); } for (uint16_t i=0; isvc, oracle8conn->err, outbind_lob[i]); OCILobClose(oracle8conn->svc, oracle8conn->err, outbind_lob[i]); OCIDescriptorFree(outbind_lob[i], OCI_DTYPE_LOB); } } inbindlobcount=0; outbindlobcount=0; #endif // free regular bind resources for (uint16_t i=0; i