1 ///////////////////////////////////////////////////////////////////////////////
\r
3 // File : $Id: transaction.cpp,v 1.1 2007/05/05 17:00:43 faust Exp $
\r
4 // Subject : IBPP, Database class implementation
\r
6 ///////////////////////////////////////////////////////////////////////////////
\r
8 // (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)
\r
10 // The contents of this file are subject to the IBPP License (the "License");
\r
11 // you may not use this file except in compliance with the License. You may
\r
12 // obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'
\r
13 // file which must have been distributed along with this file.
\r
15 // This software, distributed under the License, is distributed on an "AS IS"
\r
16 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
\r
17 // License for the specific language governing rights and limitations
\r
18 // under the License.
\r
20 ///////////////////////////////////////////////////////////////////////////////
\r
23 // * Tabulations should be set every four characters when editing this file.
\r
25 ///////////////////////////////////////////////////////////////////////////////
\r
28 #pragma warning(disable: 4786 4996)
\r
30 #pragma warning(disable: 4702)
\r
40 #include <algorithm>
\r
42 using namespace ibpp_internals;
\r
44 // (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))
\r
46 void TransactionImpl::AttachDatabase(IBPP::Database db,
\r
47 IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)
\r
50 throw LogicExceptionImpl("Transaction::AttachDatabase",
\r
51 _("Can't attach an unbound Database."));
\r
53 AttachDatabaseImpl(dynamic_cast<DatabaseImpl*>(db.intf()), am, il, lr, flags);
\r
56 void TransactionImpl::DetachDatabase(IBPP::Database db)
\r
59 throw LogicExceptionImpl("Transaction::DetachDatabase",
\r
60 _("Can't detach an unbound Database."));
\r
62 DetachDatabaseImpl(dynamic_cast<DatabaseImpl*>(db.intf()));
\r
65 void TransactionImpl::AddReservation(IBPP::Database db,
\r
66 const std::string& table, IBPP::TTR tr)
\r
69 throw LogicExceptionImpl("Transaction::AddReservation",
\r
70 _("Can't add table reservation if Transaction started."));
\r
72 throw LogicExceptionImpl("Transaction::AddReservation",
\r
73 _("Can't add table reservation on an unbound Database."));
\r
75 // Find the TPB associated with this database
\r
76 std::vector<DatabaseImpl*>::iterator pos =
\r
77 std::find(mDatabases.begin(), mDatabases.end(), dynamic_cast<DatabaseImpl*>(db.intf()));
\r
78 if (pos != mDatabases.end())
\r
80 size_t index = pos - mDatabases.begin();
\r
81 TPB* tpb = mTPBs[index];
\r
83 // Now add the reservations to the TPB
\r
86 case IBPP::trSharedWrite :
\r
87 tpb->Insert(isc_tpb_lock_write);
\r
89 tpb->Insert(isc_tpb_shared);
\r
91 case IBPP::trSharedRead :
\r
92 tpb->Insert(isc_tpb_lock_read);
\r
94 tpb->Insert(isc_tpb_shared);
\r
96 case IBPP::trProtectedWrite :
\r
97 tpb->Insert(isc_tpb_lock_write);
\r
99 tpb->Insert(isc_tpb_protected);
\r
101 case IBPP::trProtectedRead :
\r
102 tpb->Insert(isc_tpb_lock_read);
\r
103 tpb->Insert(table);
\r
104 tpb->Insert(isc_tpb_protected);
\r
107 throw LogicExceptionImpl("Transaction::AddReservation",
\r
108 _("Illegal TTR value detected."));
\r
111 else throw LogicExceptionImpl("Transaction::AddReservation",
\r
112 _("The database connection you specified is not attached to this transaction."));
\r
115 void TransactionImpl::Start()
\r
117 if (mHandle != 0) return; // Already started anyway
\r
119 if (mDatabases.empty())
\r
120 throw LogicExceptionImpl("Transaction::Start", _("No Database is attached."));
\r
127 } * teb = new ISC_TEB[mDatabases.size()];
\r
130 for (i = 0; i < mDatabases.size(); i++)
\r
132 if (mDatabases[i]->GetHandle() == 0)
\r
134 // All Databases must be connected to Start the transaction !
\r
136 throw LogicExceptionImpl("Transaction::Start",
\r
137 _("All attached Database should have been connected."));
\r
139 teb[i].db_ptr = (ISC_LONG*) mDatabases[i]->GetHandlePtr();
\r
140 teb[i].tpb_len = mTPBs[i]->Size();
\r
141 teb[i].tpb_ptr = mTPBs[i]->Self();
\r
145 (*gds.Call()->m_start_multiple)(status.Self(), &mHandle, (short)mDatabases.size(), teb);
\r
147 if (status.Errors())
\r
149 mHandle = 0; // Should be, but better be sure...
\r
150 throw SQLExceptionImpl(status, "Transaction::Start");
\r
154 void TransactionImpl::Commit()
\r
157 throw LogicExceptionImpl("Transaction::Commit", _("Transaction is not started."));
\r
161 (*gds.Call()->m_commit_transaction)(status.Self(), &mHandle);
\r
162 if (status.Errors())
\r
163 throw SQLExceptionImpl(status, "Transaction::Commit");
\r
164 mHandle = 0; // Should be, better be sure
\r
167 void TransactionImpl::CommitRetain()
\r
170 throw LogicExceptionImpl("Transaction::CommitRetain", _("Transaction is not started."));
\r
174 (*gds.Call()->m_commit_retaining)(status.Self(), &mHandle);
\r
175 if (status.Errors())
\r
176 throw SQLExceptionImpl(status, "Transaction::CommitRetain");
\r
179 void TransactionImpl::Rollback()
\r
181 if (mHandle == 0) return; // Transaction not started anyway
\r
185 (*gds.Call()->m_rollback_transaction)(status.Self(), &mHandle);
\r
186 if (status.Errors())
\r
187 throw SQLExceptionImpl(status, "Transaction::Rollback");
\r
188 mHandle = 0; // Should be, better be sure
\r
191 void TransactionImpl::RollbackRetain()
\r
194 throw LogicExceptionImpl("Transaction::RollbackRetain", _("Transaction is not started."));
\r
198 (*gds.Call()->m_rollback_retaining)(status.Self(), &mHandle);
\r
199 if (status.Errors())
\r
200 throw SQLExceptionImpl(status, "Transaction::RollbackRetain");
\r
203 IBPP::ITransaction* TransactionImpl::AddRef()
\r
205 ASSERTION(mRefCount >= 0);
\r
210 void TransactionImpl::Release()
\r
212 // Release cannot throw, except in DEBUG builds on assertion
\r
213 ASSERTION(mRefCount >= 0);
\r
215 try { if (mRefCount <= 0) delete this; }
\r
219 // (((((((( OBJECT INTERNAL METHODS ))))))))
\r
221 void TransactionImpl::Init()
\r
224 mDatabases.clear();
\r
226 mStatements.clear();
\r
231 void TransactionImpl::AttachStatementImpl(StatementImpl* st)
\r
234 throw LogicExceptionImpl("Transaction::AttachStatement",
\r
235 _("Can't attach a 0 Statement object."));
\r
237 mStatements.push_back(st);
\r
240 void TransactionImpl::DetachStatementImpl(StatementImpl* st)
\r
243 throw LogicExceptionImpl("Transaction::DetachStatement",
\r
244 _("Can't detach a 0 Statement object."));
\r
246 mStatements.erase(std::find(mStatements.begin(), mStatements.end(), st));
\r
249 void TransactionImpl::AttachBlobImpl(BlobImpl* bb)
\r
252 throw LogicExceptionImpl("Transaction::AttachBlob",
\r
253 _("Can't attach a 0 BlobImpl object."));
\r
255 mBlobs.push_back(bb);
\r
258 void TransactionImpl::DetachBlobImpl(BlobImpl* bb)
\r
261 throw LogicExceptionImpl("Transaction::DetachBlob",
\r
262 _("Can't detach a 0 BlobImpl object."));
\r
264 mBlobs.erase(std::find(mBlobs.begin(), mBlobs.end(), bb));
\r
267 void TransactionImpl::AttachArrayImpl(ArrayImpl* ar)
\r
270 throw LogicExceptionImpl("Transaction::AttachArray",
\r
271 _("Can't attach a 0 ArrayImpl object."));
\r
273 mArrays.push_back(ar);
\r
276 void TransactionImpl::DetachArrayImpl(ArrayImpl* ar)
\r
279 throw LogicExceptionImpl("Transaction::DetachArray",
\r
280 _("Can't detach a 0 ArrayImpl object."));
\r
282 mArrays.erase(std::find(mArrays.begin(), mArrays.end(), ar));
\r
285 void TransactionImpl::AttachDatabaseImpl(DatabaseImpl* dbi,
\r
286 IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)
\r
289 throw LogicExceptionImpl("Transaction::AttachDatabase",
\r
290 _("Can't attach a Database if Transaction started."));
\r
292 throw LogicExceptionImpl("Transaction::AttachDatabase",
\r
293 _("Can't attach a null Database."));
\r
295 mDatabases.push_back(dbi);
\r
297 // Prepare a new TPB
\r
298 TPB* tpb = new TPB;
\r
299 if (am == IBPP::amRead) tpb->Insert(isc_tpb_read);
\r
300 else tpb->Insert(isc_tpb_write);
\r
304 case IBPP::ilConsistency : tpb->Insert(isc_tpb_consistency); break;
\r
305 case IBPP::ilReadDirty : tpb->Insert(isc_tpb_read_committed);
\r
306 tpb->Insert(isc_tpb_rec_version); break;
\r
307 case IBPP::ilReadCommitted : tpb->Insert(isc_tpb_read_committed);
\r
308 tpb->Insert(isc_tpb_no_rec_version); break;
\r
309 default : tpb->Insert(isc_tpb_concurrency); break;
\r
312 if (lr == IBPP::lrNoWait) tpb->Insert(isc_tpb_nowait);
\r
313 else tpb->Insert(isc_tpb_wait);
\r
315 if (flags & IBPP::tfIgnoreLimbo) tpb->Insert(isc_tpb_ignore_limbo);
\r
316 if (flags & IBPP::tfAutoCommit) tpb->Insert(isc_tpb_autocommit);
\r
317 if (flags & IBPP::tfNoAutoUndo) tpb->Insert(isc_tpb_no_auto_undo);
\r
319 mTPBs.push_back(tpb);
\r
321 // Signals the Database object that it has been attached to the Transaction
\r
322 dbi->AttachTransactionImpl(this);
\r
325 void TransactionImpl::DetachDatabaseImpl(DatabaseImpl* dbi)
\r
328 throw LogicExceptionImpl("Transaction::DetachDatabase",
\r
329 _("Can't detach a Database if Transaction started."));
\r
331 throw LogicExceptionImpl("Transaction::DetachDatabase",
\r
332 _("Can't detach a null Database."));
\r
334 std::vector<DatabaseImpl*>::iterator pos =
\r
335 std::find(mDatabases.begin(), mDatabases.end(), dbi);
\r
336 if (pos != mDatabases.end())
\r
338 size_t index = pos - mDatabases.begin();
\r
339 TPB* tpb = mTPBs[index];
\r
340 mDatabases.erase(pos);
\r
341 mTPBs.erase(mTPBs.begin()+index);
\r
345 // Signals the Database object that it has been detached from the Transaction
\r
346 dbi->DetachTransactionImpl(this);
\r
349 TransactionImpl::TransactionImpl(DatabaseImpl* db,
\r
350 IBPP::TAM am, IBPP::TIL il, IBPP::TLR lr, IBPP::TFF flags)
\r
354 AttachDatabaseImpl(db, am, il, lr, flags);
\r
357 TransactionImpl::~TransactionImpl()
\r
359 // Rollback the transaction if it was Started
\r
360 try { if (Started()) Rollback(); }
\r
363 // Let's detach cleanly all Blobs from this Transaction.
\r
364 // No Blob object can still maintain pointers to this
\r
365 // Transaction which is disappearing.
\r
367 // We use a reverse traversal of the array to avoid loops.
\r
368 // The array shrinks on each loop (mBbCount decreases).
\r
369 // And during the deletion, there is a packing of the array through a
\r
370 // copy of elements from the end to the beginning of the array.
\r
372 while (mBlobs.size() > 0)
\r
373 mBlobs.back()->DetachTransactionImpl();
\r
376 // Let's detach cleanly all Arrays from this Transaction.
\r
377 // No Array object can still maintain pointers to this
\r
378 // Transaction which is disappearing.
\r
380 while (mArrays.size() > 0)
\r
381 mArrays.back()->DetachTransactionImpl();
\r
384 // Let's detach cleanly all Statements from this Transaction.
\r
385 // No Statement object can still maintain pointers to this
\r
386 // Transaction which is disappearing.
\r
388 while (mStatements.size() > 0)
\r
389 mStatements.back()->DetachTransactionImpl();
\r
392 // Very important : let's detach cleanly all Databases from this
\r
393 // Transaction. No Database object can still maintain pointers to this
\r
394 // Transaction which is disappearing.
\r
396 while (mDatabases.size() > 0)
\r
398 size_t i = mDatabases.size()-1;
\r
399 DetachDatabaseImpl(mDatabases[i]); // <-- remove link to database from mTPBs
\r
400 // array and destroy TPB object
\r
401 // Fixed : Maxim Abrashkin on 12 Jun 2002
\r
402 //mDatabases.back()->DetachTransaction(this);
\r