00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
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
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;
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
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;
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;
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;
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;
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
00213 ASSERTION(mRefCount >= 0);
00214 --mRefCount;
00215 try { if (mRefCount <= 0) delete this; }
00216 catch (...) { }
00217 }
00218
00219
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
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
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
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
00360 try { if (Started()) Rollback(); }
00361 catch (...) { }
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 try {
00372 while (mBlobs.size() > 0)
00373 mBlobs.back()->DetachTransactionImpl();
00374 } catch (...) { }
00375
00376
00377
00378
00379 try {
00380 while (mArrays.size() > 0)
00381 mArrays.back()->DetachTransactionImpl();
00382 } catch (...) { }
00383
00384
00385
00386
00387 try {
00388 while (mStatements.size() > 0)
00389 mStatements.back()->DetachTransactionImpl();
00390 } catch (...) { }
00391
00392
00393
00394
00395 try {
00396 while (mDatabases.size() > 0)
00397 {
00398 size_t i = mDatabases.size()-1;
00399 DetachDatabaseImpl(mDatabases[i]);
00400
00401
00402
00403 }
00404 } catch (...) { }
00405 }
00406
00407
00408
00409