]> git.saurik.com Git - wxWidgets.git/blobdiff - src/iodbc/connect.c
added ODBC support
[wxWidgets.git] / src / iodbc / connect.c
diff --git a/src/iodbc/connect.c b/src/iodbc/connect.c
new file mode 100644 (file)
index 0000000..c2f37e9
--- /dev/null
@@ -0,0 +1,1260 @@
+/** Connect(load) driver
+
+    Copyright (C) 1995 by Ke Jin <kejin@empress.com> 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+**/
+
+#include       <../iodbc/iodbc.h>
+
+#include       <../iodbc/isql.h>
+#include       <../iodbc/isqlext.h>
+
+#include        <../iodbc/dlproc.h>
+
+#include       <../iodbc/herr.h>
+#include       <../iodbc/henv.h>
+#include       <../iodbc/hdbc.h>
+#include       <../iodbc/hstmt.h>
+
+#include       <../iodbc/itrace.h>
+
+extern char*   _iodbcdm_getkeyvalbydsn();
+extern char*   _iodbcdm_getkeyvalinstr();
+extern RETCODE _iodbcdm_driverunload();
+
+/*
+ *   Following id string is a copyright mark. Removing(i.e. use 
+ *   souce code of this package without it or make it not appear 
+ *   in the final object file) or modifing it without permission 
+ *   from original author(kejin@empress.com) are copyright 
+ *   violation.
+ */
+static char sccsid[] 
+       = "@(#)iODBC driver manager " "2.12" ", Copyright(c) 1995 by Ke Jin";
+
+static RETCODE _iodbcdm_driverload( 
+                       char FAR*       path,   
+                       HDBC            hdbc )
+/* - Load driver share library( or increase its reference count 
+ *   if it has already been loaded by another active connection)
+ * - Call driver's SQLAllocEnv() (for the first reference only)
+ * - Call driver's SQLAllocConnect()
+ * - Call driver's SQLSetConnectOption() (set login time out)
+ * - Increase the bookkeeping reference count
+ */
+{
+       DBC_t  FAR*     pdbc = (DBC_t FAR*)hdbc;
+       GENV_t FAR*     genv; 
+       ENV_t  FAR*     penv = NULL;
+       HDLL            hdll;
+       HPROC           hproc;
+       RETCODE         retcode = SQL_SUCCESS;
+       int             sqlstat = en_00000;
+
+       if( path == NULL || path[0] == '\0' )
+       {
+               PUSHSQLERR ( pdbc->herr, en_IM002 );
+
+               return SQL_ERROR;
+       }
+
+       if( hdbc == SQL_NULL_HDBC 
+        || pdbc->genv == SQL_NULL_HENV )
+       {
+               return SQL_INVALID_HANDLE;
+       }
+
+       genv = (GENV_t FAR*)pdbc->genv;
+
+       hdll = _iodbcdm_dllopen( (char FAR*) path ); 
+                                /* This will either load the
+                                 * driver dll or increase its
+                                 * reference count */
+
+       if( hdll == SQL_NULL_HDLL )
+       {
+               PUSHSYSERR ( pdbc->herr, _iodbcdm_dllerror() );
+               PUSHSQLERR ( pdbc->herr, en_IM003 );
+               return SQL_ERROR;
+       }
+
+       penv = (ENV_t FAR*)(pdbc->henv);
+
+       if( penv != NULL )
+       {
+               if( penv->hdll != hdll )
+               {
+                       _iodbcdm_driverunload(hdbc);
+               }
+               else
+               {
+                       _iodbcdm_dllclose( hdll );
+                       /* this will not unload the driver
+                        * but only decrease its internal
+                        * reference count 
+                        */
+               }
+       }
+
+       if(penv == NULL )
+       {
+               /* find out whether this dll has already 
+                * been loaded on another connection */
+               for( penv  = (ENV_t FAR*)genv->henv;
+                    penv != NULL; 
+                    penv  = (ENV_t FAR*)penv->next )
+               {
+                       if( penv->hdll == hdll )
+                       {
+                               _iodbcdm_dllclose( hdll );
+                               /* this will not unload the driver
+                                * but only decrease its internal
+                                * reference count 
+                                */
+                               break;
+                       }
+               }
+       
+               if( penv == NULL )
+               /* no connection attaching with this dll */
+               {
+                       int     i;
+       
+                       /* create a new dll env instance */
+                       penv = (ENV_t FAR*)MEM_ALLOC ( sizeof(ENV_t) );
+       
+                       if( penv == NULL )
+                       {
+                               _iodbcdm_dllclose(hdll); 
+       
+                               PUSHSQLERR ( pdbc->herr, en_S1001 );
+       
+                               return SQL_ERROR;
+                       }
+       
+                       for( i = 0; i< SQL_EXT_API_LAST + 1; i++)
+                       {
+                               (penv->dllproc_tab)[i] = SQL_NULL_HPROC;
+                       }
+       
+                       pdbc->henv = penv;
+                       penv->hdll = hdll;
+       
+                       /* call driver's SQLAllocHandle() or SQLAllocEnv() */
+#if (ODBCVER >= 0x0300)
+                       hproc = _iodbcdm_getproc( hdbc, en_AllocHandle );
+
+                       if( hproc )
+                       {
+                               CALL_DRIVER ( hdbc, retcode, hproc, en_AllocHandle, 
+                                       ( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(penv->dhenv) )
+                       }
+                       else /* try driver's SQLAllocEnv() */
+#endif
+                       {
+                               hproc = _iodbcdm_getproc( hdbc, en_AllocEnv );
+
+                               if( hproc == SQL_NULL_HPROC)
+                               {
+                                       sqlstat = en_IM004;
+                               }
+                               else
+                               {
+                                       CALL_DRIVER ( hdbc, retcode, hproc, 
+                                       en_AllocEnv, (&(penv->dhenv)) ) 
+                               }
+                       }
+
+                       if( retcode == SQL_ERROR )
+                       {
+                               sqlstat = en_IM004;
+                       }
+
+                       if( sqlstat != en_00000 )
+                       {
+                               _iodbcdm_dllclose ( hdll );
+                               MEM_FREE ( penv );
+                               PUSHSQLERR ( pdbc->herr, en_IM004 );
+       
+                               return SQL_ERROR;
+                       }
+       
+                       /* insert into dll env list */
+                       penv->next = (ENV_t FAR*)genv->henv;
+                       genv->henv = penv;
+       
+                       /* initiate this new env entry */
+                       penv->refcount = 0;     /* we will increase it after
+                                                * driver's SQLAllocConnect()
+                                                * success
+                                                */
+               }
+       
+               pdbc->henv = penv;
+       
+               if( pdbc->dhdbc == SQL_NULL_HDBC )
+               {
+#if (ODBCVER >= 0x0300)
+                       hproc = _iodbcdm_getproc( hdbc, en_AllocHandle );
+
+                       if( hproc )
+                       {
+                               CALL_DRIVER( hdbc, retcode, hproc, en_AllocHandle,
+                               (SQL_HANDLE_DBC, penv->dhenv, &(pdbc->dhdbc)) )
+                       }
+                       else
+#endif
+                       {
+                               hproc = _iodbcdm_getproc( hdbc, en_AllocConnect );
+       
+                               if( hproc == SQL_NULL_HPROC )
+                               {
+                                       sqlstat = en_IM005;
+                               }
+                               else
+                               {
+                                       CALL_DRIVER ( hdbc, retcode, hproc, 
+                                       en_AllocConnect, (penv->dhenv, &(pdbc->dhdbc)) )
+                               }
+                       }
+
+                       if( retcode == SQL_ERROR )
+                       {
+                               sqlstat = en_IM005;
+                       }
+
+                       if( sqlstat != en_00000 )
+                       {
+                               _iodbcdm_driverunload(hdbc);
+       
+                               pdbc->dhdbc = SQL_NULL_HDBC;
+                               PUSHSQLERR ( pdbc->herr, en_IM005 );
+       
+                               return SQL_ERROR;
+                       }
+               }
+       
+               pdbc->henv = penv;
+               penv->refcount ++;  /* bookkeeping reference count on this driver */
+       }
+
+       /* driver's login timeout option must been set before 
+        * its SQLConnect() call */
+       if( pdbc->login_timeout != 0UL )
+       {
+               hproc = _iodbcdm_getproc( hdbc, en_SetConnectOption );
+
+               if( hproc == SQL_NULL_HPROC )
+               {
+                       sqlstat = en_IM004;
+               }
+               else
+               {
+                       CALL_DRIVER ( hdbc, retcode, hproc, 
+                       en_SetConnectOption, ( 
+                               pdbc->dhdbc, 
+                               SQL_LOGIN_TIMEOUT,
+                               pdbc->login_timeout ) )
+               
+                       if( retcode == SQL_ERROR )
+                       {
+                               PUSHSQLERR ( pdbc->herr, en_IM006 );
+
+                               return SQL_SUCCESS_WITH_INFO;
+                       }
+               }
+       }
+
+       return SQL_SUCCESS;
+}
+
+RETCODE        _iodbcdm_driverunload( HDBC     hdbc )
+/* - Call driver's SQLFreeConnect()
+ * - Call driver's SQLFreeEnv() ( for the last reference only)
+ * - Unload the share library( or decrease its reference
+ *   count if it is not the last referenct )
+ * - decrease bookkeeping reference count
+ * - state transition to allocated
+ */
+{
+       DBC_t  FAR*     pdbc = (DBC_t FAR*)hdbc;
+       ENV_t  FAR*     penv;
+       ENV_t  FAR*     tpenv;
+       GENV_t FAR*     genv;
+       HPROC           hproc;
+       RETCODE         retcode = SQL_SUCCESS;
+       int             sqlstat = en_00000;
+
+       if( hdbc == SQL_NULL_HDBC )
+       {
+               return SQL_INVALID_HANDLE;
+       }
+
+       /* no pointer check will be performed in this function */
+       penv = (ENV_t  FAR*)pdbc->henv;
+       genv = (GENV_t FAR*)pdbc->genv;
+
+       if( penv == NULL 
+        || penv->hdll == SQL_NULL_HDLL )
+       {
+               return SQL_SUCCESS;
+       }
+
+#if (ODBCVER >= 0x0300)
+       hproc = _iodbcdm_getproc( hdbc, en_FreeHandle );
+
+       if( hproc )
+       {
+               CALL_DRIVER ( hdbc, retcode, hproc, en_FreeHandle,
+                       ( SQL_HANDLE_DBC, pdbc->dhdbc ) )
+       }
+       else
+#endif
+       {
+               hproc = _iodbcdm_getproc( hdbc, en_FreeConnect );
+
+               if( hproc != SQL_NULL_HPROC )
+               {
+                       CALL_DRIVER ( hdbc, retcode, hproc, 
+                       en_FreeConnect, ( pdbc->dhdbc ) )
+
+                       pdbc->dhdbc = SQL_NULL_HDBC;
+               }
+       }
+
+       penv->refcount --;
+
+       if( ! penv->refcount )
+       /* no other connections still attaching with this driver */
+       {
+#if (ODBCVER >= 0x0300)
+               hproc = _iodbcdm_getproc( hdbc, en_FreeHandle );
+
+               if( hproc )
+               {
+                       CALL_DRIVER ( hdbc, retcode, hproc, en_FreeHandle,
+                               ( SQL_HANDLE_ENV, penv->dhenv ) )
+               }
+               else
+#endif
+               {
+                       hproc = _iodbcdm_getproc( hdbc, en_FreeEnv );
+
+                       if( hproc != SQL_NULL_HPROC )
+                       {
+                               CALL_DRIVER ( hdbc, retcode, hproc, en_FreeEnv, 
+                                               ( penv->dhenv ) )
+
+                               penv->dhenv = SQL_NULL_HENV;
+                       }
+               }
+
+               _iodbcdm_dllclose ( penv->hdll );
+
+               penv->hdll = SQL_NULL_HDLL; 
+
+               for( tpenv  = (ENV_t FAR*)genv->henv;
+                    tpenv != NULL;
+                    tpenv  = (ENV_t FAR*)penv->next )
+               {
+                       if( tpenv == penv )
+                       {
+                               genv->henv = penv->next;
+                               break;
+                       }
+       
+                       if( tpenv->next == penv )
+                       {
+                               tpenv->next = penv->next;
+                               break;
+                       }
+               }
+
+               MEM_FREE( penv );
+       }
+
+       pdbc->henv = SQL_NULL_HENV;     
+       pdbc->hstmt= SQL_NULL_HSTMT;
+       /* pdbc->herr = SQL_NULL_HERR; 
+               -- delay to DM's SQLFreeConnect() */ 
+       pdbc->dhdbc= SQL_NULL_HDBC;     
+       pdbc->state= en_dbc_allocated;  
+
+       /* set connect options to default values */
+       /**********
+       pdbc->access_mode       = SQL_MODE_DEFAULT;
+       pdbc->autocommit        = SQL_AUTOCOMMIT_DEFAULT;
+       pdbc->login_timeout     = 0UL;
+       **********/
+       pdbc->odbc_cursors      = SQL_CUR_DEFAULT;
+       pdbc->packet_size       = 0UL;
+       pdbc->quiet_mode        = (UDWORD)NULL;
+       pdbc->txn_isolation     = SQL_TXN_READ_UNCOMMITTED;
+
+       if( pdbc->current_qualifier != NULL )
+       {
+               MEM_FREE ( pdbc->current_qualifier );
+               pdbc->current_qualifier = NULL;
+       }
+
+       return SQL_SUCCESS;
+}
+
+static RETCODE _iodbcdm_dbcdelayset( HDBC hdbc )
+{
+       DBC_t FAR*      pdbc    = (DBC_t FAR*)hdbc;
+       ENV_t FAR*      penv;
+       HPROC           hproc;
+       RETCODE         retcode = SQL_SUCCESS;
+       RETCODE         ret;
+
+       penv = pdbc->henv;
+
+       hproc = _iodbcdm_getproc( hdbc, en_SetConnectOption );
+
+       if( hproc == SQL_NULL_HPROC )
+       {
+               PUSHSQLERR ( pdbc->herr, en_IM006 );
+
+               return SQL_SUCCESS_WITH_INFO;
+       }
+
+       if( pdbc->access_mode != SQL_MODE_DEFAULT )
+       {
+               CALL_DRIVER ( hdbc, ret, hproc, 
+                       en_SetConnectOption, ( 
+                               SQL_ACCESS_MODE, 
+                               pdbc->access_mode) )
+
+               retcode |= ret;
+       }
+
+       if( pdbc->autocommit != SQL_AUTOCOMMIT_DEFAULT )
+       {
+               CALL_DRIVER ( hdbc, ret, hproc, 
+                       en_SetConnectOption, (
+                               pdbc->dhdbc,
+                               SQL_AUTOCOMMIT,
+                               pdbc->autocommit ) )
+
+               retcode |= ret;
+       }
+
+       if( pdbc->current_qualifier != NULL )
+       {
+               CALL_DRIVER ( hdbc, ret, hproc, 
+                       en_SetConnectOption, (
+                               pdbc->dhdbc,
+                               SQL_CURRENT_QUALIFIER,
+                               pdbc->current_qualifier ) )
+
+               retcode |= ret;
+       }
+
+       if( pdbc->packet_size != 0UL )
+       {
+               CALL_DRIVER ( hdbc, ret, hproc,
+                       en_SetConnectOption, (
+                               pdbc->dhdbc,
+                               SQL_PACKET_SIZE,
+                               pdbc->packet_size ) )
+
+               retcode |= ret;
+       }
+
+       if( pdbc->quiet_mode != (UDWORD)NULL )
+       {
+               CALL_DRIVER ( hdbc, ret, hproc, 
+                       en_SetConnectOption, (
+                               pdbc->dhdbc,
+                               SQL_QUIET_MODE,
+                               pdbc->quiet_mode ) )
+
+               retcode |= ret;
+       }
+
+       if( pdbc->txn_isolation != SQL_TXN_READ_UNCOMMITTED )
+       {
+               CALL_DRIVER ( hdbc, ret, hproc,
+                       en_SetConnectOption, (
+                               pdbc->dhdbc,
+                               SQL_TXN_ISOLATION,
+                               pdbc->txn_isolation ) )
+       }
+
+       /* check error code for driver's SQLSetConnectOption() call */
+       if( retcode != SQL_SUCCESS 
+        && retcode != SQL_SUCCESS_WITH_INFO )
+       {
+               PUSHSQLERR ( pdbc->herr, en_IM006 );
+
+               retcode = SQL_ERROR;
+       }
+
+       /* get cursor behavior on transaction commit or rollback */
+       hproc = _iodbcdm_getproc( hdbc, en_GetInfo );
+
+       if( hproc == SQL_NULL_HPROC )
+       {
+               PUSHSQLERR ( pdbc->herr, en_01000 );
+
+               return retcode;
+       }
+
+       CALL_DRIVER ( hdbc, ret, hproc,
+               en_GetInfo, (
+                       pdbc->dhdbc, 
+                       SQL_CURSOR_COMMIT_BEHAVIOR,
+                       (PTR)&(pdbc->cb_commit),
+                       sizeof(pdbc->cb_commit),
+                       NULL ) )
+
+       retcode |= ret;
+
+       CALL_DRIVER ( hdbc, ret, hproc,
+               en_GetInfo, (
+                       pdbc->dhdbc,
+                       SQL_CURSOR_ROLLBACK_BEHAVIOR,
+                       (PTR)&(pdbc->cb_rollback),
+                       sizeof(pdbc->cb_rollback),
+                       NULL ) )
+
+       retcode |= ret;
+
+       if( retcode != SQL_SUCCESS
+        && retcode != SQL_SUCCESS_WITH_INFO )
+       {
+               return SQL_ERROR;
+       }
+
+       return retcode;
+}
+
+static RETCODE _iodbcdm_settracing( HDBC hdbc, char* dsn, int dsnlen )
+{
+       char    buf[256];
+       char*   ptr;
+       RETCODE setopterr = SQL_SUCCESS;
+
+       /* Get Driver's DLL path from specificed or default dsn section */
+       ptr = _iodbcdm_getkeyvalbydsn( dsn, dsnlen, "TraceFile",
+                               (char FAR*)buf, sizeof(buf));
+
+       if( ptr == NULL || ptr[0] == '\0' )
+       {
+               ptr = (char FAR*)(SQL_OPT_TRACE_FILE_DEFAULT);
+       }
+
+       setopterr |= SQLSetConnectOption( hdbc, 
+               SQL_OPT_TRACEFILE, (UDWORD)(ptr));
+
+       ptr = _iodbcdm_getkeyvalbydsn( dsn, dsnlen, "Trace",
+                               (char FAR*)buf, sizeof(buf));
+
+       if( ptr != NULL )
+       {
+               UDWORD  opt = (UDWORD)(-1L);
+
+               if( STREQ(ptr, "ON") 
+                || STREQ(ptr, "On") 
+                || STREQ(ptr, "on") 
+                || STREQ(ptr, "1" ) )
+               {
+                       opt = SQL_OPT_TRACE_ON;
+               }
+
+               if( STREQ(ptr, "OFF") 
+                || STREQ(ptr, "Off")
+                || STREQ(ptr, "off") 
+                || STREQ(ptr, "0"  ) )
+               {
+                       opt = SQL_OPT_TRACE_OFF;
+               }
+
+               if( opt != (UDWORD)(-1L) )
+               {
+                       setopterr |= SQLSetConnectOption( hdbc, 
+                               SQL_OPT_TRACE, opt);
+               }
+       }
+
+    return setopterr;
+}
+
+RETCODE SQL_API        SQLConnect (
+                       HDBC            hdbc,
+                       UCHAR FAR*      szDSN,
+                       SWORD           cbDSN,
+                       UCHAR FAR*      szUID,
+                       SWORD           cbUID,
+                       UCHAR FAR*      szAuthStr,
+                       SWORD           cbAuthStr)
+{
+       DBC_t  FAR*     pdbc    = (DBC_t FAR*)hdbc;
+       RETCODE         retcode = SQL_SUCCESS;
+       RETCODE         setopterr = SQL_SUCCESS;
+       char            driver[1024] = { '\0' }; /* MS SDK Guide 
+                                                 * specifies driver
+                                                 * path can't longer
+                                                 * than 255. */
+       char            *ptr;
+       HPROC           hproc;
+       
+       if( hdbc == SQL_NULL_HDBC )
+       {
+               return SQL_INVALID_HANDLE;
+       }
+
+       /* check arguments */
+       if( ( cbDSN < 0 && cbDSN != SQL_NTS )
+        || ( cbUID < 0 && cbUID != SQL_NTS )
+        || ( cbAuthStr < 0 && cbAuthStr != SQL_NTS )
+        || ( cbDSN > SQL_MAX_DSN_LENGTH ) )
+       {
+               PUSHSQLERR ( pdbc->herr, en_S1090 );
+
+               return SQL_ERROR;
+       }
+
+       if( szDSN == NULL || cbDSN == 0 )
+       {
+               PUSHSQLERR ( pdbc->herr, en_IM002 );
+               
+               return SQL_ERROR;
+       }
+
+       /* check state */
+       if( pdbc->state != en_dbc_allocated )
+       {
+               PUSHSQLERR ( pdbc->herr, en_08002 );
+
+               return SQL_ERROR;
+       }
+
+       setopterr |= _iodbcdm_settracing( hdbc, 
+                               (char*)szDSN, cbDSN );
+
+       ptr = _iodbcdm_getkeyvalbydsn( szDSN, cbDSN, "Driver", 
+                               (char FAR*)driver, sizeof(driver));
+
+       if( ptr == NULL )
+       /* No specified or default dsn section or
+        * no driver specification in this dsn section */
+       {
+               PUSHSQLERR ( pdbc->herr, en_IM002 );
+
+               return SQL_ERROR;
+       }
+
+       retcode = _iodbcdm_driverload( driver, hdbc );
+
+       switch( retcode )
+       {
+               case SQL_SUCCESS:
+                       break;
+
+               case SQL_SUCCESS_WITH_INFO:
+                       setopterr = SQL_ERROR;
+                       /* unsuccessed in calling driver's 
+                        * SQLSetConnectOption() to set login
+                        * timeout.
+                        */
+                       break;
+
+               default:
+                       return retcode;
+       }
+
+       hproc = _iodbcdm_getproc( hdbc, en_Connect );
+
+       if( hproc == SQL_NULL_HPROC )
+       {
+               _iodbcdm_driverunload( hdbc );
+
+               PUSHSQLERR ( pdbc->herr, en_IM001 );
+
+               return SQL_ERROR;
+       }
+
+       CALL_DRIVER ( hdbc, retcode, hproc, en_Connect, (
+                       pdbc->dhdbc, 
+                       szDSN,     cbDSN,
+                       szUID,     cbUID,
+                       szAuthStr, cbAuthStr ) )
+
+#if 0
+       retcode = hproc(pdbc->dhdbc, 
+                       szDSN,     cbDSN,
+                       szUID,     cbUID,
+                       szAuthStr, cbAuthStr );
+#endif
+
+       if( retcode != SQL_SUCCESS 
+        && retcode != SQL_SUCCESS_WITH_INFO )
+       {
+               /* not unload driver for retrive error 
+                * messge from driver */
+               /*********
+               _iodbcdm_driverunload( hdbc );
+               **********/
+
+               return retcode;
+       }
+
+       /* state transition */
+       pdbc->state = en_dbc_connected;
+
+       /* do delaid option setting */
+       setopterr |= _iodbcdm_dbcdelayset( hdbc );
+
+       if( setopterr != SQL_SUCCESS )
+       {
+               return SQL_SUCCESS_WITH_INFO;
+       }
+
+       return retcode;
+}
+       
+RETCODE SQL_API        SQLDriverConnect (
+                       HDBC            hdbc,
+                       HWND            hwnd,
+                       UCHAR FAR*      szConnStrIn,
+                       SWORD           cbConnStrIn,
+                       UCHAR FAR*      szConnStrOut,
+                       SWORD           cbConnStrOutMax,
+                       SWORD FAR*      pcbConnStrOut,
+                       UWORD           fDriverCompletion )
+{
+       DBC_t FAR*      pdbc    = (DBC_t FAR*)hdbc;
+       HDLL            hdll;
+       char  FAR*      drv;
+       char            drvbuf[1024];
+       char  FAR*      dsn;
+       char            dsnbuf[SQL_MAX_DSN_LENGTH + 1];
+       UCHAR           cnstr2drv[1024];
+
+       HPROC           hproc, dialproc;
+
+       int             sqlstat = en_00000;
+       RETCODE         retcode = SQL_SUCCESS;
+       RETCODE         setopterr = SQL_SUCCESS;
+
+       if( hdbc == SQL_NULL_HDBC )
+       {
+               return SQL_INVALID_HANDLE;
+       }
+
+       /* check arguments */
+       if( ( cbConnStrIn < 0 && cbConnStrIn != SQL_NTS )
+        || cbConnStrOutMax < 0 )
+       {
+               PUSHSQLERR (pdbc->herr, en_S1090 );
+
+               return SQL_ERROR;
+       }
+
+       /* check state */
+       if( pdbc->state != en_dbc_allocated )
+       {
+               PUSHSQLERR (pdbc->herr, en_08002 );
+
+               return SQL_ERROR;
+       }
+
+       drv = _iodbcdm_getkeyvalinstr(szConnStrIn, cbConnStrIn, 
+                               "DRIVER", drvbuf, sizeof(drvbuf));
+
+       dsn = _iodbcdm_getkeyvalinstr(szConnStrIn, cbConnStrIn,
+                               "DSN",    dsnbuf, sizeof(dsnbuf));
+
+       switch( fDriverCompletion )
+       {
+               case SQL_DRIVER_NOPROMPT:
+                       break;
+
+               case SQL_DRIVER_COMPLETE:
+               case SQL_DRIVER_COMPLETE_REQUIRED:
+                       if( dsn != NULL )
+                       {
+                               break;
+                       }
+                       /* fall to next case */
+               case SQL_DRIVER_PROMPT:
+                       /* Get data source dialog box function from
+                        * current executable */
+                       hdll = _iodbcdm_dllopen((char FAR*)NULL);
+                       dialproc = _iodbcdm_dllproc( hdll, 
+                                       "_iodbcdm_drvconn_dialbox");
+
+                       if( dialproc == SQL_NULL_HPROC )
+                       {
+                               sqlstat = en_IM008;
+                               break;
+                       }
+
+                       retcode = dialproc( 
+                                       hwnd,   /* window or display handle */
+                                       dsnbuf, /* input/output dsn buf */
+                                       sizeof(dsnbuf), /* buf size */
+                                       &sqlstat);      /* error code */
+
+                       if( retcode != SQL_SUCCESS )
+                       {
+                               break;
+                       }
+                       
+                       if( cbConnStrIn == SQL_NTS )
+                       {
+                               cbConnStrIn = STRLEN(szConnStrIn );
+                       }
+
+                       dsn = dsnbuf;
+
+                       if( dsn[0] == '\0' )
+                       {
+                               dsn = "default";
+                       }
+
+                       if( cbConnStrIn > sizeof(cnstr2drv) 
+                                       - STRLEN(dsn) - STRLEN("DSN=;") -1 )
+                       {
+                               sqlstat = en_S1001; /* a lazy way to avoid
+                                                    * using heap memory */
+                               break;
+                       }
+
+                       sprintf( (char FAR *)cnstr2drv, "DSN=%s;", dsn);
+                       cbConnStrIn += STRLEN(cnstr2drv);
+                       STRNCAT( cnstr2drv, szConnStrIn, cbConnStrIn );
+                       szConnStrIn = cnstr2drv;
+                       break;
+
+               default:
+                       sqlstat = en_S1110;
+                       break;
+       }
+
+       if( sqlstat != en_00000 )
+       {
+               PUSHSQLERR( pdbc->herr, sqlstat );
+               
+               return SQL_ERROR;
+       }
+
+       if( dsn == NULL || dsn[0] == '\0' )
+       {
+               dsn = "default";
+       }
+       else    /* if you want tracing, you must use a DSN */
+       {
+               setopterr |= _iodbcdm_settracing( hdbc, 
+                                       (char*)dsn, SQL_NTS );
+       }
+
+       if( drv == NULL || drv[0] == '\0' )
+       {
+               drv = _iodbcdm_getkeyvalbydsn( dsn, SQL_NTS, "Driver", 
+                                       drvbuf, sizeof(drvbuf));
+       }
+
+       if( drv == NULL )
+       {
+               PUSHSQLERR( pdbc->herr, en_IM002 );
+
+               return SQL_ERROR;
+       }
+
+       retcode = _iodbcdm_driverload( drv, hdbc );
+
+       switch( retcode )
+       {
+               case SQL_SUCCESS:
+                       break;
+
+               case SQL_SUCCESS_WITH_INFO:
+                       setopterr = SQL_ERROR;
+                       /* unsuccessed in calling driver's 
+                        * SQLSetConnectOption() to set login
+                        * timeout.
+                        */
+                       break;
+
+               default:
+                       return retcode;
+       }
+
+       hproc = _iodbcdm_getproc( hdbc, en_DriverConnect );
+
+       if( hproc == SQL_NULL_HPROC )
+       {
+               _iodbcdm_driverunload( hdbc );
+
+               PUSHSQLERR ( pdbc->herr, en_IM001 );
+
+               return SQL_ERROR;
+       }
+       
+       CALL_DRIVER ( hdbc, retcode, hproc, en_DriverConnect, (
+                       pdbc->dhdbc, hwnd,
+                       szConnStrIn, cbConnStrIn,
+                       szConnStrOut, cbConnStrOutMax,
+                       pcbConnStrOut, fDriverCompletion ) )
+
+#if 0
+       retcode = hproc(pdbc->dhdbc, hwnd,
+                       szConnStrIn, cbConnStrIn,
+                       szConnStrOut, cbConnStrOutMax,
+                       pcbConnStrOut, fDriverCompletion );
+#endif
+
+       if( retcode != SQL_SUCCESS 
+        && retcode != SQL_SUCCESS_WITH_INFO )
+       {
+               /* don't unload driver here for retrive 
+                * error message from driver */
+               /********
+               _iodbcdm_driverunload( hdbc );
+               *********/
+
+               return retcode;
+       }
+
+       /* state transition */
+       pdbc->state = en_dbc_connected;
+
+       /* do delaid option setting */
+       setopterr |= _iodbcdm_dbcdelayset( hdbc );
+
+       if( setopterr != SQL_SUCCESS )
+       {
+               return SQL_SUCCESS_WITH_INFO;
+       }
+
+       return retcode;
+}
+
+RETCODE SQL_API        SQLBrowseConnect ( 
+                       HDBC            hdbc,
+                       HWND            hwnd,
+                       UCHAR FAR*      szConnStrIn,
+                       SWORD           cbConnStrIn,
+                       UCHAR FAR*      szConnStrOut,
+                       SWORD           cbConnStrOutMax,
+                       SWORD FAR*      pcbConnStrOut )
+{
+       DBC_t FAR*      pdbc    = (DBC_t FAR*)hdbc;
+       HDLL            hdll;
+       char  FAR*      drv;
+       char            drvbuf[1024];
+       char  FAR*      dsn;
+       char            dsnbuf[SQL_MAX_DSN_LENGTH + 1];
+       UCHAR           cnstr2drv[1024];
+
+       HPROC           hproc, dialproc;
+
+       int             sqlstat = en_00000;
+       RETCODE         retcode = SQL_SUCCESS;
+       RETCODE         setopterr = SQL_SUCCESS;
+
+       if( hdbc == SQL_NULL_HDBC )
+       {
+               return SQL_INVALID_HANDLE;
+       }
+
+       /* check arguments */
+       if( ( cbConnStrIn < 0 && cbConnStrIn != SQL_NTS )
+        || cbConnStrOutMax < 0 )
+       {
+               PUSHSQLERR (pdbc->herr, en_S1090 );
+
+               return SQL_ERROR;
+       }
+
+       if( pdbc->state == en_dbc_allocated )
+       {
+               drv = _iodbcdm_getkeyvalinstr(szConnStrIn, cbConnStrIn, 
+                               "DRIVER", drvbuf, sizeof(drvbuf));
+       
+               dsn = _iodbcdm_getkeyvalinstr(szConnStrIn, cbConnStrIn,
+                               "DSN",    dsnbuf, sizeof(dsnbuf));
+       
+               if( dsn == NULL || dsn[0] == '\0' )
+               {
+                       dsn = "default";
+               }
+               else    /* if you want tracing, you must use a DSN */
+               {
+                       setopterr |= _iodbcdm_settracing( hdbc, 
+                                               (char*)dsn, SQL_NTS );
+               }
+       
+               if( drv == NULL || drv[0] == '\0' )
+               {
+                       drv = _iodbcdm_getkeyvalbydsn( dsn, SQL_NTS, "Driver", 
+                                               drvbuf, sizeof(drvbuf));
+               }
+       
+               if( drv == NULL )
+               {
+                       PUSHSQLERR( pdbc->herr, en_IM002 );
+       
+                       return SQL_ERROR;
+               }
+       
+               retcode = _iodbcdm_driverload( drv, hdbc );
+       
+               switch( retcode )
+               {
+                       case SQL_SUCCESS:
+                               break;
+       
+                       case SQL_SUCCESS_WITH_INFO:
+                               setopterr = SQL_ERROR;
+                               /* unsuccessed in calling driver's 
+                                * SQLSetConnectOption() to set login
+                                * timeout.
+                                */
+                               break;
+       
+                       default:
+                               return retcode;
+               }
+       }
+       else if( pdbc->state != en_dbc_needdata )
+       {
+               PUSHSQLERR ( pdbc->herr, en_08002 );
+
+               return SQL_ERROR;
+       }
+
+       hproc = _iodbcdm_getproc( hdbc, en_BrowseConnect);
+
+       if( hproc == SQL_NULL_HPROC )
+       {
+               _iodbcdm_driverunload( hdbc );
+
+               pdbc->state = en_dbc_allocated;
+
+               PUSHSQLERR( pdbc->herr, en_IM001 );
+
+               return SQL_ERROR;
+       }
+
+       CALL_DRIVER ( hdbc, retcode, hproc, en_BrowseConnect, (
+                       pdbc->dhdbc, hwnd,
+                       szConnStrIn, cbConnStrIn,
+                       szConnStrOut, cbConnStrOutMax,
+                       pcbConnStrOut ) )
+
+#if 0 
+       retcode = hproc(pdbc->dhdbc, hwnd,
+                       szConnStrIn, cbConnStrIn,
+                       szConnStrOut, cbConnStrOutMax,
+                       pcbConnStrOut );
+#endif
+
+       switch( retcode )
+       {
+               case SQL_SUCCESS: 
+               case SQL_SUCCESS_WITH_INFO:
+                       pdbc->state = en_dbc_connected;
+                       setopterr |= _iodbcdm_dbcdelayset( hdbc );
+                       if( setopterr != SQL_SUCCESS )
+                       {
+                               retcode = SQL_SUCCESS_WITH_INFO;
+                       }
+                       break;
+
+               case SQL_NEED_DATA:
+                       pdbc->state = en_dbc_needdata;
+                       break;
+
+               case SQL_ERROR:
+                       pdbc->state = en_dbc_allocated;
+                       /* but the driver will not unloaded 
+                        * to allow application retrive err
+                        * message from driver 
+                        */
+                       break;
+
+               default:
+                       break;
+       }
+
+       return retcode;
+}
+
+RETCODE SQL_API        SQLDisconnect ( HDBC hdbc )
+{
+       DBC_t   FAR*    pdbc    = (DBC_t*)hdbc;
+       STMT_t  FAR*    pstmt;
+       RETCODE         retcode;
+       HPROC           hproc;
+
+       int             sqlstat = en_00000;
+
+       if( hdbc == SQL_NULL_HDBC )
+       {
+               return SQL_INVALID_HANDLE;
+       }
+
+       /* check hdbc state */
+       if ( pdbc->state == en_dbc_allocated )
+       {
+               sqlstat = en_08003;
+       }
+
+       /* check stmt(s) state */
+       for( pstmt  = (STMT_t FAR*)pdbc->hstmt;
+            pstmt != NULL && sqlstat == en_00000;
+            pstmt  = (STMT_t FAR*)pstmt->next )
+       {
+               if( pstmt->state >= en_stmt_needdata 
+                || pstmt->asyn_on != en_NullProc )
+               /* In this case one need to call 
+                * SQLCancel() first */
+               {
+                       sqlstat = en_S1010;
+               }
+       }
+
+       if( sqlstat == en_00000 )
+       {
+               hproc = _iodbcdm_getproc( hdbc, en_Disconnect );
+
+               if( hproc == SQL_NULL_HPROC )
+               {
+                       sqlstat = en_IM001;
+               }
+       }
+
+       if( sqlstat != en_00000 )
+       {
+               PUSHSQLERR ( pdbc->herr, sqlstat );
+
+               return SQL_ERROR;
+       }
+       
+       CALL_DRIVER ( hdbc, retcode, hproc, en_Disconnect, (
+                       pdbc->dhdbc ) )
+
+#if 0
+       retcode = hproc( pdbc->dhdbc );
+#endif
+
+       if( retcode == SQL_SUCCESS
+        || retcode == SQL_SUCCESS_WITH_INFO )
+       {
+               /* diff from MS specs. We disallow
+                * driver SQLDisconnect() return
+                * SQL_SUCCESS_WITH_INFO and post
+                * error message.
+                */
+               retcode = SQL_SUCCESS;
+       }
+       else
+       {
+               return retcode;
+       }
+
+       /* free all statement handle(s) on this connection */
+       for(;pdbc->hstmt;)
+       {
+               _iodbcdm_dropstmt( pdbc->hstmt );
+       }
+
+#if 0
+       retcode = _iodbcdm_driverunload( hdbc );
+#endif
+
+       /* state transition */
+       if( retcode == SQL_SUCCESS )
+       {
+               pdbc->state = en_dbc_allocated;
+       }
+
+       return retcode;
+}
+
+RETCODE SQL_API        SQLNativeSql(
+                       HDBC            hdbc,
+                       UCHAR  FAR*     szSqlStrIn,
+                       SDWORD          cbSqlStrIn,
+                       UCHAR  FAR*     szSqlStr,
+                       SDWORD          cbSqlStrMax,
+                       SDWORD FAR*     pcbSqlStr )
+{
+       DBC_t FAR*      pdbc    = (DBC_t FAR*)hdbc;
+       HPROC           hproc;
+       int             sqlstat = en_00000;
+       RETCODE         retcode;
+       
+       if( hdbc == SQL_NULL_HDBC )
+       {
+               return SQL_INVALID_HANDLE;
+       }
+
+       /* check argument */
+       if( szSqlStrIn == NULL )
+       {
+               sqlstat = en_S1009;
+       }
+       else if( cbSqlStrIn < 0
+             && cbSqlStrIn != SQL_NTS )
+       {
+               sqlstat = en_S1090;
+       }
+
+       if( sqlstat != en_00000 )
+       {
+               PUSHSQLERR ( pdbc->herr, sqlstat );
+
+               return SQL_ERROR;
+       }
+
+       /* check state */
+       if( pdbc->state <= en_dbc_needdata )
+       {
+               PUSHSQLERR ( pdbc->herr, en_08003 );
+
+               return SQL_ERROR;
+       }
+
+       /* call driver */
+       hproc = _iodbcdm_getproc( hdbc, en_NativeSql );
+
+       if( hproc == SQL_NULL_HPROC )
+       {
+               PUSHSQLERR ( pdbc->herr, en_IM001 );
+
+               return SQL_ERROR;
+       }
+
+       CALL_DRIVER ( hdbc, retcode, hproc, en_NativeSql, (
+                       pdbc->dhdbc,
+                       szSqlStrIn,
+                       cbSqlStrIn,
+                       szSqlStr,
+                       cbSqlStrMax,
+                       pcbSqlStr ) )
+
+#if 0
+       retcode = hproc(pdbc->dhdbc,
+                       szSqlStrIn,
+                       cbSqlStrIn,
+                       szSqlStr,
+                       cbSqlStrMax,
+                       pcbSqlStr );
+#endif
+
+       return retcode;
+}