+++ /dev/null
-// 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 <oci.h>
-#include <orl.h>
-
-#include <anna/config/defines.hpp>
-#include <anna/core/tracing/Logger.hpp>
-#include <anna/core/DataBlock.hpp>
-
-#include <anna/dbms/Float.hpp>
-#include <anna/dbms/ShortBlock.hpp>
-#include <anna/dbms/LongBlock.hpp>
-#include <anna/dbms/String.hpp>
-#include <anna/dbms/Date.hpp>
-#include <anna/dbms/TimeStamp.hpp>
-
-#include <anna/dbms.oracle/oracle.hpp>
-
-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 <Database&>(dbmsStatement->getDatabase()));
- OCIError* error = database.getErrorHandler();
- Statement* statement(static_cast <Statement*>(dbmsStatement));
- dbms::Data& data = anna::dbms::Bind::getData();
- oci_param ociparam = getOCIParam(database, static_cast <oracle::Connection*>(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 <OutputBind*>(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 <dbms::Float&>(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 <dbms::ShortBlock&>(data).getValue());
- anna::DataBlock& dataBlock(const_cast <anna::DataBlock&>(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 <dbms::LongBlock&>(data).getValue());
- anna::DataBlock& dataBlock(const_cast <anna::DataBlock&>(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 <Date&>(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 <dbms::TimeStamp&>(data).setFractionalSecond(fsec / 1000);
- } else {
- date.setHour(0);
- date.setMinute(0);
- date.setSecond(0);
-
- if(data.getType() == Data::Type::TimeStamp)
- static_cast <dbms::TimeStamp&>(data).setFractionalSecond(0);
- }
-}