PageRenderTime 41ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/gambas2-2.24.0/gb.db.firebird/src/ibpp/core/database.cpp

#
C++ | 483 lines | 349 code | 83 blank | 51 comment | 118 complexity | dfc503565e774679060c9280a7a50bc6 MD5 | raw file
Possible License(s): GPL-2.0, JSON, LGPL-2.1
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File : $Id: database.cpp 57 2006-04-02 17:44:00Z epocman $
  4. // Subject : IBPP, Database class implementation
  5. //
  6. ///////////////////////////////////////////////////////////////////////////////
  7. //
  8. // (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)
  9. //
  10. // The contents of this file are subject to the IBPP License (the "License");
  11. // you may not use this file except in compliance with the License. You may
  12. // obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'
  13. // file which must have been distributed along with this file.
  14. //
  15. // This software, distributed under the License, is distributed on an "AS IS"
  16. // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  17. // License for the specific language governing rights and limitations
  18. // under the License.
  19. //
  20. ///////////////////////////////////////////////////////////////////////////////
  21. //
  22. // COMMENTS
  23. // * Tabulations should be set every four characters when editing this file.
  24. //
  25. ///////////////////////////////////////////////////////////////////////////////
  26. #ifdef _MSC_VER
  27. #pragma warning(disable: 4786 4996)
  28. #ifndef _DEBUG
  29. #pragma warning(disable: 4702)
  30. #endif
  31. #endif
  32. #include "_ibpp.h"
  33. #ifdef HAS_HDRSTOP
  34. #pragma hdrstop
  35. #endif
  36. #include <algorithm>
  37. using namespace ibpp_internals;
  38. // (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))
  39. void DatabaseImpl::Create(int dialect)
  40. {
  41. if (mHandle != 0)
  42. throw LogicExceptionImpl("Database::Create", _("Database is already connected."));
  43. if (mDatabaseName.empty())
  44. throw LogicExceptionImpl("Database::Create", _("Unspecified database name."));
  45. if (mUserName.empty())
  46. throw LogicExceptionImpl("Database::Create", _("Unspecified user name."));
  47. if (dialect != 1 && dialect != 3)
  48. throw LogicExceptionImpl("Database::Create", _("Only dialects 1 and 3 are supported."));
  49. // Build the SQL Create Statement
  50. std::string create;
  51. create.assign("CREATE DATABASE '");
  52. if (! mServerName.empty()) create.append(mServerName).append(":");
  53. create.append(mDatabaseName).append("' ");
  54. create.append("USER '").append(mUserName).append("' ");
  55. if (! mUserPassword.empty())
  56. create.append("PASSWORD '").append(mUserPassword).append("' ");
  57. if (! mCreateParams.empty()) create.append(mCreateParams);
  58. // Call ExecuteImmediate to create the database
  59. isc_tr_handle tr_handle = 0;
  60. IBS status;
  61. (*gds.Call()->m_dsql_execute_immediate)(status.Self(), &mHandle, &tr_handle,
  62. 0, const_cast<char*>(create.c_str()), short(dialect), NULL);
  63. if (status.Errors())
  64. throw SQLExceptionImpl(status, "Database::Create", _("isc_dsql_execute_immediate failed"));
  65. Disconnect();
  66. }
  67. void DatabaseImpl::Connect()
  68. {
  69. if (mHandle != 0) return; // Already connected
  70. if (mDatabaseName.empty())
  71. throw LogicExceptionImpl("Database::Connect", _("Unspecified database name."));
  72. if (mUserName.empty())
  73. throw LogicExceptionImpl("Database::Connect", _("Unspecified user name."));
  74. // Build a DPB based on the properties
  75. DPB dpb;
  76. dpb.Insert(isc_dpb_user_name, mUserName.c_str());
  77. dpb.Insert(isc_dpb_password, mUserPassword.c_str());
  78. if (! mRoleName.empty()) dpb.Insert(isc_dpb_sql_role_name, mRoleName.c_str());
  79. if (! mCharSet.empty()) dpb.Insert(isc_dpb_lc_ctype, mCharSet.c_str());
  80. std::string connect;
  81. if (! mServerName.empty())
  82. connect.assign(mServerName).append(":");
  83. connect.append(mDatabaseName);
  84. IBS status;
  85. (*gds.Call()->m_attach_database)(status.Self(), (short)connect.size(),
  86. const_cast<char*>(connect.c_str()), &mHandle, dpb.Size(), dpb.Self());
  87. if (status.Errors())
  88. {
  89. mHandle = 0; // Should be, but better be sure...
  90. throw SQLExceptionImpl(status, "Database::Connect", _("isc_attach_database failed"));
  91. }
  92. // Now, get ODS version information and dialect.
  93. // If ODS major is lower of equal to 9, we reject the connection.
  94. // If ODS major is 10 or higher, this is at least an InterBase 6.x Server
  95. // OR FireBird 1.x Server.
  96. char items[] = {isc_info_ods_version,
  97. isc_info_db_SQL_dialect,
  98. isc_info_end};
  99. RB result(100);
  100. status.Reset();
  101. (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
  102. result.Size(), result.Self());
  103. if (status.Errors())
  104. {
  105. status.Reset();
  106. (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
  107. mHandle = 0; // Should be, but better be sure...
  108. throw SQLExceptionImpl(status, "Database::Connect", _("isc_database_info failed"));
  109. }
  110. int ODS = result.GetValue(isc_info_ods_version);
  111. if (ODS <= 9)
  112. {
  113. status.Reset();
  114. (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
  115. mHandle = 0; // Should be, but better be sure...
  116. throw LogicExceptionImpl("Database::Connect",
  117. _("Unsupported Server : wrong ODS version (%d), at least '10' required."), ODS);
  118. }
  119. mDialect = result.GetValue(isc_info_db_SQL_dialect);
  120. if (mDialect != 1 && mDialect != 3)
  121. {
  122. status.Reset();
  123. (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
  124. mHandle = 0; // Should be, but better be sure...
  125. throw LogicExceptionImpl("Database::Connect", _("Dialect 1 or 3 required"));
  126. }
  127. // Now, verify the GDS32.DLL we are using is compatible with the server
  128. if (ODS >= 10 && gds.Call()->mGDSVersion < 60)
  129. {
  130. status.Reset();
  131. (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
  132. mHandle = 0; // Should be, but better be sure...
  133. throw LogicExceptionImpl("Database::Connect", _("GDS32.DLL version 5 against IBSERVER 6"));
  134. }
  135. }
  136. void DatabaseImpl::Inactivate()
  137. {
  138. if (mHandle == 0) return; // Not connected anyway
  139. IBS status;
  140. // Rollback any started transaction...
  141. for (unsigned i = 0; i < mTransactions.size(); i++)
  142. {
  143. if (mTransactions[i]->Started())
  144. mTransactions[i]->Rollback();
  145. }
  146. // Cancel all pending event traps
  147. for (unsigned i = 0; i < mEvents.size(); i++)
  148. mEvents[i]->Clear();
  149. // Let's detach from all Blobs
  150. while (mBlobs.size() > 0)
  151. mBlobs.back()->DetachDatabaseImpl();
  152. // Let's detach from all Arrays
  153. while (mArrays.size() > 0)
  154. mArrays.back()->DetachDatabaseImpl();
  155. // Let's detach from all Statements
  156. while (mStatements.size() > 0)
  157. mStatements.back()->DetachDatabaseImpl();
  158. // Let's detach from all Transactions
  159. while (mTransactions.size() > 0)
  160. mTransactions.back()->DetachDatabaseImpl(this);
  161. // Let's detach from all Events
  162. while (mEvents.size() > 0)
  163. mEvents.back()->DetachDatabaseImpl();
  164. }
  165. void DatabaseImpl::Disconnect()
  166. {
  167. if (mHandle == 0) return; // Not connected anyway
  168. // Put the connection to rest
  169. Inactivate();
  170. // Detach from the server
  171. IBS status;
  172. (*gds.Call()->m_detach_database)(status.Self(), &mHandle);
  173. // Should we throw, set mHandle to 0 first, because Disconnect() may
  174. // be called from Database destructor (keeps the object coherent).
  175. mHandle = 0;
  176. if (status.Errors())
  177. throw SQLExceptionImpl(status, "Database::Disconnect", _("isc_detach_database failed"));
  178. }
  179. void DatabaseImpl::Drop()
  180. {
  181. if (mHandle == 0)
  182. throw LogicExceptionImpl("Database::Drop", _("Database must be connected."));
  183. // Put the connection to a rest
  184. Inactivate();
  185. IBS vector;
  186. (*gds.Call()->m_drop_database)(vector.Self(), &mHandle);
  187. if (vector.Errors())
  188. throw SQLExceptionImpl(vector, "Database::Drop", _("isc_drop_database failed"));
  189. mHandle = 0;
  190. }
  191. void DatabaseImpl::Info(int* ODSMajor, int* ODSMinor,
  192. int* PageSize, int* Pages, int* Buffers, int* Sweep,
  193. bool* Sync, bool* Reserve)
  194. {
  195. if (mHandle == 0)
  196. throw LogicExceptionImpl("Database::Info", _("Database is not connected."));
  197. char items[] = {isc_info_ods_version,
  198. isc_info_ods_minor_version,
  199. isc_info_page_size,
  200. isc_info_allocation,
  201. isc_info_num_buffers,
  202. isc_info_sweep_interval,
  203. isc_info_forced_writes,
  204. isc_info_no_reserve,
  205. isc_info_end};
  206. IBS status;
  207. RB result(256);
  208. status.Reset();
  209. (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
  210. result.Size(), result.Self());
  211. if (status.Errors())
  212. throw SQLExceptionImpl(status, "Database::Info", _("isc_database_info failed"));
  213. if (ODSMajor != 0) *ODSMajor = result.GetValue(isc_info_ods_version);
  214. if (ODSMinor != 0) *ODSMinor = result.GetValue(isc_info_ods_minor_version);
  215. if (PageSize != 0) *PageSize = result.GetValue(isc_info_page_size);
  216. if (Pages != 0) *Pages = result.GetValue(isc_info_allocation);
  217. if (Buffers != 0) *Buffers = result.GetValue(isc_info_num_buffers);
  218. if (Sweep != 0) *Sweep = result.GetValue(isc_info_sweep_interval);
  219. if (Sync != 0)
  220. *Sync = result.GetValue(isc_info_forced_writes) == 1 ? true : false;
  221. if (Reserve != 0)
  222. *Reserve = result.GetValue(isc_info_no_reserve) == 1 ? false : true;
  223. }
  224. void DatabaseImpl::Statistics(int* Fetches, int* Marks, int* Reads, int* Writes)
  225. {
  226. if (mHandle == 0)
  227. throw LogicExceptionImpl("Database::Statistics", _("Database is not connected."));
  228. char items[] = {isc_info_fetches,
  229. isc_info_marks,
  230. isc_info_reads,
  231. isc_info_writes,
  232. isc_info_end};
  233. IBS status;
  234. RB result(128);
  235. status.Reset();
  236. (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
  237. result.Size(), result.Self());
  238. if (status.Errors())
  239. throw SQLExceptionImpl(status, "Database::Statistics", _("isc_database_info failed"));
  240. if (Fetches != 0) *Fetches = result.GetValue(isc_info_fetches);
  241. if (Marks != 0) *Marks = result.GetValue(isc_info_marks);
  242. if (Reads != 0) *Reads = result.GetValue(isc_info_reads);
  243. if (Writes != 0) *Writes = result.GetValue(isc_info_writes);
  244. }
  245. void DatabaseImpl::Counts(int* Insert, int* Update, int* Delete,
  246. int* ReadIdx, int* ReadSeq)
  247. {
  248. if (mHandle == 0)
  249. throw LogicExceptionImpl("Database::Counts", _("Database is not connected."));
  250. char items[] = {isc_info_insert_count,
  251. isc_info_update_count,
  252. isc_info_delete_count,
  253. isc_info_read_idx_count,
  254. isc_info_read_seq_count,
  255. isc_info_end};
  256. IBS status;
  257. RB result(1024);
  258. status.Reset();
  259. (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
  260. result.Size(), result.Self());
  261. if (status.Errors())
  262. throw SQLExceptionImpl(status, "Database::Counts", _("isc_database_info failed"));
  263. if (Insert != 0) *Insert = result.GetCountValue(isc_info_insert_count);
  264. if (Update != 0) *Update = result.GetCountValue(isc_info_update_count);
  265. if (Delete != 0) *Delete = result.GetCountValue(isc_info_delete_count);
  266. if (ReadIdx != 0) *ReadIdx = result.GetCountValue(isc_info_read_idx_count);
  267. if (ReadSeq != 0) *ReadSeq = result.GetCountValue(isc_info_read_seq_count);
  268. }
  269. void DatabaseImpl::Users(std::vector<std::string>& users)
  270. {
  271. if (mHandle == 0)
  272. throw LogicExceptionImpl("Database::Users", _("Database is not connected."));
  273. char items[] = {isc_info_user_names,
  274. isc_info_end};
  275. IBS status;
  276. RB result(8000);
  277. status.Reset();
  278. (*gds.Call()->m_database_info)(status.Self(), &mHandle, sizeof(items), items,
  279. result.Size(), result.Self());
  280. if (status.Errors())
  281. {
  282. status.Reset();
  283. throw SQLExceptionImpl(status, "Database::Users", _("isc_database_info failed"));
  284. }
  285. users.clear();
  286. char* p = result.Self();
  287. while (*p == isc_info_user_names)
  288. {
  289. p += 3; // Get to the length byte (there are two undocumented bytes which we skip)
  290. int len = (int)(*p);
  291. ++p; // Get to the first char of username
  292. if (len != 0) users.push_back(std::string().append(p, len));
  293. p += len; // Skip username
  294. }
  295. return;
  296. }
  297. IBPP::IDatabase* DatabaseImpl::AddRef()
  298. {
  299. ASSERTION(mRefCount >= 0);
  300. ++mRefCount;
  301. return this;
  302. }
  303. void DatabaseImpl::Release()
  304. {
  305. // Release cannot throw, except in DEBUG builds on assertion
  306. ASSERTION(mRefCount >= 0);
  307. --mRefCount;
  308. try { if (mRefCount <= 0) delete this; }
  309. catch (...) { }
  310. }
  311. // (((((((( OBJECT INTERNAL METHODS ))))))))
  312. void DatabaseImpl::AttachTransactionImpl(TransactionImpl* tr)
  313. {
  314. if (tr == 0)
  315. throw LogicExceptionImpl("Database::AttachTransaction",
  316. _("Transaction object is null."));
  317. mTransactions.push_back(tr);
  318. }
  319. void DatabaseImpl::DetachTransactionImpl(TransactionImpl* tr)
  320. {
  321. if (tr == 0)
  322. throw LogicExceptionImpl("Database::DetachTransaction",
  323. _("ITransaction object is null."));
  324. mTransactions.erase(std::find(mTransactions.begin(), mTransactions.end(), tr));
  325. }
  326. void DatabaseImpl::AttachStatementImpl(StatementImpl* st)
  327. {
  328. if (st == 0)
  329. throw LogicExceptionImpl("Database::AttachStatement",
  330. _("Can't attach a null Statement object."));
  331. mStatements.push_back(st);
  332. }
  333. void DatabaseImpl::DetachStatementImpl(StatementImpl* st)
  334. {
  335. if (st == 0)
  336. throw LogicExceptionImpl("Database::DetachStatement",
  337. _("Can't detach a null Statement object."));
  338. mStatements.erase(std::find(mStatements.begin(), mStatements.end(), st));
  339. }
  340. void DatabaseImpl::AttachBlobImpl(BlobImpl* bb)
  341. {
  342. if (bb == 0)
  343. throw LogicExceptionImpl("Database::AttachBlob",
  344. _("Can't attach a null Blob object."));
  345. mBlobs.push_back(bb);
  346. }
  347. void DatabaseImpl::DetachBlobImpl(BlobImpl* bb)
  348. {
  349. if (bb == 0)
  350. throw LogicExceptionImpl("Database::DetachBlob",
  351. _("Can't detach a null Blob object."));
  352. mBlobs.erase(std::find(mBlobs.begin(), mBlobs.end(), bb));
  353. }
  354. void DatabaseImpl::AttachArrayImpl(ArrayImpl* ar)
  355. {
  356. if (ar == 0)
  357. throw LogicExceptionImpl("Database::AttachArray",
  358. _("Can't attach a null Array object."));
  359. mArrays.push_back(ar);
  360. }
  361. void DatabaseImpl::DetachArrayImpl(ArrayImpl* ar)
  362. {
  363. if (ar == 0)
  364. throw LogicExceptionImpl("Database::DetachArray",
  365. _("Can't detach a null Array object."));
  366. mArrays.erase(std::find(mArrays.begin(), mArrays.end(), ar));
  367. }
  368. void DatabaseImpl::AttachEventsImpl(EventsImpl* ev)
  369. {
  370. if (ev == 0)
  371. throw LogicExceptionImpl("Database::AttachEventsImpl",
  372. _("Can't attach a null Events object."));
  373. mEvents.push_back(ev);
  374. }
  375. void DatabaseImpl::DetachEventsImpl(EventsImpl* ev)
  376. {
  377. if (ev == 0)
  378. throw LogicExceptionImpl("Database::DetachEventsImpl",
  379. _("Can't detach a null Events object."));
  380. mEvents.erase(std::find(mEvents.begin(), mEvents.end(), ev));
  381. }
  382. DatabaseImpl::DatabaseImpl(const std::string& ServerName, const std::string& DatabaseName,
  383. const std::string& UserName, const std::string& UserPassword,
  384. const std::string& RoleName, const std::string& CharSet,
  385. const std::string& CreateParams) :
  386. mRefCount(0), mHandle(0),
  387. mServerName(ServerName), mDatabaseName(DatabaseName),
  388. mUserName(UserName), mUserPassword(UserPassword), mRoleName(RoleName),
  389. mCharSet(CharSet), mCreateParams(CreateParams),
  390. mDialect(3)
  391. {
  392. }
  393. DatabaseImpl::~DatabaseImpl()
  394. {
  395. try { if (Connected()) Disconnect(); }
  396. catch(...) { }
  397. }
  398. //
  399. // EOF
  400. //