📄 ibclient.cpp
字号:
// ibClient.cpp: implementation of the IibClient class.
//
//////////////////////////////////////////////////////////////////////
#include <SQLAPI.h>
#include "ibClient.h"
#include <malloc.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <ibAPI.h>
#include "samisc.h"
#include "errmsg.h"
//////////////////////////////////////////////////////////////////////
// IibConnection Class
//////////////////////////////////////////////////////////////////////
class IibConnection : public ISAConnection
{
friend class IibCursor;
ibConnectionHandles m_handles;
ISC_STATUS m_StatusVector[20]; // Error status vector
char *m_DPB_buffer; // Address of the DPB
short m_DPB_buffer_length; // Number of bytes in the database parameter buffer (DPB)
char m_TPB_buffer[1024]; // Address of the TPB
short m_TPB_buffer_length; // Number of bytes in the transaction parameter buffer (TPB)
static void Check(
const ISC_STATUS &,
ISC_STATUS* pSV);
static SAString FormatIdentifierValue(
unsigned short nSQLDialect,
const SAString &sValue);
enum {MaxBlobPiece = (unsigned int)0xFFFF};
static void ExtractServerVersionCallback(long *pnVersion, char *sStr);
static void ExtractServerVersionStringCallback(SAString *psVersion, char *sStr);
// transaction management helpers
void StartTransaction();
void ConstructTPB(
SAIsolationLevel_t eIsolationLevel,
SAAutoCommit_t eAutoCommit);
void CommitTransaction();
void CommitRetaining();
void RollbackTransaction();
protected:
virtual ~IibConnection();
public:
IibConnection(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 ISC_QUAD &Internal);
static void CnvtDateTimeToInternal(
const SADateTime &date_time,
ISC_QUAD &Internal);
virtual void CnvtInternalToCursor(
SACommand *pCursor,
const void *pInternal);
};
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IibConnection::IibConnection(
SAConnection *pSAConnection) : ISAConnection(pSAConnection)
{
m_DPB_buffer = NULL;
m_DPB_buffer_length = 0;
m_TPB_buffer_length = 0;
}
IibConnection::~IibConnection()
{
if(m_DPB_buffer)
::free(m_DPB_buffer);
}
/*virtual */
void IibConnection::InitializeClient()
{
::AddIB5Support();
}
/*virtual */
void IibConnection::UnInitializeClient()
{
::ReleaseIB5Support();
}
/*virtual */
void IibConnection::CnvtInternalToDateTime(
SADateTime &date_time,
const void *pInternal,
int nInternalSize)
{
assert(nInternalSize == sizeof(ISC_QUAD));
if(nInternalSize != sizeof(ISC_QUAD))
return;
CnvtInternalToDateTime(date_time, *(const ISC_QUAD*)pInternal);
}
/*static */
void IibConnection::CnvtInternalToDateTime(
SADateTime &date_time,
const ISC_QUAD &Internal)
{
struct tm &_tm = (struct tm&)date_time;
g_ibAPI.isc_decode_date((ISC_QUAD*)&Internal, (void*)&_tm);
// no milli, micro or nano seconds in Interbase now
date_time.Fraction() = 0;
}
/*static */
void IibConnection::CnvtDateTimeToInternal(
const SADateTime &hire_time,
ISC_QUAD &time)
{
g_ibAPI.isc_encode_date((void*)&hire_time, &time);
// no milli, micro or nano seconds now
}
/*virtual */
void IibConnection::CnvtInternalToCursor(
SACommand * /*pCursor*/,
const void * /*pInternal*/)
{
assert(false);
}
/*virtual */
long IibConnection::GetClientVersion() const
{
return g_nIB5DLLVersionLoaded;
}
/*static */
void IibConnection::ExtractServerVersionCallback(
long *pnVersion, char *sStr)
{
char *p = strstr(sStr, "(access method)");
if(p)
*pnVersion = SAExtractVersionFromString(p);
}
/*static */
void IibConnection::ExtractServerVersionStringCallback(
SAString *psVersion, char *sStr)
{
char *p = strstr(sStr, "(access method)");
if(p)
*psVersion = sStr;
}
/*virtual */
long IibConnection::GetServerVersion() const
{
long nVersion = 0;
g_ibAPI.isc_version(
(isc_db_handle*)&m_handles.m_db_handle,
(isc_callback)ExtractServerVersionCallback,
&nVersion);
return nVersion;
}
/*virtual */
SAString IibConnection::GetServerVersionString() const
{
SAString sVersion;
g_ibAPI.isc_version(
(isc_db_handle*)&m_handles.m_db_handle,
(isc_callback)ExtractServerVersionStringCallback,
&sVersion);
return sVersion;
}
/*static */
void IibConnection::Check(
const ISC_STATUS &error_code,
ISC_STATUS *pSV)
{
SAString sErr;
if(error_code)
{
char sMsg[512];
long nLen;
ISC_STATUS *pvector; /* Pointer to pointer to status vector. */
// walk through error vector and constract error string
pvector = pSV; /* (Re)set to start of status vector. */
while((nLen = g_ibAPI.isc_interprete(sMsg, &pvector)) != 0) /* More messages? */
{
if(!sErr.IsEmpty())
sErr += "\n";
sErr += SAString(sMsg, nLen);
}
throw SAException(
SA_RDBMS_API_Error,
error_code, -1,
sErr);
}
}
/*virtual */
bool IibConnection::IsConnected() const
{
return m_handles.m_db_handle != NULL;
}
/*virtual */
void IibConnection::Connect(
const SAString &sDBString,
const SAString &sUserID,
const SAString &sPassword)
{
assert(m_handles.m_db_handle == NULL);
assert(m_handles.m_tr_handle == NULL);
assert(m_DPB_buffer == NULL);
assert(m_DPB_buffer_length == 0);
// Construct the database parameter buffer.
m_DPB_buffer = (char*)::malloc(1024);
char *dpb = m_DPB_buffer;
const char *p;
*dpb++ = isc_dpb_version1;
*dpb++ = isc_dpb_user_name;
*dpb++ = (char)sUserID.GetLength();
for(p = sUserID; *p;)
*dpb++ = *p++;
*dpb++ = isc_dpb_password;
*dpb++ = (char)sPassword.GetLength();
for(p = sPassword; *p;)
*dpb++ = *p++;
// additional entries to DPB that can be specified
typedef
struct
{
const char *sKey;
char cValue;
} DPB_Stuff_t;
// string values
DPB_Stuff_t DPB_Strings[] =
{
{"isc_dpb_lc_ctype", isc_dpb_lc_ctype},
{"isc_dpb_sql_role_name", isc_dpb_sql_role_name}
};
unsigned int i;
for(i = 0; i < sizeof(DPB_Strings)/sizeof(DPB_Stuff_t); ++i)
{
SAString sOption = m_pSAConnection->Option(DPB_Strings[i].sKey);
if(sOption.IsEmpty())
continue;
*dpb++ = DPB_Strings[i].cValue;
*dpb++ = (char)sOption.GetLength();
for(p = sOption; *p;)
*dpb++ = *p++;
}
// 1-byte values
DPB_Stuff_t DPB_Byte_1[] =
{
{"isc_dpb_num_buffers", isc_dpb_num_buffers}
};
for(i = 0; i < sizeof(DPB_Byte_1)/sizeof(DPB_Stuff_t); ++i)
{
SAString sOption = m_pSAConnection->Option(DPB_Byte_1[i].sKey);
if(sOption.IsEmpty())
continue;
*dpb++ = DPB_Byte_1[i].cValue;
*dpb++ = (char)1;
*dpb++ = (char)atoi(sOption);
}
m_DPB_buffer_length = (short)(dpb - m_DPB_buffer);
try
{
// attach
Check(g_ibAPI.isc_attach_database(
m_StatusVector, 0, (char*)(const char*)sDBString, &m_handles.m_db_handle,
m_DPB_buffer_length, m_DPB_buffer), m_StatusVector);
// do not call Construct TPB
// start transaction with default isolation level and autocommit option
StartTransaction();
}
catch(...)
{
// clean up
if(m_handles.m_db_handle)
{
g_ibAPI.isc_detach_database(
m_StatusVector, &m_handles.m_db_handle);
assert(m_handles.m_db_handle == NULL);
m_handles.m_db_handle = NULL;
}
if(m_DPB_buffer)
{
free(m_DPB_buffer);
m_DPB_buffer = NULL;
}
m_DPB_buffer_length = 0;
throw;
}
}
/*virtual */
void IibConnection::Disconnect()
{
assert(m_handles.m_db_handle);
assert(m_handles.m_tr_handle);
// first we should close transaction
CommitTransaction(); // commit and close the transaction
assert(m_handles.m_tr_handle == NULL);
// then we can detach
Check(g_ibAPI.isc_detach_database(
m_StatusVector, &m_handles.m_db_handle), m_StatusVector);
assert(m_handles.m_db_handle == NULL);
assert(m_DPB_buffer);
assert(m_DPB_buffer_length);
if(m_DPB_buffer)
::free(m_DPB_buffer);
m_DPB_buffer = NULL;
m_DPB_buffer_length = 0;
}
/*virtual */
void IibConnection::Commit()
{
// always keep transaction open
assert(m_handles.m_tr_handle != NULL);
// use isc_commit_retaining() only if user explicitly asks for it
SAString sCommitRetaining = m_pSAConnection->Option(_SA("CommitRetaining"));
if(sCommitRetaining.CompareNoCase(_SA("true")) == 0)
CommitRetaining(); // commit but leave the transaction open
else
{
CommitTransaction(); // commit and close the transaction
StartTransaction(); // reopen
}
// always keep transaction open
assert(m_handles.m_tr_handle != NULL);
}
/*virtual */
void IibConnection::Rollback()
{
// always keep transaction open
assert(m_handles.m_tr_handle != NULL);
RollbackTransaction(); // rollback and close the transaction
StartTransaction(); // reopen
// always keep transaction open
assert(m_handles.m_tr_handle != NULL);
}
void IibConnection::StartTransaction()
{
assert(m_handles.m_tr_handle == NULL);
Check(g_ibAPI.isc_start_transaction(
m_StatusVector,
&m_handles.m_tr_handle,
1, &m_handles.m_db_handle,
m_TPB_buffer_length, m_TPB_buffer), m_StatusVector);
assert(m_handles.m_tr_handle != NULL);
}
//////////////////////////////////////////////////////////////////////
// IibClient Class
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IibClient::IibClient()
{
}
IibClient::~IibClient()
{
}
ISAConnection *IibClient::QueryConnectionInterface(
SAConnection *pSAConnection)
{
return new IibConnection(pSAConnection);
}
//////////////////////////////////////////////////////////////////////
// IibCursor Class
//////////////////////////////////////////////////////////////////////
class IibCursor : public ISACursor
{
ibCommandHandles m_handles;
ISC_STATUS m_StatusVector[20]; // Error status vector
XSQLDA *m_pInXSQLDA;
XSQLDA *m_pOutXSQLDA;
bool m_bResultSet;
ISC_LONG readStmtType();
void closeResultSet();
XSQLDA *AllocXSQLDA(short nVars);
void DestroyXSQLDA(XSQLDA *&pXSQLDA);
void BindBlob(ISC_QUAD &BlobID, SAParam &Param);
virtual SADataType_t CnvtNativeToStd(
int nNativeType,
int nNativeSubType,
int nSize,
int nPrec,
int nScale) const;
unsigned short SQLDialect() const;
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;
virtual void ReadLongOrLOB(
ValueType_t eValueType,
SAValueRead &vr,
void *pValue,
unsigned int nFieldBufSize,
saLongOrLobReader_t fnReader,
unsigned int nReaderWantedPieceSize,
void *pAddlData);
public:
IibCursor(
IibConnection *pIibConnection,
SACommand *pCommand);
virtual ~IibCursor();
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 DescribeParamSP();
virtual saCommandHandles *NativeHandles();
void OnTransactionClosed(void * /*pAddlData*/);
};
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IibCursor::IibCursor(
IibConnection *pIibConnection,
SACommand *pCommand) :
ISACursor(pIibConnection, pCommand)
{
m_pInXSQLDA = NULL;
m_pOutXSQLDA = NULL;
m_bResultSet = false;
}
/*virtual */
IibCursor::~IibCursor()
{
DestroyXSQLDA(m_pInXSQLDA);
DestroyXSQLDA(m_pOutXSQLDA);
}
/*virtual */
void IibCursor::ReadLongOrLOB(
ValueType_t /*eValueType*/,
SAValueRead &vr,
void *pValue,
unsigned int nBufSize,
saLongOrLobReader_t fnReader,
unsigned int nReaderWantedPieceSize,
void *pAddlData)
{
assert(nBufSize == sizeof(ISC_QUAD));
if(nBufSize != sizeof(ISC_QUAD))
return;
ISC_QUAD *pBlobID = (ISC_QUAD*)pValue;
isc_blob_handle blob_handle = NULL; // set handle to NULL before using it
IibConnection::Check(g_ibAPI.isc_open_blob(
m_StatusVector,
&((IibConnection*)m_pISAConnection)->m_handles.m_db_handle,
&((IibConnection*)m_pISAConnection)->m_handles.m_tr_handle,
&blob_handle, // set by this function to refer to the blob
pBlobID), m_StatusVector); // Blob ID put into out_sqlda by isc_fetch()
try
{
// get blob size
char blob_items[] = {isc_info_blob_total_length};
char blob_info[100];
IibConnection::Check(g_ibAPI.isc_blob_info(
m_StatusVector,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -