⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbxodbc.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*						 cryptlib ODBC Mapping Routines						*
*						Copyright Peter Gutmann 1996-2002					*
*																			*
****************************************************************************/

/* ODBC supports a primitive type of background processing, but the level of
   granularity leaves something to be desired since it's done on a per-call
   basis so if you're performing something like SQLExecute(), SQLParamData(),
   SQLPutData() you have to wait for each one to complete before you can call
   the next one.  In addition there isn't any nice wait mechanism, any
   further calls to anything will return SQL_STILL_EXECUTING until the
   function you called has finished (rather than queueing a series of
   requests).  Also, the really slow calls like SQLConnect() are all
   synchronous.  Because of this we don't even try to use any async calls, if
   background processing is needed we do it using Win32 threads */

#include <stdio.h>
#include <string.h>
#include <time.h>
#include "../crypt.h"
#include "keyset.h"

/****************************************************************************
*																			*
*						 		Init/Shutdown Routines						*
*																			*
****************************************************************************/

/* MSDN updates from late 2000 defined SQLROWCOUNT themselves so we need to
   rename our version to allow the following code to compile */

#define SQLROWCOUNT		XSQLROWCOUNT

/* Global function pointers.  These are necessary because the functions need
   to be dynamically linked since not all systems contain the necessary
   DLL's.  Explicitly linking to them will make cryptlib unloadable on some
   systems */

#define NULL_HINSTANCE	( HINSTANCE ) NULL

static HINSTANCE hODBC = NULL_HINSTANCE;

typedef RETCODE ( SQL_API *SQLALLOCENV )( HENV FAR *phenv );
typedef RETCODE ( SQL_API *SQLALLOCCONNECT )( HENV henv, HDBC FAR *phdbc );
typedef RETCODE ( SQL_API *SQLALLOCSTMT )( HDBC hdbc, HSTMT FAR *phstmt );
typedef RETCODE ( SQL_API *SQLBINDPARAMETER )( HSTMT hstmt, UWORD ipar,
				  SWORD fParamType, SWORD fCType, SWORD fSqlType,
				  UDWORD cbColDef, SWORD ibScale, PTR rgbValue,
				  SDWORD cbValueMax, SDWORD FAR *pcbValue );
typedef RETCODE ( SQL_API *SQLCANCEL )( HSTMT hstmt );
typedef RETCODE ( SQL_API *SQLCONNECT )( HDBC hdbc, UCHAR FAR *szDSN,
				  SWORD cdDSN, UCHAR FAR *szUID, SWORD cbUID,
				  UCHAR FAR *szAuthStr, SWORD cbAuthStr );
typedef RETCODE ( SQL_API *SQLDISCONNECT )( HDBC hdbc );
typedef RETCODE ( SQL_API *SQLERROR )( HENV henv, HDBC hdbc, HSTMT hstmt,
				  UCHAR FAR *szSqlState, SDWORD FAR *pfNativeError,
				  UCHAR FAR *szErrorMsg, SWORD cbErrorMsgMax,
				  SWORD FAR *pcbErrorMsg );
typedef RETCODE ( SQL_API *SQLEXECDIRECT )( HSTMT hstmt, UCHAR FAR *szSqlStr,
				  SDWORD cbSqlStr );
typedef RETCODE ( SQL_API *SQLEXECUTE )( HSTMT hstmt );
typedef RETCODE ( SQL_API *SQLFETCH )( HSTMT hstmt );
typedef RETCODE ( SQL_API *SQLFREECONNECT )( HDBC hdbc );
typedef RETCODE ( SQL_API *SQLFREEENV )( HENV henv );
typedef RETCODE ( SQL_API *SQLFREESTMT )( HSTMT hstmt, UWORD fOption );
typedef RETCODE ( SQL_API *SQLGETDATA )( HSTMT hstmt, UWORD icol,
				  SWORD fCType, PTR rgbValue, SDWORD cbValueMax,
				  SDWORD FAR *pcbValue );
typedef RETCODE ( SQL_API *SQLGETINFO )( HDBC hdbc, UWORD fInfoType,
				  PTR rgbInfoValue, SWORD cbInfoValueMax,
				  SWORD FAR *pcbInfoValue );
typedef RETCODE ( SQL_API *SQLGETTYPEINFO )( HSTMT hstmt, SWORD fSqlType );
typedef RETCODE ( SQL_API *SQLPARAMDATA )( HSTMT hstmt, PTR FAR *prgbValue );
typedef RETCODE ( SQL_API *SQLPREPARE )( HSTMT hstmt, UCHAR FAR *szSqlStr,
				  SDWORD cbSqlStr );
typedef RETCODE ( SQL_API *SQLPUTDATA )( HSTMT hstmt, PTR rgbValue,
				  SDWORD cbValue );
typedef RETCODE ( SQL_API *SQLROWCOUNT )( HSTMT hstmt, SDWORD *cbRowCount );
typedef RETCODE ( SQL_API *SQLSETCONNECTOPTION )( HDBC hdbc, UWORD fOption,
				  UDWORD vParam );
typedef RETCODE ( SQL_API *SQLSETSTMTOPTION )( HSTMT hstmt, UWORD fOption,
				  UDWORD vParam );
typedef RETCODE ( SQL_API *SQLTRANSACT )( HENV henv, HDBC hdbc, UWORD fType );
static SQLALLOCCONNECT pSQLAllocConnect = NULL;
static SQLALLOCENV pSQLAllocEnv = NULL;
static SQLALLOCSTMT pSQLAllocStmt = NULL;
static SQLBINDPARAMETER pSQLBindParameter = NULL;
static SQLCANCEL pSQLCancel = NULL;
static SQLCONNECT pSQLConnect = NULL;
static SQLDISCONNECT pSQLDisconnect = NULL;
static SQLERROR pSQLError = NULL;
static SQLEXECDIRECT pSQLExecDirect = NULL;
static SQLEXECUTE pSQLExecute = NULL;
static SQLFETCH pSQLFetch = NULL;
static SQLFREECONNECT pSQLFreeConnect = NULL;
static SQLFREEENV pSQLFreeEnv = NULL;
static SQLFREESTMT pSQLFreeStmt = NULL;
static SQLGETDATA pSQLGetData = NULL;
static SQLGETINFO pSQLGetInfo = NULL;
static SQLGETTYPEINFO pSQLGetTypeInfo = NULL;
static SQLPARAMDATA pSQLParamData = NULL;
static SQLPREPARE pSQLPrepare = NULL;
static SQLPUTDATA pSQLPutData = NULL;
static SQLROWCOUNT pSQLRowCount = NULL;
static SQLSETCONNECTOPTION pSQLSetConnectOption = NULL;
static SQLSETSTMTOPTION pSQLSetStmtOption = NULL;
static SQLTRANSACT pSQLTransact = NULL;

/* Depending on whether we're running under Win16 or Win32 we load the ODBC
   driver under a different name */

#ifdef __WIN16__
  #define ODBC_LIBNAME	"ODBC.DLL"
#else
  #define ODBC_LIBNAME	"ODBC32.DLL"
#endif /* __WIN16__ */

/* SQLError() returns error information at various levels and is rather
   unstable in its handling of input parameters (if you pass it a valid hstmt
   then it may GPF after some calls so you need to force a NULL hstmt).  The
   following values define the levels of handle we pass in in order for
   SQLError() to work as advertised */

#define SQL_ERRLVL_0	0
#define SQL_ERRLVL_1	1
#define SQL_ERRLVL_2	2

/* Dynamically load and unload any necessary DBMS libraries */

void dbxInitODBC( void )
	{
#ifdef __WIN16__
	UINT errorMode;
#endif /* __WIN16__ */

	/* If the ODBC module is already linked in, don't do anything */
	if( hODBC != NULL_HINSTANCE )
		return;

	/* Obtain a handle to the module containing the ODBC functions */
#ifdef __WIN16__
	errorMode = SetErrorMode( SEM_NOOPENFILEERRORBOX );
	hODBC = LoadLibrary( ODBC_LIBNAME );
	SetErrorMode( errorMode );
	if( hODBC < HINSTANCE_ERROR )
		{
		hODBC = NULL_HINSTANCE;
		return;
		}
#else
	if( ( hODBC = LoadLibrary( ODBC_LIBNAME ) ) == NULL_HINSTANCE )
		return;
#endif /* __WIN32__ */

	/* Now get pointers to the functions */
	pSQLAllocConnect = ( SQLALLOCCONNECT ) GetProcAddress( hODBC, "SQLAllocConnect" );
	pSQLAllocEnv = ( SQLALLOCENV ) GetProcAddress( hODBC, "SQLAllocEnv" );
	pSQLAllocStmt = ( SQLALLOCSTMT ) GetProcAddress( hODBC, "SQLAllocStmt" );
	pSQLBindParameter = ( SQLBINDPARAMETER ) GetProcAddress( hODBC, "SQLBindParameter" );
	pSQLCancel = ( SQLCANCEL ) GetProcAddress( hODBC, "SQLCancel" );
	pSQLConnect = ( SQLCONNECT ) GetProcAddress( hODBC, "SQLConnect" );
	pSQLDisconnect = ( SQLDISCONNECT ) GetProcAddress( hODBC, "SQLDisconnect" );
	pSQLError = ( SQLERROR ) GetProcAddress( hODBC, "SQLError" );
	pSQLExecDirect = ( SQLEXECDIRECT ) GetProcAddress( hODBC, "SQLExecDirect" );
	pSQLExecute = ( SQLEXECUTE ) GetProcAddress( hODBC, "SQLExecute" );
	pSQLFetch = ( SQLFETCH ) GetProcAddress( hODBC, "SQLFetch" );
	pSQLFreeConnect = ( SQLFREECONNECT ) GetProcAddress( hODBC, "SQLFreeConnect" );
	pSQLFreeEnv = ( SQLFREEENV ) GetProcAddress( hODBC, "SQLFreeEnv" );
	pSQLFreeStmt = ( SQLFREESTMT ) GetProcAddress( hODBC, "SQLFreeStmt" );
	pSQLGetData = ( SQLGETDATA ) GetProcAddress( hODBC, "SQLGetData" );
	pSQLGetInfo = ( SQLGETINFO ) GetProcAddress( hODBC, "SQLGetInfo" );
	pSQLGetTypeInfo = ( SQLGETTYPEINFO ) GetProcAddress( hODBC, "SQLGetTypeInfo" );
	pSQLParamData = ( SQLPARAMDATA ) GetProcAddress( hODBC, "SQLParamData" );
	pSQLPrepare = ( SQLPREPARE ) GetProcAddress( hODBC, "SQLPrepare" );
	pSQLPutData = ( SQLPUTDATA ) GetProcAddress( hODBC, "SQLPutData" );
	pSQLRowCount = ( SQLROWCOUNT ) GetProcAddress( hODBC, "SQLRowCount" );
	pSQLSetConnectOption = ( SQLSETCONNECTOPTION ) GetProcAddress( hODBC, "SQLSetConnectOption" );
	pSQLSetStmtOption = ( SQLSETSTMTOPTION ) GetProcAddress( hODBC, "SQLSetStmtOption" );
	pSQLTransact = ( SQLTRANSACT ) GetProcAddress( hODBC, "SQLTransact" );

	/* Make sure we got valid pointers for every ODBC function */
	if( pSQLAllocConnect == NULL || pSQLAllocEnv == NULL ||
		pSQLAllocStmt == NULL || pSQLBindParameter == NULL ||
		pSQLCancel == NULL || pSQLConnect == NULL ||
		pSQLDisconnect == NULL || pSQLError == NULL ||
		pSQLExecDirect == NULL || pSQLExecute == NULL ||
		pSQLFetch == NULL || pSQLFreeConnect == NULL ||
		pSQLFreeEnv == NULL || pSQLFreeStmt == NULL ||
		pSQLGetData == NULL || pSQLGetInfo == NULL ||
		pSQLGetTypeInfo == NULL || pSQLParamData == NULL ||
		pSQLPrepare == NULL || pSQLPutData == NULL ||
		pSQLSetConnectOption == NULL || pSQLSetStmtOption == NULL ||
		pSQLTransact == NULL )
		{
		/* Free the library reference and reset the handle */
		FreeLibrary( hODBC );
		hODBC = NULL_HINSTANCE;
		}
	}

void dbxEndODBC( void )
	{
	if( hODBC != NULL_HINSTANCE )
		FreeLibrary( hODBC );
	hODBC = NULL_HINSTANCE;
	}

/****************************************************************************
*																			*
*						 		Utility Routines							*
*																			*
****************************************************************************/

/* Get information on an ODBC error */

