connect.c

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C语言 代码 · 共 1,242 行 · 第 1/2 页

C
1,242
字号
/*
 *  connect.c
 *
 *  $Id: connect.c,v 1.7 2000/01/20 13:19:20 GT Exp $
 *
 *  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)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?