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

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 <common/OdbcData.hpp>
  14. #include <codegen/CodeGen.hpp>
  15. #include "HandleRoot.hpp"
  16. #include "HandleDbc.hpp"
  17. #include "HandleStmt.hpp"
  18. #include "HandleDesc.hpp"
  19. HandleStmt::HandleStmt(HandleDbc* pDbc) :
  20.     StmtArea(*pDbc),
  21.     m_dbc(pDbc),
  22.     m_attrArea(m_attrSpec)
  23. {
  24.     m_attrArea.setHandle(this);
  25.     for (unsigned i = 0; i <= 1; i++) {
  26. for (unsigned u = 0; u <= 4; u++) {
  27.     m_handleDesc[i][u] = 0;
  28. }
  29.     }
  30. }
  31. HandleStmt::~HandleStmt()
  32. {
  33. }
  34. void
  35. HandleStmt::ctor(Ctx& ctx)
  36. {
  37.     for (unsigned u = 1; u <= 4; u++) {
  38. HandleDesc** ppDesc = &m_handleDesc[0][u];
  39. m_dbc->sqlAllocDesc(ctx, ppDesc);
  40. if (! ctx.ok())
  41.     return;
  42. m_descArea[u] = &(*ppDesc)->descArea();
  43. m_descArea[u]->setAlloc(Desc_alloc_auto);
  44. m_descArea[u]->setUsage((DescUsage)u);
  45.     }
  46. }
  47. void
  48. HandleStmt::dtor(Ctx& ctx)
  49. {
  50.     free(ctx);
  51.     for (unsigned u = 1; u <= 4; u++) {
  52. HandleDesc** ppDesc = &m_handleDesc[0][u];
  53. if (*ppDesc != 0)
  54.     m_dbc->sqlFreeDesc(ctx, *ppDesc);
  55. *ppDesc = 0;
  56.     }
  57. }
  58. // descriptor handles
  59. HandleDesc*
  60. HandleStmt::getHandleDesc(Ctx& ctx, DescUsage u) const
  61. {
  62.     ctx_assert(1 <= u && u <= 4);
  63.     if (m_handleDesc[1][u] != 0)
  64. return m_handleDesc[1][u];
  65.     return m_handleDesc[0][u];
  66. }
  67. void
  68. HandleStmt::setHandleDesc(Ctx& ctx, DescUsage u, SQLPOINTER handle)
  69. {
  70.     ctx_assert(1 <= u && u <= 4);
  71.     if (handle == SQL_NULL_HDESC) {
  72. m_handleDesc[1][u] = 0; // revert to implicit
  73. m_descArea[u] = &m_handleDesc[0][u]->descArea();
  74. return;
  75.     }
  76.     HandleDesc* pDesc = getRoot()->findDesc(handle);
  77.     if (pDesc == 0) {
  78. ctx.pushStatus(Sqlstate::_HY024, Error::Gen, "cannot set %s handle to invalid descriptor handle %x", DescArea::nameUsage(u), (unsigned)handle);
  79. return;
  80.     }
  81.     if (pDesc == m_handleDesc[0][u]) {
  82. m_handleDesc[1][u] = 0; // revert to implicit
  83. m_descArea[u] = &m_handleDesc[0][u]->descArea();
  84. return;
  85.     }
  86.     // XXX should check implicit handles on all statements
  87.     for (unsigned v = 1; v <= 4; v++) {
  88. if (pDesc == m_handleDesc[0][v]) {
  89.     ctx.pushStatus(Sqlstate::_HY024, Error::Gen, "cannot set %s handle to implicitly allocated %s handle", DescArea::nameUsage(u), DescArea::nameUsage((DescUsage)v));
  90.     return;
  91. }
  92.     }
  93.     m_handleDesc[1][u] = pDesc;
  94.     m_descArea[u] = &m_handleDesc[1][u]->descArea();
  95. }
  96. // allocate and free handles (no valid case)
  97. void
  98. HandleStmt::sqlAllocHandle(Ctx& ctx, SQLSMALLINT childType, HandleBase** ppChild)
  99. {
  100.     ctx.pushStatus(Sqlstate::_HY092, Error::Gen, "inappropriate handle type");
  101. }
  102. void
  103. HandleStmt::sqlFreeHandle(Ctx& ctx, SQLSMALLINT childType, HandleBase* ppChild)
  104. {
  105.     ctx.pushStatus(Sqlstate::_HY092, Error::Gen, "inappropriate handle type");
  106. }
  107. // attributes and info
  108. static bool
  109. ignore_attr(Ctx& ctx, SQLINTEGER attribute)
  110. {
  111.     switch (attribute) {
  112.     case 1211:
  113.     case 1227:
  114.     case 1228:
  115. ctx_log2(("ignore unknown ADO.NET stmt attribute %d", (int)attribute));
  116. return true;
  117.     }
  118.     return false;
  119. }
  120. void
  121. HandleStmt::sqlSetStmtAttr(Ctx& ctx, SQLINTEGER attribute, SQLPOINTER value, SQLINTEGER stringLength)
  122. {
  123.     if (ignore_attr(ctx, attribute))
  124. return;
  125.     baseSetHandleAttr(ctx, m_attrArea, attribute, value, stringLength);
  126. }
  127. void
  128. HandleStmt::sqlGetStmtAttr(Ctx& ctx, SQLINTEGER attribute, SQLPOINTER value, SQLINTEGER bufferLength, SQLINTEGER* stringLength)
  129. {
  130.     if (ignore_attr(ctx, attribute))
  131. return;
  132.     baseGetHandleAttr(ctx, m_attrArea, attribute, value, bufferLength, stringLength);
  133. }
  134. void
  135. HandleStmt::sqlSetStmtOption(Ctx& ctx, SQLUSMALLINT option, SQLUINTEGER value)
  136. {
  137.     if (ignore_attr(ctx, option))
  138. return;
  139.     baseSetHandleOption(ctx, m_attrArea, option, value);
  140. }
  141. void
  142. HandleStmt::sqlGetStmtOption(Ctx& ctx, SQLUSMALLINT option, SQLPOINTER value)
  143. {
  144.     if (ignore_attr(ctx, option))
  145. return;
  146.     baseGetHandleOption(ctx, m_attrArea, option, value);
  147. }
  148. void
  149. HandleStmt::sqlGetTypeInfo(Ctx& ctx, SQLSMALLINT dataType)
  150. {
  151.     BaseString text;
  152.     // odbc$typeinfo is a (possible unordered) view matching SQLGetTypeInfo result set
  153.     text.append("SELECT * FROM odbc$typeinfo");
  154.     if (dataType != SQL_ALL_TYPES) {
  155. switch (dataType) {
  156. case SQL_CHAR:
  157. case SQL_VARCHAR:
  158. case SQL_BINARY:
  159. case SQL_VARBINARY:
  160. case SQL_SMALLINT:
  161. case SQL_INTEGER:
  162. case SQL_BIGINT:
  163. case SQL_REAL:
  164. case SQL_DOUBLE:
  165.     break;
  166. default:
  167.     // XXX unsupported vs illegal
  168.     ctx_log1(("sqlGetTypeInfo: unknown data type %d", (int)dataType));
  169.     break;
  170. }
  171. text.appfmt(" WHERE data_type = %d", (int)dataType);
  172.     }
  173.     // sort signed before unsigned
  174.     text.append(" ORDER BY data_type, unsigned_attribute, type_name");
  175.     sqlExecDirect(ctx, (SQLCHAR*)text.c_str(), text.length());
  176. }
  177. void
  178. HandleStmt::sqlTables(Ctx& ctx, SQLCHAR* catalogName, SQLSMALLINT nameLength1, SQLCHAR* schemaName, SQLSMALLINT nameLength2, SQLCHAR* tableName, SQLSMALLINT nameLength3, SQLCHAR* tableType, SQLSMALLINT nameLength4)
  179. {
  180.     BaseString text;
  181.     // odbc$tables is a (possibly unordered) view matching SQLTables result set
  182.     text.append("SELECT * FROM odbc$tables");
  183.     SQLUINTEGER metadata_id = SQL_FALSE;
  184.     sqlGetStmtAttr(ctx, SQL_ATTR_METADATA_ID, (SQLPOINTER)&metadata_id, SQL_IS_POINTER, 0);
  185.     if (! ctx.ok())
  186. return;
  187.     unsigned count = 0;
  188.     if (catalogName != 0) {
  189. OdbcData data;
  190. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)catalogName, nameLength1);
  191. if (! ctx.ok())
  192.     return;
  193. text.append(++count == 1 ? " WHERE" : " AND");
  194. if (getOdbcVersion(ctx) == 2)
  195.     text.appfmt(" table_cat = '%s'", data.sqlchar());
  196. else if (metadata_id == SQL_TRUE)
  197.     text.appfmt(" table_cat = '%s'", data.sqlchar()); // XXX UPPER
  198. else
  199.     text.appfmt(" table_cat LIKE '%s'", data.sqlchar());
  200.     }
  201.     if (schemaName != 0) {
  202. OdbcData data;
  203. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)schemaName, nameLength2);
  204. if (! ctx.ok())
  205.     return;
  206. text.append(++count == 1 ? " WHERE" : " AND");
  207. if (metadata_id == SQL_TRUE)
  208.     text.appfmt(" table_schem = '%s'", data.sqlchar()); // XXX UPPER
  209. else
  210.     text.appfmt(" table_schem LIKE '%s'", data.sqlchar());
  211.     }
  212.     if (tableName != 0) {
  213. OdbcData data;
  214. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)tableName, nameLength3);
  215. if (! ctx.ok())
  216.     return;
  217. text.append(++count == 1 ? " WHERE" : " AND");
  218. if (metadata_id == SQL_TRUE)
  219.     text.appfmt(" table_name = '%s'", data.sqlchar()); // XXX UPPER
  220. else
  221.     text.appfmt(" table_name LIKE '%s'", data.sqlchar());
  222.     }
  223.     if (tableType != 0) {
  224. OdbcData data;
  225. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)tableType, nameLength4);
  226. if (! ctx.ok())
  227.     return;
  228. text.append(++count == 1 ? " WHERE" : " AND");
  229. text.appfmt(" table_type IN (%s)", data.sqlchar()); // XXX UPPER, quotes
  230.     }
  231.     text.append(" ORDER BY table_type, table_cat, table_schem, table_name");
  232.     sqlExecDirect(ctx, (SQLCHAR*)text.c_str(), text.length());
  233. }
  234. void
  235. HandleStmt::sqlColumns(Ctx& ctx, SQLCHAR* catalogName, SQLSMALLINT nameLength1, SQLCHAR* schemaName, SQLSMALLINT nameLength2, SQLCHAR* tableName, SQLSMALLINT nameLength3, SQLCHAR* columnName, SQLSMALLINT nameLength4)
  236. {
  237.     BaseString text;
  238.     // odbc$columns is a (possibly unordered) view matching SQLColumns result set
  239.     text.append("SELECT * FROM odbc$columns");
  240.     SQLUINTEGER metadata_id = SQL_FALSE;
  241.     sqlGetStmtAttr(ctx, SQL_ATTR_METADATA_ID, (SQLPOINTER)&metadata_id, SQL_IS_POINTER, 0);
  242.     if (! ctx.ok())
  243. return;
  244.     unsigned count = 0;
  245.     if (catalogName != 0) {
  246. OdbcData data;
  247. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)catalogName, nameLength1);
  248. if (! ctx.ok())
  249.     return;
  250. text.append(++count == 1 ? " WHERE" : " AND");
  251. if (getOdbcVersion(ctx) == 2)
  252.     text.appfmt(" table_cat = '%s'", data.sqlchar());
  253. else if (metadata_id == SQL_TRUE)
  254.     text.appfmt(" table_cat = '%s'", data.sqlchar()); // XXX UPPER
  255. else
  256.     text.appfmt(" table_cat LIKE '%s'", data.sqlchar());
  257.     }
  258.     if (schemaName != 0) {
  259. OdbcData data;
  260. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)schemaName, nameLength2);
  261. if (! ctx.ok())
  262.     return;
  263. text.append(++count == 1 ? " WHERE" : " AND");
  264. if (metadata_id == SQL_TRUE)
  265.     text.appfmt(" table_schem = '%s'", data.sqlchar()); // XXX UPPER
  266. else
  267.     text.appfmt(" table_schem LIKE '%s'", data.sqlchar());
  268.     }
  269.     if (tableName != 0) {
  270. OdbcData data;
  271. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)tableName, nameLength3);
  272. if (! ctx.ok())
  273.     return;
  274. text.append(++count == 1 ? " WHERE" : " AND");
  275. if (metadata_id == SQL_TRUE)
  276.     text.appfmt(" table_name = '%s'", data.sqlchar()); // XXX UPPER
  277. else
  278.     text.appfmt(" table_name LIKE '%s'", data.sqlchar());
  279.     }
  280.     if (columnName != 0) {
  281. OdbcData data;
  282. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)columnName, nameLength4);
  283. if (! ctx.ok())
  284.     return;
  285. text.append(++count == 1 ? " WHERE" : " AND");
  286. if (metadata_id == SQL_TRUE)
  287.     text.appfmt(" column_name = '%s'", data.sqlchar()); // XXX UPPER
  288. else
  289.     text.appfmt(" column_name LIKE '%s'", data.sqlchar());
  290.     }
  291.     text.append(" ORDER BY table_cat, table_schem, table_name, ordinal_position");
  292.     sqlExecDirect(ctx, (SQLCHAR*)text.c_str(), text.length());
  293. }
  294. void
  295. HandleStmt::sqlPrimaryKeys(Ctx& ctx, SQLCHAR* szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR* szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR* szTableName, SQLSMALLINT cbTableName)
  296. {
  297.     BaseString text;
  298.     // odbc$primarykeys is a (possible unordered) view matching SQLPrimaryKeys result set
  299.     text.append("SELECT * FROM odbc$primarykeys");
  300.     SQLUINTEGER metadata_id = SQL_FALSE;
  301.     sqlGetStmtAttr(ctx, SQL_ATTR_METADATA_ID, (SQLPOINTER)&metadata_id, SQL_IS_POINTER, 0);
  302.     if (! ctx.ok())
  303. return;
  304.     unsigned count = 0;
  305.     if (szCatalogName != 0) {
  306. OdbcData data;
  307. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)szCatalogName, cbCatalogName);
  308. if (! ctx.ok())
  309.     return;
  310. text.append(++count == 1 ? " WHERE" : " AND");
  311. if (getOdbcVersion(ctx) == 2)
  312.     text.appfmt(" table_cat = '%s'", data.sqlchar());
  313. else if (metadata_id == SQL_TRUE)
  314.     text.appfmt(" table_cat = '%s'", data.sqlchar()); // XXX UPPER
  315. else
  316.     text.appfmt(" table_cat = '%s'", data.sqlchar()); // no pattern
  317.     }
  318.     if (szSchemaName != 0) {
  319. OdbcData data;
  320. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)szSchemaName, cbSchemaName);
  321. if (! ctx.ok())
  322.     return;
  323. text.append(++count == 1 ? " WHERE" : " AND");
  324. if (metadata_id == SQL_TRUE)
  325.     text.appfmt(" table_schem = '%s'", data.sqlchar()); // XXX UPPER
  326. else
  327.     text.appfmt(" table_schem = '%s'", data.sqlchar()); // no pattern
  328.     }
  329.     if (szTableName != 0) {
  330. OdbcData data;
  331. data.copyin(ctx, OdbcData::Sqlchar, (SQLPOINTER)szTableName, cbTableName);
  332. if (! ctx.ok())
  333.     return;
  334. text.append(++count == 1 ? " WHERE" : " AND");
  335. if (metadata_id == SQL_TRUE)
  336.     text.appfmt(" table_name = '%s'", data.sqlchar()); // XXX UPPER
  337. else
  338.     text.appfmt(" table_name = '%s'", data.sqlchar()); // no pattern
  339.     } else { // no null
  340. ctx.pushStatus(Sqlstate::_HY009, Error::Gen, "null table name");
  341. return;
  342.     }
  343.     text.append(" ORDER BY table_cat, table_schem, table_name, key_seq");
  344.     sqlExecDirect(ctx, (SQLCHAR*)text.c_str(), text.length());
  345. }
  346. int
  347. HandleStmt::getOdbcVersion(Ctx& ctx)
  348. {
  349.     return m_dbc->getOdbcVersion(ctx);
  350. }
  351. // prepare and execute
  352. void
  353. HandleStmt::sqlPrepare(Ctx& ctx, SQLCHAR* statementText, SQLINTEGER textLength)
  354. {
  355.     if (m_state == Open) {
  356. ctx.pushStatus(Sqlstate::_24000, Error::Gen, "cursor is open");
  357. return;
  358.     }
  359.     free(ctx);
  360.     const char* text = reinterpret_cast<char*>(statementText);
  361.     if (textLength == SQL_NTS) {
  362. m_sqlText.assign(text);
  363.     } else if (textLength >= 0) {
  364. m_sqlText.assign(text, textLength);
  365.     } else {
  366. ctx.pushStatus(Sqlstate::_HY090, Error::Gen, "missing SQL text");
  367. return;
  368.     }
  369.     if (! useSchemaCon(ctx, true))
  370. return;
  371.     CodeGen codegen(*this);
  372.     codegen.prepare(ctx);
  373.     useSchemaCon(ctx, false);
  374.     if (! ctx.ok()) {
  375. free(ctx);
  376. return;
  377.     }
  378.     ctx_log2(("prepared %s statement", m_stmtInfo.getDesc()));
  379.     m_state = Prepared;
  380. }
  381. void
  382. HandleStmt::sqlExecute(Ctx& ctx)
  383. {
  384.     if (m_state == Open) {
  385. ctx.pushStatus(Sqlstate::_24000, Error::Gen, "cursor is open");
  386. return;
  387.     }
  388.     StmtType stmtType = m_stmtInfo.getType();
  389.     switch (stmtType) {
  390.     case Stmt_type_DDL:
  391. if (! useSchemaCon(ctx, true))
  392.     return;
  393. break;
  394.     case Stmt_type_query:
  395.     case Stmt_type_DML:
  396. if (! useConnection(ctx, true))
  397.     return;
  398. break;
  399.     default:
  400. ctx_assert(false);
  401. break;
  402.     }
  403.     CodeGen codegen(*this);
  404.     codegen.execute(ctx);
  405.     // valid only after execute says M$  XXX create this diag only on demand
  406.     setFunction(ctx);
  407.     if (ctx.getCode() == SQL_NEED_DATA) {
  408. m_state = NeedData;
  409. return;
  410.     }
  411.     ctx_log2(("execute: fetched %u tuples from NDB", (unsigned)m_tuplesFetched));
  412.     switch (stmtType) {
  413.     case Stmt_type_DDL:
  414. codegen.close(ctx);
  415. useSchemaCon(ctx, false);
  416. m_state = Prepared;
  417. break;
  418.     case Stmt_type_query:
  419. if (! ctx.ok()) {
  420.     codegen.close(ctx);
  421.     useConnection(ctx, false);
  422.     m_state = Prepared;
  423. } else {
  424.     m_state = Open;
  425. }
  426. break;
  427.     case Stmt_type_DML:
  428. codegen.close(ctx);
  429. if (m_dbc->autocommit()) {
  430.     // even if error
  431.     m_dbc->sqlEndTran(ctx, SQL_COMMIT);
  432. } else {
  433.     m_dbc->uncommitted(true); // uncommitted changes possible
  434. }
  435. useConnection(ctx, false);
  436. m_state = Prepared;
  437. break;
  438.     default:
  439. ctx_assert(false);
  440. break;
  441.     }
  442. }
  443. void
  444. HandleStmt::sqlExecDirect(Ctx& ctx, SQLCHAR* statementText, SQLINTEGER textLength)
  445. {
  446.     sqlPrepare(ctx, statementText, textLength);
  447.     if (! ctx.ok())
  448. return;
  449.     sqlExecute(ctx);
  450. }
  451. void
  452. HandleStmt::sqlFetch(Ctx& ctx)
  453. {
  454.     if (m_state != Open) {
  455. ctx.pushStatus(Sqlstate::_24000, Error::Gen, "cursor is not open");
  456. return;
  457.     }
  458.     StmtType stmtType = m_stmtInfo.getType();
  459.     switch (stmtType) {
  460.     case Stmt_type_query: {
  461. CodeGen codegen(*this);
  462. codegen.fetch(ctx);
  463. if (! ctx.ok()) {
  464.     codegen.close(ctx);
  465.     useConnection(ctx, false);
  466. }
  467. break;
  468. }
  469.     default:
  470. ctx_assert(false);
  471. break;
  472.     }
  473. }
  474. void
  475. HandleStmt::sqlRowCount(Ctx& ctx, SQLINTEGER* rowCount)
  476. {
  477.     *rowCount = m_rowCount;
  478. }
  479. void
  480. HandleStmt::sqlMoreResults(Ctx& ctx)
  481. {
  482.     if (m_state == Open) {
  483. sqlCloseCursor(ctx);
  484. if (! ctx.ok())
  485.     return;
  486.     }
  487.     ctx.setCode(SQL_NO_DATA);
  488. }
  489. void
  490. HandleStmt::sqlCancel(Ctx& ctx)
  491. {
  492.     if (m_state == NeedData) {
  493. CodeGen codegen(*this);
  494. codegen.close(ctx);
  495. m_state = Prepared;
  496.     }
  497. }
  498. void
  499. HandleStmt::sqlCloseCursor(Ctx& ctx)
  500. {
  501.     if (m_state != Open) {
  502. ctx.pushStatus(Sqlstate::_24000, Error::Gen, "cursor is not open");
  503. return;
  504.     }
  505.     ctx_log2(("execute: fetched %u tuples from NDB", (unsigned)m_tuplesFetched));
  506.     StmtType stmtType = m_stmtInfo.getType();
  507.     switch (stmtType) {
  508.     case Stmt_type_query: {
  509. CodeGen codegen(*this);
  510. codegen.close(ctx);
  511. useConnection(ctx, false);
  512. m_state = Prepared;
  513. m_rowCount = 0;
  514. m_tuplesFetched = 0;
  515. break;
  516. }
  517.     default:
  518. ctx_assert(false);
  519. break;
  520.     }
  521. }
  522. void
  523. HandleStmt::sqlGetCursorName(Ctx& ctx, SQLCHAR* cursorName, SQLSMALLINT bufferLength, SQLSMALLINT* nameLength)
  524. {
  525.     OdbcData name("SQL_CUR_DUMMY");
  526.     name.copyout(ctx, cursorName, bufferLength, 0, nameLength);
  527. }
  528. void
  529. HandleStmt::sqlSetCursorName(Ctx& ctx, SQLCHAR* cursorName, SQLSMALLINT nameLength)
  530. {
  531. }
  532. // special data access
  533. void
  534. HandleStmt::sqlGetData(Ctx& ctx, SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValue, SQLINTEGER bufferLength, SQLINTEGER* strlen_or_Ind)
  535. {
  536.     if (m_state != Open) {
  537. ctx.pushStatus(Sqlstate::_24000, Error::Gen, "cursor is not open");
  538. return;
  539.     }
  540.     if (bufferLength < 0) {
  541. ctx.pushStatus(Sqlstate::_HY090, Error::Gen, "invalid buffer length %d", (int)bufferLength);
  542. return;
  543.     }
  544.     CodeGen codegen(*this);
  545.     codegen.sqlGetData(ctx, columnNumber, targetType, targetValue, bufferLength, strlen_or_Ind);
  546. }
  547. void
  548. HandleStmt::sqlParamData(Ctx& ctx, SQLPOINTER* value)
  549. {
  550.     if (m_state != NeedData) {
  551. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "not expecting data-at-exec");
  552. return;
  553.     }
  554.     CodeGen codegen(*this);
  555.     codegen.sqlParamData(ctx, value);
  556.     if (! ctx.ok())
  557. return;
  558.     sqlExecute(ctx);
  559. }
  560. void
  561. HandleStmt::sqlPutData(Ctx& ctx, SQLPOINTER data, SQLINTEGER strlen_or_Ind)
  562. {
  563.     if (m_state != NeedData) {
  564. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "not expecting data-at-exec");
  565. return;
  566.     }
  567.     CodeGen codegen(*this);
  568.     codegen.sqlPutData(ctx, data, strlen_or_Ind);
  569. }
  570. // describe statement
  571. void
  572. HandleStmt::sqlNumParams(Ctx& ctx, SQLSMALLINT* parameterCountPtr)
  573. {
  574.     if (m_state == Free) {
  575. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "statement is not prepared");
  576. return;
  577.     }
  578.     HandleDesc* ipd = getHandleDesc(ctx, Desc_usage_IPD);
  579.     ipd->sqlGetDescField(ctx, 0, SQL_DESC_COUNT, static_cast<SQLPOINTER>(parameterCountPtr), -1, 0);
  580. }
  581. void
  582. HandleStmt::sqlDescribeParam(Ctx& ctx, SQLUSMALLINT ipar, SQLSMALLINT* pfSqlType, SQLUINTEGER* pcbParamDef, SQLSMALLINT* pibScale, SQLSMALLINT* pfNullable)
  583. {
  584.     if (m_state == Free) {
  585. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "statement is not prepared");
  586. return;
  587.     }
  588.     HandleDesc* ipd = getHandleDesc(ctx, Desc_usage_IPD);
  589.     ipd->sqlGetDescField(ctx, ipar, SQL_DESC_CONCISE_TYPE, static_cast<SQLPOINTER>(pfSqlType), -1, 0);
  590.     { // XXX fix it
  591. OdbcData data((SQLUINTEGER)0);
  592. data.copyout(ctx, (SQLPOINTER)pcbParamDef, -1, 0);
  593.     }
  594.     { // XXX fix it
  595. OdbcData data((SQLSMALLINT)0);
  596. data.copyout(ctx, (SQLPOINTER)pibScale, -1, 0);
  597.     }
  598.     ipd->sqlGetDescField(ctx, ipar, SQL_DESC_NULLABLE, static_cast<SQLPOINTER>(pfNullable), -1, 0);
  599. }
  600. void
  601. HandleStmt::sqlNumResultCols(Ctx& ctx, SQLSMALLINT* columnCount)
  602. {
  603.     if (m_state == Free) {
  604. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "statement is not prepared");
  605. return;
  606.     }
  607.     HandleDesc* const ird = getHandleDesc(ctx, Desc_usage_IRD);
  608.     ird->sqlGetDescField(ctx, 0, SQL_DESC_COUNT, static_cast<SQLPOINTER>(columnCount), -1, 0);
  609.     setFunction(ctx); // unixODBC workaround
  610. }
  611. void
  612. HandleStmt::sqlDescribeCol(Ctx& ctx, SQLUSMALLINT columnNumber, SQLCHAR* columnName, SQLSMALLINT bufferLength, SQLSMALLINT* nameLength, SQLSMALLINT* dataType, SQLUINTEGER* columnSize, SQLSMALLINT* decimalDigits, SQLSMALLINT* nullable)
  613. {
  614.     if (m_state == Free) {
  615. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "statement is not prepared");
  616. return;
  617.     }
  618.     HandleDesc* const ird = getHandleDesc(ctx, Desc_usage_IRD);
  619.     ird->sqlGetDescField(ctx, columnNumber, SQL_DESC_NAME, static_cast<SQLPOINTER>(columnName), bufferLength, 0, nameLength);
  620.     ird->sqlGetDescField(ctx, columnNumber, SQL_DESC_CONCISE_TYPE, static_cast<SQLPOINTER>(dataType), -1, 0);
  621.     if (! ctx.ok())
  622. return;
  623.     if (columnSize != 0) {
  624. switch (*dataType) {
  625. case SQL_CHAR:
  626. case SQL_VARCHAR:
  627. case SQL_BINARY:
  628. case SQL_VARBINARY:
  629.     ird->sqlGetDescField(ctx, columnNumber, SQL_DESC_LENGTH, static_cast<SQLPOINTER>(columnSize), -1, 0);
  630.     break;
  631. case SQL_SMALLINT:
  632.     *columnSize = 5;
  633.     break;
  634. case SQL_INTEGER:
  635.     *columnSize = 10;
  636.     break;
  637. case SQL_BIGINT:
  638.     *columnSize = 20; // XXX 19 for signed
  639.     break;
  640. case SQL_REAL:
  641.     *columnSize = 7;
  642.     break;
  643. case SQL_DOUBLE:
  644.     *columnSize = 15;
  645.     break;
  646. case SQL_TYPE_TIMESTAMP:
  647.     *columnSize = 30;
  648.     break;
  649. default:
  650.     *columnSize = 0;
  651.     break;
  652. }
  653.     }
  654.     if (decimalDigits != 0) {
  655. switch (*dataType) {
  656. case SQL_SMALLINT:
  657. case SQL_INTEGER:
  658. case SQL_BIGINT:
  659.     *decimalDigits = 0;
  660.     break;
  661. case SQL_TYPE_TIMESTAMP:
  662.     *decimalDigits = 10;
  663.     break;
  664. default:
  665.     *decimalDigits = 0;
  666.     break;
  667. }
  668.     }
  669.     ird->sqlGetDescField(ctx, columnNumber, SQL_DESC_NULLABLE, static_cast<SQLPOINTER>(nullable), -1, 0);
  670. }
  671. void
  672. HandleStmt::sqlColAttribute(Ctx& ctx, SQLUSMALLINT columnNumber, SQLUSMALLINT fieldIdentifier, SQLPOINTER characterAttribute, SQLSMALLINT bufferLength, SQLSMALLINT* stringLength, SQLPOINTER numericAttribute)
  673. {
  674.     if (m_state == Free) {
  675. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "statement is not prepared");
  676. return;
  677.     }
  678.     HandleDesc* const ird = getHandleDesc(ctx, Desc_usage_IRD);
  679.     ird->sqlColAttribute(ctx, columnNumber, fieldIdentifier, characterAttribute, bufferLength, stringLength, numericAttribute);
  680. }
  681. void
  682. HandleStmt::sqlColAttributes(Ctx& ctx, SQLUSMALLINT icol, SQLUSMALLINT fdescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT* pcbDesc, SQLINTEGER* pfDesc)
  683. {
  684.     if (m_state == Free) {
  685. ctx.pushStatus(Sqlstate::_HY010, Error::Gen, "statement is nor prepared");
  686. return;
  687.     }
  688.     HandleDesc* const ird = getHandleDesc(ctx, Desc_usage_IRD);
  689.     ird->sqlColAttributes(ctx, icol, fdescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
  690. }
  691. // descriptor manipulation
  692. void
  693. HandleStmt::sqlBindCol(Ctx& ctx, SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValue, SQLINTEGER bufferLength, SQLINTEGER* strlen_or_Ind)
  694. {
  695.     HandleDesc* const ard = getHandleDesc(ctx, Desc_usage_ARD);
  696.     DescArea& desc = ard->descArea();
  697.     if (desc.getCount() < columnNumber) {
  698. desc.setCount(ctx, columnNumber);
  699.     }
  700.     DescRec& rec = desc.getRecord(columnNumber);
  701.     rec.setField(ctx, SQL_DESC_TYPE, targetType);
  702.     rec.setField(ctx, SQL_DESC_CONCISE_TYPE, targetType);
  703.     rec.setField(ctx, SQL_DESC_DATA_PTR, targetValue);
  704.     rec.setField(ctx, SQL_DESC_OCTET_LENGTH, bufferLength);
  705.     rec.setField(ctx, SQL_DESC_OCTET_LENGTH_PTR, strlen_or_Ind);
  706.     rec.setField(ctx, SQL_DESC_INDICATOR_PTR, strlen_or_Ind);
  707. }
  708. void
  709. HandleStmt::sqlBindParameter(Ctx& ctx, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLUINTEGER cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER* pcbValue)
  710. {
  711.     HandleDesc* const ipd = getHandleDesc(ctx, Desc_usage_IPD);
  712.     HandleDesc* const apd = getHandleDesc(ctx, Desc_usage_APD);
  713.     DescArea& descIPD = ipd->descArea();
  714.     DescArea& descAPD = apd->descArea();
  715.     if (ipar < 1) {
  716. ctx.pushStatus(Sqlstate::_07009, Error::Gen, "invalid parameter index %u", (unsigned)ipar);
  717. return;
  718.     }
  719.     if (descIPD.getCount() < ipar) {
  720. descIPD.setCount(ctx, ipar);
  721.     }
  722.     if (descAPD.getCount() < ipar) {
  723. descAPD.setCount(ctx, ipar);
  724.     }
  725.     DescRec& recIPD = descIPD.getRecord(ipar);
  726.     DescRec& recAPD = descAPD.getRecord(ipar);
  727.     recIPD.setField(ctx, SQL_DESC_PARAMETER_TYPE, fParamType);
  728.     recAPD.setField(ctx, SQL_DESC_TYPE, fCType);
  729.     recAPD.setField(ctx, SQL_DESC_CONCISE_TYPE, fCType);
  730.     recIPD.setField(ctx, SQL_DESC_TYPE, fSqlType);
  731.     recIPD.setField(ctx, SQL_DESC_CONCISE_TYPE, fSqlType);
  732.     switch (fSqlType) {
  733.     case SQL_CHAR: // XXX not complete
  734.     case SQL_VARCHAR:
  735.     case SQL_BINARY:
  736.     case SQL_VARBINARY:
  737. recIPD.setField(ctx, SQL_DESC_LENGTH, cbColDef);
  738. break;
  739.     case SQL_DECIMAL:
  740.     case SQL_NUMERIC:
  741.     case SQL_FLOAT:
  742.     case SQL_REAL:
  743.     case SQL_DOUBLE:
  744. recIPD.setField(ctx, SQL_DESC_PRECISION, cbColDef);
  745. break;
  746.     }
  747.     switch (fSqlType) {
  748.     case SQL_TYPE_TIME: // XXX not complete
  749.     case SQL_TYPE_TIMESTAMP:
  750. recIPD.setField(ctx, SQL_DESC_PRECISION, ibScale);
  751. break;
  752.     case SQL_NUMERIC:
  753.     case SQL_DECIMAL:
  754. recIPD.setField(ctx, SQL_DESC_SCALE, ibScale);
  755. break;
  756.     }
  757.     recAPD.setField(ctx, SQL_DESC_DATA_PTR, rgbValue);
  758.     recAPD.setField(ctx, SQL_DESC_OCTET_LENGTH, cbValueMax);
  759.     recAPD.setField(ctx, SQL_DESC_OCTET_LENGTH_PTR, pcbValue);
  760.     recAPD.setField(ctx, SQL_DESC_INDICATOR_PTR, pcbValue);
  761. }
  762. void
  763. HandleStmt::sqlBindParam(Ctx& ctx, SQLUSMALLINT parameterNumber, SQLSMALLINT valueType, SQLSMALLINT parameterType, SQLUINTEGER lengthPrecision, SQLSMALLINT parameterScale, SQLPOINTER parameterValue, SQLINTEGER* strLen_or_Ind)
  764. {
  765.     sqlBindParameter(ctx, parameterNumber, SQL_PARAM_INPUT_OUTPUT, valueType, parameterType, lengthPrecision, parameterScale, parameterValue, SQL_SETPARAM_VALUE_MAX, strLen_or_Ind);
  766. }
  767. void
  768. HandleStmt::sqlSetParam(Ctx& ctx, SQLUSMALLINT parameterNumber, SQLSMALLINT valueType, SQLSMALLINT parameterType, SQLUINTEGER lengthPrecision, SQLSMALLINT parameterScale, SQLPOINTER parameterValue, SQLINTEGER* strLen_or_Ind)
  769. {
  770.     sqlBindParameter(ctx, parameterNumber, SQL_PARAM_INPUT_OUTPUT, valueType, parameterType, lengthPrecision, parameterScale, parameterValue, SQL_SETPARAM_VALUE_MAX, strLen_or_Ind);
  771. }