📄 odbcclient.cpp
字号:
// odbcClient.cpp: implementation of the IodbcClient class.////////////////////////////////////////////////////////////////////////#include <SQLAPI.h>#include "odbcClient.h"#include <assert.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h> // strtol
#include <odbcAPI.h>#include "samisc.h"#include "errmsg.h"
//////////////////////////////////////////////////////////////////////// IodbcConnection Class//////////////////////////////////////////////////////////////////////class IodbcConnection : public ISAConnection{ enum
{ MaxLongAtExecSize = 0x7fffffff+SQL_LEN_DATA_AT_EXEC(0) }; friend class IodbcCursor; odbcConnectionHandles m_handles; static void Check( SQLRETURN return_code, SQLSMALLINT HandleType, SQLHANDLE Handle); SQLINTEGER LenDataAtExec(); void issueIsolationLevel( SAIsolationLevel_t eIsolationLevel);protected: virtual ~IodbcConnection();public: IodbcConnection(SAConnection *pSAConnection);
virtual void InitializeClient();
virtual void UnInitializeClient();
virtual long GetClientVersion() const; virtual long GetServerVersion() const; virtual SAString GetServerVersionString() const; virtual bool IsConnected() const; virtual void Connect( const SAString &sDBString, const SAString &sUserID, const SAString &sPassword); virtual void Disconnect(); virtual void setIsolationLevel( SAIsolationLevel_t eIsolationLevel); virtual void setAutoCommit( SAAutoCommit_t eAutoCommit); virtual void Commit(); virtual void Rollback(); virtual saAPI *NativeAPI() const; virtual saConnectionHandles *NativeHandles(); virtual ISACursor *NewCursor(SACommand *m_pCommand); virtual void CnvtInternalToDateTime( SADateTime &date_time, const void *pInternal, int nInternalSize); static void CnvtInternalToDateTime( SADateTime &date_time, const TIMESTAMP_STRUCT &Internal); static void CnvtDateTimeToInternal( const SADateTime &date_time, TIMESTAMP_STRUCT &Internal);
virtual void CnvtInternalToCursor(
SACommand *pCursor,
const void *pInternal);
};//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////IodbcConnection::IodbcConnection( SAConnection *pSAConnection) : ISAConnection(pSAConnection){}IodbcConnection::~IodbcConnection(){}
/*virtual */
void IodbcConnection::InitializeClient()
{
::AddODBCSupport(m_pSAConnection);
assert(!m_handles.m_hevn);
g_odbcAPI.SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_handles.m_hevn);
assert(m_handles.m_hevn);
try
{
Check(g_odbcAPI.SQLSetEnvAttr(m_handles.m_hevn, SQL_ATTR_ODBC_VERSION, SQLPOINTER(SQL_OV_ODBC3), 0), SQL_HANDLE_ENV, m_handles.m_hevn);
}
catch(SAException &) // clean up
{
if(m_handles.m_hevn)
{
g_odbcAPI.SQLFreeHandle(SQL_HANDLE_ENV, m_handles.m_hevn);
m_handles.m_hevn = NULL;
}
throw;
}
}
/*virtual */
void IodbcConnection::UnInitializeClient()
{
assert(m_handles.m_hevn);
Check(g_odbcAPI.SQLFreeHandle(SQL_HANDLE_ENV, m_handles.m_hevn), SQL_HANDLE_ENV, m_handles.m_hevn);
m_handles.m_hevn = NULL;
::ReleaseODBCSupport();
}
SQLINTEGER IodbcConnection::LenDataAtExec(){ SQLSMALLINT retlen = 0; char szValue[10]; Check(g_odbcAPI.SQLGetInfo( m_handles.m_hdbc, SQL_NEED_LONG_DATA_LEN, szValue, sizeof(szValue), &retlen), SQL_HANDLE_DBC, m_handles.m_hdbc); if(retlen > 0 && (*szValue == 'Y' || *szValue == 'y')) return SQL_LEN_DATA_AT_EXEC(MaxLongAtExecSize);
return SQL_DATA_AT_EXEC;}/*virtual */void IodbcConnection::CnvtInternalToDateTime( SADateTime &date_time, const void *pInternal, int nInternalSize){ assert(nInternalSize == sizeof(TIMESTAMP_STRUCT));
if(nInternalSize != sizeof(TIMESTAMP_STRUCT))
return; CnvtInternalToDateTime(date_time, *(const TIMESTAMP_STRUCT*)pInternal);}/*static */void IodbcConnection::CnvtInternalToDateTime( SADateTime &date_time, const TIMESTAMP_STRUCT &Internal){
date_time = SADateTime(
Internal.year,
Internal.month,
Internal.day,
Internal.hour,
Internal.minute,
Internal.second);
date_time.Fraction() = Internal.fraction;
}/*static */void IodbcConnection::CnvtDateTimeToInternal( const SADateTime &date_time, TIMESTAMP_STRUCT &Internal){ Internal.year = (SQLSMALLINT)(date_time.GetYear());
Internal.month = (SQLUSMALLINT)(date_time.GetMonth());
Internal.day = (SQLUSMALLINT)date_time.GetDay();
Internal.hour = (SQLUSMALLINT)date_time.GetHour();
Internal.minute = (SQLUSMALLINT)date_time.GetMinute();
Internal.second = (SQLUSMALLINT)date_time.GetSecond();
Internal.fraction = date_time.Fraction();}
/*virtual */
void IodbcConnection::CnvtInternalToCursor(
SACommand * /*pCursor*/,
const void * /*pInternal*/)
{
assert(false);
}
/*virtual */long IodbcConnection::GetClientVersion() const{
if(g_nODBCDLLVersionLoaded == 0) // has not been detected
{
if(IsConnected())
{
char sInfoValue[1024];
SQLSMALLINT cbInfoValue;
g_odbcAPI.SQLGetInfo(m_handles.m_hdbc, SQL_DRIVER_VER, sInfoValue, sizeof(sInfoValue), &cbInfoValue);
sInfoValue[cbInfoValue] = 0;
char *sPoint;
short nMajor = (short)strtol(sInfoValue, &sPoint, 10);
assert(*sPoint == '.');
sPoint++;
short nMinor = (short)strtol(sPoint, &sPoint, 10);
return SA_MAKELONG(nMinor, nMajor);
}
}
return g_nODBCDLLVersionLoaded;}/*virtual */long IodbcConnection::GetServerVersion() const{ char sInfoValue[1024]; SQLSMALLINT cbInfoValue; g_odbcAPI.SQLGetInfo(m_handles.m_hdbc, SQL_DBMS_VER, sInfoValue, sizeof(sInfoValue), &cbInfoValue); sInfoValue[cbInfoValue] = 0; char *sPoint; short nMajor = (short)strtol(sInfoValue, &sPoint, 10); assert(*sPoint == '.'); sPoint++; short nMinor = (short)strtol(sPoint, &sPoint, 10); return SA_MAKELONG(nMinor, nMajor);}/*virtual */SAString IodbcConnection::GetServerVersionString() const{ char sInfoValue[1024]; SQLSMALLINT cbInfoValue; g_odbcAPI.SQLGetInfo(m_handles.m_hdbc, SQL_DBMS_NAME, sInfoValue, sizeof(sInfoValue), &cbInfoValue); SAString s = SAString(sInfoValue, cbInfoValue); s += " Release "; g_odbcAPI.SQLGetInfo(m_handles.m_hdbc, SQL_DBMS_VER, sInfoValue, sizeof(sInfoValue), &cbInfoValue); s += SAString(sInfoValue, cbInfoValue); return s;}/*static */void IodbcConnection::Check( SQLRETURN return_code, SQLSMALLINT HandleType, SQLHANDLE Handle){ if(return_code == SQL_SUCCESS) return; if(return_code == SQL_SUCCESS_WITH_INFO) return; SQLCHAR Sqlstate[5+1]; SQLINTEGER NativeError; char sMsg[4096] = ""; SQLSMALLINT TextLength; SQLRETURN rc = g_odbcAPI.SQLGetDiagRec(HandleType, Handle, 1, Sqlstate, &NativeError, (SQLCHAR *)sMsg, sizeof(sMsg), &TextLength); assert(rc == SQL_SUCCESS);
if(rc != SQL_SUCCESS)
throw SAException(
SA_RDBMS_API_Error,
return_code, -1,
"rc != SQL_SUCCESS");
throw SAException( SA_RDBMS_API_Error, NativeError, -1, "%s", sMsg);}/*virtual */bool IodbcConnection::IsConnected() const{ return m_handles.m_hdbc != NULL;}/*virtual */void IodbcConnection::Connect( const SAString &sDBString, const SAString &sUserID, const SAString &sPassword){ assert(m_handles.m_hevn); // allocated in InitializeClient assert(!m_handles.m_hdbc); try { Check(g_odbcAPI.SQLAllocHandle(SQL_HANDLE_DBC, m_handles.m_hevn, &m_handles.m_hdbc), SQL_HANDLE_ENV, m_handles.m_hevn);
// do not check errors from the next call
// we only want this functionality if it is supported
g_odbcAPI.SQLSetConnectAttr(
m_handles.m_hdbc,
SQL_ATTR_ODBC_CURSORS,
(SQLPOINTER)SQL_CUR_USE_IF_NEEDED,
0);
if(sDBString.Find('=') == -1) // it's not a valid connection string, but it can be DSN name Check(g_odbcAPI.SQLConnect(m_handles.m_hdbc, (SQLCHAR *)(const char*)sDBString, SQL_NTS, (SQLCHAR *)(const char*)sUserID, SQL_NTS, (SQLCHAR *)(const char*)sPassword, SQL_NTS), SQL_HANDLE_DBC, m_handles.m_hdbc); else
{
// we don't need StringLength2 on output, but UnixODBC manager can core dump
// if we pass NULL instead of &StringLength2 (pointer to SQLSMALLINT)
SQLSMALLINT StringLength2 = 0; Check(g_odbcAPI.SQLDriverConnect( m_handles.m_hdbc, NULL, (SQLCHAR *)(const char*)sDBString, SQL_NTS, NULL, 0,
&StringLength2, SQL_DRIVER_NOPROMPT), SQL_HANDLE_DBC, m_handles.m_hdbc);
} } catch(SAException &) { // clean up if(m_handles.m_hdbc) { g_odbcAPI.SQLFreeHandle(SQL_HANDLE_DBC, m_handles.m_hdbc); m_handles.m_hdbc = NULL; } throw; }}/*virtual */void IodbcConnection::Disconnect(){ assert(m_handles.m_hdbc); Check(g_odbcAPI.SQLDisconnect(m_handles.m_hdbc), SQL_HANDLE_DBC, m_handles.m_hdbc); Check(g_odbcAPI.SQLFreeHandle(SQL_HANDLE_DBC, m_handles.m_hdbc), SQL_HANDLE_DBC, m_handles.m_hdbc); m_handles.m_hdbc = NULL;}/*virtual */void IodbcConnection::Commit(){ Check(g_odbcAPI.SQLEndTran(SQL_HANDLE_DBC, m_handles.m_hdbc, SQL_COMMIT), SQL_HANDLE_DBC, m_handles.m_hdbc);}/*virtual */void IodbcConnection::Rollback(){ Check(g_odbcAPI.SQLEndTran(SQL_HANDLE_DBC, m_handles.m_hdbc, SQL_ROLLBACK), SQL_HANDLE_DBC, m_handles.m_hdbc);}//////////////////////////////////////////////////////////////////////// IodbcClient Class////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////IodbcClient::IodbcClient(){}IodbcClient::~IodbcClient(){}ISAConnection *IodbcClient::QueryConnectionInterface( SAConnection *pSAConnection){ return new IodbcConnection(pSAConnection);}//////////////////////////////////////////////////////////////////////// IodbcCursor Class//////////////////////////////////////////////////////////////////////class IodbcCursor : public ISACursor{ odbcCommandHandles m_handles; SAString CallSubProgramSQL(); SADataType_t CnvtNativeToStd( int nNativeType, int nNativeSubType, int nSize, int nPrec, int nScale) const; virtual int CnvtStdToNative(SADataType_t eDataType) const; int CnvtStdToNativeValueType(SADataType_t eDataType) const; void BindLongs();
bool m_bResultSetCanBe;
SQLINTEGER m_nRowsAffected;
void ProcessBatchUntilEndOrResultSet();protected: virtual unsigned int InputBufferSize( const SAParam &Param) const; virtual unsigned int OutputBufferSize( SADataType_t eDataType, unsigned int nDataSize) const; virtual void SetFieldBuffer( int nCol, // 1-based void *pInd, unsigned int nIndSize, void *pSize, unsigned int nSizeSize, void *pValue, unsigned int nValueSize); virtual bool IndicatorIsNull( int nPos, // 1-based SAValueRead &vr, ValueType_t eValueType, void *pInd, unsigned int nIndSize, void *pSize, unsigned int nSizeSize, unsigned int &nRealSize,
int nBulkReadingBufPos) const;public: IodbcCursor( IodbcConnection *pIodbcConnection, SACommand *pCommand); virtual ~IodbcCursor(); virtual bool IsOpened(); virtual void Open(); virtual void Close(); virtual void Prepare( const SAString &sStmt, SACommandType_t eCmdType, int nPlaceHolderCount, saPlaceHolder **ppPlaceHolders); // binds parameters void Bind( int nPlaceHolderCount, saPlaceHolder **ppPlaceHolders); // executes statement virtual void Execute(
int nPlaceHolderCount,
saPlaceHolder **ppPlaceHolders);
// cleans up after execute if needed, so the statement can be reexecuted
virtual void UnExecute();
virtual void Cancel(); virtual bool ResultSetExists(); virtual void DescribeFields(
DescribeFields_cb_t fn);
virtual void SetSelectBuffers(); virtual bool FetchNext();
virtual long GetRowsAffected(); virtual void ReadLongOrLOB( ValueType_t eValueType, SAValueRead &vr, void *pValue, unsigned int nFieldBufSize, saLongOrLobReader_t fnReader, unsigned int nReaderWantedPieceSize, void *pAddlData); virtual void DescribeParamSP(); virtual saCommandHandles *NativeHandles();};//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////IodbcCursor::IodbcCursor( IodbcConnection *pIodbcConnection, SACommand *pCommand) : ISACursor(pIodbcConnection, pCommand){
m_bResultSetCanBe = false;
m_nRowsAffected = -1;}/*virtual */IodbcCursor::~IodbcCursor(){}/*virtual */unsigned int IodbcCursor::InputBufferSize( const SAParam &Param) const{ if(!Param.isNull()) { switch(Param.DataType()) {
case SA_dtBool:
return sizeof(unsigned char); // SQL_C_BIT
case SA_dtDateTime: return sizeof(TIMESTAMP_STRUCT); case SA_dtLongBinary: case SA_dtLongChar: case SA_dtBLob: case SA_dtCLob: return 0;
default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -