X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fdbms.oracle%2FOutputBind.cpp;fp=source%2Fdbms.oracle%2FOutputBind.cpp;h=9b18d68683412ca1344210f0d41ccce414ece939;hb=78be86969d2f26a9084b0c4af6ce43d5fa4ed3fd;hp=0000000000000000000000000000000000000000;hpb=a3b95648bd76140ef55e0b5941d423eee6c3856f;p=anna.git diff --git a/source/dbms.oracle/OutputBind.cpp b/source/dbms.oracle/OutputBind.cpp new file mode 100644 index 0000000..9b18d68 --- /dev/null +++ b/source/dbms.oracle/OutputBind.cpp @@ -0,0 +1,278 @@ +// ANNA - Anna is Not Nothingness Anymore // +// // +// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo // +// // +// See project site at http://redmine.teslayout.com/projects/anna-suite // +// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE // + + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace anna; +using namespace std; + +OutputBind::OutputBind(const char* name, dbms::Data& data) : + dbms::OutputBind(name, data), + BaseBind(data), + a_ociDefine(NULL) { +} + +OutputBind::~OutputBind() { +} + +void OutputBind::prepare(dbms::Statement* dbmsStatement, dbms::Connection* connection, const int pos) +throw(dbms::DatabaseException) { + if(a_ociDefine != NULL) + return; + + Database& database(static_cast (dbmsStatement->getDatabase())); + OCIError* error = database.getErrorHandler(); + Statement* statement(static_cast (dbmsStatement)); + dbms::Data& data = anna::dbms::Bind::getData(); + oci_param ociparam = getOCIParam(database, static_cast (connection), data); + + if(data.isNulleable() == false) { + anna_dbms_oracle_check( + OCIDefineByPos( + *statement, &a_ociDefine, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type, + 0, ociparam.length, 0, OCI_DEFAULT + ), + error + ); + } else { + anna_dbms_oracle_check( + OCIDefineByPos( + *statement, &a_ociDefine, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type, + &a_nullIndicator, ociparam.length, 0, OCI_DEFAULT + ), + error + ); + } + + LOGDEBUG( + std::string msg("anna::dbms::oracle::OutputBind::prepare | "); + msg += asString(); + msg += " | Sentence: "; + msg += statement->getName(); + msg += " | Position: "; + msg += functions::asString(pos); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); +} + +//------------------------------------------------------------------------------- +// Transfiere la informacin obtenida desde Oracle. Todos los comprobados en �te +// m�odo son parametros que modificados al ejecuta la sentencia Oracle debido cmo +// hemos invocamo al m�odo OCIDefineByPos +// +// Todo esto se podr� haber hecho en la anna::dbms::DataBlock pero exigir� +// definir una clase distinta para cada RDBMS. Creo que los Binds particulares de +// cada base de datos se ocupen toda la complejidad de convertir los datos. +// +// (1) Truco para fijar el contenido y la longitud actual. +//------------------------------------------------------------------------------- +void OutputBind::decode() const +throw(RuntimeException) { + OutputBind* _this = const_cast (this); + char* str; + Data& data = _this->getData(); + data.setNull(a_nullIndicator < 0); + + switch(data.getType()) { + case Data::Type::String: + str = (char*) data.getBuffer(); + + if(data.isNull() == true) + *str = 0; + else + dbms::String::strip(str); + + break; + case Data::Type::Integer: + throw RuntimeException("anna::dbms::oracle::OutputBind::decode not implemented for Data::Type::Integer", ANNA_FILE_LOCATION); + break; + case Data::Type::Float: + decodeFloat(data); + break; + case Data::Type::ShortBlock: + decodeShortBlock(data); + break; + case Data::Type::LongBlock: + decodeLongBlock(data); + break; + case Data::Type::Date: + case Data::Type::TimeStamp: + + try { + decodeDate(data); + } catch(DatabaseException& edb) { + throw RuntimeException(edb); + } + + break; + } +} + +void OutputBind::decodeFloat(dbms::Data& data) const +throw(RuntimeException) { + dbms::Float& _float = static_cast (data); + + if(data.isNull() == true) { + _float = 0.0; + return; + } + + char* _data = (char*) a_ofb->getData(); + const char decimalPoint = oracle::Database::getDecimalPoint(); + + if(decimalPoint != 0) { + char* point = anna_strchr(_data, decimalPoint); + + if(point != NULL) + *point = '.'; + } + + sscanf(_data, _float.getFormat(), (float*) _float.getBuffer()); +} + +void OutputBind::decodeShortBlock(dbms::Data& data) const +throw(RuntimeException) { + const anna::DataBlock& constdbms(static_cast (data).getValue()); + anna::DataBlock& dataBlock(const_cast (constdbms)); + + if(data.isNull() == true) { + dataBlock.clear(); + return; + } + + const char* src = a_ofb->getData(); + + char* dest = (char*) dataBlock.getData(); + + unsigned char hex; + + int j = 0; + + for(int i = 1; i < a_length; i += 2, j ++) { + hex = asByte(src [i - 1]) << 4; + hex |= asByte(src [i]); + dest [j] = hex; + } + + dataBlock.clear(); + dataBlock.allocate(j); // (1) +} + +//-------------------------------------------------------------------------------------------- +// (1) Offset = 1 => primer caracter. +//-------------------------------------------------------------------------------------------- +void OutputBind::decodeLongBlock(dbms::Data& data) const +throw(RuntimeException) { + const anna::DataBlock& constdbms(static_cast (data).getValue()); + anna::DataBlock& dataBlock(const_cast (constdbms)); + dataBlock.clear(); + + if(data.isNull() == true) + return; + + ub1* buffer; + ub4 maxLength; + ub4 length; + sword ret; + bool stop = false; + ub4 offset = 1; // (1) + + try { + buffer = (ub1*) a_ofb->getData(); + maxLength = a_ofb->getSize(); + length = 0; + + do { + ret = OCILobRead(a_blob.context, a_blob.error, a_blob.handle, &length, offset, buffer, maxLength, 0, 0, 0, SQLCS_IMPLICIT); + + switch(ret) { + case OCI_SUCCESS: + dataBlock += anna::DataBlock((const char*) buffer, length, false); + stop = true; + break; + case OCI_NEED_DATA: + dataBlock += anna::DataBlock((const char*) buffer, length, false); + offset += length; + break; + default: + throw dbms::DatabaseException(oracle::ResultCode(ret, a_blob.error), ANNA_FILE_LOCATION); + } + } while(stop == false); + } catch(dbms::DatabaseException& edbms) { + throw RuntimeException(edbms); + } +} + +void OutputBind::do_write(const dbms::LongBlock& data) const +throw(RuntimeException, dbms::DatabaseException) { + const anna::DataBlock& dataBlock = data.getValue(); + + if(a_blob.handle == NULL) { + string msg("anna::dbms::oracle::OutputBind::do_write | "); + msg += data.asString(); + msg += " | BLOB must be loaded before modification"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + ub1* buffer = (ub1*) dataBlock.getData(); + ub4 length = dataBlock.getSize(); + anna_dbms_oracle_check( + OCILobWrite(a_blob.context, a_blob.error, a_blob.handle, &length, (ub4) 1, buffer, length, OCI_ONE_PIECE, 0, 0, 0, SQLCS_IMPLICIT), + a_blob.error + ); +} + +void OutputBind::decodeDate(dbms::Data& data) const +throw(RuntimeException, dbms::DatabaseException) { + if(data.isNull() == true) + return; + + Date& date = static_cast (data); + sb2 year; + ub1 month, day; + anna_dbms_oracle_check( + OCIDateTimeGetDate(a_datetime.env, a_datetime.error, a_datetime.handle, &year, &month, &day), + a_datetime.error + ); + date.setYear(year); + date.setMonth(month); + date.setDay(day); + ub1 hour, min, sec; + ub4 fsec; + sword status = OCIDateTimeGetTime(a_datetime.env, a_datetime.error, a_datetime.handle, &hour, &min, &sec, &fsec); + + if(status == OCI_SUCCESS) { + date.setHour(hour); + date.setMinute(min); + date.setSecond(sec); + + if(data.getType() == Data::Type::TimeStamp) + static_cast (data).setFractionalSecond(fsec / 1000); + } else { + date.setHour(0); + date.setMinute(0); + date.setSecond(0); + + if(data.getType() == Data::Type::TimeStamp) + static_cast (data).setFractionalSecond(0); + } +}