]> git.stg.codes - stg.git/blobdiff - libs/ibpp/transaction.cpp
Port to CMake, get rid of os_int.h.
[stg.git] / libs / ibpp / transaction.cpp
diff --git a/libs/ibpp/transaction.cpp b/libs/ibpp/transaction.cpp
new file mode 100644 (file)
index 0000000..47eb61c
--- /dev/null
@@ -0,0 +1,409 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: transaction.cpp,v 1.1 2007/05/05 17:00:43 faust Exp $\r
+//     Subject : IBPP, Database class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <algorithm>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void TransactionImpl::AttachDatabase(IBPP::Database db,\r
+       IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)\r
+{\r
+       if (db.intf() == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachDatabase",\r
+                               _("Can't attach an unbound Database."));\r
+\r
+       AttachDatabaseImpl(dynamic_cast<DatabaseImpl*>(db.intf()), am, il, lr, flags);\r
+}\r
+\r
+void TransactionImpl::DetachDatabase(IBPP::Database db)\r
+{\r
+       if (db.intf() == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachDatabase",\r
+                               _("Can't detach an unbound Database."));\r
+\r
+       DetachDatabaseImpl(dynamic_cast<DatabaseImpl*>(db.intf()));\r
+}\r
+\r
+void TransactionImpl::AddReservation(IBPP::Database db,\r
+       const std::string& table, IBPP::TTR tr)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Transaction::AddReservation",\r
+                               _("Can't add table reservation if Transaction started."));\r
+       if (db.intf() == 0)\r
+               throw LogicExceptionImpl("Transaction::AddReservation",\r
+                               _("Can't add table reservation on an unbound Database."));\r
+\r
+       // Find the TPB associated with this database\r
+       std::vector<DatabaseImpl*>::iterator pos =\r
+               std::find(mDatabases.begin(), mDatabases.end(), dynamic_cast<DatabaseImpl*>(db.intf()));\r
+       if (pos != mDatabases.end())\r
+       {\r
+               size_t index = pos - mDatabases.begin();\r
+               TPB* tpb = mTPBs[index];\r
+               \r
+               // Now add the reservations to the TPB\r
+               switch (tr)\r
+               {\r
+                       case IBPP::trSharedWrite :\r
+                                       tpb->Insert(isc_tpb_lock_write);\r
+                                       tpb->Insert(table);\r
+                                       tpb->Insert(isc_tpb_shared);\r
+                                       break;\r
+                       case IBPP::trSharedRead :\r
+                                       tpb->Insert(isc_tpb_lock_read);\r
+                                       tpb->Insert(table);\r
+                                       tpb->Insert(isc_tpb_shared);\r
+                                       break;\r
+                       case IBPP::trProtectedWrite :\r
+                                       tpb->Insert(isc_tpb_lock_write);\r
+                                       tpb->Insert(table);\r
+                                       tpb->Insert(isc_tpb_protected);\r
+                                       break;\r
+                       case IBPP::trProtectedRead :\r
+                                       tpb->Insert(isc_tpb_lock_read);\r
+                                       tpb->Insert(table);\r
+                                       tpb->Insert(isc_tpb_protected);\r
+                                       break;\r
+                       /*default :\r
+                                       throw LogicExceptionImpl("Transaction::AddReservation",\r
+                                               _("Illegal TTR value detected."));*/\r
+               }\r
+       }\r
+       else throw LogicExceptionImpl("Transaction::AddReservation",\r
+                       _("The database connection you specified is not attached to this transaction."));\r
+}\r
+\r
+void TransactionImpl::Start()\r
+{\r
+       if (mHandle != 0) return;       // Already started anyway\r
+\r
+       if (mDatabases.empty())\r
+               throw LogicExceptionImpl("Transaction::Start", _("No Database is attached."));\r
+\r
+       struct ISC_TEB\r
+       {\r
+               ISC_LONG* db_ptr;\r
+               ISC_LONG tpb_len;\r
+               char* tpb_ptr;\r
+       } * teb = new ISC_TEB[mDatabases.size()];\r
+\r
+       unsigned i;\r
+       for (i = 0; i < mDatabases.size(); i++)\r
+       {\r
+               if (mDatabases[i]->GetHandle() == 0)\r
+               {\r
+                       // All Databases must be connected to Start the transaction !\r
+                       delete [] teb;\r
+                       throw LogicExceptionImpl("Transaction::Start",\r
+                                       _("All attached Database should have been connected."));\r
+               }\r
+               teb[i].db_ptr = (ISC_LONG*) mDatabases[i]->GetHandlePtr();\r
+               teb[i].tpb_len = mTPBs[i]->Size();\r
+               teb[i].tpb_ptr = mTPBs[i]->Self();\r
+       }\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_start_multiple)(status.Self(), &mHandle, (short)mDatabases.size(), teb);\r
+       delete [] teb;\r
+       if (status.Errors())\r
+       {\r
+               mHandle = 0;    // Should be, but better be sure...\r
+               throw SQLExceptionImpl(status, "Transaction::Start");\r
+       }\r
+}\r
+\r
+void TransactionImpl::Commit()\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Transaction::Commit", _("Transaction is not started."));\r
+               \r
+       IBS status;\r
+\r
+       (*gds.Call()->m_commit_transaction)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Transaction::Commit");\r
+       mHandle = 0;    // Should be, better be sure\r
+}\r
+\r
+void TransactionImpl::CommitRetain()\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Transaction::CommitRetain", _("Transaction is not started."));\r
+\r
+       IBS status;\r
+\r
+       (*gds.Call()->m_commit_retaining)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Transaction::CommitRetain");\r
+}\r
+\r
+void TransactionImpl::Rollback()\r
+{\r
+       if (mHandle == 0) return;       // Transaction not started anyway\r
+\r
+       IBS status;\r
+\r
+       (*gds.Call()->m_rollback_transaction)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Transaction::Rollback");\r
+       mHandle = 0;    // Should be, better be sure\r
+}\r
+\r
+void TransactionImpl::RollbackRetain()\r
+{\r
+       if (mHandle == 0)\r
+               throw LogicExceptionImpl("Transaction::RollbackRetain", _("Transaction is not started."));\r
+\r
+       IBS status;\r
+\r
+       (*gds.Call()->m_rollback_retaining)(status.Self(), &mHandle);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Transaction::RollbackRetain");\r
+}\r
+\r
+IBPP::ITransaction* TransactionImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void TransactionImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void TransactionImpl::Init()\r
+{\r
+       mHandle = 0;\r
+       mDatabases.clear();\r
+       mTPBs.clear();\r
+       mStatements.clear();\r
+       mBlobs.clear();\r
+       mArrays.clear();\r
+}\r
+\r
+void TransactionImpl::AttachStatementImpl(StatementImpl* st)\r
+{\r
+       if (st == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachStatement",\r
+                                       _("Can't attach a 0 Statement object."));\r
+\r
+       mStatements.push_back(st);\r
+}\r
+\r
+void TransactionImpl::DetachStatementImpl(StatementImpl* st)\r
+{\r
+       if (st == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachStatement",\r
+                               _("Can't detach a 0 Statement object."));\r
+\r
+       mStatements.erase(std::find(mStatements.begin(), mStatements.end(), st));\r
+}\r
+\r
+void TransactionImpl::AttachBlobImpl(BlobImpl* bb)\r
+{\r
+       if (bb == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachBlob",\r
+                                       _("Can't attach a 0 BlobImpl object."));\r
+\r
+       mBlobs.push_back(bb);\r
+}\r
+\r
+void TransactionImpl::DetachBlobImpl(BlobImpl* bb)\r
+{\r
+       if (bb == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachBlob",\r
+                               _("Can't detach a 0 BlobImpl object."));\r
+\r
+       mBlobs.erase(std::find(mBlobs.begin(), mBlobs.end(), bb));\r
+}\r
+\r
+void TransactionImpl::AttachArrayImpl(ArrayImpl* ar)\r
+{\r
+       if (ar == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachArray",\r
+                                       _("Can't attach a 0 ArrayImpl object."));\r
+\r
+       mArrays.push_back(ar);\r
+}\r
+\r
+void TransactionImpl::DetachArrayImpl(ArrayImpl* ar)\r
+{\r
+       if (ar == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachArray",\r
+                               _("Can't detach a 0 ArrayImpl object."));\r
+\r
+       mArrays.erase(std::find(mArrays.begin(), mArrays.end(), ar));\r
+}\r
+\r
+void TransactionImpl::AttachDatabaseImpl(DatabaseImpl* dbi,\r
+       IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Transaction::AttachDatabase",\r
+                               _("Can't attach a Database if Transaction started."));\r
+       if (dbi == 0)\r
+               throw LogicExceptionImpl("Transaction::AttachDatabase",\r
+                               _("Can't attach a null Database."));\r
+\r
+       mDatabases.push_back(dbi);\r
+\r
+       // Prepare a new TPB\r
+       TPB* tpb = new TPB;\r
+    if (am == IBPP::amRead) tpb->Insert(isc_tpb_read);\r
+    else tpb->Insert(isc_tpb_write);\r
+\r
+       switch (il)\r
+       {\r
+               case IBPP::ilConsistency :              tpb->Insert(isc_tpb_consistency); break;\r
+               case IBPP::ilReadDirty :                tpb->Insert(isc_tpb_read_committed);\r
+                                                               tpb->Insert(isc_tpb_rec_version); break;\r
+               case IBPP::ilReadCommitted :    tpb->Insert(isc_tpb_read_committed);\r
+                                                                               tpb->Insert(isc_tpb_no_rec_version); break;\r
+                case IBPP::ilConcurrency :                                             tpb->Insert(isc_tpb_concurrency); break;\r
+       }\r
+\r
+    if (lr == IBPP::lrNoWait) tpb->Insert(isc_tpb_nowait);\r
+    else tpb->Insert(isc_tpb_wait);\r
+\r
+       if (flags & IBPP::tfIgnoreLimbo)        tpb->Insert(isc_tpb_ignore_limbo);\r
+       if (flags & IBPP::tfAutoCommit)         tpb->Insert(isc_tpb_autocommit);\r
+       if (flags & IBPP::tfNoAutoUndo)         tpb->Insert(isc_tpb_no_auto_undo);\r
+\r
+       mTPBs.push_back(tpb);\r
+\r
+       // Signals the Database object that it has been attached to the Transaction\r
+       dbi->AttachTransactionImpl(this);\r
+}\r
+\r
+void TransactionImpl::DetachDatabaseImpl(DatabaseImpl* dbi)\r
+{\r
+       if (mHandle != 0)\r
+               throw LogicExceptionImpl("Transaction::DetachDatabase",\r
+                               _("Can't detach a Database if Transaction started."));\r
+       if (dbi == 0)\r
+               throw LogicExceptionImpl("Transaction::DetachDatabase",\r
+                               _("Can't detach a null Database."));\r
+\r
+       std::vector<DatabaseImpl*>::iterator pos =\r
+               std::find(mDatabases.begin(), mDatabases.end(), dbi);\r
+       if (pos != mDatabases.end())\r
+       {\r
+               size_t index = pos - mDatabases.begin();\r
+               TPB* tpb = mTPBs[index];\r
+               mDatabases.erase(pos);\r
+               mTPBs.erase(mTPBs.begin()+index);\r
+               delete tpb;\r
+       }\r
+\r
+       // Signals the Database object that it has been detached from the Transaction\r
+       dbi->DetachTransactionImpl(this);\r
+}\r
+\r
+TransactionImpl::TransactionImpl(DatabaseImpl* db,\r
+       IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)\r
+       : mRefCount(0)\r
+{\r
+       Init();\r
+       AttachDatabaseImpl(db, am, il, lr, flags);\r
+}\r
+\r
+TransactionImpl::~TransactionImpl()\r
+{\r
+       // Rollback the transaction if it was Started\r
+       try { if (Started()) Rollback(); }\r
+               catch (...) { }\r
+\r
+       // Let's detach cleanly all Blobs from this Transaction.\r
+       // No Blob object can still maintain pointers to this\r
+       // Transaction which is disappearing.\r
+       //\r
+       // We use a reverse traversal of the array to avoid loops.\r
+       // The array shrinks on each loop (mBbCount decreases).\r
+       // And during the deletion, there is a packing of the array through a\r
+       // copy of elements from the end to the beginning of the array.\r
+       try {\r
+               while (mBlobs.size() > 0)\r
+                       mBlobs.back()->DetachTransactionImpl();\r
+       } catch (...) { }\r
+\r
+       // Let's detach cleanly all Arrays from this Transaction.\r
+       // No Array object can still maintain pointers to this\r
+       // Transaction which is disappearing.\r
+       try {\r
+               while (mArrays.size() > 0)\r
+                       mArrays.back()->DetachTransactionImpl();\r
+       } catch (...) { }\r
+\r
+       // Let's detach cleanly all Statements from this Transaction.\r
+       // No Statement object can still maintain pointers to this\r
+       // Transaction which is disappearing.\r
+       try {\r
+               while (mStatements.size() > 0)\r
+                       mStatements.back()->DetachTransactionImpl();\r
+       } catch (...) { }\r
+\r
+       // Very important : let's detach cleanly all Databases from this\r
+       // Transaction. No Database object can still maintain pointers to this\r
+       // Transaction which is disappearing.\r
+       try {\r
+               while (mDatabases.size() > 0)\r
+               {\r
+                       size_t i = mDatabases.size()-1;\r
+                       DetachDatabaseImpl(mDatabases[i]);      // <-- remove link to database from mTPBs\r
+                                                                                       // array and destroy TPB object\r
+                                                                                       // Fixed : Maxim Abrashkin on 12 Jun 2002\r
+                       //mDatabases.back()->DetachTransaction(this);\r
+               }\r
+       } catch (...) { }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r