00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00038
00039 #include <cassert>
00040 #include <iostream>
00041 #include <sstream>
00042
00043 #include <sigc++/object.h>
00044
00045 #include <pqxxobject/transaction.h>
00046
00047 using namespace pqxxobject;
00048
00049 namespace
00050 {
00051 std::string describe_status(transaction::state current_state)
00052 {
00053 std::string status;
00054 switch (current_state)
00055 {
00056 case transaction::STATE_EXECUTING:
00057 status = "the current transaction is executing normally";
00058 break;
00059 case transaction::STATE_ABORTING:
00060 status = "the current transaction is in the process of aborting";
00061 break;
00062 case transaction::STATE_COMMITTING:
00063 status = "the current transaction is in the process of committing";
00064 break;
00065 case transaction::STATE_NONE:
00066 status = "there is no current transaction";
00067 break;
00068 case transaction::STATE_ABORTED:
00069 status = "the current transaction is aborted";
00070 break;
00071 case transaction::STATE_COMMITTED:
00072 status = "the current transaction is committed";
00073 break;
00074 default:
00075 status = "the current transaction status is unknown";
00076 }
00077 return status;
00078 }
00079 }
00080
00081 transaction::transaction(pqxx::connection& conn,
00082 pqxx::transaction<>*& tran):
00083 m_connection(conn),
00084 m_transaction(tran),
00085 m_state(STATE_NONE),
00086 m_recursion_level(0),
00087 m_checkpoint(false)
00088 {
00089 }
00090
00091 transaction::~transaction()
00092 {
00093 }
00094
00095 void
00096 transaction::set_checkpoint(bool checkpoint_exists)
00097 {
00098 m_checkpoint = checkpoint_exists;
00099 }
00100
00101 bool
00102 transaction::get_checkpoint() const
00103 {
00104 return m_checkpoint;
00105 }
00106
00107 SigC::Signal1<void, pqxxobject::transaction&>&
00108 transaction::signal_commit()
00109 {
00110 return m_signal_commit;
00111 }
00112
00113 SigC::Signal1<void, pqxxobject::transaction&>&
00114 transaction::signal_abort()
00115 {
00116 return m_signal_abort;
00117 }
00118
00119 SigC::Signal1<void, pqxxobject::transaction&>&
00120 transaction::signal_refresh()
00121 {
00122 return m_signal_refresh;
00123 }
00124
00125 void
00126 transaction::begin(const std::string& name)
00127 {
00128 #ifdef PQXXOBJECT_DEBUG
00129 std::cerr << "transaction::begin";
00130 #endif
00131 try
00132 {
00133 ++m_recursion_level;
00134 #ifdef PQXXOBJECT_DEBUG
00135 std::cerr << "(" << m_recursion_level << ")" << std::endl;
00136 #endif
00137 if (m_recursion_level == 1)
00138 _begin(name);
00139 }
00140 catch (const std::exception& e)
00141 {
00142 _end();
00143 throw DatabaseError(e.what());
00144 }
00145 }
00146
00147 void
00148 transaction::end()
00149 {
00150 #ifdef PQXXOBJECT_DEBUG
00151 std::cerr << "transaction::end";
00152 std::cerr << "(" << m_recursion_level << ")" << std::endl;
00153 #endif
00154 try
00155 {
00156 if (m_recursion_level > 0)
00157 {
00158 --m_recursion_level;
00159 if (m_recursion_level == 0)
00160 {
00161 _end();
00162 }
00163 }
00164 else
00165 _end();
00166 }
00167 catch (const std::exception& e)
00168 {
00169 throw DatabaseError(e.what());
00170 }
00171 }
00172
00173 pqxx::result
00174 transaction::exec(const std::string& query)
00175 {
00176 #ifdef PQXXOBJECT_DEBUG
00177
00178 #endif
00179 try
00180 {
00181 if (m_state == STATE_EXECUTING)
00182 return m_transaction->exec(query);
00183 #ifdef PQXXOBJECT_DEBUG
00184
00185
00186 #endif
00187 else
00188 throw DatabaseError("The query could not be executed: " + describe_status(m_state));
00189 }
00190 catch (const std::exception& e)
00191 {
00192 throw DatabaseError(e.what());
00193 }
00194 }
00195
00196 pqxx::result
00197 transaction::exec(const std::ostringstream& query)
00198 {
00199 return exec(query.str());
00200 }
00201
00202 pqxx::result
00203 transaction::exec(const query& query)
00204 {
00205 return exec(query.str());
00206 }
00207
00208 pqxx::result::size_type
00209 transaction::exec_noresult(const std::string& query)
00210 {
00211 #ifdef PQXXOBJECT_DEBUG
00212
00213 #endif
00214 try
00215 {
00216 if (m_state == STATE_EXECUTING)
00217 {
00218 pqxx::result R = exec(query);
00219 return R.affected_rows();
00220 }
00221 #ifdef PQXXOBJECT_DEBUG
00222
00223
00224 #endif
00225 else
00226 throw DatabaseError("The query could not be executed: " + describe_status(m_state));
00227 }
00228 catch (const std::exception& e)
00229 {
00230 throw DatabaseError(e.what());
00231 }
00232 }
00233
00234 pqxx::result::size_type
00235 transaction::exec_noresult(const std::ostringstream& query)
00236 {
00237 return exec_noresult(query.str());
00238 }
00239
00240 pqxx::result::size_type
00241 transaction::exec_noresult(const query& query)
00242 {
00243 return exec_noresult(query.str());
00244 }
00245
00246 pqxx::result::size_type
00247 transaction::perform(const std::string& query,
00248 pqxx::result::size_type min_rows,
00249 pqxx::result::size_type max_rows)
00250 {
00251 #ifdef PQXXOBJECT_DEBUG
00252
00253 #endif
00254 try
00255 {
00256 if (m_state == STATE_EXECUTING)
00257 {
00258 begin("transaction::perform()");
00259
00260 pqxx::result::size_type rows;
00261 rows = exec_noresult(query);
00262
00263
00264
00265 if ((rows >= min_rows || min_rows == 0) &&
00266 (rows <= max_rows || max_rows == 0))
00267 commit();
00268 else
00269 abort();
00270
00271 return rows;
00272 }
00273 else
00274
00275
00276 throw DatabaseError("The query could not be executed: " + describe_status(m_state));
00277 }
00278 catch (const std::exception& e)
00279 {
00280 throw DatabaseError(e.what());
00281 }
00282
00283
00284 return 0;
00285 }
00286
00287 pqxx::result::size_type
00288 transaction::perform(const std::ostringstream& query,
00289 pqxx::result::size_type min_rows,
00290 pqxx::result::size_type max_rows)
00291 {
00292 return perform(query.str(), min_rows, max_rows);
00293 }
00294
00295 pqxx::result::size_type
00296 transaction::perform(const query& query,
00297 pqxx::result::size_type min_rows,
00298 pqxx::result::size_type max_rows)
00299 {
00300 return perform(query.str(), min_rows, max_rows);
00301 }
00302
00303 void
00304 transaction::commit()
00305 {
00306 commit(true);
00307 }
00308
00309 void
00310 transaction::abort()
00311 {
00312 abort(true);
00313 }
00314
00315 void
00316 transaction::_begin(const std::string& name)
00317 {
00318 #ifdef PQXXOBJECT_DEBUG
00319
00320 #endif
00321 assert (m_transaction == NULL);
00322
00323 m_transaction = new pqxx::transaction<> (m_connection, name);
00324 m_state = STATE_EXECUTING;
00325 }
00326
00327 void
00328 transaction::_end()
00329 {
00330 #ifdef PQXXOBJECT_DEBUG
00331
00332 #endif
00333 if (m_transaction)
00334 {
00335 delete m_transaction;
00336 m_transaction = 0;
00337 m_state = STATE_NONE;
00338 m_recursion_level = 0;
00339 m_checkpoint = false;
00340 }
00341 }
00342
00343 void transaction::commit(bool refresh)
00344 {
00345 #ifdef PQXXOBJECT_DEBUG
00346 std::cerr << "transaction::commit" << std::endl;
00347 #endif
00348 try
00349 {
00350 if (m_recursion_level == 1)
00351 {
00352 _commit(refresh);
00353 }
00354 else
00355 end();
00356 }
00357 catch (const std::exception& e)
00358 {
00359 _end();
00360 throw DatabaseError(e.what());
00361 }
00362 }
00363
00364 void
00365 transaction::_commit(bool refresh)
00366 {
00367 m_state = STATE_COMMITTING;
00368 m_transaction->commit();
00369 m_state = STATE_COMMITTED;
00370 end();
00371
00372
00373 if (refresh == true)
00374 {
00375
00376 begin("pqxxobject::commit[object refresh]");
00377 m_signal_commit.emit(*this);
00378 m_signal_commit.clear();
00379 m_signal_abort.clear();
00380 m_signal_refresh.emit(*this);
00381 m_signal_refresh.clear();
00382
00383 m_signal_commit.emit(*this);
00384 m_signal_commit.clear();
00385 m_signal_abort.clear();
00386 commit(false);
00387 }
00388 }
00389
00390 void
00391 transaction::abort(bool rollback)
00392 {
00393 #ifdef PQXXOBJECT_DEBUG
00394 std::cerr << "transaction::abort" << std::endl;
00395 #endif
00396 try
00397 {
00398 m_state = STATE_ABORTING;
00399 if (m_recursion_level == 1)
00400 {
00401 _abort(rollback);
00402 }
00403 else
00404 end();
00405 }
00406 catch (const std::exception& e)
00407 {
00408 _end();
00409 throw DatabaseError(e.what());
00410 }
00411 }
00412 void
00413 transaction::_abort(bool rollback)
00414 {
00415 m_state = STATE_ABORTING;
00416 m_transaction->abort();
00417 m_state = STATE_ABORTED;
00418 end();
00419
00420
00421 if (rollback == true)
00422 {
00423
00424 begin("pqxxobject::abort[object rollback]");
00425 m_signal_abort.emit(*this);
00426 m_signal_commit.clear();
00427 m_signal_abort.clear();
00428 m_signal_refresh.emit(*this);
00429 m_signal_refresh.clear();
00430
00431 m_transaction->commit();
00432 m_signal_commit.emit(*this);
00433 m_signal_commit.clear();
00434 m_signal_abort.clear();
00435 commit(false);
00436 }
00437 }
00438