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