git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@5545 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1242 lines
25 KiB
C
1242 lines
25 KiB
C
/*
|
|
* connect.c
|
|
*
|
|
* $Id$
|
|
*
|
|
* Connect (load) driver
|
|
*
|
|
* The iODBC driver manager.
|
|
*
|
|
* Copyright (C) 1995 by Ke Jin <kejin@empress.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "isql.h"
|
|
#include "isqlext.h"
|
|
|
|
#include "dlproc.h"
|
|
|
|
#include "herr.h"
|
|
#include "henv.h"
|
|
#include "hdbc.h"
|
|
#include "hstmt.h"
|
|
|
|
#include "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.5, Copyright(c) 1995 by Ke Jin";
|
|
|
|
/* - 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
|
|
*/
|
|
static RETCODE
|
|
_iodbcdm_driverload (
|
|
char FAR * path,
|
|
HDBC hdbc)
|
|
{
|
|
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;
|
|
|
|
/* This will either load the driver dll or increase its reference count */
|
|
hdll = _iodbcdm_dllopen ((char FAR *) path);
|
|
|
|
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
|
|
{
|
|
/*
|
|
* this will not unload the driver but only decrease its internal
|
|
* reference count
|
|
*/
|
|
_iodbcdm_dllclose (hdll);
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
/*
|
|
* this will not unload the driver but only decrease its internal
|
|
* reference count
|
|
*/
|
|
_iodbcdm_dllclose (hdll);
|
|
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;
|
|
}
|
|
|
|
|
|
/* - 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
|
|
*/
|
|
RETCODE
|
|
_iodbcdm_driverunload (HDBC hdbc)
|
|
{
|
|
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;
|
|
|
|
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 (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,
|
|
SQLHWND 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;
|
|
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 || drv != 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*)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 (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,
|
|
UCHAR FAR * szConnStrIn,
|
|
SWORD cbConnStrIn,
|
|
UCHAR FAR * szConnStrOut,
|
|
SWORD cbConnStrOutMax,
|
|
SWORD FAR * pcbConnStrOut)
|
|
{
|
|
DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
|
|
char FAR *drv;
|
|
char drvbuf[1024];
|
|
char FAR *dsn;
|
|
char dsnbuf[SQL_MAX_DSN_LENGTH + 1];
|
|
|
|
HPROC hproc;
|
|
|
|
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,
|
|
szConnStrIn, cbConnStrIn,
|
|
szConnStrOut, cbConnStrOutMax,
|
|
pcbConnStrOut))
|
|
|
|
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 (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);
|
|
}
|
|
|
|
/* 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))
|
|
|
|
return retcode;
|
|
}
|