odbc0odbc.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:16k
- /******************************************************
- Innobase ODBC client library
- (c) 1998 Innobase Oy
- Created 2/22/1998 Heikki Tuuri
- *******************************************************/
- #include "odbc0odbc.h"
- #include "mem0mem.h"
- #include "com0com.h"
- #include "usr0sess.h"
- #define ODBC_STAT_INITIAL 1
- #define ODBC_STAT_PREPARED 2
- #define ODBC_STAT_EXECUTED 3
- typedef struct odbc_conn_struct odbc_conn_t;
- typedef struct odbc_env_struct odbc_env_t;
- /* ODBC parameter description struct */
- typedef struct odbc_param_struct odbc_param_t;
- struct odbc_param_struct{
- ulint data_type; /* SQL_CHAR, ... */
- ibool is_input; /* TRUE if an input parameter of a stored
- procedure, FALSE if an output parameter */
- byte* buf; /* buffer where the value is stored before
- SQLExecute, or where it comes after SQLExecute
- in the case of an output parameter */
- lint* data_len; /* pointer to where the data len or the value
- SQL_NULL_DATA is stored */
- ulint buf_len; /* buffer size */
- };
- /* ODBC statement data structure */
- typedef struct odbc_stat_struct odbc_stat_t;
- struct odbc_stat_struct{
- ulint state; /* ODBC_STAT_INITIAL,
- ODBC_STAT_PREPARED,
- ODBC_STAT_EXECUTED */
- ulint id; /* statement id */
- ulint n_params; /* number of parameters */
- odbc_param_t* params; /* pointer to an array describing
- the parameters, if any */
- ulint n_params_bound; /* number of parameters that have
- been bound: the statement cannot be
- executed before n_params_bound
- == n_params */
- byte* error_msg; /* possible error message, or NULL;
- allocated separately from dynamic
- memory */
- ulint error_msg_len; /* error mesage length if it is
- non-NULL */
- odbc_conn_t* conn; /* connection */
- UT_LIST_NODE_T(odbc_stat_t)
- stat_list; /* list of the statements of the
- connection */
- };
- /* ODBC connection data structure */
- struct odbc_conn_struct{
- ibool connected; /* TRUE if connected */
- char* server_name; /* server name where connected
- (= server address) */
- ulint server_name_len;/* length of the server name */
- com_endpoint_t* com_endpoint; /* connection endpoint for this client
- connection */
- dulint out_msg_count; /* count of outgoing messages */
- byte* out_datagram_buf;/* buffer for outgoing datagrams to
- the server */
- byte* in_datagram_buf;/* buffer for incoming datagrams from
- the server */
- byte* addr_buf; /* buffer for the address from which
- an incoming datagram came; in practice,
- this will be the server address */
- dulint sess_id; /* user session id, once the
- connection to the server is
- established */
- odbc_env_t* env; /* environment */
- UT_LIST_BASE_NODE_T(odbc_stat_t)
- stat_list; /* list of the statements of the
- connection */
- UT_LIST_NODE_T(odbc_conn_t)
- conn_list; /* list of the connections of the
- environment */
- };
- /* ODBC environment data structure */
- struct odbc_env_struct{
- UT_LIST_BASE_NODE_T(odbc_conn_t) conn_list;
- /* list of the connections of the
- environment */
- };
-
- /**************************************************************************
- Gets the nth parameter description struct for a statement. */
- UNIV_INLINE
- odbc_param_t*
- stat_get_nth_param(
- /*===============*/
- /* out: nth parameter */
- odbc_stat_t* stat, /* in: pointer to statement handle */
- ulint i) /* in: parameter index */
- {
- ut_ad(stat->n_params > i);
- return(stat->params + i);
- }
- /**************************************************************************
- Allocates an SQL environment. */
- RETCODE
- SQLAllocEnv(
- /*========*/
- /* out: SQL_SUCCESS */
- HENV* phenv) /* out: pointer to an environment handle */
- {
- odbc_env_t* env;
- if (!sync_initialized) {
- sync_init();
- mem_init(2000000);
- }
- env = mem_alloc(sizeof(odbc_env_t));
- UT_LIST_INIT(env->conn_list);
- *phenv = env;
- return(SQL_SUCCESS);
- }
- /**************************************************************************
- Allocates an SQL connection. */
- RETCODE
- SQLAllocConnect(
- /*============*/
- /* out: SQL_SUCCESS */
- HENV henv, /* in: pointer to an environment handle */
- HDBC* phdbc) /* out: pointer to a connection handle */
- {
- odbc_conn_t* conn;
- odbc_env_t* env;
- ut_a(henv);
- env = henv;
- conn = mem_alloc(sizeof(odbc_conn_t));
- conn->connected = FALSE;
- conn->env = env;
- UT_LIST_INIT(conn->stat_list);
- UT_LIST_ADD_LAST(conn_list, env->conn_list, conn);
- *phdbc = conn;
- return(SQL_SUCCESS);
- }
- /**************************************************************************
- Allocates an SQL statement. */
- RETCODE
- SQLAllocStmt(
- /*=========*/
- HDBC hdbc, /* in: SQL connection */
- HSTMT* phstmt) /* out: pointer to a statement handle */
- {
- odbc_conn_t* conn;
- odbc_stat_t* stat;
- ut_a(hdbc);
- conn = hdbc;
- stat = mem_alloc(sizeof(odbc_stat_t));
- stat->state = ODBC_STAT_INITIAL;
- stat->error_msg = NULL;
- stat->conn = conn;
- UT_LIST_ADD_LAST(stat_list, conn->stat_list, stat);
- *phstmt = stat;
- return(SQL_SUCCESS);
- }
- /**************************************************************************
- Sends the message in datagram_buf to the server. */
- static
- void
- odbc_send_cli_msg(
- /*==============*/
- odbc_conn_t* conn, /* in: connection, does not have to be
- connected yet */
- ulint len) /* in: message length (excluding the standard
- header of size SESS_CLI_MSG_DATA) */
- {
- ulint ret;
- ulint fold;
- byte* msg;
- ut_a(len + SESS_CLI_MSG_DATA <= ODBC_DATAGRAM_SIZE);
- msg = conn->out_datagram_buf;
- mach_write_to_8(msg + SESS_CLI_MSG_NO, conn->out_msg_count);
- UT_DULINT_INC(conn->out_msg_count);
- fold = ut_fold_binary(msg + 4, len + SESS_CLI_MSG_DATA - 4);
- ut_ad(SESS_CLI_MSG_CHECKSUM == 0);
- mach_write_to_4(msg + SESS_CLI_MSG_CHECKSUM, fold);
- ret = com_sendto(conn->com_endpoint, msg, SESS_CLI_MSG_DATA + len,
- conn->server_name, conn->server_name_len);
- ut_a(ret == 0);
- }
- /**************************************************************************
- Receives a message in datagram_buf from the server. */
- static
- void
- odbc_recv_srv_msg(
- /*==============*/
- odbc_conn_t* conn, /* in: connection, does not have to be
- connected yet */
- ulint* len) /* out: received message length (excluding the
- standard header of size SESS_SRV_MSG_DATA) */
- {
- ulint total_len;
- ulint addr_len;
- ulint ret;
- ret = com_recvfrom(conn->com_endpoint, conn->in_datagram_buf,
- ODBC_DATAGRAM_SIZE, &total_len, (char*)conn->addr_buf,
- ODBC_ADDRESS_SIZE, &addr_len);
- ut_a(ret == 0);
- ut_a(total_len >= SESS_SRV_MSG_DATA);
- *len = total_len - SESS_SRV_MSG_DATA;
- }
-
- /**************************************************************************
- Connects to a database server process (establishes a connection and a
- session). */
- RETCODE
- SQLConnect(
- /*=======*/
- /* out: SQL_SUCCESS */
- HDBC hdbc, /* in: SQL connection handle */
- UCHAR* szDSN, /* in: data source name (server name) */
- SWORD cbDSN, /* in: data source name length */
- UCHAR* szUID, /* in: user name */
- SWORD cbUID, /* in: user name length */
- UCHAR* szAuthStr, /* in: password */
- SWORD cbAuthStr) /* in: password length */
- {
- com_endpoint_t* ep;
- odbc_conn_t* conn;
- ulint err;
- ulint size;
- byte* msg;
- ulint len;
- UCHAR catenated_name[100];
-
- ut_a(hdbc && szDSN);
- UT_NOT_USED(szUID);
- UT_NOT_USED(cbUID);
- UT_NOT_USED(szAuthStr);
- UT_NOT_USED(cbAuthStr);
- conn = hdbc;
-
- ut_a(!conn->connected);
- conn->server_name = mem_alloc(cbDSN);
- ut_memcpy(conn->server_name, szDSN, cbDSN);
- conn->server_name_len = cbDSN;
- ep = com_endpoint_create(COM_SHM);
-
- ut_a(ep);
- conn->com_endpoint = ep;
- conn->out_msg_count = ut_dulint_zero;
-
- size = ODBC_DATAGRAM_SIZE;
-
- err = com_endpoint_set_option(ep, COM_OPT_MAX_DGRAM_SIZE,
- (byte*)&size, 4);
- ut_a(err == 0);
- /* Make the data source name catenated to user name as the
- address of the communications endpoint */
- ut_a((ulint)cbDSN + (ulint)cbUID < 100);
-
- ut_memcpy(catenated_name, szDSN, (ulint)cbDSN);
- ut_memcpy(catenated_name + (ulint)cbDSN, szUID, (ulint)cbUID);
-
- err = com_bind(ep, (char*)catenated_name, (ulint)cbDSN
- + (ulint)cbUID);
- ut_a(err == 0);
- conn->in_datagram_buf = mem_alloc(ODBC_DATAGRAM_SIZE);
- msg = mem_alloc(ODBC_DATAGRAM_SIZE);
- conn->out_datagram_buf = msg;
- conn->addr_buf = mem_alloc(ODBC_ADDRESS_SIZE);
- /* Set the session id to dulint 0 as we are not yet connected */
-
- sess_cli_msg_set_sess(msg, ut_dulint_zero);
- sess_cli_msg_set_type(msg, SESS_CLI_CONNECT);
- /*------------------------------------------*/
-
- odbc_send_cli_msg(conn, 0);
- odbc_recv_srv_msg(conn, &len);
- /*------------------------------------------*/
-
- ut_a(len == 0);
- ut_a(sess_srv_msg_get_type(conn->in_datagram_buf)
- == SESS_SRV_ACCEPT_CONNECT);
-
- conn->sess_id = mach_read_from_8(conn->in_datagram_buf
- + SESS_SRV_MSG_SESS_ID);
- /* Write the session id to out_datagram_buf: it will not be rewritten
- until the connection is closed, as the session id will stay the same */
-
- sess_cli_msg_set_sess(msg, conn->sess_id);
- /* We currently only send single part messages: the following will
- stay 0 during the connection */
- mach_write_to_4(msg + SESS_CLI_MSG_CONTINUE, 0);
- mach_write_to_4(msg + SESS_CLI_MSG_CONT_SIZE, 0);
-
- conn->connected = TRUE;
- return(SQL_SUCCESS);
- }
- /**************************************************************************
- Stores an error message to a statement handle, so that it can be later
- queried with SQLError. */
- static
- void
- odbc_stat_store_error_msg(
- /*======================*/
- odbc_stat_t* stat, /* in: statement handle */
- byte* msg, /* in: error message sent by the server */
- ulint len) /* in: length of msg */
- {
- if (stat->error_msg) {
- mem_free(stat->error_msg);
- }
- stat->error_msg_len = len;
- len += SESS_SRV_MSG_DATA;
- stat->error_msg = mem_alloc(len);
- ut_memcpy(stat->error_msg, msg, len);
- }
- /**************************************************************************
- Queries an error message. */
- RETCODE
- SQLError(
- /*=====*/
- /* out: SQL_SUCCESS or SQL_NO_DATA_FOUND */
- HENV henv, /* in: SQL_NULL_HENV */
- HDBC hdbc, /* in: SQL_NULL_HDBC */
- HSTMT hstmt, /* in: statement handle */
- UCHAR* szSqlState, /* in/out: SQLSTATE as a null-terminated string,
- (currently, always == "S1000") */
- SDWORD* pfNativeError, /* out: native error code */
- UCHAR* szErrorMsg, /* in/out: buffer for an error message as a
- null-terminated string */
- SWORD cbErrorMsgMax, /* in: buffer size for szErrorMsg */
- SWORD* pcbErrorMsg) /* out: error message length */
- {
- odbc_stat_t* stat;
- ulint len;
-
- ut_a(henv == SQL_NULL_HENV);
- ut_a(hdbc == SQL_NULL_HDBC);
- ut_a(hstmt);
- ut_a(cbErrorMsgMax > 1);
-
- stat = hstmt;
- if (stat->error_msg == NULL) {
- return(SQL_NO_DATA_FOUND);
- }
- *pfNativeError = 0;
- ut_memcpy(szSqlState, "S1000", 6);
- len = (ulint)cbErrorMsgMax - 1;
- if (stat->error_msg_len < len) {
- len = stat->error_msg_len;
- }
-
- ut_memcpy(szErrorMsg, stat->error_msg + SESS_SRV_MSG_DATA, len);
- *(szErrorMsg + len) = ' ';
-
- *pcbErrorMsg = (SWORD)len;
- if (stat->error_msg) {
- mem_free(stat->error_msg);
- stat->error_msg = NULL;
- }
- return(SQL_SUCCESS);
- }
- /**************************************************************************
- Makes the server to parse and optimize an SQL string. */
- RETCODE
- SQLPrepare(
- /*=======*/
- /* out: SQL_SUCCESS or SQL_ERROR */
- HSTMT hstmt, /* in: statement handle */
- UCHAR* szSqlStr, /* in: SQL string */
- SDWORD cbSqlStr) /* in: SQL string length */
- {
- odbc_stat_t* stat;
- odbc_conn_t* conn;
- odbc_param_t* param;
- ulint len;
- byte* msg;
- ulint i;
- stat = hstmt;
- conn = stat->conn;
- if (stat->error_msg) {
- mem_free(stat->error_msg);
- stat->error_msg = NULL;
- }
- ut_memcpy(conn->out_datagram_buf + SESS_CLI_MSG_DATA, szSqlStr,
- 1 + (ulint)cbSqlStr);
-
- sess_cli_msg_set_type(conn->out_datagram_buf, SESS_CLI_PREPARE);
- /* The client message will be decoded in sess_receive_prepare */
- /*------------------------------------------*/
- odbc_send_cli_msg(conn, 1 + (ulint)cbSqlStr);
- odbc_recv_srv_msg(conn, &len);
- /*------------------------------------------*/
- /* The server message was coded in sess_receive_prepare */
- ut_a(len >= 8);
- msg = conn->in_datagram_buf;
- if (sess_srv_msg_get_type(msg) != SESS_SRV_SUCCESS) {
- ut_a(sess_srv_msg_get_type(msg) == SESS_SRV_ERROR);
- odbc_stat_store_error_msg(stat, msg, len);
- return(SQL_ERROR);
- }
- stat->id = mach_read_from_4(msg + SESS_SRV_MSG_DATA);
- stat->n_params = mach_read_from_4(msg + SESS_SRV_MSG_DATA + 4);
- stat->n_params_bound = 0;
- ut_a(len == 8 + stat->n_params);
- if (stat->n_params > 0) {
- stat->params = mem_alloc(stat->n_params
- * sizeof(odbc_param_t));
- for (i = 0; i < stat->n_params; i++) {
- param = stat_get_nth_param(stat, i);
-
- param->is_input = mach_read_from_1(
- msg + SESS_SRV_MSG_DATA + 8 + i);
- /* Set buf to NULL so that we know when the parameter
- has been bound */
- param->buf = NULL;
- }
- }
-
- stat->state = ODBC_STAT_PREPARED;
- return(SQL_SUCCESS);
- }
- /**************************************************************************
- Binds a parameter in a prepared statement. */
- RETCODE
- SQLBindParameter(
- /*=============*/
- /* out: SQL_SUCCESS */
- HSTMT hstmt, /* in: statement handle */
- UWORD ipar, /* in: parameter index, starting from 1 */
- SWORD fParamType, /* in: SQL_PARAM_INPUT or SQL_PARAM_OUTPUT */
- SWORD fCType, /* in: SQL_C_CHAR, ... */
- SWORD fSqlType, /* in: SQL_CHAR, ... */
- UDWORD cbColDef, /* in: precision: ignored */
- SWORD ibScale, /* in: scale: ignored */
- PTR rgbValue, /* in: pointer to a buffer for the data */
- SDWORD cbValueMax, /* in: buffer size */
- SDWORD* pcbValue) /* in: pointer to a buffer for the data
- length or SQL_NULL_DATA */
- {
- odbc_stat_t* stat;
- odbc_param_t* param;
- stat = hstmt;
- ut_a(stat->state != ODBC_STAT_INITIAL);
- ut_a(rgbValue);
- ut_a(ipar <= stat->n_params);
- ut_a(ipar > 0);
- ut_a(cbValueMax >= 0);
- ut_a(pcbValue);
- UT_NOT_USED(ibScale);
- UT_NOT_USED(fCType);
- UT_NOT_USED(cbColDef);
- if (stat->error_msg) {
- mem_free(stat->error_msg);
- stat->error_msg = NULL;
- }
- param = stat_get_nth_param(stat, ipar - 1);
- if (param->buf == NULL) {
- stat->n_params_bound++;
- }
- param->data_type = fSqlType;
- ut_a((fParamType != SQL_PARAM_INPUT) || param->is_input);
- ut_a((fParamType == SQL_PARAM_INPUT) || !param->is_input);
-
- param->buf = rgbValue;
- param->buf_len = cbValueMax;
- param->data_len = pcbValue;
- return(SQL_SUCCESS);
- }
- /**************************************************************************
- Executes a prepared statement where all parameters have been bound. */
- RETCODE
- SQLExecute(
- /*=======*/
- /* out: SQL_SUCCESS or SQL_ERROR */
- HSTMT hstmt) /* in: statement handle */
- {
- odbc_stat_t* stat;
- odbc_conn_t* conn;
- odbc_param_t* param;
- lint len;
- ulint msg_len;
- byte* msg;
- byte* ptr;
- lint int_val;
- ulint i;
- stat = hstmt;
- ut_a(stat->state != ODBC_STAT_INITIAL);
- ut_a(stat->n_params == stat->n_params_bound);
-
- if (stat->error_msg) {
- mem_free(stat->error_msg);
- stat->error_msg = NULL;
- }
- conn = stat->conn;
- msg = conn->out_datagram_buf;
- sess_cli_msg_set_type(msg, SESS_CLI_EXECUTE);
- ptr = msg + SESS_CLI_MSG_DATA;
- mach_write_to_4(ptr, stat->id);
- ptr += 4;
- for (i = 0; i < stat->n_params; i++) {
- param = stat_get_nth_param(stat, i);
- if (param->is_input) {
- /* Copy its length and data to the message buffer */
- len = *(param->data_len);
- mach_write_to_4(ptr, (ulint)len);
- ptr += 4;
- if (len != SQL_NULL_DATA) {
- if (param->data_type == SQL_INTEGER) {
- ut_ad(len == 4);
- int_val = *((lint*)(param->buf));
- mach_write_to_4(ptr, (ulint)int_val);
- } else {
- ut_memcpy(ptr, param->buf, len);
- }
- ptr += len;
- }
- }
- }
- /* The client message will be decoded in sess_receive_command */
-
- /*------------------------------------------*/
-
- odbc_send_cli_msg(conn, ptr - (msg + SESS_CLI_MSG_DATA));
- odbc_recv_srv_msg(conn, &msg_len);
- /*------------------------------------------*/
- /* The server message was coded in sess_command_completed_message */
- msg = conn->in_datagram_buf;
- if (sess_srv_msg_get_type(msg) != SESS_SRV_SUCCESS) {
- ut_a(sess_srv_msg_get_type(msg) == SESS_SRV_ERROR);
- odbc_stat_store_error_msg(stat, msg, msg_len);
-
- return(SQL_ERROR);
- }
- ptr = msg + SESS_SRV_MSG_DATA;
-
- for (i = 0; i < stat->n_params; i++) {
- param = stat_get_nth_param(stat, i);
- if (!param->is_input) {
- /* Copy its length and data from the message buffer */
- len = (lint)mach_read_from_4(ptr);
- ptr += 4;
- *(param->data_len) = len;
- if (len != SQL_NULL_DATA) {
- if (param->data_type == SQL_INTEGER) {
- ut_ad(len == 4);
- int_val = (lint)mach_read_from_4(ptr);
- *((lint*)(param->buf)) = int_val;
- } else {
- ut_memcpy(param->buf, ptr, (ulint)len);
- }
- ptr += len;
- }
- }
- }
- ut_ad(msg + SESS_SRV_MSG_DATA + msg_len == ptr);
- return(SQL_SUCCESS);
- }