database.cpp

Go to the documentation of this file.
00001 ///////////////////////////////////////////////////////////////////////////////
00002 //
00003 //      File    : $Id: database.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 DatabaseImpl::Create(int dialect)
00047 {
00048         if (mHandle != 0)
00049                 throw LogicExceptionImpl("Database::Create", _("Database is already connected."));
00050         if (mDatabaseName.empty())
00051                 throw LogicExceptionImpl("Database::Create", _("Unspecified database name."));
00052         if (mUserName.empty())
00053                 throw LogicExceptionImpl("Database::Create", _("Unspecified user name."));
00054         if (dialect != 1 && dialect != 3)
00055                 throw LogicExceptionImpl("Database::Create", _("Only dialects 1 and 3 are supported."));
00056 
00057         // Build the SQL Create Statement
00058         std::string create;
00059         create.assign("CREATE DATABASE '");
00060         if (! mServerName.empty()) create.append(mServerName).append(":");
00061         create.append(mDatabaseName).append("' ");
00062 
00063         create.append("USER '").append(mUserName).append("' ");
00064         if (! mUserPassword.empty())
00065                 create.append("PASSWORD '").append(mUserPassword).append("' ");
00066 
00067         if (! mCreateParams.empty()) create.append(mCreateParams);
00068 
00069         // Call ExecuteImmediate to create the database
00070         isc_tr_handle tr_handle = 0;
00071         IBS status;
00072     (*gds.Call()->m_dsql_execute_immediate)(status.Self(), &mHandle, &tr_handle,
00073         0, const_cast<char*>(create.c_str()), short(dialect), NULL);
00074     if (status.Errors())
00075                 throw SQLExceptionImpl(status, "Database::Create", _("isc_dsql_execute_immediate failed"));
00076 
00077         Disconnect();
00078 }
00079 
00080 void DatabaseImpl::Connect()
00081 {
00082         if (mHandle != 0) return;       // Already connected
00083 
00084         if (mDatabaseName.empty())
00085                 throw LogicExceptionImpl("Database::Connect", _("Unspecified database name."));
00086         if (mUserName.empty())
00087                 throw LogicExceptionImpl("Database::Connect", _("Unspecified user name."));
00088 
00089     // Build a DPB based on the properties
00090         DPB dpb;
00091     dpb.Insert(isc_dpb_user_name, mUserName.c_str());
00092     dpb.Insert(isc_dpb_password, mUserPassword.c_str());
00093     if (! mRoleName.empty()) dpb.Insert(isc_dpb_sql_role_name, mRoleName.c_str());
00094     if (! mCharSet.empty()) dpb.Insert(isc_dpb_lc_ctype, mCharSet.c_str());
00095 
00096         std::string connect;
00097         if (! mServerName.empty())
00098                 connect.assign(mServerName).append(":");
00099         connect.append(mDatabaseName);
00100 
00101         IBS status;
00102         (*gds.Call()->m_attach_database)(status.Self(), (short)connect.size(),
00103                 const_cast<char*>(connect.c_str()), &mHandle, dpb.Size(), dpb.Self());
00104     if (status.Errors())
00105     {
00106         mHandle = 0;     // Should be, but better be sure...
00107                 throw SQLExceptionImpl(status, "Database::Connect", _("isc_attach_database failed"));
00108     }
00109 
00110         // Now, get ODS version information and dialect.
00111         // If ODS major is lower of equal to 9, we reject the connection.
00112         // If ODS major is 10 or higher, this is at least an InterBase 6.x Server
00113         // OR FireBird 1.x Server.
00114 
00115         char items[] = {isc_info_ods_version,
00116                                         isc_info_db_SQL_dialect,
00117                                         isc_info_end};
00118         RB result(100);
00119 
00120         status.Reset();
00121         (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
00122                 result.Size(), result.Self());
00123         if (status.Errors())
00124         {
00125                 status.Reset();
00126             (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
00127         mHandle = 0;     // Should be, but better be sure...
00128                 throw SQLExceptionImpl(status, "Database::Connect", _("isc_database_info failed"));
00129         }
00130 
00131         int ODS = result.GetValue(isc_info_ods_version);
00132         if (ODS <= 9)
00133         {
00134                 status.Reset();
00135             (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
00136         mHandle = 0;     // Should be, but better be sure...
00137                 throw LogicExceptionImpl("Database::Connect",
00138                         _("Unsupported Server : wrong ODS version (%d), at least '10' required."), ODS);
00139         }
00140 
00141         mDialect = result.GetValue(isc_info_db_SQL_dialect);
00142         if (mDialect != 1 && mDialect != 3)
00143         {
00144                 status.Reset();
00145             (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
00146         mHandle = 0;     // Should be, but better be sure...
00147                 throw LogicExceptionImpl("Database::Connect", _("Dialect 1 or 3 required"));
00148         }
00149 
00150         // Now, verify the GDS32.DLL we are using is compatible with the server
00151         if (ODS >= 10 && gds.Call()->mGDSVersion < 60)
00152         {
00153                 status.Reset();
00154             (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
00155         mHandle = 0;     // Should be, but better be sure...
00156                 throw LogicExceptionImpl("Database::Connect", _("GDS32.DLL version 5 against IBSERVER 6"));
00157         }
00158 }
00159 
00160 void DatabaseImpl::Inactivate()
00161 {
00162         if (mHandle == 0) return;       // Not connected anyway
00163 
00164     // Rollback any started transaction...
00165         for (unsigned i = 0; i < mTransactions.size(); i++)
00166         {
00167                 if (mTransactions[i]->Started())
00168                         mTransactions[i]->Rollback();
00169         }
00170 
00171         // Cancel all pending event traps
00172         for (unsigned i = 0; i < mEvents.size(); i++)
00173                 mEvents[i]->Clear();
00174 
00175         // Let's detach from all Blobs
00176         while (mBlobs.size() > 0)
00177                 mBlobs.back()->DetachDatabaseImpl();
00178 
00179         // Let's detach from all Arrays
00180         while (mArrays.size() > 0)
00181                 mArrays.back()->DetachDatabaseImpl();
00182 
00183         // Let's detach from all Statements
00184         while (mStatements.size() > 0)
00185                 mStatements.back()->DetachDatabaseImpl();
00186 
00187         // Let's detach from all Transactions
00188         while (mTransactions.size() > 0)
00189                 mTransactions.back()->DetachDatabaseImpl(this);
00190 
00191         // Let's detach from all Events
00192         while (mEvents.size() > 0)
00193                 mEvents.back()->DetachDatabaseImpl();
00194 }
00195 
00196 void DatabaseImpl::Disconnect()
00197 {
00198         if (mHandle == 0) return;       // Not connected anyway
00199 
00200         // Put the connection to rest
00201         Inactivate();
00202 
00203         // Detach from the server
00204         IBS status;
00205     (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
00206 
00207     // Should we throw, set mHandle to 0 first, because Disconnect() may
00208         // be called from Database destructor (keeps the object coherent).
00209         mHandle = 0;
00210     if (status.Errors())
00211                 throw SQLExceptionImpl(status, "Database::Disconnect", _("isc_detach_database failed"));
00212 }
00213 
00214 void DatabaseImpl::Drop()
00215 {
00216         if (mHandle == 0)
00217                 throw LogicExceptionImpl("Database::Drop", _("Database must be connected."));
00218 
00219         // Put the connection to a rest
00220         Inactivate();
00221 
00222         IBS vector;
00223         (*gds.Call()->m_drop_database)(vector.Self(), &mHandle);
00224     if (vector.Errors())
00225         throw SQLExceptionImpl(vector, "Database::Drop", _("isc_drop_database failed"));
00226 
00227     mHandle = 0;
00228 }
00229 
00230 void DatabaseImpl::Info(int* ODSMajor, int* ODSMinor,
00231         int* PageSize, int* Pages, int* Buffers, int* Sweep,
00232         bool* Sync, bool* Reserve)
00233 {
00234         if (mHandle == 0)
00235                 throw LogicExceptionImpl("Database::Info", _("Database is not connected."));
00236 
00237         char items[] = {isc_info_ods_version,
00238                                         isc_info_ods_minor_version,
00239                                         isc_info_page_size,
00240                                         isc_info_allocation,
00241                                         isc_info_num_buffers,
00242                                         isc_info_sweep_interval,
00243                                         isc_info_forced_writes,
00244                                         isc_info_no_reserve,
00245                                         isc_info_end};
00246     IBS status;
00247         RB result(256);
00248 
00249         status.Reset();
00250         (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
00251                 result.Size(), result.Self());
00252         if (status.Errors())
00253                 throw SQLExceptionImpl(status, "Database::Info", _("isc_database_info failed"));
00254 
00255         if (ODSMajor != 0) *ODSMajor = result.GetValue(isc_info_ods_version);
00256         if (ODSMinor != 0) *ODSMinor = result.GetValue(isc_info_ods_minor_version);
00257         if (PageSize != 0) *PageSize = result.GetValue(isc_info_page_size);
00258         if (Pages != 0) *Pages = result.GetValue(isc_info_allocation);
00259         if (Buffers != 0) *Buffers = result.GetValue(isc_info_num_buffers);
00260         if (Sweep != 0) *Sweep = result.GetValue(isc_info_sweep_interval);
00261         if (Sync != 0)
00262                 *Sync = result.GetValue(isc_info_forced_writes) == 1 ? true : false;
00263         if (Reserve != 0)
00264                 *Reserve = result.GetValue(isc_info_no_reserve) == 1 ? false : true;
00265 }
00266 
00267 void DatabaseImpl::Statistics(int* Fetches, int* Marks, int* Reads, int* Writes)
00268 {
00269         if (mHandle == 0)
00270                 throw LogicExceptionImpl("Database::Statistics", _("Database is not connected."));
00271 
00272         char items[] = {isc_info_fetches,
00273                                         isc_info_marks,
00274                                         isc_info_reads,
00275                                         isc_info_writes,
00276                                         isc_info_end};
00277     IBS status;
00278         RB result(128);
00279 
00280         status.Reset();
00281         (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
00282                 result.Size(), result.Self());
00283         if (status.Errors())
00284                 throw SQLExceptionImpl(status, "Database::Statistics", _("isc_database_info failed"));
00285 
00286         if (Fetches != 0) *Fetches = result.GetValue(isc_info_fetches);
00287         if (Marks != 0) *Marks = result.GetValue(isc_info_marks);
00288         if (Reads != 0) *Reads = result.GetValue(isc_info_reads);
00289         if (Writes != 0) *Writes = result.GetValue(isc_info_writes);
00290 }
00291 
00292 void DatabaseImpl::Counts(int* Insert, int* Update, int* Delete, 
00293         int* ReadIdx, int* ReadSeq)
00294 {
00295         if (mHandle == 0)
00296                 throw LogicExceptionImpl("Database::Counts", _("Database is not connected."));
00297 
00298         char items[] = {isc_info_insert_count,
00299                                         isc_info_update_count,
00300                                         isc_info_delete_count,
00301                                         isc_info_read_idx_count,
00302                                         isc_info_read_seq_count,
00303                                         isc_info_end};
00304     IBS status;
00305         RB result(1024);
00306 
00307         status.Reset();
00308         (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
00309                 result.Size(), result.Self());
00310         if (status.Errors())
00311                 throw SQLExceptionImpl(status, "Database::Counts", _("isc_database_info failed"));
00312 
00313         if (Insert != 0) *Insert = result.GetCountValue(isc_info_insert_count);
00314         if (Update != 0) *Update = result.GetCountValue(isc_info_update_count);
00315         if (Delete != 0) *Delete = result.GetCountValue(isc_info_delete_count);
00316         if (ReadIdx != 0) *ReadIdx = result.GetCountValue(isc_info_read_idx_count);
00317         if (ReadSeq != 0) *ReadSeq = result.GetCountValue(isc_info_read_seq_count);
00318 }
00319 
00320 void DatabaseImpl::Users(std::vector<std::string>& users)
00321 {
00322         if (mHandle == 0)
00323                 throw LogicExceptionImpl("Database::Users", _("Database is not connected."));
00324 
00325         char items[] = {isc_info_user_names,
00326                                         isc_info_end};
00327     IBS status;
00328         RB result(8000);
00329 
00330         status.Reset();
00331         (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
00332                 result.Size(), result.Self());
00333         if (status.Errors())
00334         {
00335                 status.Reset();
00336                 throw SQLExceptionImpl(status, "Database::Users", _("isc_database_info failed"));
00337         }
00338 
00339         users.clear();
00340         char* p = result.Self();
00341         while (*p == isc_info_user_names)
00342         {
00343                 p += 3;         // Get to the length byte (there are two undocumented bytes which we skip)
00344                 int len = (int)(*p);
00345                 ++p;            // Get to the first char of username
00346         if (len != 0) users.push_back(std::string().append(p, len));
00347                 p += len;       // Skip username
00348     }
00349         return;
00350 }
00351 
00352 IBPP::IDatabase* DatabaseImpl::AddRef()
00353 {
00354         ASSERTION(mRefCount >= 0);
00355         ++mRefCount;
00356         return this;
00357 }
00358 
00359 void DatabaseImpl::Release()
00360 {
00361         // Release cannot throw, except in DEBUG builds on assertion
00362         ASSERTION(mRefCount >= 0);
00363         --mRefCount;
00364         try { if (mRefCount <= 0) delete this; }
00365                 catch (...) { }
00366 }
00367 
00368 //      (((((((( OBJECT INTERNAL METHODS ))))))))
00369 
00370 void DatabaseImpl::AttachTransactionImpl(TransactionImpl* tr)
00371 {
00372         if (tr == 0)
00373                 throw LogicExceptionImpl("Database::AttachTransaction",
00374                                         _("Transaction object is null."));
00375 
00376         mTransactions.push_back(tr);
00377 }
00378 
00379 void DatabaseImpl::DetachTransactionImpl(TransactionImpl* tr)
00380 {
00381         if (tr == 0)
00382                 throw LogicExceptionImpl("Database::DetachTransaction",
00383                                 _("ITransaction object is null."));
00384 
00385         mTransactions.erase(std::find(mTransactions.begin(), mTransactions.end(), tr));
00386 }
00387 
00388 void DatabaseImpl::AttachStatementImpl(StatementImpl* st)
00389 {
00390         if (st == 0)
00391                 throw LogicExceptionImpl("Database::AttachStatement",
00392                                         _("Can't attach a null Statement object."));
00393 
00394         mStatements.push_back(st);
00395 }
00396 
00397 void DatabaseImpl::DetachStatementImpl(StatementImpl* st)
00398 {
00399         if (st == 0)
00400                 throw LogicExceptionImpl("Database::DetachStatement",
00401                                 _("Can't detach a null Statement object."));
00402 
00403         mStatements.erase(std::find(mStatements.begin(), mStatements.end(), st));
00404 }
00405 
00406 void DatabaseImpl::AttachBlobImpl(BlobImpl* bb)
00407 {
00408         if (bb == 0)
00409                 throw LogicExceptionImpl("Database::AttachBlob",
00410                                         _("Can't attach a null Blob object."));
00411 
00412         mBlobs.push_back(bb);
00413 }
00414 
00415 void DatabaseImpl::DetachBlobImpl(BlobImpl* bb)
00416 {
00417         if (bb == 0)
00418                 throw LogicExceptionImpl("Database::DetachBlob",
00419                                 _("Can't detach a null Blob object."));
00420 
00421         mBlobs.erase(std::find(mBlobs.begin(), mBlobs.end(), bb));
00422 }
00423 
00424 void DatabaseImpl::AttachArrayImpl(ArrayImpl* ar)
00425 {
00426         if (ar == 0)
00427                 throw LogicExceptionImpl("Database::AttachArray",
00428                                         _("Can't attach a null Array object."));
00429 
00430         mArrays.push_back(ar);
00431 }
00432 
00433 void DatabaseImpl::DetachArrayImpl(ArrayImpl* ar)
00434 {
00435         if (ar == 0)
00436                 throw LogicExceptionImpl("Database::DetachArray",
00437                                 _("Can't detach a null Array object."));
00438 
00439         mArrays.erase(std::find(mArrays.begin(), mArrays.end(), ar));
00440 }
00441 
00442 void DatabaseImpl::AttachEventsImpl(EventsImpl* ev)
00443 {
00444         if (ev == 0)
00445                 throw LogicExceptionImpl("Database::AttachEventsImpl",
00446                                         _("Can't attach a null Events object."));
00447 
00448         mEvents.push_back(ev);
00449 }
00450 
00451 void DatabaseImpl::DetachEventsImpl(EventsImpl* ev)
00452 {
00453         if (ev == 0)
00454                 throw LogicExceptionImpl("Database::DetachEventsImpl",
00455                                 _("Can't detach a null Events object."));
00456 
00457         mEvents.erase(std::find(mEvents.begin(), mEvents.end(), ev));
00458 }
00459 
00460 DatabaseImpl::DatabaseImpl(const std::string& ServerName, const std::string& DatabaseName,
00461                                                    const std::string& UserName, const std::string& UserPassword,
00462                                                    const std::string& RoleName, const std::string& CharSet,
00463                                                    const std::string& CreateParams) :
00464 
00465         mRefCount(0), mHandle(0),
00466         mServerName(ServerName), mDatabaseName(DatabaseName),
00467         mUserName(UserName), mUserPassword(UserPassword), mRoleName(RoleName),
00468         mCharSet(CharSet), mCreateParams(CreateParams),
00469         mDialect(3)
00470 {
00471 }
00472 
00473 DatabaseImpl::~DatabaseImpl()
00474 {
00475         try { if (Connected()) Disconnect(); }
00476                 catch(...) { }
00477 }
00478 
00479 //
00480 //      EOF
00481 //

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