odbc0odbc.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:16k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. Innobase ODBC client library
  3. (c) 1998 Innobase Oy
  4. Created 2/22/1998 Heikki Tuuri
  5. *******************************************************/
  6. #include "odbc0odbc.h"
  7. #include "mem0mem.h"
  8. #include "com0com.h"
  9. #include "usr0sess.h"
  10. #define ODBC_STAT_INITIAL 1
  11. #define ODBC_STAT_PREPARED 2
  12. #define ODBC_STAT_EXECUTED 3
  13. typedef struct odbc_conn_struct odbc_conn_t;
  14. typedef struct odbc_env_struct odbc_env_t;
  15. /* ODBC parameter description struct */
  16. typedef struct odbc_param_struct odbc_param_t;
  17. struct odbc_param_struct{
  18. ulint data_type; /* SQL_CHAR, ... */
  19. ibool is_input; /* TRUE if an input parameter of a stored
  20. procedure, FALSE if an output parameter */
  21. byte* buf; /* buffer where the value is stored before
  22. SQLExecute, or where it comes after SQLExecute
  23. in the case of an output parameter */
  24. lint* data_len; /* pointer to where the data len or the value
  25. SQL_NULL_DATA is stored */
  26. ulint buf_len; /* buffer size */
  27. };
  28. /* ODBC statement data structure */
  29. typedef struct odbc_stat_struct odbc_stat_t;
  30. struct odbc_stat_struct{
  31. ulint state; /* ODBC_STAT_INITIAL,
  32. ODBC_STAT_PREPARED,
  33. ODBC_STAT_EXECUTED */
  34. ulint id; /* statement id */
  35. ulint n_params; /* number of parameters */
  36. odbc_param_t* params; /* pointer to an array describing
  37. the parameters, if any */
  38. ulint n_params_bound; /* number of parameters that have
  39. been bound: the statement cannot be
  40. executed before n_params_bound
  41. == n_params */
  42. byte* error_msg; /* possible error message, or NULL;
  43. allocated separately from dynamic
  44. memory */
  45. ulint error_msg_len; /* error mesage length if it is
  46. non-NULL */
  47. odbc_conn_t* conn; /* connection */
  48. UT_LIST_NODE_T(odbc_stat_t)
  49. stat_list; /* list of the statements of the
  50. connection */
  51. };
  52. /* ODBC connection data structure */
  53. struct odbc_conn_struct{
  54. ibool connected; /* TRUE if connected */
  55. char* server_name; /* server name where connected
  56. (= server address) */
  57. ulint server_name_len;/* length of the server name */
  58. com_endpoint_t* com_endpoint; /* connection endpoint for this client
  59. connection */
  60. dulint out_msg_count; /* count of outgoing messages */
  61. byte* out_datagram_buf;/* buffer for outgoing datagrams to
  62. the server */
  63. byte* in_datagram_buf;/* buffer for incoming datagrams from
  64. the server */
  65. byte* addr_buf; /* buffer for the address from which
  66. an incoming datagram came; in practice,
  67. this will be the server address */
  68. dulint sess_id; /* user session id, once the
  69. connection to the server is
  70. established */
  71. odbc_env_t* env; /* environment */
  72. UT_LIST_BASE_NODE_T(odbc_stat_t)
  73. stat_list; /* list of the statements of the
  74. connection */
  75. UT_LIST_NODE_T(odbc_conn_t)
  76. conn_list; /* list of the connections of the
  77. environment */
  78. };
  79. /* ODBC environment data structure */
  80. struct odbc_env_struct{
  81. UT_LIST_BASE_NODE_T(odbc_conn_t) conn_list;
  82. /* list of the connections of the
  83. environment */
  84. };
  85. /**************************************************************************
  86. Gets the nth parameter description struct for a statement. */
  87. UNIV_INLINE
  88. odbc_param_t*
  89. stat_get_nth_param(
  90. /*===============*/
  91. /* out: nth parameter */
  92. odbc_stat_t* stat, /* in: pointer to statement handle */
  93. ulint i) /* in: parameter index */
  94. {
  95. ut_ad(stat->n_params > i);
  96. return(stat->params + i);
  97. }
  98. /**************************************************************************
  99. Allocates an SQL environment. */
  100. RETCODE
  101. SQLAllocEnv(
  102. /*========*/
  103. /* out: SQL_SUCCESS */
  104. HENV* phenv) /* out: pointer to an environment handle */
  105. {
  106. odbc_env_t* env;
  107. if (!sync_initialized) {
  108. sync_init();
  109. mem_init(2000000);
  110. }
  111. env = mem_alloc(sizeof(odbc_env_t));
  112. UT_LIST_INIT(env->conn_list);
  113. *phenv = env;
  114. return(SQL_SUCCESS);
  115. }
  116. /**************************************************************************
  117. Allocates an SQL connection. */
  118. RETCODE
  119. SQLAllocConnect(
  120. /*============*/
  121. /* out: SQL_SUCCESS */
  122. HENV henv, /* in: pointer to an environment handle */
  123. HDBC* phdbc) /* out: pointer to a connection handle */
  124. {
  125. odbc_conn_t* conn;
  126. odbc_env_t* env;
  127. ut_a(henv);
  128. env = henv;
  129. conn = mem_alloc(sizeof(odbc_conn_t));
  130. conn->connected = FALSE;
  131. conn->env = env;
  132. UT_LIST_INIT(conn->stat_list);
  133. UT_LIST_ADD_LAST(conn_list, env->conn_list, conn);
  134. *phdbc = conn;
  135. return(SQL_SUCCESS);
  136. }
  137. /**************************************************************************
  138. Allocates an SQL statement. */
  139. RETCODE
  140. SQLAllocStmt(
  141. /*=========*/
  142. HDBC hdbc, /* in: SQL connection */
  143. HSTMT* phstmt) /* out: pointer to a statement handle */
  144. {
  145. odbc_conn_t* conn;
  146. odbc_stat_t* stat;
  147. ut_a(hdbc);
  148. conn = hdbc;
  149. stat = mem_alloc(sizeof(odbc_stat_t));
  150. stat->state = ODBC_STAT_INITIAL;
  151. stat->error_msg = NULL;
  152. stat->conn = conn;
  153. UT_LIST_ADD_LAST(stat_list, conn->stat_list, stat);
  154. *phstmt = stat;
  155. return(SQL_SUCCESS);
  156. }
  157. /**************************************************************************
  158. Sends the message in datagram_buf to the server. */
  159. static
  160. void
  161. odbc_send_cli_msg(
  162. /*==============*/
  163. odbc_conn_t* conn, /* in: connection, does not have to be
  164. connected yet */
  165. ulint  len) /* in: message length (excluding the standard
  166. header of size SESS_CLI_MSG_DATA) */
  167. {
  168. ulint ret;
  169. ulint fold;
  170. byte* msg;
  171. ut_a(len + SESS_CLI_MSG_DATA <= ODBC_DATAGRAM_SIZE);
  172. msg = conn->out_datagram_buf;
  173. mach_write_to_8(msg + SESS_CLI_MSG_NO, conn->out_msg_count);
  174. UT_DULINT_INC(conn->out_msg_count);
  175. fold = ut_fold_binary(msg + 4, len + SESS_CLI_MSG_DATA - 4);
  176.   ut_ad(SESS_CLI_MSG_CHECKSUM == 0);
  177. mach_write_to_4(msg + SESS_CLI_MSG_CHECKSUM, fold);
  178. ret = com_sendto(conn->com_endpoint, msg, SESS_CLI_MSG_DATA + len,
  179. conn->server_name, conn->server_name_len);
  180. ut_a(ret == 0);
  181. }
  182. /**************************************************************************
  183. Receives a message in datagram_buf from the server. */
  184. static
  185. void
  186. odbc_recv_srv_msg(
  187. /*==============*/
  188. odbc_conn_t* conn, /* in: connection, does not have to be
  189. connected yet */
  190. ulint*  len) /* out: received message length (excluding the
  191. standard header of size SESS_SRV_MSG_DATA) */
  192. {
  193. ulint total_len;
  194. ulint addr_len;
  195. ulint ret;
  196. ret = com_recvfrom(conn->com_endpoint, conn->in_datagram_buf,
  197. ODBC_DATAGRAM_SIZE, &total_len, (char*)conn->addr_buf,
  198. ODBC_ADDRESS_SIZE, &addr_len);
  199. ut_a(ret == 0);
  200. ut_a(total_len >= SESS_SRV_MSG_DATA);
  201. *len = total_len - SESS_SRV_MSG_DATA;
  202. }
  203. /**************************************************************************
  204. Connects to a database server process (establishes a connection and a
  205. session). */
  206. RETCODE
  207. SQLConnect(
  208. /*=======*/
  209. /* out: SQL_SUCCESS */
  210. HDBC hdbc, /* in: SQL connection handle */
  211. UCHAR* szDSN, /* in: data source name (server name) */
  212. SWORD cbDSN, /* in: data source name length */
  213. UCHAR* szUID, /* in: user name */
  214. SWORD cbUID, /* in: user name length */
  215. UCHAR* szAuthStr, /* in: password */
  216. SWORD cbAuthStr) /* in: password length */
  217. {
  218. com_endpoint_t* ep;
  219. odbc_conn_t* conn;
  220. ulint err;
  221. ulint size;
  222. byte* msg;
  223. ulint len;
  224. UCHAR catenated_name[100];
  225. ut_a(hdbc && szDSN);
  226. UT_NOT_USED(szUID);
  227. UT_NOT_USED(cbUID);
  228. UT_NOT_USED(szAuthStr);
  229. UT_NOT_USED(cbAuthStr);
  230. conn = hdbc;
  231. ut_a(!conn->connected);
  232. conn->server_name = mem_alloc(cbDSN);
  233. ut_memcpy(conn->server_name, szDSN, cbDSN);
  234. conn->server_name_len = cbDSN;
  235. ep = com_endpoint_create(COM_SHM);
  236. ut_a(ep);
  237. conn->com_endpoint = ep;
  238. conn->out_msg_count = ut_dulint_zero;
  239. size = ODBC_DATAGRAM_SIZE;
  240. err = com_endpoint_set_option(ep, COM_OPT_MAX_DGRAM_SIZE,
  241. (byte*)&size, 4);
  242. ut_a(err == 0);
  243. /* Make the data source name catenated to user name as the
  244. address of the communications endpoint */
  245. ut_a((ulint)cbDSN + (ulint)cbUID < 100);
  246. ut_memcpy(catenated_name, szDSN, (ulint)cbDSN);
  247. ut_memcpy(catenated_name + (ulint)cbDSN, szUID, (ulint)cbUID);
  248. err = com_bind(ep, (char*)catenated_name, (ulint)cbDSN
  249. + (ulint)cbUID);
  250. ut_a(err == 0);
  251. conn->in_datagram_buf = mem_alloc(ODBC_DATAGRAM_SIZE);
  252. msg = mem_alloc(ODBC_DATAGRAM_SIZE);
  253. conn->out_datagram_buf = msg;
  254. conn->addr_buf = mem_alloc(ODBC_ADDRESS_SIZE);
  255. /* Set the session id to dulint 0 as we are not yet connected */
  256. sess_cli_msg_set_sess(msg, ut_dulint_zero);
  257. sess_cli_msg_set_type(msg, SESS_CLI_CONNECT);
  258. /*------------------------------------------*/
  259. odbc_send_cli_msg(conn, 0);
  260. odbc_recv_srv_msg(conn, &len);
  261. /*------------------------------------------*/
  262. ut_a(len == 0);
  263. ut_a(sess_srv_msg_get_type(conn->in_datagram_buf)
  264. == SESS_SRV_ACCEPT_CONNECT);
  265. conn->sess_id = mach_read_from_8(conn->in_datagram_buf
  266. + SESS_SRV_MSG_SESS_ID);
  267. /* Write the session id to out_datagram_buf: it will not be rewritten
  268. until the connection is closed, as the session id will stay the same */
  269. sess_cli_msg_set_sess(msg, conn->sess_id);
  270. /* We currently only send single part messages: the following will
  271. stay 0 during the connection */
  272. mach_write_to_4(msg + SESS_CLI_MSG_CONTINUE, 0);
  273. mach_write_to_4(msg + SESS_CLI_MSG_CONT_SIZE, 0);
  274. conn->connected = TRUE;
  275. return(SQL_SUCCESS);
  276. }
  277. /**************************************************************************
  278. Stores an error message to a statement handle, so that it can be later
  279. queried with SQLError. */
  280. static
  281. void
  282. odbc_stat_store_error_msg(
  283. /*======================*/
  284. odbc_stat_t* stat, /* in: statement handle */
  285. byte* msg, /* in: error message sent by the server */
  286. ulint len) /* in: length of msg */
  287. {
  288. if (stat->error_msg) {
  289. mem_free(stat->error_msg);
  290. }
  291. stat->error_msg_len = len;
  292. len += SESS_SRV_MSG_DATA;
  293. stat->error_msg = mem_alloc(len);
  294. ut_memcpy(stat->error_msg, msg, len);
  295. }
  296. /**************************************************************************
  297. Queries an error message. */
  298. RETCODE
  299. SQLError(
  300. /*=====*/
  301. /* out: SQL_SUCCESS or SQL_NO_DATA_FOUND */
  302. HENV henv, /* in: SQL_NULL_HENV */
  303. HDBC hdbc, /* in: SQL_NULL_HDBC */
  304. HSTMT hstmt, /* in: statement handle */
  305. UCHAR* szSqlState, /* in/out: SQLSTATE as a null-terminated string,
  306. (currently, always == "S1000") */
  307. SDWORD* pfNativeError, /* out: native error code */
  308. UCHAR* szErrorMsg, /* in/out: buffer for an error message as a
  309. null-terminated string */
  310. SWORD cbErrorMsgMax, /* in: buffer size for szErrorMsg */
  311. SWORD* pcbErrorMsg) /* out: error message length */
  312. {
  313. odbc_stat_t* stat;
  314. ulint len;
  315. ut_a(henv == SQL_NULL_HENV);
  316. ut_a(hdbc == SQL_NULL_HDBC);
  317. ut_a(hstmt);
  318. ut_a(cbErrorMsgMax > 1);
  319. stat = hstmt;
  320. if (stat->error_msg == NULL) {
  321. return(SQL_NO_DATA_FOUND);
  322. }
  323. *pfNativeError = 0;
  324. ut_memcpy(szSqlState, "S1000", 6);
  325. len = (ulint)cbErrorMsgMax - 1;
  326. if (stat->error_msg_len < len) {
  327. len = stat->error_msg_len;
  328. }
  329. ut_memcpy(szErrorMsg, stat->error_msg + SESS_SRV_MSG_DATA, len);
  330. *(szErrorMsg + len) = '';
  331. *pcbErrorMsg = (SWORD)len;
  332. if (stat->error_msg) {
  333. mem_free(stat->error_msg);
  334. stat->error_msg = NULL;
  335. }
  336. return(SQL_SUCCESS);
  337. }
  338. /**************************************************************************
  339. Makes the server to parse and optimize an SQL string. */
  340. RETCODE
  341. SQLPrepare(
  342. /*=======*/
  343. /* out: SQL_SUCCESS or SQL_ERROR */
  344. HSTMT hstmt, /* in: statement handle */
  345. UCHAR* szSqlStr, /* in: SQL string */
  346. SDWORD cbSqlStr) /* in: SQL string length */
  347. {
  348. odbc_stat_t* stat;
  349. odbc_conn_t* conn;
  350. odbc_param_t* param;
  351. ulint len;
  352. byte* msg;
  353. ulint i;
  354. stat = hstmt;
  355. conn = stat->conn;
  356. if (stat->error_msg) {
  357. mem_free(stat->error_msg);
  358. stat->error_msg = NULL;
  359. }
  360. ut_memcpy(conn->out_datagram_buf + SESS_CLI_MSG_DATA, szSqlStr,
  361. 1 + (ulint)cbSqlStr);
  362. sess_cli_msg_set_type(conn->out_datagram_buf, SESS_CLI_PREPARE);
  363. /* The client message will be decoded in sess_receive_prepare */
  364. /*------------------------------------------*/
  365. odbc_send_cli_msg(conn, 1 + (ulint)cbSqlStr);
  366. odbc_recv_srv_msg(conn, &len);
  367. /*------------------------------------------*/
  368. /* The server message was coded in sess_receive_prepare */
  369. ut_a(len >= 8);
  370. msg = conn->in_datagram_buf;
  371. if (sess_srv_msg_get_type(msg) != SESS_SRV_SUCCESS) {
  372. ut_a(sess_srv_msg_get_type(msg) == SESS_SRV_ERROR);
  373. odbc_stat_store_error_msg(stat, msg, len);
  374. return(SQL_ERROR);
  375. }
  376. stat->id = mach_read_from_4(msg + SESS_SRV_MSG_DATA);
  377. stat->n_params = mach_read_from_4(msg + SESS_SRV_MSG_DATA + 4);
  378. stat->n_params_bound = 0;
  379. ut_a(len == 8 + stat->n_params);
  380. if (stat->n_params > 0) {
  381. stat->params = mem_alloc(stat->n_params
  382. * sizeof(odbc_param_t));
  383. for (i = 0; i < stat->n_params; i++) {
  384. param = stat_get_nth_param(stat, i);
  385. param->is_input = mach_read_from_1(
  386.     msg + SESS_SRV_MSG_DATA + 8 + i);
  387. /* Set buf to NULL so that we know when the parameter
  388. has been bound */
  389. param->buf = NULL;
  390. }
  391. }
  392. stat->state = ODBC_STAT_PREPARED;
  393. return(SQL_SUCCESS);
  394. }
  395. /**************************************************************************
  396. Binds a parameter in a prepared statement. */
  397. RETCODE
  398. SQLBindParameter(
  399. /*=============*/
  400. /* out: SQL_SUCCESS */
  401. HSTMT hstmt, /* in: statement handle */
  402. UWORD ipar, /* in: parameter index, starting from 1 */
  403. SWORD fParamType, /* in: SQL_PARAM_INPUT or SQL_PARAM_OUTPUT */
  404. SWORD fCType, /* in: SQL_C_CHAR, ... */
  405. SWORD fSqlType, /* in: SQL_CHAR, ... */
  406. UDWORD cbColDef, /* in: precision: ignored */
  407. SWORD ibScale, /* in: scale: ignored */
  408. PTR rgbValue, /* in: pointer to a buffer for the data */
  409. SDWORD cbValueMax, /* in: buffer size */
  410. SDWORD* pcbValue) /* in: pointer to a buffer for the data
  411. length or SQL_NULL_DATA */
  412. {
  413. odbc_stat_t* stat;
  414. odbc_param_t* param;
  415. stat = hstmt;
  416. ut_a(stat->state != ODBC_STAT_INITIAL);
  417. ut_a(rgbValue);
  418. ut_a(ipar <= stat->n_params);
  419. ut_a(ipar > 0);
  420. ut_a(cbValueMax >= 0);
  421. ut_a(pcbValue);
  422. UT_NOT_USED(ibScale);
  423. UT_NOT_USED(fCType);
  424. UT_NOT_USED(cbColDef);
  425. if (stat->error_msg) {
  426. mem_free(stat->error_msg);
  427. stat->error_msg = NULL;
  428. }
  429. param = stat_get_nth_param(stat, ipar - 1);
  430. if (param->buf == NULL) {
  431. stat->n_params_bound++;
  432. }
  433. param->data_type = fSqlType;
  434. ut_a((fParamType != SQL_PARAM_INPUT) || param->is_input);
  435. ut_a((fParamType == SQL_PARAM_INPUT) || !param->is_input);
  436. param->buf = rgbValue;
  437. param->buf_len = cbValueMax;
  438. param->data_len = pcbValue;
  439. return(SQL_SUCCESS);
  440. }
  441. /**************************************************************************
  442. Executes a prepared statement where all parameters have been bound. */
  443. RETCODE
  444. SQLExecute(
  445. /*=======*/
  446. /* out: SQL_SUCCESS or SQL_ERROR */
  447. HSTMT hstmt) /* in: statement handle */
  448. {
  449. odbc_stat_t* stat;
  450. odbc_conn_t* conn;
  451. odbc_param_t* param;
  452. lint len;
  453. ulint msg_len;
  454. byte* msg;
  455. byte* ptr;
  456. lint int_val;
  457. ulint i;
  458. stat = hstmt;
  459. ut_a(stat->state != ODBC_STAT_INITIAL);
  460. ut_a(stat->n_params == stat->n_params_bound);
  461. if (stat->error_msg) {
  462. mem_free(stat->error_msg);
  463. stat->error_msg = NULL;
  464. }
  465. conn = stat->conn;
  466. msg = conn->out_datagram_buf;
  467. sess_cli_msg_set_type(msg, SESS_CLI_EXECUTE);
  468. ptr = msg + SESS_CLI_MSG_DATA;
  469. mach_write_to_4(ptr, stat->id);
  470. ptr += 4;
  471. for (i = 0; i < stat->n_params; i++) {
  472. param = stat_get_nth_param(stat, i);
  473. if (param->is_input) {
  474. /* Copy its length and data to the message buffer */
  475. len = *(param->data_len);
  476. mach_write_to_4(ptr, (ulint)len);
  477. ptr += 4;
  478. if (len != SQL_NULL_DATA) {
  479. if (param->data_type == SQL_INTEGER) {
  480. ut_ad(len == 4);
  481. int_val = *((lint*)(param->buf));
  482. mach_write_to_4(ptr, (ulint)int_val);
  483. } else {
  484. ut_memcpy(ptr, param->buf, len);
  485. }
  486. ptr += len;
  487. }
  488. }
  489. }
  490. /* The client message will be decoded in sess_receive_command */
  491. /*------------------------------------------*/
  492. odbc_send_cli_msg(conn, ptr - (msg + SESS_CLI_MSG_DATA));
  493. odbc_recv_srv_msg(conn, &msg_len);
  494. /*------------------------------------------*/
  495. /* The server message was coded in sess_command_completed_message */
  496. msg = conn->in_datagram_buf;
  497. if (sess_srv_msg_get_type(msg) != SESS_SRV_SUCCESS) {
  498. ut_a(sess_srv_msg_get_type(msg) == SESS_SRV_ERROR);
  499. odbc_stat_store_error_msg(stat, msg, msg_len);
  500. return(SQL_ERROR);
  501. }
  502. ptr = msg + SESS_SRV_MSG_DATA;
  503. for (i = 0; i < stat->n_params; i++) {
  504. param = stat_get_nth_param(stat, i);
  505. if (!param->is_input) {
  506. /* Copy its length and data from the message buffer */
  507. len = (lint)mach_read_from_4(ptr);
  508. ptr += 4;
  509. *(param->data_len) = len;
  510. if (len != SQL_NULL_DATA) {
  511. if (param->data_type == SQL_INTEGER) {
  512. ut_ad(len == 4);
  513. int_val = (lint)mach_read_from_4(ptr);
  514. *((lint*)(param->buf)) = int_val;
  515. } else {
  516. ut_memcpy(param->buf, ptr, (ulint)len);
  517. }
  518. ptr += len;
  519. }
  520. }
  521. }
  522. ut_ad(msg + SESS_SRV_MSG_DATA + msg_len == ptr);
  523. return(SQL_SUCCESS);
  524. }