static int getErrorInfo( DBMS_STATE_INFO *dbmsInfo, const int errorLevel,
						 const int defaultStatus )
	{
	HDBC hdbc = ( errorLevel < 1 ) ? SQL_NULL_HDBC : dbmsInfo->hDbc;
	HDBC hstmt = ( errorLevel < 2 ) ? SQL_NULL_HSTMT : dbmsInfo->hStmt;
	char altErrorMessage[ MAX_ERRMSG_SIZE ];
	char szSqlState[ SQL_SQLSTATE_SIZE ], szAltSqlState[ SQL_SQLSTATE_SIZE ];
	SDWORD dwNativeError, dwAltNativeError;
	SWORD dummy;
	RETCODE retCode;

	retCode = pSQLError( dbmsInfo->hEnv, hdbc, hstmt, szSqlState,
						 &dwNativeError, dbmsInfo->errorMessage,
						 MAX_ERRMSG_SIZE - 1, &dummy );
	dbmsInfo->errorCode = ( int ) dwNativeError;	/* Usually 0 */

	/* Work around a bug in ODBC 2.0 drivers (still present on older NT 4
	   machines) in which the primary error is some bizarre nonsense value
	   and the actual error is present at the second level */
	retCode = pSQLError( dbmsInfo->hEnv, hdbc, hstmt, szAltSqlState,
						 &dwAltNativeError, altErrorMessage,
						 MAX_ERRMSG_SIZE - 1, &dummy );
	if( !strncmp( szSqlState, "01004", 5 ) )
		{
		memcpy( szSqlState, szAltSqlState, SQL_SQLSTATE_SIZE );
		strcpy( dbmsInfo->errorMessage, altErrorMessage );
		}

	/* Some of the information returned by SQLError() is pretty odd.  It
	   usually returns an ANSI SQL2 error state in SQLSTATE, but also returns
	   a native error code in NativeError.  However the NativeError codes
	   aren't documented anywhere, so we rely on SQLSTATE having a useful
	   value.  	We can also get SQL_NO_DATA_FOUND with SQLSTATE set to
	   "00000" and the error message string empty */
	if( !strncmp( szSqlState, "S0002", 5 ) ||	/* ODBC 2.x */
		!strncmp( szSqlState, "42S02", 5 ) ||	/* ODBC 3.x */
		( !strncmp( szSqlState, "00000", 5 ) && retCode == SQL_NO_DATA_FOUND ) )
		{
		/* Make sure the caller gets a sensible error message if they
		   try to examine the extended error information */
		if( !*dbmsInfo->errorMessage )
			strcpy( dbmsInfo->errorMessage, "No data found." );
		return( CRYPT_ERROR_NOTFOUND );
		}

	/* When we're trying to create a new keyset, there may already be one
	   present giving an S0001 (table already exists) or S0011 (index
	   already exists) error .  We could check for the table by doing a
	   dummy read, but it's easier to just try the update anyway and convert
	   the error code to the correct value here if there's a problem */
	if( !strncmp( szSqlState, "S0001", 5 ) ||
		!strncmp( szSqlState, "S0011", 5 ) ||	/* ODBC 2.x */
		!strncmp( szSqlState, "42S01", 5 ) ||
		!strncmp( szSqlState, "42S11", 5 ) )	/* ODBX 3.x */
		return( CRYPT_ERROR_DUPLICATE );

	/* This one is a bit odd: An integrity constraint violation occurred,
	   which means (among other things) that an attempt was made to write a
	   duplicate value to a column constrained to contain unique values.  It
	   can also include things like writing a NULL value to a column
	   constrained to be NOT NULL, but this wouldn't normally happen so we
	   can convert this one to a duplicate data error */
	if( !strncmp( szSqlState, "23000", 5 ) )
		return( CRYPT_ERROR_DUPLICATE );

	return( defaultStatus );
	}

/* Some MS database engines uses nonstandard SQL for primary keys.  Instead
   of allowing a simple PRIMARY KEY qualifier, they require that the use of
   a primary key to be given as constraint on a column, which also involves
   creating an index on that column.  In theory we could rewrite the primary
   key qualifier to create a fixed-name index using the constraint notation,
   however Access and SQL Server go even further and create an implied unique
   index for the key, making it both useless for its intended purpose
   (forcing clustering of identical entries) as well as rendering the table
   unusable (since it'll only allow a single value to be added).  Because of
   this we have to remove the PRIMARY KEY qualifier entirely.

   Detecting when this is necessary is tricky, it's required for Access, and
   SQL Server but not for Foxpro or (probably) any non-MS products, so we
   check for a DBMS name of "Access" or "SQL Server" and remove it if we find
   either.  In addition if we find Access we fix up some other problems it
   has as well */

static void convertQuery( DBMS_STATE_INFO *dbmsInfo, char *query,
						  const char *command )

⌨️ 快捷键说明

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