odbc_xsb.c

00001 /* File:      odbc_xsb.c
00002 ** Author(s): Lily Dong, David S. Warren
00003 ** Contact:   xsb-contact@cs.sunysb.edu
00004 **
00005 ** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1998
00006 **
00007 ** XSB is free software; you can redistribute it and/or modify it under the
00008 ** terms of the GNU Library General Public License as published by the Free
00009 ** Software Foundation; either version 2 of the License, or (at your option)
00010 ** any later version.
00011 **
00012 ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
00013 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014 ** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
00015 ** more details.
00016 **
00017 ** You should have received a copy of the GNU Library General Public License
00018 ** along with XSB; if not, write to the Free Software Foundation,
00019 ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 **
00021 ** $Id: odbc_xsb.c,v 1.60 2006/06/08 14:27:42 evansbj Exp $
00022 **
00023 */
00024 
00025 #include "xsb_config.h"
00026 #include "cell_xsb.h"
00027 
00028 #ifdef CYGWIN
00029 #define FAR
00030 #include "sql.h"
00031 #include "sqlext.h"
00032 #include "odbc_string.h"
00033 #else
00034 #ifdef WIN_NT
00035 #include <windows.h>
00036 #endif
00037 #include <sql.h>
00038 #include <sqlext.h>
00039 #include <string.h>
00040 #endif
00041 
00042 #include <stdio.h>
00043 
00044 #include <stdlib.h>
00045 #include <assert.h>
00046 
00047 #include "cinterf.h"
00048 #include "deref.h"
00049 
00050 #include "error_xsb.h"
00051 #include "export.h"
00052 #include "register.h"
00053 #include "ptoc_tag_xsb_i.h"
00054 #include "io_builtins_xsb.h"
00055 #include "flags_xsb.h"
00056 #include "auxlry.h"
00057 #include "flag_defs_xsb.h"
00058 #include "loader_xsb.h"
00059 #include "memory_xsb.h"
00060 #include "heap_xsb.h"
00061 //#include "error_xsb.h"
00062 #include "context.h"
00063 #include "varstring_xsb.h"
00064 #include "thread_xsb.h"
00065 
00066 #define MAXCURSORNUM                    200
00067 #define MAXVARSTRLEN                    65000
00068 #define MAXI(a,b)                       ((a)>(b)?(a):(b))
00069 
00070 static Psc     nullFctPsc = NULL;
00071 /* static int      numberOfCursors = 0; */
00072 static long      SQL_NTSval = SQL_NTS;
00073 static long      SQL_NULL_DATAval = SQL_NULL_DATA;
00074 
00075 static HENV henv = NULL;
00076 /*HDBC hdbc;*/
00077 
00078 struct Cursor {
00079   struct Cursor *NCursor; /* Next Cursor in cursor chain*/
00080   struct Cursor *PCursor; /* Prev Cursor in cursor chain*/
00081   HDBC hdbc;            /* connection handle for this cursor*/
00082   int driver_code;      /* our code for driver, to handle ODBC inconsistencies, set in FindFreeCursor */
00083                         /* = 0 default, = 1 for MS Access */
00084   int Status;           /* status of the cursor*/
00085   UCHAR *Sql;           /* pointer to the sql statement*/
00086   HSTMT hstmt;          /* the statement handle*/
00087   int NumBindVars;      /* number of bind values*/
00088   UCHAR **BindList;     /* pointer to array of pointers to the bind values*/
00089   int *BindTypes;       /* types of the bind values, 0->int, 1->float, 2->char, 3->nullvalue(anytype)*/
00090   SQLINTEGER *BindLens; /* lengths of the bind values that are strings */
00091   SWORD NumCols;        /* number of columns selected*/
00092   SWORD *ColTypes;      /* pointer to array of column types*/
00093   UDWORD *ColLen;       /* pointer to array of max column lengths*/
00094   UDWORD *OutLen;       /* pointer to array of actual column lengths*/
00095   UCHAR **Data;         /* pointer to array of pointers to data*/
00096 };
00097 
00098 /* Number of Cursors per Connection */
00099 struct NumberofCursors{
00100   HDBC hdbc;
00101   int CursorCount;
00102   struct NumberofCursors *NCurNum;
00103 };
00104 
00105 //The below variables are declaired global for single-threaded XSB, and declaired
00106 //in thread context for multi-threaded XSB.
00107 #ifndef MULTI_THREAD
00108 struct NumberofCursors *FCurNum; /* First in the list of Number of Cursors */
00109 /* global cursor table*/
00110 struct Cursor *FCursor;  /* root of curser chain*/
00111 struct Cursor *LCursor;  /* tail of curser chain*/
00112 
00113 #endif
00114 
00115 /* for debugging: just dumps memory... */
00116 void print_hdbc(char *msg, HDBC hdbc) {
00117   int *ptr;
00118   int wds = 48;
00119 
00120   printf("\n%s\nhdbc: %p",msg,hdbc);
00121   for(ptr = (int *)(((int)hdbc / 32) * 32); ptr < (int *)hdbc+wds ; ptr++) {
00122     if (((int)ptr % 32) == 0) printf("\n%p: ",ptr);
00123     printf(" %08x",*ptr);
00124   }
00125   printf("\n\n");
00126 }
00127 
00128 SWORD ODBCToXSBType(SWORD odbcType)
00129 {
00130   switch (odbcType) {
00131   case SQL_TINYINT:
00132   case SQL_SMALLINT:
00133   case SQL_INTEGER:
00134     return SQL_C_SLONG;
00135   case SQL_DECIMAL:
00136   case SQL_NUMERIC:
00137   case SQL_REAL:
00138   case SQL_FLOAT:
00139   case SQL_DOUBLE:
00140     return SQL_C_FLOAT;
00141   case SQL_BINARY:
00142   case SQL_VARBINARY:
00143   case SQL_LONGVARBINARY:
00144     return SQL_C_BINARY;
00145   case SQL_DATE:
00146   case SQL_TIME:
00147   case SQL_TIMESTAMP:
00148   case SQL_CHAR:
00149   case SQL_VARCHAR:
00150   default:
00151     return SQL_C_CHAR;
00152   }
00153 }
00154 
00155 int GetInfoTypeType(int SQL_INFO_TYPE)
00156 {       //-1: Unkown
00157         //0 : String
00158         //1 : SQLUSMALLINT
00159         //2 : SQLUINTEGER
00160         //3 : SQLUINTEGER bitmask
00161         //4 : SQLUINTEGER flag
00162 
00163         int type;
00164         switch(SQL_INFO_TYPE) {
00165                 case SQL_ACCESSIBLE_PROCEDURES:
00166                 case SQL_ACCESSIBLE_TABLES:
00167 #if (ODBCVER >= 0x0300)
00168                 case SQL_CATALOG_NAME:
00169         case SQL_COLLATION_SEQ:
00170 #endif        
00171                 case SQL_CATALOG_NAME_SEPARATOR:
00172                 case SQL_CATALOG_TERM:
00173                 case SQL_COLUMN_ALIAS:
00174                 case SQL_DATA_SOURCE_NAME:
00175                 case SQL_DATA_SOURCE_READ_ONLY:
00176                 case SQL_DATABASE_NAME:
00177                 case SQL_DBMS_NAME:
00178                 case SQL_DBMS_VER:
00179                 case SQL_DESCRIBE_PARAMETER:
00180                 case SQL_DM_VER:
00181                 case SQL_DRIVER_NAME:
00182                 case SQL_DRIVER_ODBC_VER:
00183                 case SQL_DRIVER_VER:
00184                 case SQL_EXPRESSIONS_IN_ORDERBY:
00185                 case SQL_IDENTIFIER_QUOTE_CHAR:
00186                 case SQL_INTEGRITY:
00187                 case SQL_KEYWORDS:
00188                 case SQL_LIKE_ESCAPE_CLAUSE:
00189                 case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
00190                 case SQL_MULT_RESULT_SETS:
00191                 case SQL_MULTIPLE_ACTIVE_TXN:
00192                 case SQL_NEED_LONG_DATA_LEN:
00193                 case SQL_ODBC_VER:
00194                 case SQL_ORDER_BY_COLUMNS_IN_SELECT:
00195                 case SQL_PROCEDURE_TERM:
00196                 case SQL_PROCEDURES:
00197                 case SQL_ROW_UPDATES:
00198                 case SQL_SCHEMA_TERM:
00199                 case SQL_SEARCH_PATTERN_ESCAPE:
00200                 case SQL_SERVER_NAME:
00201                 case SQL_SPECIAL_CHARACTERS:
00202                 case SQL_TABLE_TERM:
00203                 case SQL_USER_NAME:
00204                 case SQL_XOPEN_CLI_YEAR:
00205                         type = 0;
00206                         break;
00207 #if (ODBCVER >= 0x0300)
00208                 case SQL_ACTIVE_ENVIRONMENTS:
00209 #endif        
00210                 case SQL_CATALOG_LOCATION:
00211                 case SQL_CONCAT_NULL_BEHAVIOR:
00212                 case SQL_CORRELATION_NAME:
00213                 case SQL_CURSOR_COMMIT_BEHAVIOR:
00214                 case SQL_CURSOR_ROLLBACK_BEHAVIOR:
00215                 case SQL_FILE_USAGE:
00216                 case SQL_GROUP_BY:
00217                 case SQL_IDENTIFIER_CASE:
00218                 case SQL_MAX_CATALOG_NAME_LEN:
00219                 case SQL_MAX_COLUMN_NAME_LEN:
00220                 case SQL_MAX_COLUMNS_IN_GROUP_BY:
00221                 case SQL_MAX_COLUMNS_IN_INDEX:
00222                 case SQL_MAX_COLUMNS_IN_ORDER_BY:
00223                 case SQL_MAX_COLUMNS_IN_SELECT:
00224                 case SQL_MAX_COLUMNS_IN_TABLE:
00225                 case SQL_MAX_CONCURRENT_ACTIVITIES:
00226                 case SQL_MAX_CURSOR_NAME_LEN:
00227                 case SQL_MAX_DRIVER_CONNECTIONS:
00228                 case SQL_MAX_IDENTIFIER_LEN:
00229                 case SQL_MAX_PROCEDURE_NAME_LEN:
00230                 case SQL_MAX_SCHEMA_NAME_LEN:
00231                 case SQL_MAX_TABLE_NAME_LEN:
00232                 case SQL_MAX_TABLES_IN_SELECT:
00233                 case SQL_MAX_USER_NAME_LEN:
00234                 case SQL_NON_NULLABLE_COLUMNS:
00235                 case SQL_NULL_COLLATION:
00236                 case SQL_QUOTED_IDENTIFIER_CASE:
00237                 case SQL_TXN_CAPABLE:
00238                         type = 1;
00239                         break;
00240 #if (ODBCVER >= 0x0300)
00241                 case SQL_ASYNC_MODE:
00242                 //case SQL_CURSOR_ROLLBACK_SQL_CURSOR_SENSITIVITY:
00243                 case SQL_DDL_INDEX:
00244 #endif        
00245                 case SQL_DEFAULT_TXN_ISOLATION:
00246                 case SQL_DRIVER_HDBC:
00247                 case SQL_DRIVER_HENV:
00248                 case SQL_DRIVER_HDESC:
00249                 case SQL_DRIVER_HLIB:
00250                 case SQL_DRIVER_HSTMT:
00251                 case SQL_MAX_ASYNC_CONCURRENT_STATEMENTS:
00252                 case SQL_MAX_BINARY_LITERAL_LEN:
00253                 case SQL_MAX_CHAR_LITERAL_LEN:
00254                 case SQL_MAX_INDEX_SIZE:
00255                 case SQL_MAX_ROW_SIZE:
00256                 case SQL_MAX_STATEMENT_LEN:
00257                 case SQL_ODBC_INTERFACE_CONFORMANCE:
00258                 case SQL_SQL_CONFORMANCE:
00259                         type = 2;
00260                         break;
00261 
00262                 case SQL_ALTER_TABLE:
00263                 case SQL_BOOKMARK_PERSISTENCE:
00264                 case SQL_CATALOG_USAGE:
00265                 case SQL_CONVERT_BIGINT:
00266                 case SQL_CONVERT_BINARY:
00267                 case SQL_CONVERT_BIT:
00268                 case SQL_CONVERT_CHAR:
00269 #ifdef SQL_CONVERT_GUID
00270                 case SQL_CONVERT_GUID:
00271 #endif        
00272                 case SQL_CONVERT_DATE:
00273                 case SQL_CONVERT_DECIMAL:
00274                 case SQL_CONVERT_DOUBLE:
00275                 case SQL_CONVERT_FLOAT:
00276                 case SQL_CONVERT_INTEGER:
00277 #if (ODBCVER >= 0x0300)
00278                 case SQL_AGGREGATE_FUNCTIONS:
00279                 case SQL_ALTER_DOMAIN:
00280                 case SQL_BATCH_ROW_COUNT:
00281                 case SQL_BATCH_SUPPORT:
00282                 case SQL_CONVERT_INTERVAL_YEAR_MONTH:
00283                 case SQL_CONVERT_INTERVAL_DAY_TIME:
00284                 case SQL_CREATE_ASSERTION:
00285                 case SQL_CREATE_CHARACTER_SET:
00286                 case SQL_CREATE_COLLATION:
00287                 case SQL_CREATE_DOMAIN:
00288                 case SQL_CREATE_SCHEMA:
00289                 case SQL_CREATE_TABLE:
00290                 case SQL_CREATE_TRANSLATION:
00291                 case SQL_CREATE_VIEW:
00292                 case SQL_DATETIME_LITERALS:
00293 #endif
00294                 case SQL_CONVERT_LONGVARBINARY:
00295                 case SQL_CONVERT_LONGVARCHAR:
00296                 case SQL_CONVERT_NUMERIC:
00297                 case SQL_CONVERT_REAL:
00298                 case SQL_CONVERT_SMALLINT:
00299                 case SQL_CONVERT_TIME:
00300                 case SQL_CONVERT_TIMESTAMP:
00301                 case SQL_CONVERT_TINYINT:
00302                 case SQL_CONVERT_VARBINARY:
00303                 case SQL_CONVERT_VARCHAR:
00304                 case SQL_CONVERT_FUNCTIONS:
00305                 case SQL_DROP_ASSERTION:
00306                 case SQL_DROP_CHARACTER_SET:
00307                 case SQL_DROP_COLLATION:
00308                 case SQL_DROP_DOMAIN:
00309                 case SQL_DROP_SCHEMA:
00310                 case SQL_DROP_TABLE:
00311                 case SQL_DROP_TRANSLATION:
00312                 case SQL_DROP_VIEW:
00313                 case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
00314                 case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
00315                 case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
00316                 case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
00317                 case SQL_GETDATA_EXTENSIONS:
00318                 case SQL_INDEX_KEYWORDS:
00319                 case SQL_INFO_SCHEMA_VIEWS:
00320                 case SQL_INSERT_STATEMENT:
00321                 case SQL_KEYSET_CURSOR_ATTRIBUTES1:
00322                 case SQL_KEYSET_CURSOR_ATTRIBUTES2:
00323                 case SQL_NUMERIC_FUNCTIONS:
00324                 case SQL_OJ_CAPABILITIES:
00325                 case SQL_PARAM_ARRAY_ROW_COUNTS:
00326                 case SQL_PARAM_ARRAY_SELECTS:
00327                 case SQL_POS_OPERATIONS:
00328                 case SQL_SCHEMA_USAGE:
00329                 case SQL_SCROLL_OPTIONS:
00330                 case SQL_SQL92_DATETIME_FUNCTIONS:
00331                 case SQL_SQL92_FOREIGN_KEY_DELETE_RULE:
00332                 case SQL_SQL92_FOREIGN_KEY_UPDATE_RULE:
00333                 case SQL_SQL92_GRANT:
00334                 case SQL_SQL92_NUMERIC_VALUE_FUNCTIONS:
00335                 case SQL_SQL92_PREDICATES:
00336                 case SQL_SQL92_RELATIONAL_JOIN_OPERATORS:
00337                 case SQL_SQL92_REVOKE:
00338                 case SQL_SQL92_ROW_VALUE_CONSTRUCTOR:
00339                 case SQL_SQL92_STRING_FUNCTIONS:
00340                 case SQL_SQL92_VALUE_EXPRESSIONS:
00341                 case SQL_STANDARD_CLI_CONFORMANCE:
00342                 case SQL_STATIC_CURSOR_ATTRIBUTES1:
00343                 case SQL_STATIC_CURSOR_ATTRIBUTES2:
00344                 case SQL_STRING_FUNCTIONS:
00345                 case SQL_SUBQUERIES:
00346                 case SQL_SYSTEM_FUNCTIONS:
00347                 case SQL_TIMEDATE_ADD_INTERVALS:
00348                 case SQL_TIMEDATE_DIFF_INTERVALS:
00349                 case SQL_TIMEDATE_FUNCTIONS:
00350                 case SQL_TXN_ISOLATION_OPTION:
00351                 case SQL_UNION:
00352                         type = 3;
00353                         break;
00354                 default:
00355                         type= -1;
00356         }
00357         return type;
00358 }
00359 
00360 /*-----------------------------------------------------------------------------*/
00361 /*  FUNCTION NAME:*/
00362 /*     PrintErrorMsg()*/
00363 /*  PARAMETERS:*/
00364 /*     struct Cursor *c - pointer to a cursor, or NULL*/
00365 /*  NOTES:*/
00366 /*     PrintErrorMsg() prints out the error message that associates*/
00367 /*     with the statement handler of cursor i.*/
00368 /*-----------------------------------------------------------------------------*/
00369 int PrintErrorMsg(struct Cursor *cur)
00370 {
00371   UCHAR FAR *szsqlstate;
00372   SDWORD FAR *pfnativeerror;
00373   UCHAR FAR *szerrormsg;
00374   SWORD cberrormsgmax;
00375   SWORD FAR *pcberrormsg;
00376   RETCODE rc;
00377 
00378   szsqlstate=(UCHAR FAR *)malloc(sizeof(UCHAR FAR)*10);
00379   pfnativeerror=(SDWORD FAR *)malloc(sizeof(SDWORD FAR));
00380   szerrormsg=(UCHAR FAR *)malloc(sizeof(UCHAR FAR)*SQL_MAX_MESSAGE_LENGTH);
00381   pcberrormsg=(SWORD FAR *)malloc(sizeof(SWORD FAR));
00382   cberrormsgmax=SQL_MAX_MESSAGE_LENGTH-1;
00383   if (cur != NULL)
00384     rc = SQLError(SQL_NULL_HENV, cur->hdbc, cur->hstmt, szsqlstate,
00385                   pfnativeerror, szerrormsg,cberrormsgmax,pcberrormsg);
00386   else
00387     rc = SQLError(SQL_NULL_HENV, NULL, SQL_NULL_HSTMT, szsqlstate,
00388                   pfnativeerror, szerrormsg,cberrormsgmax,pcberrormsg);
00389   if ((rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO)) {
00390     printf("ODBC SYSCALL ERROR (CODE %s): %s\n", szsqlstate, szerrormsg);
00391   }
00392   free(szsqlstate);
00393   free(pfnativeerror);
00394   free(szerrormsg);
00395   free(pcberrormsg);
00396   return 1;
00397 }
00398 
00399 /*-----------------------------------------------------------------------------*/
00400 /*  FUNCTION NAME:*/
00401 /*     SetCursorClose()*/
00402 /*  PARAMETER:*/
00403 /*     struct Cursor *cur - pointer to current cursor*/
00404 /*  NOTES:*/
00405 /*     free all the memory resource allocated for cursor cur*/
00406 /*-----------------------------------------------------------------------------*/
00407 void SetCursorClose(struct Cursor *cur)
00408 {
00409   int j;
00410 
00411   SQLFreeStmt(cur->hstmt, SQL_CLOSE);    /* free statement handler*/
00412 
00413   if (cur->NumBindVars) {                 /* free bind variable list*/
00414     for (j = 0; j < cur->NumBindVars; j++)
00415       if (cur->BindTypes[j] < 2) free((void *)cur->BindList[j]);
00416     free(cur->BindList);
00417     free(cur->BindTypes);
00418     free(cur->BindLens);
00419   }
00420 
00421   if (cur->NumCols) {                  /* free the resulting row set*/
00422     for (j = 0; j < cur->NumCols; j++)
00423       free(cur->Data[j]);
00424     free(cur->ColTypes);
00425     free(cur->ColLen);
00426     free(cur->OutLen);
00427     free(cur->Data);
00428   }
00429 
00430   /* free memory for the sql statement associated w/ this cursor*/
00431   if (cur->Sql) free(cur->Sql);
00432   /* initialize the variables.  set them to the right value*/
00433   cur->Sql = 0;
00434   cur->NumCols =
00435     cur->Status =
00436     cur->NumBindVars = 0;
00437 }
00438 
00439 /*-----------------------------------------------------------------------------*/
00440 /*  FUNCTION NAME:*/
00441 /*     ODBCConnect()*/
00442 /*  PARAMETERS:*/
00443 /*     R1: 1*/
00444 /*     R2: 0 -> call connect with server/user/pw */
00445 /*         1 -> call driver_connect with full connection string */
00446 /*     R3: Server or connection_string*/
00447 /*     R4: User name or don't care*/
00448 /*     R5: Password or don't care*/
00449 /*     R6: var, for returned Connection ID.*/
00450 /*  NOTES:*/
00451 /*     This function is called when a user wants to start a db session,*/
00452 /*     assuming that she doesn't have one open.  It initializes system*/
00453 /*     resources for the new session, including allocations of various things:*/
00454 /*     environment handler, connection handler, statement handlers and then*/
00455 /*     tries to connect to the database, either by server,userid,pw if R2=0,*/
00456 /*     or thrugh a driver by using r3 as the connections tring, if R2=1. */
00457 /*     If any of these allocations or connection fails, function returns a*/
00458 /*     failure code 1.  Otherwise 0. */
00459 /*-----------------------------------------------------------------------------*/
00460 void ODBCConnect(CTXTdecl)
00461 {
00462   UCHAR uid[128];
00463   UCHAR *server;
00464   UCHAR *pwd;
00465   UCHAR *connectIn;
00466   HDBC hdbc = NULL;
00467   RETCODE rc;
00468   int new;
00469 
00470   /* if we don't yet have an environment, allocate one.*/
00471   if (!henv) {
00472     //locked to prevent two threads from fighting over who creates the env.
00473     SYS_MUTEX_LOCK( MUTEX_ODBC) ;
00474     /* allocate environment handler*/
00475     rc = SQLAllocEnv(&henv);
00476     if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
00477       xsb_error("Environment allocation failed");
00478       ctop_int(CTXTc 6, 0);
00479       return;
00480     }
00481     /*    SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC2,
00482                 SQL_IS_UINTEGER);
00483     */
00484 
00485     LCursor = FCursor = NULL;
00486     FCurNum = NULL;
00487     if (nullFctPsc == NULL)
00488         nullFctPsc = pair_psc(insert("NULL",1,global_mod,&new));
00489     SYS_MUTEX_UNLOCK( MUTEX_ODBC) ;
00490   }
00491 
00492   /* allocate connection handler*/
00493   rc = SQLAllocConnect(henv, &hdbc);
00494   if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
00495     xsb_error("Connection Resources Allocation Failed");
00496     ctop_int(CTXTc 6, 0);
00497     return;
00498   }
00499 
00500   if (!ptoc_int(CTXTc 2)) {
00501     /* get server name, user id and password*/
00502     server = (UCHAR *)ptoc_string(CTXTc 3);
00503     strcpy(uid, (UCHAR *)ptoc_string(CTXTc 4));
00504     pwd = (UCHAR *)ptoc_string(CTXTc 5);
00505     
00506     /* connect to database*/
00507     rc = SQLConnect(hdbc, server, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
00508     if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
00509       SQLFreeConnect(hdbc);
00510       xsb_error("Connection to server %s failed", server);
00511       ctop_int(CTXTc 6, 0);
00512       return;
00513     }
00514   } else {
00515     /* connecting through driver using a connection string */
00516     connectIn = (UCHAR *)ptoc_longstring(CTXTc 3);
00517     rc = SQLDriverConnect(hdbc, NULL, connectIn, SQL_NTS, NULL, 0, NULL,SQL_DRIVER_NOPROMPT);
00518     if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
00519       SQLFreeConnect(hdbc);
00520       xsb_error("Connection to driver failed: %s", connectIn);
00521       ctop_int(CTXTc 6, 0);
00522       return;
00523     }
00524   }
00525   
00526   ctop_int(CTXTc 6, (long)hdbc);
00527   return;
00528 }
00529 
00530 /*-----------------------------------------------------------------------------*/
00531 /*  FUNCTION NAME:*/
00532 /*     ODBCDisconnect()    */
00533 /*  PARAMETERS:*/
00534 /*     R1: 2*/
00535 /*     R2: hdbc if closing a particular connection*/
00536 /*         0 if closing entire ODBC session.*/
00537 /*  NOTES:*/
00538 /*     Disconnect us from the server and free all the system resources we*/
00539 /*     allocated for the session - statement handlers, connection handler,*/
00540 /*     environment handler and memory space. */
00541 /*-----------------------------------------------------------------------------*/
00542 void ODBCDisconnect(CTXTdecl)
00543 {
00544   struct Cursor *cur = FCursor;
00545   struct Cursor *tcur;
00546   struct NumberofCursors *numi = FCurNum, *numj = FCurNum;
00547   HDBC hdbc = (HDBC)ptoc_int(CTXTc 2);
00548   RETCODE rc;
00549 
00550   rc = SQLTransact(henv,hdbc,SQL_COMMIT);
00551   if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
00552     xsb_abort("[ODBC] Error committing transactions");
00553   }
00554 
00555   if (hdbc == NULL) {  /* close entire connection*/
00556     if (FCursor != NULL)
00557       xsb_abort("[ODBC] Must close all connections before shutting down");
00558     SQLFreeEnv(henv);
00559     return;
00560   }
00561 
00562   /* only free cursors associated with this connection (hdbc)*/
00563   while((numj != NULL) && (numj->hdbc != hdbc)){
00564     if(numj != FCurNum) numi=numi->NCurNum;
00565     numj=numj->NCurNum;
00566   }
00567 
00568   if(numj != NULL){
00569     if(numj == FCurNum) FCurNum=numj->NCurNum;
00570     else numi->NCurNum=numj->NCurNum;
00571     free(numj);
00572   }
00573 
00574   while (cur != NULL) {
00575     if (cur->hdbc == hdbc) {
00576       tcur = cur->NCursor;
00577       if (cur->Status != 0) {
00578         SetCursorClose(cur);
00579       }
00580       SQLFreeStmt(cur->hstmt,SQL_DROP);
00581       if (cur->PCursor) (cur->PCursor)->NCursor = cur->NCursor;
00582       else FCursor = cur->NCursor;
00583       if (cur->NCursor) (cur->NCursor)->PCursor = cur->PCursor;
00584       else LCursor = cur->PCursor;
00585       free(cur);
00586       /*      (num->CursorCount)-- */
00587        cur = tcur;
00588     }
00589     else cur = cur->NCursor;
00590   }
00591 
00592   SQLDisconnect(hdbc);
00593   SQLFreeConnect(hdbc);
00594   /*  SQLFreeEnv(henv);*/
00595 }
00596 
00597 /*-----------------------------------------------------------------------------*/
00598 /*  FUNCTION NAME:*/
00599 /*     FindFreeCursor()*/
00600 /*  PARAMETERS:*/
00601 /*     R1: 7*/
00602 /*     R2: Connection Handle*/
00603 /*     R3: SQL Statement*/
00604 /*     R4: var, in which Cursor addr is returned*/
00605 /*  NOTES:*/
00606 /*     Find a free statement handler and return its index number into the*/
00607 /*     global cursor table.  It gives priority to a closed cursor with same*/
00608 /*     stantement number over ordinary closed cursors.  If there is no handler*/
00609 /*     left,  function returns NULL. possible cursor status values are*/
00610 /*     0 - never been used - no resource associated w/ the cursor */
00611 /*     1 - used before but having been closed-the cursor has all the resource*/
00612 /*     2 - reusing a used cursor w/ the same statement number, no resource*/
00613 /*         needs to be allocated*/
00614 /*     3 - using a cursor that has no resource - it needs to be allocated*/
00615 /*-----------------------------------------------------------------------------*/
00616 void FindFreeCursor(CTXTdecl)
00617 {
00618   struct Cursor *curi = FCursor, *curj = NULL, *curk = NULL;
00619   struct NumberofCursors *num = FCurNum;
00620   HDBC hdbc = (HDBC)ptoc_int(CTXTc 2);
00621   char *Sql_stmt = ptoc_longstring(CTXTc 3);
00622   RETCODE rc;
00623   char drname[25]; SQLSMALLINT drnamelen;
00624 
00625   /* search */
00626   while (curi != NULL) {
00627     if (curi->hdbc == hdbc) { /* only look at stmt handles for this connection */
00628       if (curi->Status == 0) curj = curi; /* cursor never been used*/
00629       else {
00630         if (curi->Status == 1) {    /* a closed cursor*/
00631           /* same statement as this one, so grab and return it*/
00632           if (!strcmp(curi->Sql,Sql_stmt)) {
00633             if (curi != FCursor) {
00634               (curi->PCursor)->NCursor = curi->NCursor;
00635               if (curi == LCursor) LCursor = curi->PCursor;
00636               else (curi->NCursor)->PCursor = curi->PCursor;
00637               FCursor->PCursor = curi;
00638               curi->PCursor = NULL;
00639               curi->NCursor = FCursor;
00640               FCursor = curi;
00641             }
00642             curi->Status = 2;
00643             ctop_int(CTXTc 4, (long)curi);
00644             /*printf("reuse cursor: %p\n",curi);*/
00645             return;
00646           } else {
00647             curk = curi;                      /* otherwise just record it*/
00648           }
00649         }
00650       }
00651     }
00652     curi = curi->NCursor;
00653   }
00654 
00655   /* done w/ the search; see what was found*/
00656   if (curj != NULL) {   /* give priority to an unused cursor*/
00657     curi = curj;
00658     /*printf("take unused cursor: %p\n",curi);*/
00659   }
00660   else {
00661     while((num != NULL) && (num->hdbc != hdbc)){
00662       num=num->NCurNum;
00663     }
00664     if(num == NULL){
00665       num = (struct NumberofCursors *)malloc(sizeof(struct NumberofCursors));
00666       num->hdbc = hdbc;
00667       num->NCurNum=FCurNum;
00668       FCurNum=num;
00669       num->CursorCount=0;
00670     }
00671 
00672     if (num->CursorCount < MAXCURSORNUM) { /* allocate a new cursor if allowed*/
00673     /* problem here: should have numberOfCursors for each connection */
00674     curi = (struct Cursor *)calloc(sizeof(struct Cursor),1);
00675     curi->PCursor = NULL;
00676     curi->NCursor = FCursor;
00677     if (FCursor == NULL) LCursor = curi;
00678     else FCursor->PCursor = curi;
00679     FCursor = curi;
00680 
00681     rc = SQLAllocStmt(hdbc,&(curi->hstmt));
00682     if (!((rc==SQL_SUCCESS) ||
00683           (rc==SQL_SUCCESS_WITH_INFO))) {
00684       free(curi);
00685       /*      numberOfCursors--; */
00686       xsb_abort("[ODBC] ERROR while trying to allocate ODBC statement\n");
00687     }
00688 
00689     num->CursorCount++;
00690 
00691     /*printf("allocate a new cursor: %p\n",curi);*/
00692     }
00693     else if (curk == NULL) {  /* no cursor left*/
00694       ctop_int(CTXTc 4, 0);
00695       return;
00696     }
00697     else {                    /* steal a cursor*/
00698       curi = curk;
00699       SetCursorClose(curi);
00700       /*printf("steal a cursor: %p\n",curi);*/
00701     }
00702   }
00703 
00704   /* move to front of list.*/
00705   if (curi != FCursor) {
00706     (curi->PCursor)->NCursor = curi->NCursor;
00707     if (curi == LCursor) LCursor = curi->PCursor;
00708     else (curi->NCursor)->PCursor = curi->PCursor;
00709     FCursor->PCursor = curi;
00710     curi->PCursor = NULL;
00711     curi->NCursor = FCursor;
00712     FCursor = curi;
00713   }
00714 
00715   rc = SQLGetInfo(hdbc,SQL_DRIVER_NAME,drname,(SQLSMALLINT)25,&drnamelen);
00716   if (rc != SQL_SUCCESS) curi->driver_code = 0;
00717   else if (!strcmp(drname,"odbcjt32.dll")) curi->driver_code = 1;
00718   else curi->driver_code = 0;
00719 
00720   curi->hdbc = hdbc;
00721   curi->Sql = (UCHAR *)strdup(Sql_stmt);
00722   if (!curi->Sql)
00723     xsb_abort("[ODBC] Not enough memory for SQL stmt in FindFreeCursor!\n");
00724   curi->Status = 3;
00725   ctop_int(CTXTc 4, (long)curi);
00726   return;
00727 }
00728 
00729 /*-----------------------------------------------------------------------------*/
00730 /*  FUNCTION NAME:*/
00731 /*     SetBindVarNum() */
00732 /*  PARAMETERS:*/
00733 /*     R1: 3*/
00734 /*     R2: Cursor Address*/
00735 /*     R3: Number of bind values*/
00736 /*  NOTES:*/
00737 /*     set the number of bind variables.  Note that the memory to*/
00738 /*     store their values is not allocated here since we don't know*/
00739 /*     their type: no information on how much memory is needed.  If*/
00740 /*     we're reusing an old statement handler we don't have to worry*/
00741 /*     about these things.  All we need to do is to make sure that*/
00742 /*     the statement is indeed the same statement w/ the same bind*/
00743 /*     variable number.*/
00744 /*-----------------------------------------------------------------------------*/
00745 void SetBindVarNum(CTXTdecl)
00746 {
00747   struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
00748   int NumBindVars = ptoc_int(CTXTc 3);
00749 
00750   if (cur->Status == 2) {
00751     if (cur->NumBindVars != NumBindVars)
00752       xsb_abort("[ODBC] Number of Bind values provided does not agree with query\n");
00753     return;
00754   }
00755 
00756   cur->NumBindVars = NumBindVars;
00757   cur->BindList = malloc(sizeof(UCHAR *) * NumBindVars);
00758   if (!cur->BindList)
00759     xsb_abort("[ODBC] Not enough memory for cur->BindList!");
00760   cur->BindTypes = malloc(sizeof(int) * NumBindVars);
00761   if (!cur->BindTypes)
00762     xsb_abort("[ODBC] Not enough memory for cur->BindTypes!");
00763   cur->BindLens = malloc(sizeof(SQLINTEGER) * NumBindVars);
00764   if (!cur->BindLens)
00765     xsb_abort("[ODBC] Not enough memory for cur->BindLens!");
00766 
00767 }
00768 
00769 DllExport void call_conv write_canonical_term(CTXTdeclc Cell prologterm, int letterflag);
00770 #define wcan_string tsgLBuff1
00771 
00772 #define MAX_BIND_VALS 30
00773 char *term_string[MAX_BIND_VALS] = {0};
00774 
00775 void string_to_char(Cell list, char **term_string) {
00776   Cell tlist, car;
00777   char *charptr;
00778   int len = 0;
00779   
00780   if (*term_string) free(*term_string);
00781   XSB_Deref(list);
00782   tlist = list;
00783   while (islist(tlist)) {
00784     len++;
00785     tlist = p2p_cdr(tlist);
00786     XSB_Deref(tlist);
00787   }
00788   *term_string = charptr = malloc(len+1);
00789   while (islist(list)) {
00790     car = p2p_car(list);
00791     XSB_Deref(car);
00792     *(charptr++) = int_val(car);
00793     list = p2p_cdr(list);
00794     XSB_Deref(list);
00795   }
00796   *charptr = '\0';
00797 }
00798 
00799 /*-----------------------------------------------------------------------------*/
00800 /*  FUNCTION NAME:*/
00801 /*     SetBindVal()   */
00802 /*  PARAMETERS:*/
00803 /*     R1: 6*/
00804 /*     R2: Cursor Addr*/
00805 /*     R3: Bind variable index (starting from 0)*/
00806 /*     R4: Value to give the bind variable*/
00807 /*     R5: var, for returned status*/
00808 /*  NOTES:*/
00809 /*     set the bind variables' values. */
00810 /*     allocate memory if it is needed(status == 3)*/
00811 /*-----------------------------------------------------------------------------*/
00812 void SetBindVal(CTXTdecl)
00813 {
00814   RETCODE rc;
00815   struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
00816   int j = ptoc_int(CTXTc 3);
00817   Cell BindVal = ptoc_tag(CTXTc 4);
00818 
00819   if (!((j >= 0) && (j < cur->NumBindVars)))
00820     xsb_abort("[ODBC] Abnormal argument in SetBindVal!");
00821 
00822   /* if we're reusing an opened cursor w/ the statement number*/
00823   /* reallocate BindVar if type has changed (May not be such a good idea?)*/
00824   if (cur->Status == 2) {
00825     if (isinteger(BindVal)) {
00826       if (cur->BindTypes[j] != 0) {
00827         if (cur->BindTypes[j] < 2) free((void *)cur->BindList[j]);
00828         cur->BindList[j] = (UCHAR *)malloc(sizeof(int));
00829         cur->BindTypes[j] = 0;
00830         rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, (int *)(cur->BindList[j]), 0, NULL);
00831         if (rc != SQL_SUCCESS) {
00832           ctop_int(CTXTc 5,PrintErrorMsg(cur));
00833           SetCursorClose(cur);
00834           return;
00835         }
00836       }
00837       *((int *)cur->BindList[j]) = oint_val(BindVal);
00838     } else if (isofloat(BindVal)) {
00839       if (cur->BindTypes[j] != 1) {
00840         /*printf("ODBC: Changing Type: flt to %d\n",cur->BindTypes[j]);*/
00841         if (cur->BindTypes[j] < 2) free((void *)cur->BindList[j]);
00842         cur->BindList[j] = (UCHAR *)malloc(sizeof(float));
00843         cur->BindTypes[j] = 1;
00844         rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, 0, 0, (float *)(cur->BindList[j]), 0, NULL);
00845         if (rc != SQL_SUCCESS) {
00846           ctop_int(CTXTc 5,PrintErrorMsg(cur));
00847           SetCursorClose(cur);
00848           return;
00849         }
00850       }
00851       *((float *)cur->BindList[j]) = (float)ofloat_val(BindVal);
00852     } else if (isstring(BindVal)) {
00853       if (cur->BindTypes[j] != 2) {
00854         /*printf("ODBC: Changing Type: str to %d\n",cur->BindTypes[j]);*/
00855         if (cur->BindTypes[j] < 2) free((void *)cur->BindList[j]);
00856         cur->BindTypes[j] = 2;
00857         /* SQLBindParameter will be done later in parse for char variables*/
00858       }
00859       cur->BindList[j] = string_val(BindVal);
00860     } else if (isconstr(BindVal) && get_str_psc(BindVal) == nullFctPsc) {
00861       if (cur->BindTypes[j] < 2) free((void *)cur->BindList[j]);
00862       cur->BindTypes[j] = 3;
00863       cur->BindList[j] = NULL;
00864     } else if (isconstr(BindVal) && get_arity(get_str_psc(BindVal))==1) {
00865       if (!strcmp(get_name(get_str_psc(BindVal)),"string")) {
00866         if (cur->BindTypes[j] < 2) free((void *)cur->BindList[j]);
00867         string_to_char(p2p_arg(BindVal,1),&(term_string[j]));
00868         cur->BindTypes[j] = 2;
00869         cur->BindList[j] = term_string[j];
00870       } else {
00871         if (cur->BindTypes[j] < 2) free((void *)cur->BindList[j]);
00872         write_canonical_term(CTXTc p2p_arg(BindVal,1),1);
00873         if (term_string[j]) free(term_string[j]);
00874         term_string[j] = malloc(wcan_string->length+1);
00875         strcpy(term_string[j],wcan_string->string);
00876         cur->BindTypes[j] = 2;
00877         cur->BindList[j] = term_string[j];
00878       }
00879     } else {
00880       xsb_abort("[ODBC] Unknown bind variable type, %d", cur->BindTypes[j]);
00881     }
00882     ctop_int(CTXTc 5,0);
00883     return;
00884   }
00885 
00886   /* otherwise, memory needs to be allocated in this case*/
00887   if (isinteger(BindVal)) {
00888     cur->BindTypes[j] = 0;
00889     cur->BindList[j] = (UCHAR *)malloc(sizeof(int));
00890     if (!cur->BindList[j])
00891       xsb_abort("[ODBC] Not enough memory for an int in SetBindVal!");
00892     *((int *)cur->BindList[j]) = oint_val(BindVal);
00893   } else if (isofloat(BindVal)) {
00894     cur->BindTypes[j] = 1;
00895     cur->BindList[j] = (UCHAR *)malloc(sizeof(float));
00896     if (!cur->BindList[j])
00897       xsb_abort("[ODBC] Not enough memory for a float in SetBindVal!");
00898     *((float *)cur->BindList[j]) = (float)ofloat_val(BindVal);
00899   } else if (isstring(BindVal)) {
00900     cur->BindTypes[j] = 2;
00901     cur->BindList[j] = string_val(BindVal);
00902     } else if (isconstr(BindVal) && get_str_psc(BindVal) == nullFctPsc) {
00903     cur->BindTypes[j] = 3;
00904     cur->BindList[j] = NULL;
00905   } else if (isconstr(BindVal) && get_arity(get_str_psc(BindVal))==1) {
00906     if (!strcmp(get_name(get_str_psc(BindVal)),"string")) {
00907         string_to_char(p2p_arg(BindVal,1),&(term_string[j]));
00908         cur->BindTypes[j] = 2;
00909         cur->BindList[j] = term_string[j];
00910     } else {
00911       write_canonical_term(CTXTc p2p_arg(BindVal,1),1);
00912       if (term_string[j]) free(term_string[j]);
00913       term_string[j] = malloc(wcan_string->length+1);
00914       strcpy(term_string[j],wcan_string->string);
00915       cur->BindTypes[j] = 2;
00916       cur->BindList[j] = term_string[j];
00917     }
00918   } else {
00919     xsb_abort("[ODBC] Unknown bind variable type, %d", cur->BindTypes[j]);
00920   }
00921   ctop_int(CTXTc 5,0);
00922   return;
00923 }
00924 
00925 
00926 /*-----------------------------------------------------------------------------*/
00927 /*  FUNCTION NAME:*/
00928 /*     Parse()*/
00929 /*  PARAMETERS:*/
00930 /*     R1: 2*/
00931 /*     R2: the SQL statement for the cursor*/
00932 /*     R3: var, returned cursor address*/
00933 /*  NOTES:*/
00934 /*     parse the sql statement and submit it to DBMS to execute.  if all these*/
00935 /*     succeed, then prepare for resulting row fetching.  this includes*/
00936 /*     determination of column number in the resulting rowset and the length*/
00937 /*     of each column and memory allocation which is used to store each row.*/
00938 /*-----------------------------------------------------------------------------*/
00939 void Parse(CTXTdecl)
00940 {
00941 int j;
00942 struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
00943 RETCODE rc;
00944   if (cur->Status == 2) { /* reusing opened cursor*/
00945     rc = SQLFreeStmt(cur->hstmt,SQL_CLOSE);
00946     if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO)) {
00947       ctop_int(CTXTc 3, PrintErrorMsg(cur));
00948       SetCursorClose(cur);
00949       return;
00950     }
00951     /* reset just char and null vars, since they store addr of chars, and set lengths*/
00952     for (j = 0; j < cur->NumBindVars; j++) {
00953       cur->BindLens[j] = 0;
00954       switch (cur->BindTypes[j])
00955                 {
00956                 case 2:
00957                   cur->BindLens[j] = strlen((char *)cur->BindList[j]);
00958                   if (cur->driver_code == 1)
00959                     rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0,(char *)cur->BindList[j], 0, &SQL_NTSval);
00960                   else rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0,(char *)cur->BindList[j], cur->BindLens[j], &cur->BindLens[j]);
00961                   break;
00962                 case 3:
00963                         rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0,NULL, 0, &SQL_NULL_DATAval);
00964                         break;
00965                 }
00966     }
00967   } else {
00968     if (SQL_SUCCESS != (rc = SQLPrepare(cur->hstmt, cur->Sql, SQL_NTS)))
00969                 {
00970                 ctop_int(CTXTc 3,PrintErrorMsg(cur));
00971                 SetCursorClose(cur);
00972                 return;
00973                 }
00974 
00975 
00976     /* set the bind variables*/
00977     for (j = 0; j < cur->NumBindVars; j++) {
00978       switch (cur->BindTypes[j])
00979                 {
00980                 case 0:
00981                         rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, (int *)(cur->BindList[j]), 0, NULL);
00982                         break;
00983                 case 1:
00984                         rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, 0, 0, (float *)cur->BindList[j], 0, NULL);
00985                         break;
00986                 case 2:
00987                         /* we're sloppy here.  it's ok for us to use the default values*/
00988                   cur->BindLens[j] = strlen((char *)cur->BindList[j]);
00989                   if (cur->driver_code == 1)
00990                     rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0,(char *)cur->BindList[j], 0, &SQL_NTSval);
00991                   else rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0,(char *)cur->BindList[j], cur->BindLens[j], &cur->BindLens[j]);
00992                   break;
00993                 case 3:
00994                         rc = SQLBindParameter(cur->hstmt, (short)(j+1), SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0,NULL, 0, &SQL_NULL_DATAval);
00995                         break;
00996                 default:
00997                         xsb_abort("[ODBC] illegal BindVal");
00998                         rc = 0;
00999                 }
01000       if (rc != SQL_SUCCESS)
01001                 {
01002                 ctop_int(CTXTc 3,PrintErrorMsg(cur));
01003                 SetCursorClose(cur);
01004                 return;
01005                 }
01006     }
01007   }
01008   /* submit it for execution*/
01009   if (SQLExecute(cur->hstmt) != SQL_SUCCESS) {
01010     ctop_int(CTXTc 3,PrintErrorMsg(cur));
01011     SetCursorClose(cur);
01012     return;
01013   }
01014   ctop_int(CTXTc 3,0);
01015   return;
01016 }
01017 
01018 /*-----------------------------------------------------------------------------*/
01019 /*  FUNCTION NAME:*/
01020 /*     ODBCCommit()*/
01021 /*  PARAMETERS:*/
01022 /*     R1: 10*/
01023 /*     R2: Connection Handle*/
01024 /*     R3: var, returned status, 0 if successful*/
01025 /*-----------------------------------------------------------------------------*/
01026 void ODBCCommit(CTXTdecl)
01027 {
01028   struct Cursor *cur = FCursor;
01029   HDBC hdbc = (HDBC)ptoc_int(CTXTc 2);
01030   RETCODE rc;
01031 
01032   if (((rc=SQLTransact(henv,hdbc,SQL_COMMIT)) == SQL_SUCCESS) ||
01033       (rc == SQL_SUCCESS_WITH_INFO)) {
01034     /* close only those with right hdbc....*/
01035     while (cur != NULL) {
01036       if (cur->hdbc == hdbc && cur->Status != 0) SetCursorClose(cur);
01037       cur = cur->NCursor;
01038     }
01039     ctop_int(CTXTc 3,0);
01040   } else
01041     ctop_int(CTXTc 3,PrintErrorMsg(NULL));
01042   return;
01043 }
01044 
01045 /*-----------------------------------------------------------------------------*/
01046 /*  FUNCTION NAME:*/
01047 /*     ODBCRollback()*/
01048 /*  PARAMETERS:*/
01049 /*     R1: 11*/
01050 /*     R2: Connection Handle*/
01051 /*     R3: var, for returned status: 0 if successful*/
01052 /*-----------------------------------------------------------------------------*/
01053 void ODBCRollback(CTXTdecl)
01054 {
01055   struct Cursor *cur = FCursor;
01056   HDBC hdbc = (HDBC)ptoc_int(CTXTc 2);
01057   RETCODE rc;
01058 
01059   if (((rc=SQLTransact(henv,hdbc,SQL_ROLLBACK)) == SQL_SUCCESS) ||
01060       (rc == SQL_SUCCESS_WITH_INFO)) {
01061     /* only close those with right hdbc*/
01062     while (cur != NULL) {
01063       if (cur->hdbc == hdbc && cur->Status != 0) SetCursorClose(cur);
01064       cur = cur->NCursor;
01065     }
01066     ctop_int(CTXTc 3,0);
01067   } else
01068     ctop_int(CTXTc 3, PrintErrorMsg(NULL));
01069   return;
01070 }
01071 
01072 /*-----------------------------------------------------------------------------*/
01073 /*  FUNCTION NAME:*/
01074 /*     ODBCColumns()*/
01075 /*  PARAMETERS:*/
01076 /*     R1: 12*/
01077 /*     R2: Cursor Index*/
01078 /*     R3: Table name*/
01079 /*     R4: var for returned status: 0 if successful*/
01080 /*-----------------------------------------------------------------------------*/
01081 void ODBCColumns(CTXTdecl)
01082 {
01083   struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
01084   char tmpstr[255];
01085   char *str1, *str2, *str3;
01086   RETCODE rc;
01087 
01088   strcpy(tmpstr,ptoc_string(CTXTc 3));
01089   str1 = strtok(tmpstr,".");
01090   str2 = str3 = NULL;
01091   if (str1) str2 = strtok(NULL,".");
01092   if (str2) str3 = strtok(NULL,".");
01093   if (!str3 && !str2) {str3 = str1; str1 = NULL;}
01094   else if (!str3) {str3 = str2; str2 = NULL;}
01095   /*  printf("str1 %s, str2 %s, str3 %s\n",str1,str2,str3);*/
01096   if (((rc=SQLColumns(cur->hstmt,
01097                       str1, SQL_NTS,
01098                       str2, SQL_NTS,
01099                       str3, SQL_NTS,
01100                       NULL,0)) == SQL_SUCCESS) ||
01101       (rc == SQL_SUCCESS_WITH_INFO)) {
01102     ctop_int(CTXTc 4,0);
01103   } else {
01104     ctop_int(CTXTc 4,PrintErrorMsg(cur));
01105     SetCursorClose(cur);
01106   }
01107   return;
01108 }
01109 
01110 /*-----------------------------------------------------------------------------*/
01111 /*  FUNCTION NAME:*/
01112 /*     ODBCTables()*/
01113 /*  PARAMETERS:*/
01114 /*     R1: 13*/
01115 /*     R2: Cursor*/
01116 /*     R3: var, returned status: 0 if successful*/
01117 /*-----------------------------------------------------------------------------*/
01118 void ODBCTables(CTXTdecl)
01119 {
01120   struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
01121   RETCODE rc;
01122 
01123   if (cur->Status == 2) { /* reusing opened cursor*/
01124     rc = SQLFreeStmt(cur->hstmt,SQL_CLOSE);
01125     if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO)) {
01126       ctop_int(CTXTc 3, PrintErrorMsg(cur));
01127       SetCursorClose(cur);
01128       return;
01129     }
01130   }
01131 
01132   if (((rc=SQLTables(cur->hstmt,
01133                      NULL, 0,
01134                      NULL, 0,
01135                      NULL, 0,
01136                      NULL, 0)) == SQL_SUCCESS) ||
01137       (rc == SQL_SUCCESS_WITH_INFO)) {
01138     ctop_int(CTXTc 3,0);
01139   } else {
01140     ctop_int(CTXTc 3,PrintErrorMsg(cur));
01141     SetCursorClose(cur);
01142   }
01143   return;
01144 }
01145 
01146 /*-----------------------------------------------------------------------------*/
01147 /*  FUNCTION NAME:*/
01148 /*     ODBCUserTables()*/
01149 /*  PARAMETERS:*/
01150 /*     R1: 14*/
01151 /*     R2: Cursor*/
01152 /*     R3: var, for returned status: 0 if successful*/
01153 /*-----------------------------------------------------------------------------*/
01154 void ODBCUserTables(CTXTdecl)
01155 {
01156   struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
01157   UWORD TablePrivilegeExists;
01158   RETCODE rc;
01159 
01160   /* since some ODBC drivers don't implement the function SQLTablePrivileges*/
01161   /* we check it first*/
01162   SQLGetFunctions(cur->hdbc,SQL_API_SQLTABLEPRIVILEGES,&TablePrivilegeExists);
01163   if (!TablePrivilegeExists) {
01164     printf("Privilege concept does not exist in this DVMS: you probably can access any of the existing tables\n");
01165     ctop_int(CTXTc 3, 2);
01166     return;
01167   }
01168   if (((rc=SQLTablePrivileges(cur->hstmt,
01169                               NULL, 0,
01170                               NULL, 0,
01171                               NULL, 0)) == SQL_SUCCESS) ||
01172       (rc == SQL_SUCCESS_WITH_INFO))
01173     ctop_int(CTXTc 3,0);
01174   else {
01175     ctop_int(CTXTc 3,PrintErrorMsg(cur));
01176     SetCursorClose(cur);
01177   }
01178   return;
01179 }
01180 
01181 /*-----------------------------------------------------------------------------*/
01182 /*  FUNCTION NAME:*/
01183 /*     DisplayColSize()*/
01184 /*  PARAMETERS:*/
01185 /*     SWORD coltype - column type which is a single word.*/
01186 /*     UDWORD collen - column length which is returned by SQLDescribeCol*/
01187 /*     UCHAR *colname - pointer to column name string*/
01188 /*  RETURN VALUE:*/
01189 /*     column length - the size of memory that is needed to store the column*/
01190 /*     value for supported column types*/
01191 /*     0             - otherwise*/
01192 /*-----------------------------------------------------------------------------*/
01193 UDWORD DisplayColSize(SWORD coltype, UDWORD collen, UCHAR *colname)
01194 {
01195   switch (ODBCToXSBType(coltype)) {
01196   case SQL_C_SLONG:
01197     return sizeof(long *);
01198   case SQL_C_CHAR: {
01199     UDWORD tmp = MAXI(collen+1, strlen((char *) colname));
01200     if (tmp < MAXVARSTRLEN) return tmp;
01201     else return MAXVARSTRLEN;
01202   }
01203   case SQL_C_BINARY: {
01204     return MAXVARSTRLEN;
01205   }
01206   case SQL_C_FLOAT:
01207     return sizeof(float *);
01208   default:
01209     printf("Illegal ODBC Type: %d\n",coltype);
01210     return 0;
01211   }
01212 }
01213 extern xsbBool unify(CTXTdecltypec Cell, Cell);
01214 
01215 /*-----------------------------------------------------------------------------*/
01216 /*  FUNCTION NAME:*/
01217 /*     ODBCDataSources()*/
01218 /*  PARAMETERS:*/
01219 /*     R1: 1 - first call; 2 - subsequent calls */
01220 /*     R2: var, returns DSN */
01221 /*     R3: var, returns DS description */
01222 /*     R4: var, returns status */
01223 /*  NOTES:*/
01224 /*-----------------------------------------------------------------------------*/
01225 void ODBCDataSources(CTXTdecl)
01226 {
01227   SQLCHAR DSN[SQL_MAX_DSN_LENGTH+1];
01228   SQLCHAR Description[SQL_MAX_DSN_LENGTH+1];
01229   RETCODE rc;
01230   int seq, new;
01231   SWORD dsn_size, descr_size;
01232   Cell op2 = ptoc_tag(CTXTc 3);
01233   Cell op3 = ptoc_tag(CTXTc 4);
01234 
01235   if (!henv) {
01236     //locked to prevent two threads from fighting over who creates the env
01237     SYS_MUTEX_LOCK( MUTEX_ODBC) ;
01238     /* allocate environment handler*/
01239     rc = SQLAllocEnv(&henv);
01240     if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
01241       xsb_error("Environment allocation failed");
01242       ctop_int(CTXTc 5,1);
01243       return;
01244     }
01245     LCursor = FCursor = NULL;
01246     FCurNum = NULL;
01247     if (nullFctPsc == NULL)
01248         nullFctPsc = pair_psc(insert("NULL",1,global_mod,&new));
01249     SYS_MUTEX_UNLOCK( MUTEX_ODBC) ;
01250   }
01251 
01252   seq = ptoc_int(CTXTc 2);
01253   if (seq == 1) {
01254     rc = SQLDataSources(henv,SQL_FETCH_FIRST,DSN,
01255                         SQL_MAX_DSN_LENGTH,&dsn_size,
01256                         Description,SQL_MAX_DSN_LENGTH,
01257                         &descr_size);
01258     if (rc == SQL_NO_DATA_FOUND) {
01259       ctop_int(CTXTc 5,2);
01260       return;
01261     }
01262     if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
01263       xsb_error("Environment allocation failed");
01264       ctop_int(CTXTc 5,1);
01265       return;
01266     }
01267   } else {
01268     rc = SQLDataSources(henv,SQL_FETCH_NEXT,DSN,
01269                         SQL_MAX_DSN_LENGTH,&dsn_size,
01270                         Description,SQL_MAX_DSN_LENGTH,
01271                         &descr_size);
01272     if (rc == SQL_NO_DATA_FOUND) {
01273       ctop_int(CTXTc 5,2);
01274       return;
01275     }
01276     if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
01277       xsb_error("Environment allocation failed");
01278       ctop_int(CTXTc 5,1);
01279       return;
01280     }
01281   }
01282   XSB_Deref(op2);
01283   if (isref(op2))
01284   {
01285           char * tempDSNstring= string_find(DSN,1);
01286           Cell cellStr = makestring(tempDSNstring);
01287     unify(CTXTc op2, cellStr);
01288   }
01289   else {
01290     xsb_error("[ODBCDataSources] Param 2 should be a free variable.");
01291     ctop_int(CTXTc 5,1);
01292     return;
01293   }
01294   XSB_Deref(op3);
01295   if (isref(op3))
01296   {
01297     unify(CTXTc op3, makestring(string_find(Description,1)));
01298   }
01299   else {
01300     xsb_error("[ODBCDataSources] Param 3 should be a free variable.");
01301     ctop_int(CTXTc 5,1);
01302     return;
01303   }
01304   ctop_int(CTXTc 5,0);
01305   return;
01306 }
01307 
01308 /*-----------------------------------------------------------------------------*/
01309 /*  FUNCTION NAME:*/
01310 /*     DescribeSelect()*/
01311 /*  PARAMETERS:*/
01312 /*     R1: 15*/
01313 /*     R2: Ptr to cursor record*/
01314 /*     R3: var, for returned status:*/
01315 /*         0 - the result row has at least one column and*/
01316 /*         1 - something goes wrong, we can't retrieve column information, */
01317 /*             memory allocation fails (if this happens program stops).*/
01318 /*         2 - no column is affected*/
01319 /*  NOTES:*/
01320 /*     memory is also allocated for future data storage*/
01321 /*-----------------------------------------------------------------------------*/
01322 void ODBCDescribeSelect(CTXTdecl)
01323 {
01324   int j;
01325   UCHAR colname[50];
01326   SWORD colnamelen;
01327   SWORD scale;
01328   SWORD nullable;
01329   UDWORD collen;
01330   struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
01331 
01332   cur->NumCols = 0;
01333   SQLNumResultCols(cur->hstmt, (SQLSMALLINT*)&(cur->NumCols));
01334   if (!(cur->NumCols)) {
01335     /* no columns are affected, set cursor status to unused */
01336     cur->Status = 1;
01337     ctop_int(CTXTc 3,2);
01338     return;
01339   }
01340   /* if we aren't reusing a closed statement handle, we need to get*/
01341   /* resulting rowset info and allocate memory for it*/
01342   if (cur->Status != 2) {
01343     cur->ColTypes =
01344       (SWORD *)malloc(sizeof(SWORD) * cur->NumCols);
01345     if (!cur->ColTypes)
01346       xsb_abort("[ODBC] Not enough memory for ColTypes!");
01347 
01348     cur->Data =
01349       (UCHAR **)malloc(sizeof(char *) * cur->NumCols);
01350     if (!cur->Data)
01351       xsb_abort("[ODBC] Not enough memory for Data!");
01352 
01353     cur->OutLen =
01354       (UDWORD *)malloc(sizeof(UDWORD) * cur->NumCols);
01355     if (!cur->OutLen)
01356       xsb_abort("[ODBC] Not enough memory for OutLen!");
01357 
01358     cur->ColLen =
01359       (UDWORD *)malloc(sizeof(UDWORD) * cur->NumCols);
01360     if (!cur->ColLen)
01361       xsb_abort("[ODBC] Not enough memory for ColLen!");
01362 
01363     for (j = 0; j < cur->NumCols; j++) {
01364       SQLDescribeCol(cur->hstmt, (short)(j+1), (UCHAR FAR*)colname,
01365                      sizeof(colname), &colnamelen,
01366                      &(cur->ColTypes[j]),
01367                      &collen, &scale, &nullable);
01368       /* SQLServer returns this wierd type for a system table, treat it as varchar?*/
01369       if (cur->ColTypes[j] == -9) cur->ColTypes[j] = SQL_VARCHAR;
01370       colnamelen = (colnamelen > 49) ? 49 : colnamelen;
01371       colname[colnamelen] = '\0';
01372       cur->ColLen[j] = DisplayColSize(cur->ColTypes[j],collen,colname);
01373       if (!(cur->ColLen[j])) {
01374         /* let SetCursorClose function correctly free all the memory allocated*/
01375         /* for Data storage: cur->Data[j]'s*/
01376         cur->NumCols = j; /* set so close frees memory allocated thus far*/
01377         SetCursorClose(cur);
01378         /*      return(1);*/
01379         ctop_int(CTXTc 3,1);
01380         return;
01381       }
01382       cur->Data[j] =
01383         (UCHAR *) malloc(((unsigned) cur->ColLen[j]+1)*sizeof(UCHAR));
01384       if (!cur->Data[j])
01385         xsb_abort("[ODBC] Not enough memory for Data[j]!");
01386     }
01387   }
01388   /* bind them*/
01389   for (j = 0; j < cur->NumCols; j++) {
01390     SQLBindCol(cur->hstmt, (short)(j+1),
01391                ODBCToXSBType(cur->ColTypes[j]), cur->Data[j],
01392                cur->ColLen[j], (SDWORD FAR *)(&(cur->OutLen[j])));
01393   }
01394   /*  return 0;*/
01395   ctop_int(CTXTc 3,0);
01396   return;
01397 }
01398 
01399 /*-----------------------------------------------------------------------------*/
01400 /*  FUNCTION NAME:*/
01401 /*     FetchNextRow()*/
01402 /*  PARAMETERS:*/
01403 /*     R1: 4*/
01404 /*     R2: Cursor Address*/
01405 /*     R3: var, for returned status*/
01406 /*         0 => successful, a row is read and available*/
01407 /*         1 => successful, no row avaliable*/
01408 /*         2 => unsuccessful, an error occurred in fetching.*/
01409 /*  NOTES:*/
01410 /*     fetch next row of result rowset.*/
01411 /*-----------------------------------------------------------------------------*/
01412 void FetchNextRow(CTXTdecl)
01413 {
01414   struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
01415   RETCODE rc;
01416 
01417   if (cur->Status == 0) {
01418     ctop_int(CTXTc 3,2);
01419     return;
01420   }
01421 
01422   rc = SQLFetch(cur->hstmt);
01423 
01424   if ((rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO))
01425     ctop_int(CTXTc 3,0);
01426   else if (rc == SQL_NO_DATA_FOUND){
01427     cur->Status = 1; /* done w/fetching. set cursor status to unused */
01428     ctop_int(CTXTc 3,1);
01429   }
01430   else {
01431     SetCursorClose(cur);         /* error occured in fetching*/
01432     ctop_int(CTXTc 3,2);
01433   }
01434   return;
01435 }
01436 
01437 /*-----------------------------------------------------------------------------*/
01438 /*  FUNCTION NAME:*/
01439 /*     ODBCConnectOption() */
01440 /*  PARAMETERS:*/
01441 /*     R1: 16*/
01442 /*     R2: Connection Handle*/
01443 /*     R3: 0 -> get; 1 -> set*/
01444 /*     R4: Option indicator (int)*/
01445 /*     R5: if R2=0 -> variable that attr val is returned in*/
01446 /*         if R2=1 -> value used to set attr*/
01447 /*     R6: Return Code*/
01448 /*  NOTES:*/
01449 /*     either gets value of a connection option, or sets it.*/
01450 /*-----------------------------------------------------------------------------*/
01451 void ODBCConnectOption(CTXTdecl)
01452 {
01453   HDBC hdbc = (HDBC)ptoc_int(CTXTc 2);
01454   int set = ptoc_int(CTXTc 3);
01455   long value = 0;
01456   RETCODE rc;
01457 
01458   if (set) {
01459     rc = SQLSetConnectOption(hdbc,(UWORD)ptoc_int(CTXTc 4),(UDWORD)ptoc_int(CTXTc 5));
01460   } else {
01461     rc = SQLGetConnectOption(hdbc,(UWORD)ptoc_int(CTXTc 4),(PTR)&value);
01462     ctop_int(CTXTc 5,value);
01463   }
01464   if ((rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO))
01465     ctop_int(CTXTc 6,0);
01466   else ctop_int(CTXTc 6,PrintErrorMsg(NULL));
01467 }
01468 
01469 //extern xsbBool glstack_realloc(CTXTc int,int);
01470 
01471 Cell build_codes_list(CTXTdeclc char *charptr) {
01472   int len = strlen(charptr);
01473 
01474   if (len == 0) {
01475     return makenil;
01476   } else {
01477     CPtr this_term, prev_tail;
01478     check_glstack_overflow(4,pcreg,2*sizeof(Cell)*len);
01479     this_term = hreg;
01480     cell(hreg++) = makeint((int)*charptr); charptr++;
01481     prev_tail = hreg++;
01482     while (*charptr != 0) {
01483       cell(prev_tail) = makelist(hreg);
01484       cell(hreg++) = makeint((int)*charptr); charptr++;
01485       prev_tail = hreg++;
01486     }
01487     cell(prev_tail) = makenil;
01488     return makelist(this_term);
01489   }
01490 }
01491 /*-----------------------------------------------------------------------------*/
01492 /*  FUNCTION NAME:*/
01493 /*     GetColumn() */
01494 /*  PARAMETERS:*/
01495 /*     R1: 5*/
01496 /*     R2: Cursor*/
01497 /*     R3: Column Index*/
01498 /*     R4: Column Value returned*/
01499 /*     R5: Return Code*/
01500 /*  NOTES:*/
01501 /*     get the indicated column.*/
01502 /*-----------------------------------------------------------------------------*/
01503 int GetColumn(CTXTdecl)
01504 {
01505   struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
01506   int ColCurNum = ptoc_int(CTXTc 3);
01507   Cell op = ptoc_tag(CTXTc 4);
01508   UDWORD len;
01509   if (ColCurNum < 0 || ColCurNum >= cur->NumCols) {
01510     /* no more columns in the result row*/
01511     ctop_int(CTXTc 5,1);
01512     return TRUE;
01513   }
01514   ctop_int(CTXTc 5,0);
01515 
01516   /* get the data*/
01517   if (cur->OutLen[ColCurNum] == SQL_NULL_DATA) {
01518     /* column value is NULL*/
01519     Cell nullterm = makecs(hreg);
01520     new_heap_functor(hreg,nullFctPsc);
01521     new_heap_free(hreg);
01522     if (isconstr(op) && get_arity(get_str_psc(op)) == 1) 
01523       /* for "string" and "term"... */
01524       return unify(CTXTc cell(clref_val(op)+1),nullterm);
01525     else return unify(CTXTc op,nullterm);
01526   }
01527 
01528   /* convert the string to either integer, float or string*/
01529   /* according to the column type and pass it back to XSB*/
01530   switch (ODBCToXSBType(cur->ColTypes[ColCurNum])) {
01531   case SQL_C_CHAR:
01532     /* convert the column string to a C string */
01533     len = ((cur->ColLen[ColCurNum] < cur->OutLen[ColCurNum])?
01534            cur->ColLen[ColCurNum]:cur->OutLen[ColCurNum]);
01535     *(cur->Data[ColCurNum]+len) = '\0';
01536 
01537     /* compare strings here, so don't intern strings unnecessarily*/
01538     XSB_Deref(op);
01539     if (isref(op))
01540       return unify(CTXTc op, makestring(string_find(cur->Data[ColCurNum],1)));
01541     if (isconstr(op) && get_arity(get_str_psc(op)) == 1) {
01542       if (!strcmp(get_name(get_str_psc(op)),"string")) {
01543         return unify(CTXTc cell(clref_val(ptoc_tag(CTXTc 4))+1),  /* op might have moved! */
01544                      build_codes_list(CTXTc cur->Data[ColCurNum]));
01545       } else {
01546         STRFILE strfile;
01547         
01548         strfile.strcnt = strlen(cur->Data[ColCurNum]);
01549         if (strfile.strcnt >= MAXVARSTRLEN-1)
01550           xsb_warn("[ODBC] Likely overflow of data in column of PROLOG_TERM type\n");
01551         strfile.strptr = strfile.strbase = cur->Data[ColCurNum];
01552         read_canonical_term(CTXTc NULL,&strfile,2); /* terminating '.'? */
01553         return TRUE;
01554       }
01555     }
01556     if (!isstring(op)) return FALSE;
01557     if (strcmp(string_val(op),cur->Data[ColCurNum])) return FALSE;
01558     return TRUE;
01559   case SQL_C_BINARY:
01560     /* convert the column string to a C string */
01561     len = ((cur->ColLen[ColCurNum] < cur->OutLen[ColCurNum])?
01562            cur->ColLen[ColCurNum]:cur->OutLen[ColCurNum]);
01563     *(cur->Data[ColCurNum]+len) = '\0';
01564 
01565     /* compare strings here, so don't intern strings unnecessarily*/
01566     XSB_Deref(op);
01567     if (isref(op))
01568       return unify(CTXTc op, makestring(string_find(cur->Data[ColCurNum],1)));
01569     if (isconstr(op) && get_arity(get_str_psc(op)) == 1) {
01570       if (!strcmp(get_name(get_str_psc(op)),"string")) {
01571         return unify(CTXTc cell(clref_val(ptoc_tag(CTXTc 4))+1),  /* op might have moved! */
01572                      build_codes_list(CTXTc cur->Data[ColCurNum]));
01573       } else {
01574         STRFILE strfile;
01575         
01576         strfile.strcnt = strlen(cur->Data[ColCurNum]);
01577         strfile.strptr = strfile.strbase = cur->Data[ColCurNum];
01578         read_canonical_term(CTXTc NULL,&strfile,2); /* terminating '.'? */
01579         return TRUE;
01580       }
01581     }
01582     if (!isstring(op)) return FALSE;
01583     if (strcmp(string_val(op),cur->Data[ColCurNum])) return FALSE;
01584     return TRUE;
01585   case SQL_C_SLONG:
01586     return unify(CTXTc op,makeint(*(long *)(cur->Data[ColCurNum])));
01587   case SQL_C_FLOAT:
01588     return unify(CTXTc op,makefloat(*(float *)(cur->Data[ColCurNum])));
01589   }
01590   return FALSE;
01591 }
01592 /*-----------------------------------------------------------------------------*/
01593 /*  FUNCTION NAME:*/
01594 /*     ODBCGetInfo() */
01595 /*  PARAMETERS:*/
01596 /*     R1: 18*/
01597 /*     R2: Connection Handle*/
01598 /*     R3: InfoType*/
01599 /*     R4: Info*/
01600 /*     R5: Return Code*/
01601 /*  NOTES:*/
01602 /*     Returns meta data information about the connection. Type of information */
01603 /*         available is detailed in ODBC API under the SQLGetInfo Function. The    */
01604 /*         information returned can be of type string or integer.  Return Code     */
01605 /*         values 0 means success, 1 is error getting the info, -1 is unkown       */
01606 /*         information type,-2 SQLGetInfo is not supported by the connection.      */
01607 /*                                                                                                                                                         */
01608 /*-----------------------------------------------------------------------------*/
01609 void ODBCGetInfo(CTXTdecl)
01610 {
01611   HDBC hdbc       = (HDBC) ptoc_int(CTXTc 2);
01612   SQLRETURN sqlrc = SQL_SUCCESS;
01613 
01614   SQLCHAR strValue[50];
01615   SQLUSMALLINT  supported;
01616   SQLRETURN retcode;
01617   SQLINTEGER nValue;
01618   SQLSMALLINT pcbValue;
01619 
01620   short int InfoType = ptoc_int(CTXTc 3);
01621   short int InfoTypeType = GetInfoTypeType(InfoType);
01622 
01623   /* check to see if SQLGetInfo() is supported */
01624   sqlrc = SQLGetFunctions(hdbc, SQL_API_SQLGETINFO, &supported);
01625 
01626   if (supported == SQL_TRUE)
01627   {
01628           switch(InfoTypeType) {
01629           case 0:
01630                 retcode = SQLGetInfo(hdbc, InfoType, strValue, 50, &pcbValue);
01631                 if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
01632             {
01633                         //printf("string type:%d:%s:%d\n",InfoType,strValue,pcbValue);
01634                         ctop_string(CTXTc 4,string_find(strValue,1));
01635                         ctop_int(CTXTc 5,0);
01636                 } else {
01637                         ctop_int(CTXTc 5,1);
01638                 }
01639                 break;
01640           case 1:
01641           case 2:
01642           case 3:
01643           case 4:
01644                 retcode = SQLGetInfo(hdbc, InfoType, &nValue, 0, &pcbValue);
01645                 if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
01646             {
01647                         //printf("int type:%d:%d:%d\n",InfoType,nValue,pcbValue);
01648                         ctop_int(CTXTc 4,nValue);
01649                         ctop_int(CTXTc 5,0);
01650                 } else {
01651                         ctop_int(CTXTc 5,1);
01652                 }
01653                 break;
01654           case -1:
01655           default:
01656                 ctop_int(CTXTc 5, -1);
01657                 break;
01658           }
01659   } else {
01660           ctop_int(CTXTc 5,-2);
01661   }
01662 }
01663 /*------------------------------------------------------------------------------*/
01664 /*  FUNCTION NAME:                                                              */
01665 /*     ODBCRowCount()                                                           */
01666 /*  PARAMETERS:                                                                 */
01667 /*     R1: 19                                                                   */
01668 /*     R2: Cursor                                                               */
01669 /*     R3: returned count                                                       */
01670 /*     R4: Return Code                                                          */
01671 /*  NOTES:                                                                      */
01672 /*     Returns the row-count value returned by the ODBC call to SQLRowCount.    */
01673 /*     This value is the count of rows affected by the immediately preceding    */
01674 /*     executed UPDATE, INSERT, or DELETE statement.                            */
01675 /*     Return Code is 0 for success, 1 error, ...                               */
01676 /*------------------------------------------------------------------------------*/
01677 void ODBCRowCount(CTXTdecl) {
01678   struct Cursor *cur = (struct Cursor *)ptoc_int(CTXTc 2);
01679   SQLINTEGER count;
01680   RETCODE rc;
01681 
01682   rc = SQLRowCount(cur->hstmt, &count);
01683   if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO)) {
01684     ctop_int(CTXTc 3, 0);
01685     ctop_int(CTXTc 4, PrintErrorMsg(cur));
01686     return;
01687   }
01688 
01689   ctop_int(CTXTc 3,count);
01690   ctop_int(CTXTc 4,0);
01691   return;
01692 }

Generated on Wed Jul 26 13:30:41 2006 for XSB by  doxygen 1.4.5