00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "xsb_config.h"
00028
00029 #ifdef WIN_NT
00030 #include <windows.h>
00031 #endif
00032
00033 #ifdef WIN_NT
00034 #define XSB_DLL
00035 #endif
00036
00037 #include "odbc_driver_defs.h"
00038
00039 static int driverODBC_getXSBType(SQLSMALLINT dataType);
00040 static void driverODBC_error(SQLSMALLINT handleType, SQLHANDLE handle);
00041 static struct xsb_data** driverODBC_getNextRow(struct driverODBC_queryInfo* query, int direct);
00042
00043 struct driverODBC_connectionInfo* odbcHandles[MAX_HANDLES];
00044 struct driverODBC_queryInfo* odbcQueries[MAX_QUERIES];
00045 int numHandles, numQueries;
00046 SQLCHAR* errorMesg;
00047 SQLHENV henv;
00048
00049 DllExport int call_conv driverODBC_initialise()
00050 {
00051 numHandles = numQueries = 0;
00052 errorMesg = NULL;
00053
00054 return TRUE;
00055 }
00056
00057
00058 int driverODBC_connect(struct xsb_connectionHandle* handle)
00059 {
00060 struct driverODBC_connectionInfo* odbcHandle;
00061 SQLRETURN val;
00062
00063 odbcHandle = (struct driverODBC_connectionInfo *)malloc(sizeof(struct driverODBC_connectionInfo));
00064
00065 val = SQLAllocEnv(&henv);
00066 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00067 errorMesg = (SQLCHAR *) "HENV allocation error\n";
00068 return FAILURE;
00069 }
00070
00071 val = SQLAllocConnect(henv, &(odbcHandle->hdbc));
00072 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00073 driverODBC_error(SQL_HANDLE_ENV, henv);
00074 free(odbcHandle);
00075 return FAILURE;
00076 }
00077
00078 val = (SQLRETURN) SQLConnect(odbcHandle->hdbc,
00079 (SQLCHAR *) handle->dsn,
00080 SQL_NTS, (SQLCHAR *) handle->user,
00081 SQL_NTS, (SQLCHAR *) handle->password,
00082 SQL_NTS);
00083 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00084 driverODBC_error(SQL_HANDLE_DBC, (SQLCHAR *) odbcHandle->hdbc);
00085 val = SQLFreeHandle(SQL_HANDLE_DBC, odbcHandle->hdbc);
00086 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO)
00087 driverODBC_error(SQL_HANDLE_DBC, odbcHandle->hdbc);
00088 free(odbcHandle);
00089 return FAILURE;
00090 }
00091
00092 odbcHandle->handle =
00093 (char *)malloc((strlen(handle->handle) + 1) * sizeof(char));
00094 strcpy(odbcHandle->handle, handle->handle);
00095 odbcHandles[numHandles++] = odbcHandle;
00096
00097 return SUCCESS;
00098 }
00099
00100
00101 int driverODBC_disconnect(struct xsb_connectionHandle* handle)
00102 {
00103 SQLRETURN val;
00104 int i, j;
00105
00106 for (i = 0 ; i < numHandles ; i++) {
00107 if (!strcmp(odbcHandles[i]->handle, handle->handle)) {
00108 val = SQLDisconnect(odbcHandles[i]->hdbc);
00109 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00110 driverODBC_error(SQL_HANDLE_DBC, odbcHandles[i]->hdbc);
00111 return FAILURE;
00112 }
00113
00114 val = SQLFreeHandle(SQL_HANDLE_DBC, odbcHandles[i]->hdbc);
00115 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00116 driverODBC_error(SQL_HANDLE_DBC, odbcHandles[i]->hdbc);
00117 return FAILURE;
00118 }
00119
00120 free(odbcHandles[i]->handle);
00121 free(odbcHandles[i]);
00122
00123 for (j = i + 1 ; j < numHandles ; j++)
00124 odbcHandles[j-1] = odbcHandles[j];
00125 odbcHandles[numHandles-1] = NULL;
00126 numHandles--;
00127 break;
00128 }
00129 }
00130
00131 return SUCCESS;
00132 }
00133
00134
00135 struct xsb_data** driverODBC_query(struct xsb_queryHandle* handle)
00136 {
00137 struct driverODBC_queryInfo* query;
00138 SQLHDBC hdbc;
00139 SQLRETURN val;
00140 int i;
00141
00142 query = NULL;
00143 hdbc = NULL;
00144 if (handle->state == QUERY_RETRIEVE) {
00145 for (i = 0 ; i < numQueries ; i++) {
00146 if (!strcmp(odbcQueries[i]->handle, handle->handle)) {
00147 query = odbcQueries[i];
00148 break;
00149 }
00150 }
00151 }
00152 else if (handle->state == QUERY_BEGIN) {
00153 for (i = 0 ; i < numHandles ; i++) {
00154 if (!strcmp(odbcHandles[i]->handle, handle->connHandle->handle)) {
00155 hdbc = odbcHandles[i]->hdbc;
00156 break;
00157 }
00158 }
00159
00160 query = (struct driverODBC_queryInfo *)malloc(sizeof(struct driverODBC_queryInfo));
00161 query->handle = (char *)malloc((strlen(handle->handle) + 1) * sizeof(char));
00162 strcpy(query->handle, handle->handle);
00163 query->query = (char *)malloc((strlen(handle->query) + 1) * sizeof(char));
00164 strcpy(query->query, handle->query);
00165
00166 val = SQLAllocStmt(hdbc, &(query->hstmt));
00167 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00168 driverODBC_error(SQL_HANDLE_DBC, hdbc);
00169 return NULL;
00170 }
00171
00172 val = SQLExecDirect(query->hstmt, (SQLCHAR *) handle->query, SQL_NTS);
00173 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00174 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00175 return NULL;
00176 }
00177
00178 query->resultmeta = (struct driverODBC_meta *)malloc(sizeof(struct driverODBC_meta));
00179 val = SQLNumResultCols(query->hstmt, (SQLSMALLINT *)(&(query->resultmeta->numCols)));
00180 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00181 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00182 return NULL;
00183 }
00184 handle->numResultCols = query->resultmeta->numCols;
00185 if (query->resultmeta->numCols == 0) {
00186 return NULL;
00187 }
00188
00189 query->resultmeta->types = (struct driverODBC_columnmeta **)malloc(query->resultmeta->numCols * sizeof(struct driverODBC_columnmeta *));
00190 for (i = 0 ; i < query->resultmeta->numCols ; i++) {
00191 query->resultmeta->types[i] = (struct driverODBC_columnmeta *)malloc(sizeof(struct driverODBC_columnmeta));
00192 val = SQLColAttribute(query->hstmt, (SQLUSMALLINT) (i + 1), SQL_COLUMN_TYPE, NULL, 0, NULL, (SQLPOINTER) &(query->resultmeta->types[i]->type));
00193 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00194 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00195 return NULL;
00196 }
00197 val = SQLColAttribute(query->hstmt, (SQLUSMALLINT) (i + 1), SQL_COLUMN_LENGTH, NULL, 0, NULL, (SQLPOINTER) &(query->resultmeta->types[i]->length));
00198 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00199 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00200 return NULL;
00201 }
00202 }
00203
00204 handle->state = QUERY_RETRIEVE;
00205 odbcQueries[numQueries++] = query;
00206 }
00207
00208 return driverODBC_getNextRow(query, 1);
00209 }
00210
00211
00212 static struct xsb_data** driverODBC_getNextRow(struct driverODBC_queryInfo* query, int direct)
00213 {
00214 struct xsb_data** result;
00215 SQLINTEGER** pcbValues;
00216 SQLRETURN val;
00217 int i;
00218
00219 result = (struct xsb_data **)malloc(query->resultmeta->numCols * sizeof(struct xsb_data *));
00220 pcbValues = (SQLINTEGER **)malloc(query->resultmeta->numCols * sizeof(SQLINTEGER *));
00221 for (i = 0 ; i < query->resultmeta->numCols ; i++) {
00222 result[i] = (struct xsb_data *)malloc(sizeof(struct xsb_data));
00223 result[i]->val = (union xsb_value *)malloc(sizeof(union xsb_value));
00224 pcbValues[i] = (SQLINTEGER *)malloc(sizeof(SQLINTEGER));
00225 if (driverODBC_getXSBType(query->resultmeta->types[i]->type) == STRING_TYPE) {
00226 result[i]->type = STRING_TYPE;
00227 result[i]->length = query->resultmeta->types[i]->length + 1;
00228 result[i]->val->str_val = (char *)malloc(result[i]->length * sizeof(char));
00229 val = SQLBindCol(query->hstmt, (SQLUSMALLINT) (i + 1), SQL_C_CHAR, (SQLPOINTER *)result[i]->val->str_val, (SQLINTEGER)result[i]->length, pcbValues[i]);
00230 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00231 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00232 return NULL;
00233 }
00234 }
00235 else if (driverODBC_getXSBType(query->resultmeta->types[i]->type) == INT_TYPE) {
00236 result[i]->type = INT_TYPE;
00237 result[i]->val->i_val = (int *)malloc(sizeof(int));
00238 val = SQLBindCol(query->hstmt, (SQLUSMALLINT) (i + 1), SQL_C_SLONG, (SQLPOINTER *)result[i]->val->i_val, 0, pcbValues[i]);
00239 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00240 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00241 return NULL;
00242 }
00243 }
00244 else if (driverODBC_getXSBType(query->resultmeta->types[i]->type) == FLOAT_TYPE) {
00245 result[i]->type = FLOAT_TYPE;
00246 result[i]->val->f_val = (double *)malloc(sizeof(double));
00247 val = SQLBindCol(query->hstmt, (SQLUSMALLINT) (i + 1), SQL_C_DOUBLE, (SQLPOINTER *)result[i]->val->f_val, 0, pcbValues[i]);
00248 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00249 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00250 return NULL;
00251 }
00252 }
00253 }
00254
00255 val = SQLFetch(query->hstmt);
00256
00257 if (val == SQL_SUCCESS || val == SQL_SUCCESS_WITH_INFO) {
00258 for (i = 0 ; i < query->resultmeta->numCols ; i++) {
00259 if (*(pcbValues[i]) == SQL_NULL_DATA)
00260 result[i]->val = NULL;
00261 }
00262 }
00263
00264 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00265 if (direct != 1) {
00266 val = SQLFreeStmt(query->hstmt, SQL_CLOSE);
00267 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO)
00268 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00269 }
00270 return NULL;
00271 }
00272
00273 if (val != SQL_SUCCESS && val != SQL_NO_DATA && val != SQL_SUCCESS_WITH_INFO) {
00274 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00275 return NULL;
00276 }
00277
00278 return result;
00279 }
00280
00281
00282 int driverODBC_prepareStatement(struct xsb_queryHandle* qHandle)
00283 {
00284 struct driverODBC_queryInfo* query;
00285 SQLRETURN val;
00286 SQLHDBC hdbc;
00287 int i;
00288
00289 hdbc = NULL;
00290
00291 query = (struct driverODBC_queryInfo *)malloc(sizeof(struct driverODBC_queryInfo));
00292 query->handle = (char *)malloc((strlen(qHandle->handle) + 1) * sizeof(char));
00293 strcpy(query->handle, qHandle->handle);
00294 query->query = (char *)malloc((strlen(qHandle->query) + 1) * sizeof(char));
00295 strcpy(query->query, qHandle->query);
00296
00297 for (i = 0 ; i < numHandles ; i++) {
00298 if (!strcmp(qHandle->connHandle->handle, odbcHandles[i]->handle)) {
00299 hdbc = odbcHandles[i]->hdbc;
00300 break;
00301 }
00302 }
00303
00304 val = SQLAllocStmt(hdbc, &(query->hstmt));
00305 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00306 driverODBC_error(SQL_HANDLE_DBC, hdbc);
00307 return FAILURE;
00308 }
00309
00310 val = SQLPrepare(query->hstmt, (SQLCHAR *) query->query, SQL_NTS);
00311 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00312 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00313 return FAILURE;
00314 }
00315
00316 query->parammeta = (struct driverODBC_meta *)malloc(sizeof(struct driverODBC_meta));
00317 val = SQLNumParams(query->hstmt, &(query->parammeta->numCols));
00318 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00319 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00320 return FAILURE;
00321 }
00322
00323 query->parammeta->types = (struct driverODBC_columnmeta **)malloc(query->parammeta->numCols * sizeof(struct driverODBC_columnmeta));
00324 for (i = 0 ; i < query->parammeta->numCols ; i++) {
00325 query->parammeta->types[i] = (struct driverODBC_columnmeta *)malloc(sizeof(struct driverODBC_columnmeta));
00326 val = SQLDescribeParam(query->hstmt, (SQLUSMALLINT) (i + 1), &(query->parammeta->types[i]->type), &(query->parammeta->types[i]->length), NULL, NULL);
00327 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00328 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00329 return FAILURE;
00330 }
00331 }
00332
00333 odbcQueries[numQueries++] = query;
00334
00335 return query->parammeta->numCols;
00336 }
00337
00338
00339 struct xsb_data** driverODBC_execPrepareStatement(struct xsb_data** param, struct xsb_queryHandle* handle)
00340 {
00341 struct driverODBC_queryInfo* query;
00342 SQLRETURN val;
00343 int i;
00344
00345 val = 0;
00346 query = NULL;
00347 for (i = 0 ; i < numQueries ; i++) {
00348 if (!strcmp(odbcQueries[i]->handle, handle->handle)) {
00349 query = odbcQueries[i];
00350 break;
00351 }
00352 }
00353
00354 if (handle->state == QUERY_RETRIEVE)
00355 return driverODBC_getNextRow(query, 0);
00356
00357 for (i = 0 ; i < query->parammeta->numCols ; i++) {
00358 if (param[i]->type == STRING_TYPE)
00359 val = SQLBindParameter(query->hstmt, (SQLUSMALLINT)(i + 1), SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(param[i]->val->str_val) + 1, 0, (SQLPOINTER)param[i]->val->str_val, 0, NULL);
00360 else if (param[i]->type == INT_TYPE)
00361 val = SQLBindParameter(query->hstmt, (SQLUSMALLINT)(i + 1), SQL_PARAM_INPUT, SQL_C_DEFAULT, SQL_INTEGER, 0, 0, (SQLPOINTER)param[i]->val->i_val, 0, NULL);
00362 else if (param[i]->type == FLOAT_TYPE)
00363 val = SQLBindParameter(query->hstmt, (SQLUSMALLINT) (i + 1), SQL_PARAM_INPUT, SQL_C_DEFAULT, SQL_DOUBLE, 0, 0, (SQLPOINTER)param[i]->val->f_val, 0, NULL);
00364 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00365 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00366 return NULL;
00367 }
00368 }
00369
00370 val = SQLExecute(query->hstmt);
00371 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00372 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00373 return NULL;
00374 }
00375
00376 query->resultmeta = (struct driverODBC_meta *)malloc(sizeof(struct driverODBC_meta));
00377 val = SQLNumResultCols(query->hstmt, (SQLSMALLINT *)(&(query->resultmeta->numCols)));
00378 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00379 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00380 return NULL;
00381 }
00382 handle->numResultCols = query->resultmeta->numCols;
00383 if (query->resultmeta->numCols == 0) {
00384 return NULL;
00385 }
00386
00387 query->resultmeta->types = (struct driverODBC_columnmeta **)malloc(query->resultmeta->numCols * sizeof(struct driverODBC_columnmeta *));
00388 for (i = 0 ; i < query->resultmeta->numCols ; i++) {
00389 query->resultmeta->types[i] = (struct driverODBC_columnmeta *)malloc(sizeof(struct driverODBC_columnmeta));
00390 val = SQLColAttribute(query->hstmt, (SQLUSMALLINT) (i + 1), SQL_COLUMN_TYPE, NULL, 0, NULL, (SQLPOINTER) &(query->resultmeta->types[i]->type));
00391 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00392 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00393 return NULL;
00394 }
00395 val = SQLColAttribute(query->hstmt, (SQLUSMALLINT) (i + 1), SQL_COLUMN_LENGTH, NULL, 0, NULL, (SQLPOINTER) &(query->resultmeta->types[i]->length));
00396 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00397 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00398 return NULL;
00399 }
00400 }
00401
00402 handle->state = QUERY_RETRIEVE;
00403
00404 return driverODBC_getNextRow(query, 0);
00405 }
00406
00407
00408 int driverODBC_closeStatement(struct xsb_queryHandle* handle)
00409 {
00410 struct driverODBC_queryInfo* query;
00411 SQLRETURN val;
00412 int i, j;
00413
00414 for (i = 0 ; i < numQueries ; i++) {
00415 if (!strcmp(odbcQueries[i]->handle, handle->handle)) {
00416 query = odbcQueries[i];
00417 for (j = 0 ; j < query->resultmeta->numCols ; j++)
00418 free(query->resultmeta->types[j]);
00419 free(query->resultmeta->types);
00420 free(query->resultmeta);
00421 val = SQLFreeHandle(SQL_HANDLE_STMT, query->hstmt);
00422 if (val != SQL_SUCCESS && val != SQL_SUCCESS_WITH_INFO) {
00423 driverODBC_error(SQL_HANDLE_STMT, query->hstmt);
00424 return FAILURE;
00425 }
00426 for (j = i + 1 ; j < numQueries ; j++)
00427 odbcQueries[j-1] = odbcQueries[j];
00428 free(query->handle);
00429 free(query->query);
00430 free(query);
00431 numQueries--;
00432 }
00433 }
00434
00435 return SUCCESS;
00436 }
00437
00438
00439 char* driverODBC_errorMesg()
00440 {
00441 char* temp;
00442 if (errorMesg != NULL) {
00443 temp = (char *)malloc(SQL_MAX_MESSAGE_LENGTH * sizeof(char));
00444 strcpy(temp, (char *)errorMesg);
00445 free(errorMesg);
00446 errorMesg = NULL;
00447 return temp;
00448 }
00449 return NULL;
00450 }
00451
00452
00453 static int driverODBC_getXSBType(SQLSMALLINT dataType)
00454 {
00455 int type;
00456 type = STRING_TYPE;
00457 switch (dataType) {
00458 case SQL_CHAR:
00459 case SQL_VARCHAR:
00460 case SQL_LONGVARCHAR:
00461 type = STRING_TYPE;
00462 break;
00463
00464 case SQL_DECIMAL:
00465 case SQL_NUMERIC:
00466 case SQL_REAL:
00467 case SQL_DOUBLE:
00468 type = FLOAT_TYPE;
00469 break;
00470
00471 case SQL_SMALLINT:
00472 case SQL_INTEGER:
00473 case SQL_TINYINT:
00474 case SQL_BIGINT:
00475 type = INT_TYPE;
00476 break;
00477 }
00478
00479 return type;
00480 }
00481
00482
00483 static void driverODBC_error(SQLSMALLINT handleType, SQLHANDLE handle)
00484 {
00485 SQLCHAR* sqlState;
00486
00487 if (errorMesg != NULL) {
00488 free(errorMesg);
00489 errorMesg = NULL;
00490 }
00491
00492 errorMesg = (SQLCHAR *)malloc(SQL_MAX_MESSAGE_LENGTH * sizeof(SQLCHAR));
00493 sqlState = (SQLCHAR *)malloc(6 * sizeof(SQLCHAR));
00494 SQLGetDiagRec(handleType, handle, 1, sqlState, NULL, errorMesg, SQL_MAX_MESSAGE_LENGTH - 1, NULL);
00495 free(sqlState);
00496 }
00497
00498
00499 DllExport int call_conv driverODBC_register(void)
00500 {
00501 union functionPtrs* funcConnect;
00502 union functionPtrs* funcDisconnect;
00503 union functionPtrs* funcQuery;
00504 union functionPtrs* funcPrepare;
00505 union functionPtrs* funcExecPrepare;
00506 union functionPtrs* funcCloseStmt;
00507 union functionPtrs* funcErrorMesg;
00508
00509 registerXSBDriver("odbc", 7);
00510
00511 funcConnect = (union functionPtrs *)malloc(sizeof(union functionPtrs));
00512 funcConnect->connectDriver = driverODBC_connect;
00513 registerXSBFunction("odbc", CONNECT, funcConnect);
00514
00515 funcDisconnect = (union functionPtrs *)malloc(sizeof(union functionPtrs));
00516 funcDisconnect->disconnectDriver = driverODBC_disconnect;
00517 registerXSBFunction("odbc", DISCONNECT, funcDisconnect);
00518
00519 funcQuery = (union functionPtrs *)malloc(sizeof(union functionPtrs));
00520 funcQuery->queryDriver = driverODBC_query;
00521 registerXSBFunction("odbc", QUERY, funcQuery);
00522
00523 funcPrepare = (union functionPtrs *)malloc(sizeof(union functionPtrs));
00524 funcPrepare->prepareStmtDriver = driverODBC_prepareStatement;
00525 registerXSBFunction("odbc", PREPARE, funcPrepare);
00526
00527 funcExecPrepare = (union functionPtrs *)malloc(sizeof(union functionPtrs));
00528 funcExecPrepare->executeStmtDriver = driverODBC_execPrepareStatement;
00529 registerXSBFunction("odbc", EXEC_PREPARE, funcExecPrepare);
00530
00531 funcCloseStmt = (union functionPtrs *)malloc(sizeof(union functionPtrs));
00532 funcCloseStmt->closeStmtDriver = driverODBC_closeStatement;
00533 registerXSBFunction("odbc", CLOSE_STMT, funcCloseStmt);
00534
00535 funcErrorMesg = (union functionPtrs *)malloc(sizeof(union functionPtrs));
00536 funcErrorMesg->errorMesgDriver = driverODBC_errorMesg;
00537 registerXSBFunction("odbc", ERROR_MESG, funcErrorMesg);
00538
00539 return TRUE;
00540 }
00541
00542