X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fdbms.mysql%2FOutputBind.cpp;fp=source%2Fdbms.mysql%2FOutputBind.cpp;h=016b9e9dfb131980d7db3def65465ca0c79ae09b;hb=78be86969d2f26a9084b0c4af6ce43d5fa4ed3fd;hp=0000000000000000000000000000000000000000;hpb=a3b95648bd76140ef55e0b5941d423eee6c3856f;p=anna.git diff --git a/source/dbms.mysql/OutputBind.cpp b/source/dbms.mysql/OutputBind.cpp new file mode 100644 index 0000000..016b9e9 --- /dev/null +++ b/source/dbms.mysql/OutputBind.cpp @@ -0,0 +1,174 @@ +// 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 + +using namespace anna; +using namespace std; + +OutputBind::OutputBind(const char* name, dbms::Data& data) : + dbms::OutputBind(name, data), + BaseBind(data) { + a_blob = (data.getType() == Data::Type::LongBlock) ? new Blob : NULL; +} + +OutputBind::~OutputBind() { + delete a_blob; +} + +/* + * El dato de LONG BLOB se recoge según cuenta: + * http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html. + */ +void OutputBind::prepare(anna::dbms::Statement* dbmsStmt, anna::dbms::Connection*, const int pos) +throw(RuntimeException) { + st_mysql_bind* bind = static_cast (dbmsStmt)->getBindResults() + pos; + Data& data = anna::dbms::Bind::getData(); + BaseBind::setupBind(*bind, data); + + if(data.getType() == Data::Type::LongBlock) { + dbms::mysql::Statement* myStmt = static_cast (dbmsStmt); + a_blob->stmt = *myStmt; + a_blob->binds = myStmt->getBindResults(); + a_blob->pos = pos; + bind->buffer_type = MYSQL_TYPE_BLOB; + bind->buffer = NULL; + bind->buffer_length = 0; + bind->length = &a_length; + } +} + +/* + * Transfiere la información del los MYSQL_BIND del API C de MySQL a las + * estructuras dbms::Data de nuestro programa C++. + */ +void OutputBind::decode() const +throw(RuntimeException) { + OutputBind* _this = const_cast (this); + char* str; + Data& data = _this->getData(); + data.setNull(a_nullIndicator == true); + + 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::Float: + + if(data.isNull() == true) + static_cast (data) = 0.0; + + break; + case Data::Type::Date: + case Data::Type::TimeStamp: + _this->decodeDate(data); + break; + case Data::Type::Integer: + throw RuntimeException("anna::dbms::mysql::OutputBind::decode not implemented for Data::Type::Integer", ANNA_FILE_LOCATION); + break; + case Data::Type::ShortBlock: + throw RuntimeException("anna::dbms::mysql::OutputBind::decode not implemented for Data::Type::ShortBlock", ANNA_FILE_LOCATION); + break; + case Data::Type::LongBlock: + + try { + _this->decodeLongBlob(data); + } catch(dbms::DatabaseException& edb) { + throw RuntimeException(edb); + } + + break; + } +} + +void OutputBind::do_write(const dbms::LongBlock&) const +throw(RuntimeException, dbms::DatabaseException) { +} + +/* + * El m�todo BaseBind::setupBind asocia� el contenido de la variable + * a_time al buffer de salida de la sentencia SQL, as� que el contenido + * de la columna est� contenido ah�. S�lo tendremos que copiar dichos + * contenidos en la variable C++ de nuestro entorno. + */ +void OutputBind::decodeDate(dbms::Data& data) +throw() { + if(data.isNull() == true) + return; + + Date& date = static_cast (data); + date.setYear(a_time->year); + date.setMonth(a_time->month); + date.setDay(a_time->day); + date.setHour(a_time->hour); + date.setMinute(a_time->minute); + date.setSecond(a_time->second); + + if(data.getType() == Data::Type::TimeStamp) + static_cast (data).setFractionalSecond(a_time->second_part); +} + +/* + * Según http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html + * + * Recoge el contenido total de BLOB en partes que va componiendo sobre el + * DataBlock final asociado al anna::dbms::LongBlock sobre el que trabaja el + * programador final. + */ +void OutputBind::decodeLongBlob(dbms::Data& data) const +throw(RuntimeException, dbms::DatabaseException) { + const int bufferSize = a_blob->buffer.getMaxSize(); + st_mysql_bind& bind = a_blob->binds [a_blob->pos]; + DataBlock& target = static_cast (data).getValue(); + const int maxloop = *bind.length / bufferSize; + const int remainder = *bind.length % bufferSize; + int offset = 0; + target.clear(); + bind.buffer = (void*) a_blob->buffer.getData(); + + for(int iloop = 0; iloop < maxloop; iloop ++) { + bind.buffer_length = bufferSize; + anna_dbms_mysql_check( + mysql_stmt_fetch_column(a_blob->stmt, a_blob->binds, a_blob->pos, offset), a_blob->stmt + ); + target += DataBlock((const char*) bind.buffer, bind.buffer_length, false); + offset += bufferSize; + } + + if(remainder) { + bind.buffer_length = remainder; + anna_dbms_mysql_check( + mysql_stmt_fetch_column(a_blob->stmt, a_blob->binds, a_blob->pos, offset), a_blob->stmt + ); + target += DataBlock((const char*) bind.buffer, remainder, false); + } +} + +OutputBind::Blob::Blob() : + buffer(true) { + buffer.allocate(64 * 1024); +}