1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #include <anna/config/defines.hpp>
38 #include <anna/core/tracing/TraceMethod.hpp>
40 #include <anna/xml/Node.hpp>
41 #include <anna/xml/Attribute.hpp>
43 #include <anna/dbms/Connection.hpp>
44 #include <anna/dbms/Database.hpp>
45 #include <anna/dbms/Statement.hpp>
46 #include <anna/dbms/Statement.hpp>
51 //-----------------------------------------------------------------------------------------------------------
52 // (1) Si no tiene variables de salida => consideramos que es un update, insert o delete.
53 //-----------------------------------------------------------------------------------------------------------
54 dbms::ResultCode dbms::Connection::execute(Statement* statement)
55 throw(RuntimeException, dbms::DatabaseException) {
56 if(statement == NULL) {
57 string msg(asString());
58 msg += " | Cannot execute a NULL sentence";
59 throw RuntimeException(msg, ANNA_FILE_LOCATION);
62 LOGMETHOD(TraceMethod ttmm("dbms::Connection", "execute", ANNA_FILE_LOCATION));
64 string msg("Using Connection | ");
66 Logger::debug(msg, ANNA_FILE_LOCATION)
68 Guard guard(statement, "Statement from dbms::Connection::execute");
69 const Microsecond init = functions::hardwareClock();
71 if(statement->a_prepared == false) {
72 statement->prepare(this);
73 statement->a_prepared = true;
77 string msg("dbms::Connection::execute | ");
78 msg += statement->asString();
79 Logger::debug(msg, ANNA_FILE_LOCATION);
82 if(statement->requiresCommit() == true && a_rollbackPending == true) { // (1)
83 string msg("dbms::Connection::execute | ");
85 msg += " | Connection has pending ROLLBACKS for execution";
86 throw RuntimeException(msg, ANNA_FILE_LOCATION);
93 result = statement->execute(this);
95 if(result.lostConnection() == false)
98 string msg = asString();
100 msg += statement->asString();
102 msg += result.asString();
103 Logger::alert(msg, ANNA_FILE_LOCATION);
104 a_database.recover(*this, ++ tryCounter);
107 statement->measureTiming(init, functions::hardwareClock());
109 if(result.successful() == false && result.notFound() == false) {
110 string msg(asString());
111 msg += " | Sentence: ";
112 msg += statement->getName();
113 Logger::write(Logger::Error, msg, result.asString(), ANNA_FILE_LOCATION);
116 if(statement->requiresCommit() == true) { // (1)
117 if(result.successful() == false) {
118 if(statement->isCritical() == true) {
119 a_rollbackPending = true;
120 throw DatabaseException(statement->getName(), result, ANNA_FILE_LOCATION);
125 if(a_maxCommitPending > 0 && a_commitPending > a_maxCommitPending) {
128 a_rollbackPending = false;
136 //------------------------------------------------------------------------------------------------
137 // (1) Esto no es estrictamente necesario, pero lo hacemos para que no nos despisten las trazas
138 // y los volcados de contexto.
139 //------------------------------------------------------------------------------------------------
140 void dbms::Connection::commit()
141 throw(RuntimeException, dbms::DatabaseException) {
143 string msg("dbms::Connection::commit | ");
145 Logger::information(msg, ANNA_FILE_LOCATION);
148 if(isAvailable() == false) {
149 string msg(asString());
150 msg += " | Unavailable connection";
151 throw RuntimeException(msg, ANNA_FILE_LOCATION);
155 a_commitPending = 0; // (1)
156 a_rollbackPending = false;
159 //------------------------------------------------------------------------------------------------
160 // (1) Esto no es estrictamente necesario, pero lo hacemos para que no nos despisten las trazas
161 // y los volcados de contexto.
162 //------------------------------------------------------------------------------------------------
163 void dbms::Connection::rollback()
166 string msg("dbms::Connection::rollback | ");
168 Logger::warning(msg, ANNA_FILE_LOCATION);
171 if(isAvailable() == false) {
172 string msg(asString());
173 msg += " | Unavailable connection";
174 throw RuntimeException(msg, ANNA_FILE_LOCATION);
179 a_rollbackPending = false; // (1)
182 void dbms::Connection::lock()
183 throw(RuntimeException) {
184 if(isAvailable() == false) {
185 string msg(asString());
186 msg += " | Unavailable connection";
187 throw RuntimeException(msg, ANNA_FILE_LOCATION);
190 comm::Resource::lock();
192 if(a_lockingCounter ++ == 0) {
194 a_rollbackPending = false;
197 if(do_beginTransaction() == true)
199 } catch(dbms::DatabaseException& edb) {
200 throw RuntimeException(edb);
205 string msg("dbms::Connection::lock | ");
207 Logger::debug(msg, ANNA_FILE_LOCATION)
211 void dbms::Connection::unlock()
214 string msg("dbms::Connection::unlock | ");
216 Logger::debug(msg, ANNA_FILE_LOCATION)
219 if(-- a_lockingCounter <= 0) {
220 a_lockingCounter = 0;
223 if(a_rollbackPending == true)
225 else if(a_commitPending > 0)
227 } catch(Exception& ex) {
228 Logger::emergency(ex.getText(), ex.getFromFile(), ex.getFromLine());
232 comm::Resource::unlock();
235 string dbms::Connection::asString() const
237 string result("dbms::Connection { ");
238 result += comm::Resource::asString();
240 result += a_database.asString();
241 result += " | user: ";
243 result += functions::asText(" | LockingCounter: ", a_lockingCounter);
244 result += functions::asText(" | password: ******* | CommitPending: ", a_commitPending);
245 result += functions::asText(" | RollbackPending: ", a_rollbackPending);
246 return result += " }";
249 xml::Node* dbms::Connection::asXML(xml::Node* parent) const
251 xml::Node* result = comm::Resource::asXML(parent);
252 result->createAttribute("User", a_user);
253 result->createAttribute("LockingCounter", a_lockingCounter);
254 result->createAttribute("CommitPending", a_commitPending);
255 result->createAttribute("RollbackPending", functions::asString(a_rollbackPending));