X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fdbms.oracle%2FInputBind.cpp;fp=source%2Fdbms.oracle%2FInputBind.cpp;h=c554843791b528c98b2e2dcee7e6cd6a35559315;hb=78be86969d2f26a9084b0c4af6ce43d5fa4ed3fd;hp=0000000000000000000000000000000000000000;hpb=a3b95648bd76140ef55e0b5941d423eee6c3856f;p=anna.git diff --git a/source/dbms.oracle/InputBind.cpp b/source/dbms.oracle/InputBind.cpp new file mode 100644 index 0000000..c554843 --- /dev/null +++ b/source/dbms.oracle/InputBind.cpp @@ -0,0 +1,208 @@ +// 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 std; +using namespace anna; + +InputBind::InputBind(const char* name, dbms::Data& data) : + dbms::InputBind(name, data), + BaseBind(data), + a_ociBind(NULL) { +} + +InputBind::~InputBind() { +} + +// Slo se invoca una vez. Establece las variables atrav� de las que nos vamos a poder +// comunicar con Oracle, para indicar la longitud de una variable, o su estado de nulo o +// no nulo. +void InputBind::prepare(dbms::Statement* dbmsStatement, dbms::Connection* connection, const int pos) +throw(RuntimeException, dbms::DatabaseException) { + if(a_ociBind != NULL) + return; + + Data& data = anna::dbms::Bind::getData(); + + if(data.getType() == Data::Type::LongBlock) { + string msg("anna::dbms::oracle::InputBind::prepare | "); + msg += data.asString(); + msg += " | This RDBMS doesn't support BLOB type as BindInput (see anna::dbms::OutputBind::write)"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + Database& database = static_cast (dbmsStatement->getDatabase()); + OCIError* error = database.getErrorHandler(); + Statement* statement(static_cast (dbmsStatement)); + oci_param ociparam = getOCIParam(database, static_cast (connection), data); + + if(data.isNulleable() == false) { + anna_dbms_oracle_check( + OCIBindByPos( + *statement, &a_ociBind, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type, + 0, ociparam.length, 0, 0, 0, OCI_DEFAULT + ), + error + ); + } else { + anna_dbms_oracle_check( + OCIBindByPos( + *statement, &a_ociBind, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type, + &a_nullIndicator, ociparam.length, 0, 0, 0, OCI_DEFAULT + ), + error + ); + } + + LOGDEBUG( + std::string msg("anna::dbms::oracle::InputBind::prepare | "); + msg += asString(); + msg += " | Sentence: "; + msg += statement->getName(); + msg += " | Position: "; + msg += functions::asString(pos); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); +} + +//------------------------------------------------------------------------------- +// Establece la informacin mediante la que conectamos con Oracle. Todos los +// par�etros que modificamos en �te m�odo tienen efecto en la llamada a Oracle +// debido cmo hemos invocamo al m�odo OCIBindByPos. +// +// 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. +//------------------------------------------------------------------------------- +void InputBind::code() const +throw(RuntimeException) { + InputBind* _this = const_cast (this); + Data& data = _this->getData(); + + if((_this->a_nullIndicator = data.isNull() ? -1 : 0) == -1) + return; + + switch(data.getType()) { + case Data::Type::String: + throw RuntimeException("anna::dbms::oracle::InputBind::code not implemented for Data::Type::String", ANNA_FILE_LOCATION); + break; + case Data::Type::Integer: + throw RuntimeException("anna::dbms::oracle::InputBind::code not implemented for Data::Type::Integer", ANNA_FILE_LOCATION); + break; + case Data::Type::Float: + codeFloat(data); + break; + case Data::Type::ShortBlock: + codeShortBlock(data); + break; + case Data::Type::LongBlock: + throw RuntimeException("anna::dbms::oracle::InputBind::code not implemented for Data::Type::LongBlock", ANNA_FILE_LOCATION); + break; + case Data::Type::Date: + case Data::Type::TimeStamp: + + try { + codeDate(data); + } catch(DatabaseException& edb) { + throw RuntimeException(edb); + } + + break; + } +} + +/** + * Transfiere el valor numerico del float, al buffer reservado para + * ubiucarlo como una cadena. Éste buffer es el que está "conectado" con + * Oracle (tm). + */ +void InputBind::codeFloat(dbms::Data& data) const +throw() { + dbms::Float& _float = static_cast (data); + InputBind* _this = const_cast (this); + char* buffer = (char*) _this->a_ofb->getData(); + snprintf(buffer, FloatSize, _float.getFormat(), _float.getValue()); + const char decimalPoint = oracle::Database::getDecimalPoint(); + + if(decimalPoint != 0) { + char* point = anna_strchr(buffer, '.'); + + if(point != NULL) + *point = decimalPoint; + } +} + +void InputBind::codeShortBlock(dbms::Data& data) const +throw() { + const int length = static_cast (data).getSize(); + InputBind* _this = const_cast (this); + + if(length == 0) { + _this->a_ofb->clear(); + _this->a_length = 0; + return; + } + + const char* src = (const char*) data.getBuffer(); + + char* dest = const_cast (a_ofb->getData()); + + int j = 0; + + for(int i = 0; i < length; i ++) { + dest [j ++] = asCharacter((src [i] & 0xf0) >> 4); + dest [j ++] = asCharacter(src [i] & 0x0f); + } + + dest [j ++] = 0; + _this->a_length = j; +} + +void InputBind::codeDate(dbms::Data& data) const +throw(RuntimeException, dbms::DatabaseException) { + dbms::Date& date = static_cast (data); + ub4 fsec(0); + + if(data.getType() == Data::Type::TimeStamp) + fsec = static_cast (data).getFractionalSecond() * 1000; + + anna_dbms_oracle_check( + OCIDateTimeConstruct( + a_datetime.env, a_datetime.error, a_datetime.handle, + date.getYear(), date.getMonth(), date.getDay(), date.getHour(), date.getMinute(), date.getSecond(), fsec, NULL, 0 + ), + a_datetime.error + ); + ub4 errorMask(0); + anna_dbms_oracle_check( + OCIDateTimeCheck(a_datetime.env, a_datetime.error, a_datetime.handle, &errorMask), + a_datetime.error + ); + + if(errorMask != 0) { + string msg(data.asString()); + msg += anna::functions::asHexText(" | Invalid date | ErrorCode: ", (int) errorMask); + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } +}