+/** 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;
+}