⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ibclient.cpp

📁 通用的数据库中间库
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// 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 + -