X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fdbms%2FConnection.cpp;fp=source%2Fdbms%2FConnection.cpp;h=9dcdcb543bc97d3b1783698f4a1cd248825424e9;hb=78be86969d2f26a9084b0c4af6ce43d5fa4ed3fd;hp=0000000000000000000000000000000000000000;hpb=a3b95648bd76140ef55e0b5941d423eee6c3856f;p=anna.git diff --git a/source/dbms/Connection.cpp b/source/dbms/Connection.cpp new file mode 100644 index 0000000..9dcdcb5 --- /dev/null +++ b/source/dbms/Connection.cpp @@ -0,0 +1,230 @@ +// 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 + +using namespace std; +using namespace anna; + +//----------------------------------------------------------------------------------------------------------- +// (1) Si no tiene variables de salida => consideramos que es un update, insert o delete. +//----------------------------------------------------------------------------------------------------------- +dbms::ResultCode dbms::Connection::execute(Statement* statement) +throw(RuntimeException, dbms::DatabaseException) { + if(statement == NULL) { + string msg(asString()); + msg += " | Cannot execute a NULL sentence"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + LOGMETHOD(TraceMethod ttmm("dbms::Connection", "execute", ANNA_FILE_LOCATION)); + LOGDEBUG( + string msg("Using Connection | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + Guard guard(statement, "Statement from dbms::Connection::execute"); + const Microsecond init = functions::hardwareClock(); + + if(statement->a_prepared == false) { + statement->prepare(this); + statement->a_prepared = true; + } + + LOGDEBUG( + string msg("dbms::Connection::execute | "); + msg += statement->asString(); + Logger::debug(msg, ANNA_FILE_LOCATION); + ); + + if(statement->requiresCommit() == true && a_rollbackPending == true) { // (1) + string msg("dbms::Connection::execute | "); + msg += asString(); + msg += " | Connection has pending ROLLBACKS for execution"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + ResultCode result; + int tryCounter = 0; + + while(true) { + result = statement->execute(this); + + if(result.lostConnection() == false) + break; + + string msg = asString(); + msg += " | "; + msg += statement->asString(); + msg += " | "; + msg += result.asString(); + Logger::alert(msg, ANNA_FILE_LOCATION); + a_database.recover(*this, ++ tryCounter); + } + + statement->measureTiming(init, functions::hardwareClock()); + + if(result.successful() == false && result.notFound() == false) { + string msg(asString()); + msg += " | Sentence: "; + msg += statement->getName(); + Logger::write(Logger::Error, msg, result.asString(), ANNA_FILE_LOCATION); + } + + if(statement->requiresCommit() == true) { // (1) + if(result.successful() == false) { + if(statement->isCritical() == true) { + a_rollbackPending = true; + throw DatabaseException(statement->getName(), result, ANNA_FILE_LOCATION); + } + } else { + a_commitPending ++; + + if(a_maxCommitPending > 0 && a_commitPending > a_maxCommitPending) { + commit(); + a_commitPending = 0; + a_rollbackPending = false; + } + } + } + + return result; +} + +//------------------------------------------------------------------------------------------------ +// (1) Esto no es estrictamente necesario, pero lo hacemos para que no nos despisten las trazas +// y los volcados de contexto. +//------------------------------------------------------------------------------------------------ +void dbms::Connection::commit() +throw(RuntimeException, dbms::DatabaseException) { + LOGINFORMATION( + string msg("dbms::Connection::commit | "); + msg += asString(); + Logger::information(msg, ANNA_FILE_LOCATION); + ); + + if(isAvailable() == false) { + string msg(asString()); + msg += " | Unavailable connection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + do_commit(); + a_commitPending = 0; // (1) + a_rollbackPending = false; +} + +//------------------------------------------------------------------------------------------------ +// (1) Esto no es estrictamente necesario, pero lo hacemos para que no nos despisten las trazas +// y los volcados de contexto. +//------------------------------------------------------------------------------------------------ +void dbms::Connection::rollback() +throw() { + LOGWARNING( + string msg("dbms::Connection::rollback | "); + msg += asString(); + Logger::warning(msg, ANNA_FILE_LOCATION); + ); + + if(isAvailable() == false) { + string msg(asString()); + msg += " | Unavailable connection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + do_rollback(); + a_commitPending = 0; + a_rollbackPending = false; // (1) +} + +void dbms::Connection::lock() +throw(RuntimeException) { + if(isAvailable() == false) { + string msg(asString()); + msg += " | Unavailable connection"; + throw RuntimeException(msg, ANNA_FILE_LOCATION); + } + + comm::Resource::lock(); + + if(a_lockingCounter ++ == 0) { + a_commitPending = 0; + a_rollbackPending = false; + + try { + if(do_beginTransaction() == true) + a_commitPending = 1; + } catch(dbms::DatabaseException& edb) { + throw RuntimeException(edb); + } + } + + LOGDEBUG( + string msg("dbms::Connection::lock | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); +} + +void dbms::Connection::unlock() +throw() { + LOGDEBUG( + string msg("dbms::Connection::unlock | "); + msg += asString(); + Logger::debug(msg, ANNA_FILE_LOCATION) + ); + + if(-- a_lockingCounter <= 0) { + a_lockingCounter = 0; + + try { + if(a_rollbackPending == true) + rollback(); + else if(a_commitPending > 0) + commit(); + } catch(Exception& ex) { + Logger::emergency(ex.getText(), ex.getFromFile(), ex.getFromLine()); + } + } + + comm::Resource::unlock(); +} + +string dbms::Connection::asString() const +throw() { + string result("dbms::Connection { "); + result += comm::Resource::asString(); + result += " | "; + result += a_database.asString(); + result += " | user: "; + result += a_user; + result += functions::asText(" | LockingCounter: ", a_lockingCounter); + result += functions::asText(" | password: ******* | CommitPending: ", a_commitPending); + result += functions::asText(" | RollbackPending: ", a_rollbackPending); + return result += " }"; +} + +xml::Node* dbms::Connection::asXML(xml::Node* parent) const +throw() { + xml::Node* result = comm::Resource::asXML(parent); + result->createAttribute("User", a_user); + result->createAttribute("LockingCounter", a_lockingCounter); + result->createAttribute("CommitPending", a_commitPending); + result->createAttribute("RollbackPending", functions::asString(a_rollbackPending)); + return result; +} +