📄 odbc.c
字号:
/****************************************************************************
* *
* cryptlib ODBC Mapping Routines *
* Copyright Peter Gutmann 1996-2007 *
* *
****************************************************************************/
#include <stdio.h> /* For sprintf() */
#if defined( INC_ALL )
#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 */
/* 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 )
/* DBMS back-ends that require special handling */
enum { DBMS_NONE, DBMS_ACCESS, DBMS_INTERBASE, DBMS_POSTGRES };
/* The level at which we want SQLDiagRec() to return error information to
us */
typedef enum { SQL_ERRLVL_NONE, SQL_ERRLVL_STMT, SQL_ERRLVL_DBC,
SQL_ERRLVL_ENV, SQL_ERRLVL_LAST } SQL_ERRLVL_TYPE;
/* When rewriting an SQL query we have to provide a slightly larger buffer
to allow for possible expansion of some SQL strings */
#define SQL_QUERY_BUFSIZE ( MAX_SQL_QUERY_SIZE + 64 )
#ifdef USE_ODBC
/* When processing bound data we need to store the state information used by
SQLBindParameter() until the SQL operation completes. The following
structure provides the necessary state storage */
typedef struct {
SQLINTEGER lengthStorage[ BOUND_DATA_MAXITEMS + 8 ];
SQL_TIMESTAMP_STRUCT timestampStorage;
} BOUND_DATA_STATE;
/****************************************************************************
* *
* 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
shared libraries. 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 issue, this particular function is typedef'd with a _FN
suffix.
Several of the ODBC functions allow such a mess of parameters, with
options for pointers to be cast to integers indexing a table of data
values hidden under someone's bed and other peculiarities, that several
of the following markups are only approximations for the way the
functions are used here. If markups are absent entirely (e.g. for the
SQLSetXXXAttr() functions) it's because the polymorphism of parameters
doesn't allow any coherent annotation to be given */
static INSTANCE_HANDLE hODBC = NULL_INSTANCE;
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLALLOCHANDLE )\
( SQLSMALLINT HandleType, IN SQLHANDLE InputHandle,
OUT_PTR SQLHANDLE *OutputHandlePtr );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLBINDPARAMETER )\
( IN SQLHSTMT StatementHandle,
SQLUSMALLINT ParameterNumber, SQLSMALLINT InputOutputType,
SQLSMALLINT ValueType, SQLSMALLINT ParameterType,
SQLUINTEGER ColumnSize, SQLSMALLINT DecimalDigits,
IN_BUFFER_OPT( BufferLength ) SQLPOINTER ParameterValuePtr,
SQLINTEGER BufferLength,
INOUT_OPT SQLINTEGER *StrLen_or_IndPtr );
typedef SQLRETURN ( SQL_API *SQLCLOSECURSOR )( IN SQLHSTMT StatementHandle );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLCONNECT )\
( IN SQLHDBC ConnectionHandle,
IN_BUFFER( NameLength1 ) SQLCHAR *ServerName,
SQLSMALLINT NameLength1,
IN_BUFFER( NameLength2 ) SQLCHAR *UserName,
SQLSMALLINT NameLength2,
IN_BUFFER( NameLength3 ) SQLCHAR *Authentication,
SQLSMALLINT NameLength3 );
typedef SQLRETURN ( SQL_API *SQLDISCONNECT )( IN SQLHDBC ConnectionHandle );
typedef SQLRETURN ( SQL_API *SQLENDTRAN )( SQLSMALLINT HandleType,
IN SQLHANDLE Handle, SQLSMALLINT CompletionType );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLEXECDIRECT )\
( SQLHSTMT StatementHandle,
IN_BUFFER( TextLength ) SQLCHAR *StatementText,
SQLINTEGER TextLength );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLEXECUTE )\
( IN SQLHSTMT StatementHandle );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLFETCH )\
( IN SQLHSTMT StatementHandle );
typedef SQLRETURN ( SQL_API *SQLFREEHANDLE )( SQLSMALLINT HandleType,
IN SQLHANDLE Handle );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETDATA )\
( SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber,
SQLSMALLINT TargetType,
OUT_BUFFER( BufferLength, *StrLen_or_IndPtr ) \
SQLPOINTER TargetValuePtr,
SQLINTEGER BufferLength, SQLINTEGER *StrLen_or_IndPtr );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETDIAGREC )\
( SQLSMALLINT HandleType,
IN SQLHANDLE Handle, SQLSMALLINT RecNumber,
OUT_BUFFER_FIXED( SQL_SQLSTATE_SIZE ) SQLCHAR *Sqlstate,
OUT SQLINTEGER *NativeErrorPtr,
OUT_BUFFER( BufferLength, *TextLengthPtr ) \
SQLCHAR *MessageText,
SQLSMALLINT BufferLength, SQLSMALLINT *TextLengthPtr );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETINFO )\
( IN SQLHDBC ConnectionHandle,
SQLUSMALLINT InfoType,
OUT_BUFFER( BufferLength, *StringLengthPtr ) \
SQLPOINTER InfoValuePtr,
SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETSTMTATTR )\
( IN SQLHSTMT StatementHandle,
SQLINTEGER Attribute, OUT SQLPOINTER ValuePtr,
SQLINTEGER BufferLength,
STDC_UNUSED SQLINTEGER *StringLengthPtr );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETTYPEINFO )\
( IN SQLHSTMT StatementHandle,
SQLSMALLINT DataType );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLPREPARE )\
( IN SQLHSTMT StatementHandle,
IN_BUFFER( TextLength ) SQLCHAR *StatementText,
SQLINTEGER TextLength );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLROWCOUNT_FN )\
( IN SQLHSTMT StatementHandle,
OUT SQLINTEGER *RowCountPtr );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLSETCONNECTATTR )\
( IN SQLHDBC ConnectionHandle,
SQLINTEGER Attribute, SQLPOINTER ValuePtr,
SQLINTEGER StringLength );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLSETENVATTR )\
( IN SQLHENV EnvironmentHandle,
SQLINTEGER Attribute, SQLPOINTER ValuePtr,
SQLINTEGER StringLength );
typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLSETSTMTATTR )\
( IN SQLHSTMT StatementHandle,
SQLINTEGER Attribute, SQLPOINTER ValuePtr,
SQLINTEGER StringLength );
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 SQLPREPARE pSQLPrepare = NULL;
static SQLROWCOUNT_FN pSQLRowCount = NULL;
static SQLSETCONNECTATTR pSQLSetConnectAttr = NULL;
static SQLSETENVATTR pSQLSetEnvAttr = NULL;
static SQLSETSTMTATTR pSQLSetStmtAttr = NULL;
/* 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 SQLPrepare pSQLPrepare
#define SQLRowCount pSQLRowCount
#define SQLSetConnectAttr pSQLSetConnectAttr
#define SQLSetEnvAttr pSQLSetEnvAttr
#define SQLSetStmtAttr pSQLSetStmtAttr
/* 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
/* Currently we default to UnixODBC, which uses libodbc.so. If this
fails, we fall back to the next-most-common one, iODBC. If you're
using something else, you'll need to change the entry below to
specify your library name */
#define ODBC_LIBNAME "libodbc.so"
#define ODBC_ALT_LIBNAME "libiodbc.so"
#endif /* Mac OS X vs. other Unixen */
#endif /* System-specific ODBC library names */
/* Dynamically load and unload any necessary DBMS libraries */
CHECK_RETVAL \
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 */
#if defined( __WIN16__ )
errorMode = SetErrorMode( SEM_NOOPENFILEERRORBOX );
hODBC = LoadLibrary( ODBC_LIBNAME );
SetErrorMode( errorMode );
if( hODBC < HINSTANCE_ERROR )
{
hODBC = NULL_INSTANCE;
return( CRYPT_ERROR );
}
#elif defined( __UNIX__ ) && !defined( __APPLE__ )
if( ( hODBC = DynamicLoad( ODBC_LIBNAME ) ) == NULL_INSTANCE && \
( hODBC = DynamicLoad( ODBC_ALT_LIBNAME ) ) == 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" );
pSQLPrepare = ( SQLPREPARE ) DynamicBind( hODBC, "SQLPrepare" );
pSQLRowCount = ( SQLROWCOUNT_FN ) DynamicBind( hODBC, "SQLRowCount" );
pSQLSetConnectAttr = ( SQLSETCONNECTATTR ) DynamicBind( hODBC, "SQLSetConnectAttr" );
pSQLSetEnvAttr = ( SQLSETENVATTR ) DynamicBind( hODBC, "SQLSetEnvAttr" );
pSQLSetStmtAttr = ( SQLSETSTMTATTR ) DynamicBind( hODBC, "SQLSetStmtAttr" );
/* 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 || pSQLPrepare == 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
CHECK_RETVAL \
int dbxInitODBC( void )
{
return( CRYPT_OK );
}
void dbxEndODBC( void )
{
}
#endif /* DYNAMIC_LOAD */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Get information on an ODBC error. The statement handle is specified as a
distinct parameter because it may be an ephemeral handle not part of the
state information data */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int getErrorInfo( INOUT DBMS_STATE_INFO *dbmsInfo,
IN_ENUM( SQL_ERRLVL ) const SQL_ERRLVL_TYPE errorLevel,
const SQLHSTMT hStmt,
IN_ERROR const int defaultStatus )
{
ERROR_INFO *errorInfo = &dbmsInfo->errorInfo;
char szSqlState[ SQL_SQLSTATE_SIZE + 8 ];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -