HandleDbc.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #include <limits.h>
  14. #include <NdbApi.hpp>
  15. #include <common/common.hpp>
  16. #include <common/DiagArea.hpp>
  17. #include <common/StmtArea.hpp>
  18. #include "HandleRoot.hpp"
  19. #include "HandleEnv.hpp"
  20. #include "HandleDbc.hpp"
  21. #include "HandleStmt.hpp"
  22. #include "HandleDesc.hpp"
  23. #include "PoolNdb.hpp"
  24. #ifndef INT_MAX
  25. #define INT_MAX 2147483647
  26. #endif
  27. HandleDbc::HandleDbc(HandleEnv* pEnv) :
  28.     m_env(pEnv),
  29.     m_attrArea(m_attrSpec)
  30. {
  31.     m_attrArea.setHandle(this);
  32. }
  33. HandleDbc::~HandleDbc()
  34. {
  35. }
  36. void
  37. HandleDbc::ctor(Ctx& ctx)
  38. {
  39. }
  40. void
  41. HandleDbc::dtor(Ctx& ctx)
  42. {
  43.     if (m_state == Connected) {
  44. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "cannot delete connection handle - connection is open");
  45. return;
  46.     }
  47.     if (m_state == Transacting) {
  48. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "cannot delete connection handle - transaction is active");
  49. return;
  50.     }
  51. }
  52. // allocate and free handles
  53. void
  54. HandleDbc::sqlAllocStmt(Ctx& ctx, HandleStmt** ppStmt)
  55. {
  56.     if (ppStmt == 0) {
  57. ctx.pushStatus(Sqlstate::_HY009, Error::Gen, "cannot allocate statement handle - null return address");
  58. return;
  59.     }
  60.     if (m_state == Free) {
  61. ctx.pushStatus(Sqlstate::_08003, Error::Gen, "cannot allocate statement handle - not connected to database");
  62. return;
  63.     }
  64.     HandleStmt* pStmt = new HandleStmt(this);
  65.     pStmt->ctor(ctx);
  66.     if (! ctx.ok()) {
  67. pStmt->dtor(ctx);
  68. delete pStmt;
  69. return;
  70.     }
  71.     m_listStmt.push_back(pStmt);
  72.     getRoot()->record(SQL_HANDLE_STMT, pStmt, true);
  73.     *ppStmt = pStmt;
  74. }
  75. void
  76. HandleDbc::sqlAllocDesc(Ctx& ctx, HandleDesc** ppDesc)
  77. {
  78.     if (ppDesc == 0) {
  79. ctx.pushStatus(Sqlstate::_HY009, Error::Gen, "cannot allocate descriptor handle - null return address");
  80. return;
  81.     }
  82.     if (m_state == Free) {
  83. ctx.pushStatus(Sqlstate::_08003, Error::Gen, "cannot allocate descriptor handle - not connected to database");
  84. return;
  85.     }
  86.     HandleDesc* pDesc = new HandleDesc(this);
  87.     pDesc->ctor(ctx);
  88.     if (! ctx.ok()) {
  89. pDesc->dtor(ctx);
  90. delete pDesc;
  91. return;
  92.     }
  93.     m_listDesc.push_back(pDesc);
  94.     getRoot()->record(SQL_HANDLE_DESC, pDesc, true);
  95.     *ppDesc = pDesc;
  96. }
  97. void
  98. HandleDbc::sqlAllocHandle(Ctx& ctx, SQLSMALLINT childType, HandleBase** ppChild)
  99. {
  100.     switch (childType) {
  101.     case SQL_HANDLE_STMT:
  102. sqlAllocStmt(ctx, (HandleStmt**)ppChild);
  103. return;
  104.     case SQL_HANDLE_DESC:
  105. sqlAllocDesc(ctx, (HandleDesc**)ppChild);
  106. return;
  107.     }
  108.     ctx.pushStatus(Sqlstate::_HY092, Error::Gen, "invalid child handle type %d", (int)childType);
  109. }
  110. void
  111. HandleDbc::sqlFreeStmt(Ctx& ctx, HandleStmt* pStmt, SQLUSMALLINT iOption)
  112. {
  113.     switch (iOption) {
  114.     case SQL_CLOSE:
  115. // no error if not open
  116. if (pStmt->getState() == HandleStmt::Open)
  117.     pStmt->sqlCloseCursor(ctx);
  118. return;
  119.     case SQL_DROP:
  120. pStmt->dtor(ctx);
  121. if (! ctx.ok())
  122.     return;
  123. m_listStmt.remove(pStmt);
  124. getRoot()->record(SQL_HANDLE_STMT, pStmt, false);
  125. delete pStmt;
  126. return;
  127.     case SQL_UNBIND: {
  128. DescArea& ard = pStmt->getHandleDesc(ctx, Desc_usage_ARD)->descArea();
  129. ard.setCount(ctx, 0);
  130. return;
  131. }
  132.     case SQL_RESET_PARAMS: {
  133. DescArea& apd = pStmt->getHandleDesc(ctx, Desc_usage_APD)->descArea();
  134. apd.setCount(ctx, 0);
  135. // SQLFreeStmt doc misses this part
  136. DescArea& ipd = pStmt->getHandleDesc(ctx, Desc_usage_IPD)->descArea();
  137. ipd.setCount(ctx, 0);
  138. return;
  139. }
  140.     }
  141.     ctx.pushStatus(Sqlstate::_HY092, Error::Gen, "invalid free statement option %u", (unsigned)iOption);
  142. }
  143. void
  144. HandleDbc::sqlFreeDesc(Ctx& ctx, HandleDesc* pDesc)
  145. {
  146.     pDesc->dtor(ctx);
  147.     if (! ctx.ok())
  148. return;
  149.     m_listDesc.remove(pDesc);
  150.     getRoot()->record(SQL_HANDLE_DESC, pDesc, false);
  151.     delete pDesc;
  152. }
  153. void
  154. HandleDbc::sqlFreeHandle(Ctx& ctx, SQLSMALLINT childType, HandleBase* pChild)
  155. {
  156.     switch (childType) {
  157.     case SQL_HANDLE_STMT:
  158. sqlFreeStmt(ctx, (HandleStmt*)pChild, SQL_DROP);
  159. return;
  160.     case SQL_HANDLE_DESC:
  161. sqlFreeDesc(ctx, (HandleDesc*)pChild);
  162. return;
  163.     }
  164.     ctx.pushStatus(Sqlstate::_HY092, Error::Gen, "invalid child handle type %d", (int)childType);
  165. }
  166. // attributes and info functions
  167. static bool
  168. ignore_attr(Ctx& ctx, SQLINTEGER attribute)
  169. {
  170.     switch (attribute) {
  171.     case 1246:
  172. ctx_log2(("ignore unknown ADO.NET connect attribute %d", (int)attribute));
  173. return true;
  174.     }
  175.     return false;
  176. }
  177. void
  178. HandleDbc::sqlSetConnectAttr(Ctx& ctx, SQLINTEGER attribute, SQLPOINTER value, SQLINTEGER stringLength)
  179. {
  180.     if (ignore_attr(ctx, attribute))
  181. return;
  182.     baseSetHandleAttr(ctx, m_attrArea, attribute, value, stringLength);
  183. }
  184. void
  185. HandleDbc::sqlGetConnectAttr(Ctx& ctx, SQLINTEGER attribute, SQLPOINTER value, SQLINTEGER bufferLength, SQLINTEGER* stringLength)
  186. {
  187.     if (ignore_attr(ctx, attribute))
  188. return;
  189.     baseGetHandleAttr(ctx, m_attrArea, attribute, value, bufferLength, stringLength);
  190. }
  191. void
  192. HandleDbc::sqlSetConnectOption(Ctx& ctx, SQLUSMALLINT option, SQLUINTEGER value)
  193. {
  194.     if (ignore_attr(ctx, option))
  195. return;
  196.     baseSetHandleOption(ctx, m_attrArea, option, value);
  197. }
  198. void
  199. HandleDbc::sqlGetConnectOption(Ctx& ctx, SQLUSMALLINT option, SQLPOINTER value)
  200. {
  201.     if (ignore_attr(ctx, option))
  202. return;
  203.     baseGetHandleOption(ctx, m_attrArea, option, value);
  204. }
  205. void
  206. HandleDbc::sqlGetFunctions(Ctx& ctx, SQLUSMALLINT functionId, SQLUSMALLINT* supported)
  207. {
  208.     if (functionId == SQL_API_ALL_FUNCTIONS) {
  209. for (int i = 0; i < 100; i++)
  210.     supported[i] = SQL_FALSE;
  211. FuncTab* f;
  212. for (f = m_funcTab; f->m_supported != -1; f++) {
  213.     SQLUSMALLINT id = f->m_functionId;
  214.     if (id < 100 && f->m_supported)
  215. supported[id] = SQL_TRUE;
  216. }
  217.     } else if (functionId == SQL_API_ODBC3_ALL_FUNCTIONS) {
  218. for (int i = 0; i < SQL_API_ODBC3_ALL_FUNCTIONS_SIZE; i++)
  219.     supported[i] = 0;
  220. FuncTab* f;
  221. for (f = m_funcTab; f->m_supported != -1; f++) {
  222.     SQLUSMALLINT id = f->m_functionId;
  223.     ctx_assert((id >> 4) < SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
  224.     if (f->m_supported)
  225. supported[id >> 4] |= (1 << (id & 0xf));
  226. }
  227.     } else {
  228. FuncTab* f;
  229. for (f = m_funcTab; f->m_supported != -1; f++) {
  230.     if (f->m_functionId == functionId)
  231. break;
  232. }
  233. if (f->m_supported != -1)
  234.     supported[0] = f->m_supported ? SQL_TRUE : SQL_FALSE;
  235. else
  236.     ctx.pushStatus(Sqlstate::_HY095, Error::Gen, "invalid function id %u", (unsigned)functionId);
  237.     }
  238. }
  239. void
  240. HandleDbc::sqlGetInfo(Ctx& ctx, SQLUSMALLINT infoType, SQLPOINTER infoValue, SQLSMALLINT bufferLength, SQLSMALLINT* stringLength)
  241. {
  242.     InfoTab* f;
  243.     for (f = m_infoTab; f->m_format != InfoTab::End; f++) {
  244. if (f->m_id == infoType)
  245.     break;
  246.     }
  247.     if (f->m_format == InfoTab::End) {
  248. ctx.pushStatus(Sqlstate::_HY096, Error::Gen, "invalid info type %u", (unsigned)infoType);
  249. return;
  250.     }
  251.     if (f->m_format == InfoTab::Char || f->m_format == InfoTab::YesNo) {
  252. ctx_log3(("SQLGetInfo: type=%u value='%s'", (unsigned)infoType, f->m_str));
  253. OdbcData data(f->m_str);
  254. data.copyout(ctx, infoValue, bufferLength, 0, stringLength);
  255. return;
  256.     }
  257.     if (f->m_format == InfoTab::Short) {
  258. ctx_log3(("SQLGetInfo: type=%u value=%d", (unsigned)infoType, (int)f->m_int));
  259. OdbcData data((SQLUSMALLINT)f->m_int);
  260. data.copyout(ctx, infoValue, 0, 0);
  261. return;
  262.     }
  263.     if (f->m_format == InfoTab::Long || f->m_format == InfoTab::Bitmask) {
  264. ctx_log3(("SQLGetInfo: type=%u value=0x%x", (unsigned)infoType, (int)f->m_int));
  265. OdbcData data((SQLUINTEGER)f->m_int);
  266. data.copyout(ctx, infoValue, 0, 0);
  267. return;
  268.     }
  269.     ctx_assert(false);
  270. }
  271. int
  272. HandleDbc::getOdbcVersion(Ctx& ctx)
  273. {
  274.     return m_env->getOdbcVersion(ctx);
  275. }
  276. // connect and transactions
  277. void
  278. HandleDbc::sqlConnect(Ctx& ctx, SQLCHAR* serverName, SQLSMALLINT nameLength1, SQLCHAR* userName, SQLSMALLINT nameLength2, SQLCHAR* authentication, SQLSMALLINT nameLength3)
  279. {
  280.     if (m_state != Free) {
  281. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "already connected");
  282. return;
  283.     }
  284.     OdbcData data;
  285.     m_attrArea.getAttr(ctx, SQL_ATTR_CONNECTION_TIMEOUT, data);
  286.     int timeout = data.uinteger();
  287.     if (timeout <= 0)
  288. timeout = INT_MAX;
  289.     PoolNdb* poolNdb = getRoot()->getPoolNdb();
  290.     Ndb* pNdb = poolNdb->allocate(ctx, timeout);
  291.     if (pNdb == 0) {
  292. return;
  293.     }
  294.     m_ndbObject = pNdb;
  295.     m_state = Connected;
  296.     m_autocommit = true;
  297. }
  298. void
  299. HandleDbc::sqlDriverConnect(Ctx& ctx, SQLHWND hwnd, SQLCHAR* szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR* szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT* pcbConnStrOut, SQLUSMALLINT fDriverCompletion)
  300. {
  301.     ctx_log2(("driver connect %.*s", cbConnStrIn, szConnStrIn == 0 ? "" : (char*)szConnStrIn));
  302.     sqlConnect(ctx, (SQLCHAR*)"", 0, (SQLCHAR*)"", 0, (SQLCHAR*)"", 0);
  303.     if (! ctx.ok())
  304. return;
  305.     OdbcData data("DNS=DEFAULT");
  306.     if (szConnStrOut != 0) // ADO NET
  307. data.copyout(ctx, static_cast<SQLPOINTER>(szConnStrOut), cbConnStrOutMax, 0, pcbConnStrOut);
  308. }
  309. void
  310. HandleDbc::sqlDisconnect(Ctx& ctx)
  311. {
  312.     if (m_state == Free) {
  313. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "already disconnected");
  314. return;
  315.     }
  316.     // XXX missing check for uncommited changes
  317.     ListStmt::iterator i = m_listStmt.begin();
  318.     while (i != m_listStmt.end()) {
  319. HandleStmt* pStmt = *i;
  320. ListStmt::iterator j = i++;
  321. pStmt->dtor(ctx);
  322. getRoot()->record(SQL_HANDLE_STMT, pStmt, false);
  323. delete pStmt;
  324. m_listStmt.erase(j);
  325.     }
  326.     PoolNdb* poolNdb = getRoot()->getPoolNdb();
  327.     poolNdb->release(ctx, m_ndbObject);
  328.     m_ndbObject = 0;
  329.     m_state = Free;
  330.     m_autocommit = true;
  331. }
  332. void
  333. HandleDbc::sqlEndTran(Ctx& ctx, SQLSMALLINT completionType)
  334. {
  335.     if (completionType != SQL_COMMIT && completionType != SQL_ROLLBACK) {
  336. ctx.pushStatus(Sqlstate::_HY012, Error::Gen, "invalid completion type %d", (int)completionType);
  337. return;
  338.     }
  339.     if (m_state == Free) {
  340. ctx.pushStatus(Sqlstate::_08003, Error::Gen, "not connected");
  341. return;
  342.     }
  343.     Ndb* ndb = m_ndbObject;
  344.     ctx_assert(ndb != 0);
  345.     if (m_state == Connected) {
  346. ctx_log2(("sqlEndTran: no transaction active"));
  347. return;
  348.     }
  349.     NdbConnection* tcon = m_ndbConnection;
  350.     ctx_assert(tcon != 0);
  351.     if (completionType == SQL_COMMIT) {
  352. if (tcon->execute(Commit) == -1) {
  353.     if (tcon->getNdbError().code != 626)
  354. ctx.pushStatus(ndb, tcon, 0, "execute commit");
  355.     else
  356. ctx_log1(("ignore no data (626) at execute commit"));
  357. } else {
  358.     ctx_log2(("sqlEndTran: transaction commit done"));
  359.     m_uncommitted = false;
  360. }
  361.     } else {
  362. if (tcon->execute(Rollback) == -1) {
  363.     if (tcon->getNdbError().code != 626)
  364. ctx.pushStatus(ndb, tcon, 0, "execute rollback");
  365.     else
  366. ctx_log1(("ignore no data (626) at execute rollback"));
  367. } else {
  368.     ctx_log2(("sqlEndTran: transaction rollback done"));
  369.     m_uncommitted = false;
  370. }
  371.     }
  372.     for (ListStmt::iterator i = m_listStmt.begin(); i != m_listStmt.end(); i++) {
  373. HandleStmt* pStmt = *i;
  374. if (pStmt->getState() == HandleStmt::Open) {
  375.     pStmt->sqlCloseCursor(ctx); // SQL_CB_CLOSE behaviour
  376. }
  377. pStmt->useConnection(ctx, false);
  378.     }
  379.     if (! m_autocommit) {
  380. useConnection(ctx, false);
  381. useConnection(ctx, true);
  382.     }
  383. }
  384. void
  385. HandleDbc::sqlTransact(Ctx& ctx, SQLUSMALLINT completionType)
  386. {
  387.     sqlEndTran(ctx, completionType);
  388. }