Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

pqxx-object/transaction.cc

Go to the documentation of this file.
00001 // database transaction convenience wrapper                      -*- C++ -*-
00002 // $Id: transaction.cc,v 1.7 2004/01/28 21:21:08 roger Exp $
00003 //
00004 // Copyright (C) 2003  Roger Leigh <rleigh@debian.org>
00005 //
00006 //
00007 //  All rights reserved.
00008 //
00009 //  Redistribution and use in source and binary forms, with or without
00010 //  modification, are permitted provided that the following conditions
00011 //  are met:
00012 //
00013 //  * Redistributions of source code must retain the above copyright
00014 //    notice, this list of conditions and the following disclaimer.
00015 //  * Redistributions in binary form must reproduce the above
00016 //    copyright notice, this list of conditions and the following
00017 //    disclaimer in the documentation and/or other materials provided
00018 //    with the distribution.
00019 //  * Neither the name of the author, nor the names of other
00020 //    contributors may be used to endorse or promote products derived
00021 //    from this software without specific prior written permission.
00022 //
00023 //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
00024 //  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
00025 //  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00026 //  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 //  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
00028 //  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00029 //  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00030 //  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00031 //  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00032 //  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
00033 //  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00034 //  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00035 //  SUCH DAMAGE.
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 {
00087 }
00088 
00089 transaction::~transaction()
00090 {
00091 }
00092 
00093 SigC::Signal1<void, pqxxobject::transaction&>&
00094 transaction::signal_commit()
00095 {
00096   return m_signal_commit;
00097 }
00098 
00099 SigC::Signal1<void, pqxxobject::transaction&>&
00100 transaction::signal_abort()
00101 {
00102   return m_signal_abort;
00103 }
00104 
00105 void
00106 transaction::begin(const std::string& name)
00107 {
00108 //   std::cerr << "transaction::begin";
00109   try
00110     {
00111       ++m_recursion_level;
00112 //       std::cerr << "(" << m_recursion_level << ")" << std::endl;
00113       if (m_recursion_level == 1)
00114         _begin(name);
00115     }
00116   catch (const std::exception& e)
00117     {
00118       _end();
00119       throw DatabaseError(e.what());
00120     }
00121 }
00122 
00123 void
00124 transaction::end()
00125 {
00126 //   std::cerr << "transaction::end";
00127 //   std::cerr << "(" << m_recursion_level << ")" << std::endl;
00128   try
00129     {
00130       if (m_recursion_level > 0)
00131         {
00132           --m_recursion_level;
00133           if (m_recursion_level == 0)
00134             {
00135               _end();
00136             }
00137         }
00138       else
00139         _end();
00140     }
00141   catch (const std::exception& e)
00142     {
00143       throw DatabaseError(e.what());
00144     }
00145 }
00146 
00147 pqxx::result
00148 transaction::exec(const std::string& query)
00149 {
00150 //   std::cerr << "transaction::exec" << std::endl;
00151   try
00152     {
00153       if (m_state == STATE_EXECUTING)
00154         return m_transaction->exec(query);
00155 //       else if (m_state == STATE_ABORTING || m_state == STATE_COMMITTING)
00156 //      throw Abort
00157       else
00158         throw DatabaseError("The query could not be executed: " + describe_status(m_state));
00159     }
00160   catch (const std::exception& e)
00161     {
00162       throw DatabaseError(e.what());
00163     }
00164 }
00165 
00166 pqxx::result::size_type
00167 transaction::exec_noresult(const std::string& query)
00168 {
00169 //   std::cerr << "transaction::exec_noresult" << std::endl;
00170   try
00171     {
00172       if (m_state == STATE_EXECUTING)
00173         {
00174           pqxx::result R = exec(query);
00175           return R.affected_rows();
00176         }
00177 //       else if (m_state == STATE_ABORTING || m_state == STATE_COMMITTING)
00178 //      throw Abort
00179       else
00180         throw DatabaseError("The query could not be executed: " + describe_status(m_state));
00181     }
00182   catch (const std::exception& e)
00183     {
00184       throw DatabaseError(e.what());
00185     }
00186 }
00187 
00188 pqxx::result::size_type
00189 transaction::perform(const std::string& query,
00190                      pqxx::result::size_type min_rows,
00191                      pqxx::result::size_type max_rows)
00192 {
00193 //   std::cerr << "transaction::perform" << std::endl;
00194   try
00195     {
00196       if (m_state == STATE_EXECUTING)
00197         {
00198           begin("transaction::perform()");
00199 
00200           pqxx::result::size_type rows;
00201           rows = exec_noresult(query);
00202 
00203           // Commit if the number of altered rows is greater or equal to
00204           // min_rows, or if min_rows is 0.
00205           if ((rows >= min_rows || min_rows == 0) &&
00206               (rows <= max_rows || max_rows == 0))
00207             commit();
00208           else
00209             abort();
00210 
00211           return rows;
00212         }
00213       else
00214 //       else if (m_state == STATE_ABORTING || m_state == STATE_COMMITTING)
00215 //      throw Abort
00216         throw DatabaseError("The query could not be executed: " + describe_status(m_state));
00217     }
00218   catch (const std::exception& e)
00219     {
00220       _end();
00221       throw DatabaseError(e.what());
00222     }
00223 
00224   // This should never be reached.
00225   return 0;
00226 }
00227 
00228 void
00229 transaction::commit()
00230 {
00231   commit(true);
00232 }
00233 
00234 void
00235 transaction::abort()
00236 {
00237   abort(true);
00238 }
00239 
00240 void
00241 transaction::_begin(const std::string& name)
00242 {
00243 //   std::cerr << "transaction::_begin" << std::endl;
00244   assert (m_transaction == NULL);
00245 
00246   m_transaction = new pqxx::transaction<> (m_connection, name);
00247   m_state = STATE_EXECUTING;
00248 }
00249 
00250 void
00251 transaction::_end()
00252 {
00253 //   std::cerr << "transaction::_end" << std::endl;
00254   if (m_transaction)
00255     {
00256       delete m_transaction;
00257       m_transaction = 0;
00258       m_state = STATE_NONE;
00259       m_recursion_level = 0;
00260     }
00261 }
00262 
00263 void transaction::commit(bool refresh)
00264 {
00265 //   std::cerr << "transaction::commit" << std::endl;
00266   try
00267     {
00268       if (m_recursion_level == 1)
00269         {
00270           _commit(refresh);
00271         }
00272       else // end() is implict above
00273         end();
00274     }
00275   catch (const std::exception& e)
00276     {
00277       _end();
00278       throw DatabaseError(e.what());
00279     }
00280 }
00281 
00282 void
00283 transaction::_commit(bool refresh)
00284 {
00285   m_state = STATE_COMMITTING;
00286   m_transaction->commit();
00287   m_state = STATE_COMMITTED;
00288   end();
00289 
00290   // Start a new transaction for object refresh phase.
00291   if (refresh == true)
00292     {
00293       begin("pqxxobject::commit[object refresh]");
00294       m_signal_commit.emit(*this);
00295       m_signal_commit.clear();
00296       m_signal_abort.clear();
00297       commit(false);
00298     }
00299 }
00300 
00301 void
00302 transaction::abort(bool refresh)
00303 {
00304 //   std::cerr << "transaction::abort" << std::endl;
00305   try
00306     {
00307       m_state = STATE_ABORTING;
00308       if (m_recursion_level == 1)
00309         {
00310           _abort(refresh);
00311         }
00312       else // end() is implict above
00313         end();
00314     }
00315   catch (const std::exception& e)
00316     {
00317       _end();
00318       throw DatabaseError(e.what());
00319     }
00320 }
00321 void
00322 transaction::_abort(bool refresh)
00323 {
00324   m_state = STATE_ABORTING;
00325   m_transaction->abort();
00326   m_state = STATE_ABORTED;
00327   end();
00328 
00329   // Start a new transaction for object refresh phase.
00330   if (refresh == true)
00331     {
00332       begin("pqxxobject::abort[object refresh]");
00333       m_signal_commit.emit(*this);
00334       m_signal_commit.clear();
00335       m_signal_abort.clear();
00336       m_transaction->commit();
00337       commit(false);
00338     }
00339 }
00340 

Generated on Wed Jan 28 21:22:48 2004 for pqxx-object API Reference by doxygen 1.3.4