📄 odbc.c
字号:
/****************************************************************************
* *
* cryptlib ODBC Mapping Routines *
* Copyright Peter Gutmann 1996-2004 *
* *
****************************************************************************/
#include <stdio.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "keyset.h"
#include "dbms.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "keyset.h"
#include "dbms.h"
#else
#include "crypt.h"
#include "keyset/keyset.h"
#include "keyset/dbms.h"
#endif /* Compiler-specific includes */
/* The following code can be run under any version of ODBC from 1.x to 3.x,
although it assumes that a 3.x-level SDK is being used. This is fairly
likely, since this has been around since mid-1995. If a pre-3.0 SDK is
being used, then the following mappings will need to be applied:
SQL_C_SLONG -> SQL_C_LONG
SQLCHAR -> UCHAR
SQLHANDLE -> Generic HENV/HSTMT/HDBC
SQLHDBC -> HDBC
SQLHENV -> HENV
SQLHSTMT -> HSTMT
SQLINTEGER -> SDWORD
SQLPOINTER -> PTR
SQLRETURN -> RETCODE
SQLSMALLINT - SWORD
SQLUINTEGER -> UDWORD
SQLUSMALLINT -> UWORD
Note that this can't be done automatically because the values are
typedefs rather than #defines, which can't be detected at compile time.
In addition under Windows the ODBC1x define needs to be used to enable
the mapping of ODBC 1.x functions */
/* The ODBC 1.x SQLError() function returns error information at various
levels and is rather unstable in its handling of input parameters, for
example with some Win16 drivers 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 that we pass in in order for the ODBC
1.x SQLError() to work as advertised.
For ODBC 3.x only a single handle is used for SQLDiagRec(), but we still
need these codes to indicate the type of the handle that's being passed */
#define SQL_ERRLVL_STMT 0
#define SQL_ERRLVL_DBC 1
#define SQL_ERRLVL_ENV 2
/* ODBC functions can return either SQL_SUCCESS or SQL_SUCCESS_WITH_INFO to
indicate successful completion, to make them easier to work with we use
a general status-check macro along the lines of cryptStatusOK() */
#define sqlStatusOK( status ) \
( ( status ) == SQL_SUCCESS || ( status ) == SQL_SUCCESS_WITH_INFO )
#ifdef USE_ODBC
/****************************************************************************
* *
* Init/Shutdown Routines *
* *
****************************************************************************/
#ifdef DYNAMIC_LOAD
/* Global function pointers. These are necessary because the functions need
to be dynamically linked since not all systems contain the necessary
DLL/shared libs's. Explicitly linking to them will make cryptlib
unloadable on some systems.
MSDN updates from late 2000 defined SQLROWCOUNT themselves (which could be
fixed by undefining it), however after late 2002 the value was typedef'd,
requring all sorts of extra trickery to handle the different cases.
Because of this this particular function is typedef'd with a _FN suffix
to reduce problems */
static INSTANCE_HANDLE hODBC = NULL_INSTANCE;
typedef SQLRETURN ( SQL_API *SQLALLOCHANDLE )( SQLSMALLINT HandleType,
SQLHANDLE InputHandle, SQLHANDLE *OutputHandlePtr );
typedef SQLRETURN ( SQL_API *SQLBINDPARAMETER )( SQLHSTMT StatementHandle,
SQLUSMALLINT ParameterNumber, SQLSMALLINT InputOutputType,
SQLSMALLINT ValueType, SQLSMALLINT ParameterType,
SQLUINTEGER ColumnSize, SQLSMALLINT DecimalDigits,
SQLPOINTER ParameterValuePtr, SQLINTEGER BufferLength,
SQLINTEGER *StrLen_or_IndPtr );
typedef SQLRETURN ( SQL_API *SQLCLOSECURSOR )( SQLHSTMT StatementHandle );
typedef SQLRETURN ( SQL_API *SQLCONNECT )( SQLHDBC ConnectionHandle,
SQLCHAR *ServerName, SQLSMALLINT NameLength1,
SQLCHAR *UserName, SQLSMALLINT NameLength2,
SQLCHAR *Authentication, SQLSMALLINT NameLength3 );
typedef SQLRETURN ( SQL_API *SQLDISCONNECT )( SQLHDBC ConnectionHandle );
typedef SQLRETURN ( SQL_API *SQLENDTRAN )( SQLSMALLINT HandleType,
SQLHANDLE Handle, SQLSMALLINT CompletionType );
typedef SQLRETURN ( SQL_API *SQLEXECDIRECT )( SQLHSTMT StatementHandle,
SQLCHAR *StatementText, SQLINTEGER TextLength );
typedef SQLRETURN ( SQL_API *SQLEXECUTE )( SQLHSTMT StatementHandle );
typedef SQLRETURN ( SQL_API *SQLFETCH )( SQLHSTMT StatementHandle );
typedef SQLRETURN ( SQL_API *SQLFREEHANDLE )( SQLSMALLINT HandleType,
SQLHANDLE Handle );
typedef SQLRETURN ( SQL_API *SQLGETDATA )( SQLHSTMT StatementHandle,
SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr, SQLINTEGER BufferLength,
SQLINTEGER *StrLen_or_IndPtr );
typedef SQLRETURN ( SQL_API *SQLGETDIAGREC )( SQLSMALLINT HandleType,
SQLHANDLE Handle, SQLSMALLINT RecNumber,
SQLCHAR *Sqlstate, SQLINTEGER *NativeErrorPtr,
SQLCHAR *MessageText, SQLSMALLINT BufferLength,
SQLSMALLINT *TextLengthPtr );
typedef SQLRETURN ( SQL_API *SQLGETINFO )( SQLHDBC ConnectionHandle,
SQLUSMALLINT InfoType, SQLPOINTER InfoValuePtr,
SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr );
typedef SQLRETURN ( SQL_API *SQLGETSTMTATTR )( SQLHSTMT StatementHandle,
SQLINTEGER Attribute, SQLPOINTER ValuePtr,
SQLINTEGER BufferLength, SQLINTEGER *StringLengthPtr );
typedef SQLRETURN ( SQL_API *SQLGETTYPEINFO )( SQLHSTMT StatementHandle,
SQLSMALLINT DataType );
typedef SQLRETURN ( SQL_API *SQLPARAMDATA )( SQLHSTMT StatementHandle,
SQLPOINTER *ValuePtrPtr );
typedef SQLRETURN ( SQL_API *SQLPREPARE )( SQLHSTMT StatementHandle,
SQLCHAR *StatementText, SQLINTEGER TextLength );
typedef SQLRETURN ( SQL_API *SQLPUTDATA )( SQLHSTMT StatementHandle,
SQLPOINTER DataPtr, SQLINTEGER StrLen_or_Ind );
typedef SQLRETURN ( SQL_API *SQLROWCOUNT_FN )( SQLHSTMT StatementHandle,
SQLINTEGER *RowCountPtr );
typedef SQLRETURN ( SQL_API *SQLSETCONNECTATTR )( SQLHDBC ConnectionHandle,
SQLINTEGER Attribute, SQLPOINTER ValuePtr,
SQLINTEGER StringLength );
typedef SQLRETURN ( SQL_API *SQLSETENVATTR )( SQLHENV EnvironmentHandle,
SQLINTEGER Attribute, SQLPOINTER ValuePtr,
SQLINTEGER StringLength );
typedef SQLRETURN ( SQL_API *SQLSETSTMTATTR )( SQLHSTMT StatementHandle,
SQLINTEGER Attribute, SQLPOINTER ValuePtr,
SQLINTEGER StringLength );
#ifdef ODBC1x
typedef SQLRETURN ( SQL_API *SQLALLOCENV )( SQLHENV *phEnv );
typedef SQLRETURN ( SQL_API *SQLALLOCCONNECT )( SQLHENV hEnv,
SQLHDBC *phDbc );
typedef SQLRETURN ( SQL_API *SQLALLOCSTMT )( SQLHDBC hDbc,
SQLHSTMT *phStmt );
typedef SQLRETURN ( SQL_API *SQLERROR )( SQLHENV henv, SQLHDBC hDbc,
SQLHSTMT hStmt, SQLCHAR *szSqlState,
SQLINTEGER *pfNativeError, SQLCHAR *szErrorMsg,
SQLSMALLINT cbErrorMsgMax, SQLSMALLINT *pcbErrorMsg );
typedef SQLRETURN ( SQL_API *SQLFREECONNECT )( SQLHDBC hDbc );
typedef SQLRETURN ( SQL_API *SQLFREEENV )( SQLHENV hEnv );
typedef SQLRETURN ( SQL_API *SQLFREESTMT )( SQLHSTMT hStmt, SQLUSMALLINT fOption );
typedef SQLRETURN ( SQL_API *SQLSETCONNECTOPTION )( SQLHDBC hdbc, UWORD fOption,
UDWORD vParam );
typedef SQLRETURN ( SQL_API *SQLSETSTMTOPTION )( SQLHSTMT hstmt, UWORD fOption,
UDWORD vParam );
typedef SQLRETURN ( SQL_API *SQLTRANSACT )( SQLHENV hEnv, SQLHDBC hDbc, SQLUSMALLINT fType );
#endif /* ODBC1x */
static SQLALLOCHANDLE pSQLAllocHandle = NULL;
static SQLBINDPARAMETER pSQLBindParameter = NULL;
static SQLCLOSECURSOR pSQLCloseCursor = NULL;
static SQLCONNECT pSQLConnect = NULL;
static SQLDISCONNECT pSQLDisconnect = NULL;
static SQLENDTRAN pSQLEndTran = NULL;
static SQLEXECDIRECT pSQLExecDirect = NULL;
static SQLEXECUTE pSQLExecute = NULL;
static SQLFETCH pSQLFetch = NULL;
static SQLFREEHANDLE pSQLFreeHandle = NULL;
static SQLGETDATA pSQLGetData = NULL;
static SQLGETDIAGREC pSQLGetDiagRec = NULL;
static SQLGETINFO pSQLGetInfo = NULL;
static SQLGETSTMTATTR pSQLGetStmtAttr = NULL;
static SQLGETTYPEINFO pSQLGetTypeInfo = NULL;
static SQLPARAMDATA pSQLParamData = NULL;
static SQLPREPARE pSQLPrepare = NULL;
static SQLPUTDATA pSQLPutData = NULL;
static SQLROWCOUNT_FN pSQLRowCount = NULL;
static SQLSETCONNECTATTR pSQLSetConnectAttr = NULL;
static SQLSETENVATTR pSQLSetEnvAttr = NULL;
static SQLSETSTMTATTR pSQLSetStmtAttr = NULL;
#ifdef ODBC1x
static SQLALLOCCONNECT pSQLAllocConnect = NULL;
static SQLALLOCENV pSQLAllocEnv = NULL;
static SQLALLOCSTMT pSQLAllocStmt = NULL;
static SQLERROR pSQLError = NULL;
static SQLFREECONNECT pSQLFreeConnect = NULL;
static SQLFREEENV pSQLFreeEnv = NULL;
static SQLFREESTMT pSQLFreeStmt = NULL;
static SQLSETCONNECTOPTION pSQLSetConnectOption = NULL;
static SQLSETSTMTOPTION pSQLSetStmtOption = NULL;
static SQLTRANSACT pSQLTransact = NULL;
#endif /* ODBC1x */
/* The use of dynamically bound function pointers vs. statically linked
functions requires a bit of sleight of hand since we can't give the
pointers the same names as prototyped functions. To get around this we
redefine the actual function names to the names of the pointers */
#define SQLAllocHandle pSQLAllocHandle
#define SQLBindParameter pSQLBindParameter
#define SQLCloseCursor pSQLCloseCursor
#define SQLConnect pSQLConnect
#define SQLDisconnect pSQLDisconnect
#define SQLEndTran pSQLEndTran
#define SQLExecDirect pSQLExecDirect
#define SQLExecute pSQLExecute
#define SQLFetch pSQLFetch
#define SQLFreeHandle pSQLFreeHandle
#define SQLGetData pSQLGetData
#define SQLGetDiagRec pSQLGetDiagRec
#define SQLGetInfo pSQLGetInfo
#define SQLGetStmtAttr pSQLGetStmtAttr
#define SQLGetTypeInfo pSQLGetTypeInfo
#define SQLParamData pSQLParamData
#define SQLPrepare pSQLPrepare
#define SQLPutData pSQLPutData
#define SQLRowCount pSQLRowCount
#define SQLSetConnectAttr pSQLSetConnectAttr
#define SQLSetEnvAttr pSQLSetEnvAttr
#define SQLSetStmtAttr pSQLSetStmtAttr
#ifdef ODBC1x
#define SQLAllocConnect pSQLAllocConnect
#define SQLAllocEnv pSQLAllocEnv
#define SQLAllocStmt pSQLAllocStmt
#define SQLError pSQLError
#define SQLFreeConnect pSQLFreeConnect
#define SQLFreeEnv pSQLFreeEnv
#define SQLFreeStmt pSQLFreeStmt
#define SQLSetConnectOption pSQLSetConnectOption
#define SQLSetStmtOption pSQLSetStmtOption
#define SQLTransact pSQLTransact
#endif /* ODBC1x */
/* Depending on whether we're running under Win16, Win32, or Unix we load the
ODBC driver under a different name */
#if defined( __WIN16__ )
#define ODBC_LIBNAME "ODBC.DLL"
#elif defined( __WIN32__ )
#define ODBC_LIBNAME "ODBC32.DLL"
#elif defined( __UNIX__ )
#if defined( __APPLE__ )
/* OS X has built-in ODBC support via iODBC */
#define ODBC_LIBNAME "libiodbc.dylib"
#else
#define ODBC_LIBNAME "libodbc.so"
#endif /* Mac OS X vs. other Unixen */
#endif /* System-specific ODBC library names */
/* Dynamically load and unload any necessary DBMS libraries */
int dbxInitODBC( void )
{
#ifdef __WIN16__
UINT errorMode;
#endif /* __WIN16__ */
/* If the ODBC module is already linked in, don't do anything */
if( hODBC != NULL_INSTANCE )
return( CRYPT_OK );
/* 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_INSTANCE;
return( CRYPT_ERROR );
}
#else
if( ( hODBC = DynamicLoad( ODBC_LIBNAME ) ) == NULL_INSTANCE )
return( CRYPT_ERROR );
#endif /* __WIN32__ */
/* Now get pointers to the functions */
pSQLAllocHandle = ( SQLALLOCHANDLE ) DynamicBind( hODBC, "SQLAllocHandle" );
pSQLBindParameter = ( SQLBINDPARAMETER ) DynamicBind( hODBC, "SQLBindParameter" );
pSQLCloseCursor = ( SQLCLOSECURSOR ) DynamicBind( hODBC, "SQLCloseCursor" );
pSQLConnect = ( SQLCONNECT ) DynamicBind( hODBC, "SQLConnect" );
pSQLDisconnect = ( SQLDISCONNECT ) DynamicBind( hODBC, "SQLDisconnect" );
pSQLEndTran = ( SQLENDTRAN ) DynamicBind( hODBC, "SQLEndTran" );
pSQLExecDirect = ( SQLEXECDIRECT ) DynamicBind( hODBC, "SQLExecDirect" );
pSQLExecute = ( SQLEXECUTE ) DynamicBind( hODBC, "SQLExecute" );
pSQLFetch = ( SQLFETCH ) DynamicBind( hODBC, "SQLFetch" );
pSQLFreeHandle = ( SQLFREEHANDLE ) DynamicBind( hODBC, "SQLFreeHandle" );
pSQLGetData = ( SQLGETDATA ) DynamicBind( hODBC, "SQLGetData" );
pSQLGetDiagRec = ( SQLGETDIAGREC ) DynamicBind( hODBC, "SQLGetDiagRec" );
pSQLGetInfo = ( SQLGETINFO ) DynamicBind( hODBC, "SQLGetInfo" );
pSQLGetStmtAttr = ( SQLGETSTMTATTR ) DynamicBind( hODBC, "SQLGetStmtAttr" );
pSQLGetTypeInfo = ( SQLGETTYPEINFO ) DynamicBind( hODBC, "SQLGetTypeInfo" );
pSQLParamData = ( SQLPARAMDATA ) DynamicBind( hODBC, "SQLParamData" );
pSQLPrepare = ( SQLPREPARE ) DynamicBind( hODBC, "SQLPrepare" );
pSQLPutData = ( SQLPUTDATA ) DynamicBind( hODBC, "SQLPutData" );
pSQLRowCount = ( SQLROWCOUNT_FN ) DynamicBind( hODBC, "SQLRowCount" );
pSQLSetConnectAttr = ( SQLSETCONNECTATTR ) DynamicBind( hODBC, "SQLSetConnectAttr" );
pSQLSetEnvAttr = ( SQLSETENVATTR ) DynamicBind( hODBC, "SQLSetEnvAttr" );
pSQLSetStmtAttr = ( SQLSETSTMTATTR ) DynamicBind( hODBC, "SQLSetStmtAttr" );
#ifdef ODBC1x
pSQLAllocConnect = ( SQLALLOCCONNECT ) DynamicBind( hODBC, "SQLAllocConnect" );
pSQLAllocEnv = ( SQLALLOCENV ) DynamicBind( hODBC, "SQLAllocEnv" );
pSQLAllocStmt = ( SQLALLOCSTMT ) DynamicBind( hODBC, "SQLAllocStmt" );
pSQLError = ( SQLERROR ) DynamicBind( hODBC, "SQLError" );
pSQLFreeConnect = ( SQLFREECONNECT ) DynamicBind( hODBC, "SQLFreeConnect" );
pSQLFreeEnv = ( SQLFREEENV ) DynamicBind( hODBC, "SQLFreeEnv" );
pSQLFreeStmt = ( SQLFREESTMT ) DynamicBind( hODBC, "SQLFreeStmt" );
pSQLSetConnectOption = ( SQLSETCONNECTOPTION ) DynamicBind( hODBC, "SQLSetConnectOption" );
pSQLSetStmtOption = ( SQLSETSTMTOPTION ) DynamicBind( hODBC, "SQLSetStmtOption" );
pSQLTransact = ( SQLTRANSACT ) DynamicBind( hODBC, "SQLTransact" );
#endif /* ODBC1x */
/* Make sure that we got valid pointers for every ODBC function */
if( pSQLAllocHandle == NULL || pSQLBindParameter == NULL ||
pSQLCloseCursor == NULL || pSQLConnect == NULL ||
pSQLDisconnect == NULL || pSQLEndTran == NULL ||
pSQLExecDirect == NULL || pSQLExecute == NULL ||
pSQLFetch == NULL || pSQLFreeHandle == NULL ||
pSQLGetData == NULL || pSQLGetDiagRec == NULL ||
pSQLGetInfo == NULL || pSQLGetStmtAttr == NULL ||
pSQLGetTypeInfo == NULL || pSQLParamData == NULL ||
pSQLPrepare == NULL || pSQLPutData == NULL ||
pSQLSetConnectAttr == NULL || pSQLSetEnvAttr == NULL ||
pSQLSetStmtAttr == NULL )
{
/* Free the library reference and reset the handle */
DynamicUnload( hODBC );
hODBC = NULL_INSTANCE;
return( CRYPT_ERROR );
}
return( CRYPT_OK );
}
void dbxEndODBC( void )
{
if( hODBC != NULL_INSTANCE )
DynamicUnload( hODBC );
hODBC = NULL_INSTANCE;
}
#else
int dbxInitODBC( void )
{
return( CRYPT_OK );
}
void dbxEndODBC( void )
{
}
#endif /* DYNAMIC_LOAD */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -