📄 vmodbcconnection.cpp
字号:
/*****************************************************************************/
/* SOURCE FILE */
/*****************************************************************************/
/*
$Archive: $
$Revision: $
$Date: $
$Author: $
Description: Implementation of a 'clone of' the MFC CDatabase class that
is implemented without all of the AFX goo....
TOOL And XML FORMS License
==========================
Except where otherwise noted, all of the documentation
and software included in the TOOL package is
copyrighted by Michael Swartzendruber.
Copyright (C) 2005 Michael John Swartzendruber.
All rights reserved.
Access to this code, whether intentional or accidental,
does NOT IMPLY any transfer of rights.
This software is provided "as-is," without any express
or implied warranty. In no event shall the author be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for
any purpose, including commercial applications, and to
alter and redistribute it, provided that the following
conditions are met:
1. All redistributions of source code files must retain
all copyright notices that are currently in place,
and this list of conditions without modification.
2. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
3. If you use this software in another product, an acknowledgment
in the product documentation would be appreciated but is
not required.
4. Modified versions in source or binary form must be plainly
marked as such, and must not be misrepresented as being
the original software.
*/
static char OBJECT_ID[] = "$Revision: $ : $Date: $";
/*****************************************************************************/
#include <assert.h>
#include "../../../StdAfx.h"
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>
#include "../TraceTools/VMWatcherOutput.h"
#include "../TraceTools/VMPerfTracking.h"
#include "../VMException.h"
#include "VMString.h"
#include "VMODBCConnection.h"
#include "VMVersionInfo.h"
// mjs, should protect with critical section
//
HENV VMODBCConnection::m_henvAllConnections = SQL_NULL_HENV;
int VMODBCConnection::m_nAllocatedConnections = 0;
const DWORD DEFAULT_LOGIN_TIMEOUT = 5;
const DWORD DEFAULT_QUERY_TIMEOUT = 5;
const int MAX_TNAME_LEN = 64;
const int MAX_CONNECT_LEN = 255;
const char cachODBCTrail[] = "ODBC;";
const char cachComma[] = ",";
const char cachLiteralSeparator = '\'';
const char cachCall[] = "{CALL ";
const char cachParamCall[] = "{?";
const char cachSelect[] = "SELECT ";
const char cachFrom[] = " FROM ";
const char cachWhere[] = " WHERE ";
const char cachOrderBy[] = " ORDER BY ";
const char cachForUpdate[] = " FOR UPDATE ";
const char cachRowFetch[] = "State:01S01";
const char cachDataTruncated[] = "State:01004";
const char cachInfoRange[] = "State:S1096";
const char cachOutOfSequence[] = "State:S1010";
const char cachDriverNotCapable[] = "State:S1C00";
const char cachODBCDLL[] = "ODBC32.DLL";
// communications failure codes
//
// NOTE: These are VERY LIKELY TO BE MS-SQL Server dependant
// If change to another dbms, then these values may be
// all wrong and will have to be adjusted
//
const char UNABLE_TO_CONNECT[] = "08001";
const char ALREADY_IN_USE[] = "08002";
const char COMM_LINK_FAILED[] = "08S01";
const char COMM_LINK_FAILURE[] = "37000";
const int ciLogonWait = 15;
/*****************************************************************************/
/*
FUNCTION NAME: VMODBCConnection::VMODBCConnection
DESCRIPTION: ctor. inits this
INPUT: void
OUTPUT: none
RETURNS: none
*/
VMODBCConnection::VMODBCConnection( void )
{
m_hdbc = SQL_NULL_HDBC;
m_hstmt = SQL_NULL_HSTMT;
m_bUpdatable = false;
m_bTransactions = false;
m_dwLoginTimeout = DEFAULT_LOGIN_TIMEOUT;
m_dwQueryTimeout = DEFAULT_QUERY_TIMEOUT;
m_bStripTrailingSpaces = false;
m_bIncRecordCountOnAdd = false;
m_bAddForUpdate = false;
m_uiReconnectWait = 1000 * ciLogonWait;
m_bReconnectTimer = false;
m_bIsOpen = false;
strcpy( (char*)m_auchErrorMsg, "" );
}
/* End of function "VMODBCConnection::VMODBCConnection"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMODBCConnection::~VMODBCConnection
DESCRIPTION: dtor. frees all resources
INPUT: void
OUTPUT: none
RETURNS: none
*/
VMODBCConnection::~VMODBCConnection( void )
{
Free();
}
/* End of function "VMODBCConnection::~VMODBCConnection"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMODBCConnection::GetDbmsHostName
DESCRIPTION: retrieves the name of the host where the database is
actually running
INPUT: pchOutput - pointer to output buffer
iBufferLength - size of the output buffer
OUTPUT:
RETURNS: true if worked, false if not
*/
bool VMODBCConnection::GetDbmsHostName( char* pchOutput, int iBufferLength )
{
short iLength;
// get the driver dll hmodule and use that for version info
//
SQLGetInfo( m_hdbc,
SQL_SERVER_NAME,
pchOutput,
iBufferLength,
&iLength );
if ( iLength == 0 )
{
return( false );
}
else
{
return( true );
}
}
/* End of function "VMODBCConnection::GetDbmsHostName"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMODBCConnection::GetVendorInfo
DESCRIPTION: Define what kind of dbms this is connected to
INPUT: pchOutput - output buffer
iBufferLength - length of the output buffer
OUTPUT:
RETURNS: true if data returned, false if not
*/
bool VMODBCConnection::GetVendorInfo( char* pchOutput, int iBufferLength )
{
short iLength;
HINSTANCE hInstance;
// get the driver dll hmodule and use that for version info
//
SQLGetInfo( m_hdbc,
SQL_DRIVER_HLIB,
&hInstance,
sizeof( HINSTANCE ),
&iLength );
if ( hInstance == NULL )
{
return( false );
}
VMVersionInfo oVerInfo( hInstance );
const char* pchTemp;
pchTemp = oVerInfo.GetCompanyName();
strcpy( pchOutput, pchTemp );
strcat( pchOutput, " " );
pchTemp = oVerInfo.GetProductName();
strcat( pchOutput, pchTemp );
strcat( pchOutput, " " );
pchTemp = oVerInfo.GetProductVersion();
strcat( pchOutput, pchTemp );
strcat( pchOutput, " " );
pchTemp = oVerInfo.GetFileVersion();
strcat( pchOutput, pchTemp );
strcat( pchOutput, " " );
pchTemp = oVerInfo.GetFileDescription();
strcat( pchOutput, pchTemp );
strcat( pchOutput, " " );
pchTemp = oVerInfo.GetOriginalFileName();
strcat( pchOutput, pchTemp );
strcat( pchOutput, " " );
pchTemp = oVerInfo.GetInternalName();
strcat( pchOutput, pchTemp );
return( true );
}
/* End of function "VMODBCConnection::GetVendorInfo"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMODBCConnection::Open
DESCRIPTION: opens the connection to the database
INPUT: lpszDSN - pointer to string containing dsn to use for the
connection
bExclusive - true if this is an exclusive connection to the
dbms
bReadonly - true if this is a read only connection
lpszConnect - the string argument to the connection
bUseCursorLib - true if cursors are to be used
OUTPUT:
RETURNS: true if worked, false if not
*/
bool VMODBCConnection::Open( LPCTSTR lpszDSN,
bool bExclusive,
bool bReadonly,
LPCTSTR lpszConnect,
bool bUseCursorLib )
{
VMString oConnect;
if ( lpszConnect != NULL )
{
oConnect = lpszConnect;
}
// For VB/Access compatibility, require "ODBC;" (or "odbc;")
// prefix to the connect string
//
if ( _tcsnicmp( oConnect, "ODBC;", lstrlen( "ODBC;" ) ) != 0 )
{
return( false );
}
// Strip "ODBC;"
//
oConnect.Right( oConnect.GetLength() - lstrlen( "ODBC;" ), oConnect );
if ( lpszDSN != NULL && lstrlen( lpszDSN ) != 0 )
{
// Append "DSN=" lpszDSN
//
oConnect += _T( ";DSN=" );
oConnect += lpszDSN;
}
DWORD dwOptions = 0;
if ( bExclusive )
{
dwOptions |= openExclusive;
}
if ( bReadonly )
{
dwOptions |= openReadOnly;
}
if ( bUseCursorLib )
{
dwOptions |= useCursorLib;
}
return( OpenEx( (const char*)oConnect, dwOptions ) );
}
/* End of function "VMODBCConnection::Open"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMODBCConnection::OpenEx
DESCRIPTION: opens a connections to the dbms
INPUT: lpszConnectString - pointer to string containing connection
info
dwOptions - connection options
OUTPUT:
RETURNS: true if worked, false if not
*/
bool VMODBCConnection::OpenEx( LPCTSTR lpszConnectString, DWORD dwOptions )
{
assert( !( dwOptions & noOdbcDialog && dwOptions & forceOdbcDialog ) );
// Exclusive access not supported.
//
assert( !( dwOptions & openExclusive ) );
m_bUpdatable = !( dwOptions & openReadOnly );
m_oConnect = lpszConnectString;
try
{
// Allocate the HDBC and make connection
//
AllocConnect( dwOptions );
if ( !Connect( dwOptions ) )
{
return( false );
}
// Verify support for required functionality and cache info
//
VerifyConnect();
GetConnectInfo();
m_bIsOpen = true;
}
catch( VMException* poError )
{
Free();
throw poError;
}
return( true );
}
/* End of function "VMODBCConnection::OpenEx"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMODBCConnection::CanTransact
DESCRIPTION: determines if transactions are supported in the driver / dbms
INPUT: void
OUTPUT: none
RETURNS: true if can, false if can not
*/
bool VMODBCConnection::CanTransact( void ) const
{
return( m_bTransactions );
}
/* End of function "VMODBCConnection::CanTransact"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: VMODBCConnection::ExecuteSQLGetRowCount
DESCRIPTION: used to execute a specific sql command againts the dbms
INPUT: lpszSQL - pointer to string containing the command to exec
OUTPUT: none
RETURNS: affected row count from dbms drivers
*/
int VMODBCConnection::ExecuteSQLGetRowCount( LPCTSTR lpszSQL )
{
VMPerfTimer oTimer( "ExecuteSQLGetRowCount" );
SQLINTEGER iResult = 0;
RETCODE nRetCode;
HSTMT hstmt;
nRetCode = ::SQLAllocStmt( m_hdbc, &hstmt );
if ( !CheckHstmt( nRetCode, hstmt ) )
{
GetErrorMessages( SQL_HANDLE_STMT, hstmt );
throw new VMException( __FILE__, __LINE__, "SQLAllocStatement Failed.", VMException::fatal );
}
try
{
OnSetOptions( hstmt );
// Give derived VMODBCConnection classes option to use parameters
//
BindParameters( hstmt );
if ( CanTransact() )
{
BeginTrans();
}
VMPerfTimer oExecTime( "SQLExecDirect", false );
oExecTime.StartTimer();
ODBC_CALL_WAIT( ::SQLExecDirect( hstmt,
(unsigned char*) lpszSQL,
SQL_NTS ) );
oExecTime.StopTimer();
if ( CanTransact() )
{
CommitTrans();
}
if ( !CheckHstmt( nRetCode, hstmt ) )
{
GetErrorMessages( SQL_HANDLE_STMT, hstmt );
// test for a lost database connection
//
char* pcTest = strstr( (const char*)m_auchErrorMsg, COMM_LINK_FAILED );
if( pcTest != NULL )
{
// connection has been broken
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -