+++ /dev/null
-///////////////////////////////////////////////////////////////////////////////\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