transaction.cpp

Go to the documentation of this file.
00001 ///////////////////////////////////////////////////////////////////////////////
00002 //
00003 //      File    : $Id: transaction.cpp 9523 2011-05-13 18:20:03Z frederico.bede $
00004 //      Subject : IBPP, Database class implementation
00005 //
00006 ///////////////////////////////////////////////////////////////////////////////
00007 //
00008 //      (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)
00009 //
00010 //      The contents of this file are subject to the IBPP License (the "License");
00011 //      you may not use this file except in compliance with the License.  You may
00012 //      obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'
00013 //      file which must have been distributed along with this file.
00014 //
00015 //      This software, distributed under the License, is distributed on an "AS IS"
00016 //      basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
00017 //      License for the specific language governing rights and limitations
00018 //      under the License.
00019 //
00020 ///////////////////////////////////////////////////////////////////////////////
00021 //
00022 //      COMMENTS
00023 //      * Tabulations should be set every four characters when editing this file.
00024 //
00025 ///////////////////////////////////////////////////////////////////////////////
00026 
00027 #if defined(_MSC_VER)
00028 #pragma warning(disable: 4786 4996)
00029 #ifndef _DEBUG
00030 #pragma warning(disable: 4702)
00031 #endif
00032 #endif
00033 
00034 #include "_ibpp.h"
00035 
00036 #ifdef HAS_HDRSTOP
00037 #pragma hdrstop
00038 #endif
00039 
00040 #include <algorithm>
00041 
00042 using namespace ibpp_internals;
00043 
00044 //      (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))
00045 
00046 void TransactionImpl::AttachDatabase(IBPP::Database db,
00047         IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)
00048 {
00049         if (db.intf() == 0)
00050                 throw LogicExceptionImpl("Transaction::AttachDatabase",
00051                                 _("Can't attach an unbound Database."));
00052 
00053         AttachDatabaseImpl(dynamic_cast<DatabaseImpl*>(db.intf()), am, il, lr, flags);
00054 }
00055 
00056 void TransactionImpl::DetachDatabase(IBPP::Database db)
00057 {
00058         if (db.intf() == 0)
00059                 throw LogicExceptionImpl("Transaction::DetachDatabase",
00060                                 _("Can't detach an unbound Database."));
00061 
00062         DetachDatabaseImpl(dynamic_cast<DatabaseImpl*>(db.intf()));
00063 }
00064 
00065 void TransactionImpl::AddReservation(IBPP::Database db,
00066         const std::string& table, IBPP::TTR tr)
00067 {
00068         if (mHandle != 0)
00069                 throw LogicExceptionImpl("Transaction::AddReservation",
00070                                 _("Can't add table reservation if Transaction started."));
00071         if (db.intf() == 0)
00072                 throw LogicExceptionImpl("Transaction::AddReservation",
00073                                 _("Can't add table reservation on an unbound Database."));
00074 
00075         // Find the TPB associated with this database
00076         std::vector<DatabaseImpl*>::iterator pos =
00077                 std::find(mDatabases.begin(), mDatabases.end(), dynamic_cast<DatabaseImpl*>(db.intf()));
00078         if (pos != mDatabases.end())
00079         {
00080                 size_t index = pos - mDatabases.begin();
00081                 TPB* tpb = mTPBs[index];
00082                 
00083                 // Now add the reservations to the TPB
00084                 switch (tr)
00085                 {
00086                         case IBPP::trSharedWrite :
00087                                         tpb->Insert(isc_tpb_lock_write);
00088                                         tpb->Insert(table);
00089                                         tpb->Insert(isc_tpb_shared);
00090                                         break;
00091                         case IBPP::trSharedRead :
00092                                         tpb->Insert(isc_tpb_lock_read);
00093                                         tpb->Insert(table);
00094                                         tpb->Insert(isc_tpb_shared);
00095                                         break;
00096                         case IBPP::trProtectedWrite :
00097                                         tpb->Insert(isc_tpb_lock_write);
00098                                         tpb->Insert(table);
00099                                         tpb->Insert(isc_tpb_protected);
00100                                         break;
00101                         case IBPP::trProtectedRead :
00102                                         tpb->Insert(isc_tpb_lock_read);
00103                                         tpb->Insert(table);
00104                                         tpb->Insert(isc_tpb_protected);
00105                                         break;
00106                         default :
00107                                         throw LogicExceptionImpl("Transaction::AddReservation",
00108                                                 _("Illegal TTR value detected."));
00109                 }
00110         }
00111         else throw LogicExceptionImpl("Transaction::AddReservation",
00112                         _("The database connection you specified is not attached to this transaction."));
00113 }
00114 
00115 void TransactionImpl::Start()
00116 {
00117         if (mHandle != 0) return;       // Already started anyway
00118 
00119         if (mDatabases.empty())
00120                 throw LogicExceptionImpl("Transaction::Start", _("No Database is attached."));
00121 
00122         struct ISC_TEB
00123         {
00124                 ISC_LONG* db_ptr;
00125                 ISC_LONG tpb_len;
00126                 char* tpb_ptr;
00127         } * teb = new ISC_TEB[mDatabases.size()];
00128 
00129         unsigned i;
00130         for (i = 0; i < mDatabases.size(); i++)
00131         {
00132                 if (mDatabases[i]->GetHandle() == 0)
00133                 {
00134                         // All Databases must be connected to Start the transaction !
00135                         delete [] teb;
00136                         throw LogicExceptionImpl("Transaction::Start",
00137                                         _("All attached Database should have been connected."));
00138                 }
00139                 teb[i].db_ptr = (ISC_LONG*) mDatabases[i]->GetHandlePtr();
00140                 teb[i].tpb_len = mTPBs[i]->Size();
00141                 teb[i].tpb_ptr = mTPBs[i]->Self();
00142         }
00143 
00144         IBS status;
00145         (*gds.Call()->m_start_multiple)(status.Self(), &mHandle, (short)mDatabases.size(), teb);
00146         delete [] teb;
00147         if (status.Errors())
00148         {
00149                 mHandle = 0;    // Should be, but better be sure...
00150                 throw SQLExceptionImpl(status, "Transaction::Start");
00151         }
00152 }
00153 
00154 void TransactionImpl::Commit()
00155 {
00156         if (mHandle == 0)
00157                 throw LogicExceptionImpl("Transaction::Commit", _("Transaction is not started."));
00158                 
00159         IBS status;
00160 
00161         (*gds.Call()->m_commit_transaction)(status.Self(), &mHandle);
00162         if (status.Errors())
00163                 throw SQLExceptionImpl(status, "Transaction::Commit");
00164         mHandle = 0;    // Should be, better be sure
00165 }
00166 
00167 void TransactionImpl::CommitRetain()
00168 {
00169         if (mHandle == 0)
00170                 throw LogicExceptionImpl("Transaction::CommitRetain", _("Transaction is not started."));
00171 
00172         IBS status;
00173 
00174         (*gds.Call()->m_commit_retaining)(status.Self(), &mHandle);
00175         if (status.Errors())
00176                 throw SQLExceptionImpl(status, "Transaction::CommitRetain");
00177 }
00178 
00179 void TransactionImpl::Rollback()
00180 {
00181         if (mHandle == 0) return;       // Transaction not started anyway
00182 
00183         IBS status;
00184 
00185         (*gds.Call()->m_rollback_transaction)(status.Self(), &mHandle);
00186         if (status.Errors())
00187                 throw SQLExceptionImpl(status, "Transaction::Rollback");
00188         mHandle = 0;    // Should be, better be sure
00189 }
00190 
00191 void TransactionImpl::RollbackRetain()
00192 {
00193         if (mHandle == 0)
00194                 throw LogicExceptionImpl("Transaction::RollbackRetain", _("Transaction is not started."));
00195 
00196         IBS status;
00197 
00198         (*gds.Call()->m_rollback_retaining)(status.Self(), &mHandle);
00199         if (status.Errors())
00200                 throw SQLExceptionImpl(status, "Transaction::RollbackRetain");
00201 }
00202 
00203 IBPP::ITransaction* TransactionImpl::AddRef()
00204 {
00205         ASSERTION(mRefCount >= 0);
00206         ++mRefCount;
00207         return this;
00208 }
00209 
00210 void TransactionImpl::Release()
00211 {
00212         // Release cannot throw, except in DEBUG builds on assertion
00213         ASSERTION(mRefCount >= 0);
00214         --mRefCount;
00215         try { if (mRefCount <= 0) delete this; }
00216                 catch (...) { }
00217 }
00218 
00219 //      (((((((( OBJECT INTERNAL METHODS ))))))))
00220 
00221 void TransactionImpl::Init()
00222 {
00223         mHandle = 0;
00224         mDatabases.clear();
00225         mTPBs.clear();
00226         mStatements.clear();
00227         mBlobs.clear();
00228         mArrays.clear();
00229 }
00230 
00231 void TransactionImpl::AttachStatementImpl(StatementImpl* st)
00232 {
00233         if (st == 0)
00234                 throw LogicExceptionImpl("Transaction::AttachStatement",
00235                                         _("Can't attach a 0 Statement object."));
00236 
00237         mStatements.push_back(st);
00238 }
00239 
00240 void TransactionImpl::DetachStatementImpl(StatementImpl* st)
00241 {
00242         if (st == 0)
00243                 throw LogicExceptionImpl("Transaction::DetachStatement",
00244                                 _("Can't detach a 0 Statement object."));
00245 
00246         mStatements.erase(std::find(mStatements.begin(), mStatements.end(), st));
00247 }
00248 
00249 void TransactionImpl::AttachBlobImpl(BlobImpl* bb)
00250 {
00251         if (bb == 0)
00252                 throw LogicExceptionImpl("Transaction::AttachBlob",
00253                                         _("Can't attach a 0 BlobImpl object."));
00254 
00255         mBlobs.push_back(bb);
00256 }
00257 
00258 void TransactionImpl::DetachBlobImpl(BlobImpl* bb)
00259 {
00260         if (bb == 0)
00261                 throw LogicExceptionImpl("Transaction::DetachBlob",
00262                                 _("Can't detach a 0 BlobImpl object."));
00263 
00264         mBlobs.erase(std::find(mBlobs.begin(), mBlobs.end(), bb));
00265 }
00266 
00267 void TransactionImpl::AttachArrayImpl(ArrayImpl* ar)
00268 {
00269         if (ar == 0)
00270                 throw LogicExceptionImpl("Transaction::AttachArray",
00271                                         _("Can't attach a 0 ArrayImpl object."));
00272 
00273         mArrays.push_back(ar);
00274 }
00275 
00276 void TransactionImpl::DetachArrayImpl(ArrayImpl* ar)
00277 {
00278         if (ar == 0)
00279                 throw LogicExceptionImpl("Transaction::DetachArray",
00280                                 _("Can't detach a 0 ArrayImpl object."));
00281 
00282         mArrays.erase(std::find(mArrays.begin(), mArrays.end(), ar));
00283 }
00284 
00285 void TransactionImpl::AttachDatabaseImpl(DatabaseImpl* dbi,
00286         IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)
00287 {
00288         if (mHandle != 0)
00289                 throw LogicExceptionImpl("Transaction::AttachDatabase",
00290                                 _("Can't attach a Database if Transaction started."));
00291         if (dbi == 0)
00292                 throw LogicExceptionImpl("Transaction::AttachDatabase",
00293                                 _("Can't attach a null Database."));
00294 
00295         mDatabases.push_back(dbi);
00296 
00297         // Prepare a new TPB
00298         TPB* tpb = new TPB;
00299     if (am == IBPP::amRead) tpb->Insert(isc_tpb_read);
00300     else tpb->Insert(isc_tpb_write);
00301 
00302         switch (il)
00303         {
00304                 case IBPP::ilConsistency :              tpb->Insert(isc_tpb_consistency); break;
00305                 case IBPP::ilReadDirty :                tpb->Insert(isc_tpb_read_committed);
00306                                                                 tpb->Insert(isc_tpb_rec_version); break;
00307                 case IBPP::ilReadCommitted :    tpb->Insert(isc_tpb_read_committed);
00308                                                                                 tpb->Insert(isc_tpb_no_rec_version); break;
00309                 default :                                               tpb->Insert(isc_tpb_concurrency); break;
00310         }
00311 
00312     if (lr == IBPP::lrNoWait) tpb->Insert(isc_tpb_nowait);
00313     else tpb->Insert(isc_tpb_wait);
00314 
00315         if (flags & IBPP::tfIgnoreLimbo)        tpb->Insert(isc_tpb_ignore_limbo);
00316         if (flags & IBPP::tfAutoCommit)         tpb->Insert(isc_tpb_autocommit);
00317         if (flags & IBPP::tfNoAutoUndo)         tpb->Insert(isc_tpb_no_auto_undo);
00318 
00319         mTPBs.push_back(tpb);
00320 
00321         // Signals the Database object that it has been attached to the Transaction
00322         dbi->AttachTransactionImpl(this);
00323 }
00324 
00325 void TransactionImpl::DetachDatabaseImpl(DatabaseImpl* dbi)
00326 {
00327         if (mHandle != 0)
00328                 throw LogicExceptionImpl("Transaction::DetachDatabase",
00329                                 _("Can't detach a Database if Transaction started."));
00330         if (dbi == 0)
00331                 throw LogicExceptionImpl("Transaction::DetachDatabase",
00332                                 _("Can't detach a null Database."));
00333 
00334         std::vector<DatabaseImpl*>::iterator pos =
00335                 std::find(mDatabases.begin(), mDatabases.end(), dbi);
00336         if (pos != mDatabases.end())
00337         {
00338                 size_t index = pos - mDatabases.begin();
00339                 TPB* tpb = mTPBs[index];
00340                 mDatabases.erase(pos);
00341                 mTPBs.erase(mTPBs.begin()+index);
00342                 delete tpb;
00343         }
00344 
00345         // Signals the Database object that it has been detached from the Transaction
00346         dbi->DetachTransactionImpl(this);
00347 }
00348 
00349 TransactionImpl::TransactionImpl(DatabaseImpl* db,
00350         IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)
00351         : mRefCount(0)
00352 {
00353         Init();
00354         AttachDatabaseImpl(db, am, il, lr, flags);
00355 }
00356 
00357 TransactionImpl::~TransactionImpl()
00358 {
00359         // Rollback the transaction if it was Started
00360         try { if (Started()) Rollback(); }
00361                 catch (...) { }
00362 
00363         // Let's detach cleanly all Blobs from this Transaction.
00364         // No Blob object can still maintain pointers to this
00365         // Transaction which is disappearing.
00366         //
00367         // We use a reverse traversal of the array to avoid loops.
00368         // The array shrinks on each loop (mBbCount decreases).
00369         // And during the deletion, there is a packing of the array through a
00370         // copy of elements from the end to the beginning of the array.
00371         try {
00372                 while (mBlobs.size() > 0)
00373                         mBlobs.back()->DetachTransactionImpl();
00374         } catch (...) { }
00375 
00376         // Let's detach cleanly all Arrays from this Transaction.
00377         // No Array object can still maintain pointers to this
00378         // Transaction which is disappearing.
00379         try {
00380                 while (mArrays.size() > 0)
00381                         mArrays.back()->DetachTransactionImpl();
00382         } catch (...) { }
00383 
00384         // Let's detach cleanly all Statements from this Transaction.
00385         // No Statement object can still maintain pointers to this
00386         // Transaction which is disappearing.
00387         try {
00388                 while (mStatements.size() > 0)
00389                         mStatements.back()->DetachTransactionImpl();
00390         } catch (...) { }
00391 
00392         // Very important : let's detach cleanly all Databases from this
00393         // Transaction. No Database object can still maintain pointers to this
00394         // Transaction which is disappearing.
00395         try {
00396                 while (mDatabases.size() > 0)
00397                 {
00398                         size_t i = mDatabases.size()-1;
00399                         DetachDatabaseImpl(mDatabases[i]);      // <-- remove link to database from mTPBs
00400                                                                                         // array and destroy TPB object
00401                                                                                         // Fixed : Maxim Abrashkin on 12 Jun 2002
00402                         //mDatabases.back()->DetachTransaction(this);
00403                 }
00404         } catch (...) { }
00405 }
00406 
00407 //
00408 //      EOF
00409 //

Generated on Sun Jul 29 04:01:29 2012 for TerraLib - Development Source by  doxygen 1.5.3