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

📄 sybclient.cpp

📁 通用的数据库中间库
💻 CPP
📖 第 1 页 / 共 4 页
字号:
// sybClient.cpp: implementation of the IsybClient class.
//
//////////////////////////////////////////////////////////////////////

#include <SQLAPI.h>
#include "sybClient.h"

#include <assert.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>

#include <sybAPI.h>
#include "samisc.h"
#include "errmsg.h"

SQLAPI_API SybErrInfo_t *getSybErrInfo(CS_CONTEXT *context)
{
	SybErrInfo_t *pSybErrInfo = NULL;
	// get (allocated) user data where to return error info
	g_sybAPI.cs_config(
		context,
		CS_GET,
		CS_USERDATA,
		&pSybErrInfo,
		sizeof(SybErrInfo_t *),
		NULL);

	assert(pSybErrInfo);
	return pSybErrInfo;
}

CS_RETCODE CS_PUBLIC DefaultClientMsg_cb(
	CS_CONTEXT *context, CS_CONNECTION * /*connection*/, CS_CLIENTMSG *message)
{
	SybErrInfo_t *pSybErrInfo = getSybErrInfo(context);

	if(pSybErrInfo->msgnumber == 0	// only if no error is waiting to be handled yet
		&& message->severity != CS_SV_INFORM)
	{
		pSybErrInfo->msgnumber = message->msgnumber;
		strncpy(pSybErrInfo->msgstring, message->msgstring, message->msgstringlen);
		pSybErrInfo->msgstring[message->msgstringlen] = 0;
		pSybErrInfo->line = -1;
	}

	return CS_SUCCEED;
}

CS_RETCODE CS_PUBLIC DefaultServerMsg_cb(
	CS_CONTEXT *context, CS_CONNECTION * /*connection*/, CS_SERVERMSG *message)
{
	SybErrInfo_t *pSybErrInfo = getSybErrInfo(context);

	if(pSybErrInfo->msgnumber == 0	// only if no error is waiting to be handled yet
		&& message->severity > 10)	
	{
		pSybErrInfo->msgnumber = message->msgnumber;
		strncpy(pSybErrInfo->msgstring, message->text, message->textlen);
		pSybErrInfo->msgstring[message->textlen] = 0;
		pSybErrInfo->line = message->line;
	}

	return CS_SUCCEED;
}

//////////////////////////////////////////////////////////////////////
// IsybConnection Class
//////////////////////////////////////////////////////////////////////

class IsybConnection : public ISAConnection
{
	friend class IsybCursor;
	friend class IsybClient;

	sybConnectionHandles m_handles;

	SAString	m_sServerName;
	SAString	m_sDatabase;

	CS_RETCODE Check(CS_RETCODE rcd) const;
	CS_RETCODE CheckSilent(CS_RETCODE rcd) const;
	SAString ConvertToString(
		CS_INT srctype, CS_VOID	*src, CS_INT srclen);

	enum {MaxLongPiece = (unsigned int)2147483647};

protected:
	virtual ~IsybConnection();

public:
	IsybConnection(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);
	void CnvtInternalToDateTime(
		SADateTime &date_time,
		const CS_DATETIME &time);
	static void CnvtDateTimeToInternal(
		const SADateTime &date_time,
		SAString &sInternal);
	void CnvtDateTimeToInternal(
		const SADateTime &date_time,
		CS_DATETIME *pInternal);

	virtual void CnvtInternalToCursor(
		SACommand *pCursor,
		const void *pInternal);
};

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

IsybConnection::IsybConnection(
	SAConnection *pSAConnection) : ISAConnection(pSAConnection)
{
}

IsybConnection::~IsybConnection()
{
}

/*virtual */
void IsybConnection::InitializeClient()
{
	::AddSybSupport();

	assert(m_handles.m_context == NULL);

	// allocate context
	CS_CONTEXT *context = NULL;

	try
	{
		// try 11.0 behavior
		CS_INT version = CS_VERSION_110;
		CS_RETCODE rc = g_sybAPI.cs_ctx_alloc(version, &context);
		if(rc == CS_FAIL)	// 11.0 behavior not supported?
		{
			// try 10.0 behavior
			version = CS_VERSION_100;
			rc = g_sybAPI.cs_ctx_alloc(version, &context);
		}
		if(rc == CS_MEM_ERROR)
			throw SAException(SA_Library_Error, -1, -1, "cs_ctx_alloc -> CS_MEM_ERROR");
		if(rc == CS_FAIL)
			throw SAException(SA_Library_Error, -1, -1, "cs_ctx_alloc -> CS_FAIL");
		assert(rc == CS_SUCCEED);

		rc = g_sybAPI.ct_init(context, version);
		if(rc == CS_MEM_ERROR)
			throw SAException(SA_Library_Error, -1, -1, "ct_init -> CS_MEM_ERROR");
		if(rc == CS_FAIL)
			throw SAException(SA_Library_Error, -1, -1, "ct_init -> CS_FAIL");
		assert(rc == CS_SUCCEED);

		// set (allocated) user data where to return error info
		SybErrInfo_t *pSybErrInfo = new SybErrInfo_t;
		memset(pSybErrInfo, 0, sizeof(SybErrInfo_t));

		g_sybAPI.cs_config(
			context, 
			CS_SET,
			CS_USERDATA,
			&pSybErrInfo,
			sizeof(SybErrInfo_t *),
			NULL);
		// set context level callbacks
		g_sybAPI.ct_callback(
			context, NULL, CS_SET, CS_CLIENTMSG_CB,
			(CS_VOID *)DefaultClientMsg_cb);
		g_sybAPI.ct_callback(
			context, NULL, CS_SET, CS_SERVERMSG_CB,
			(CS_VOID *)DefaultServerMsg_cb);

		m_handles.m_context = context;
	}
	catch(SAException &)
	{
		// clean up
		if(context)
		{
			CS_RETCODE retcode = g_sybAPI.ct_exit(context, CS_UNUSED);
			assert(retcode == CS_SUCCEED);
			if(retcode != CS_SUCCEED)
				g_sybAPI.ct_exit(context, CS_FORCE_EXIT);

			g_sybAPI.cs_ctx_drop(context);
		}

		throw;
	}
}

/*virtual */
void IsybConnection::UnInitializeClient()
{
	assert(m_handles.m_context != NULL);

	Check(g_sybAPI.ct_exit(m_handles.m_context, CS_UNUSED));

	SybErrInfo_t *pSybErrInfo = NULL;
	// free user data where to return error info
	g_sybAPI.cs_config(
		m_handles.m_context,
		CS_GET,
		CS_USERDATA,
		&pSybErrInfo,
		sizeof(SybErrInfo_t *),
		NULL);
	delete pSybErrInfo;
	g_sybAPI.cs_ctx_drop(m_handles.m_context);
	m_handles.m_context = NULL;

	::ReleaseSybSupport();
}

CS_RETCODE IsybConnection::Check(CS_RETCODE rcd) const
{
	SybErrInfo_t *pSybErrInfo = NULL;
	// get (allocated) user data where to return error info
	g_sybAPI.cs_config(
		m_handles.m_context, 
		CS_GET,
		CS_USERDATA,
		&pSybErrInfo,
		sizeof(SybErrInfo_t *),
		NULL);
	assert(pSybErrInfo);

	// save
	SybErrInfo_t SybErrInfoSave = *pSybErrInfo;

	// clear
	memset(pSybErrInfo, 0, sizeof(SybErrInfo_t));

	if(SybErrInfoSave.msgnumber)
		throw SAException(
			SA_RDBMS_API_Error,
			SybErrInfoSave.msgnumber, 
			SybErrInfoSave.line,
			SybErrInfoSave.msgstring);

	return rcd;
}

CS_RETCODE IsybConnection::CheckSilent(CS_RETCODE rcd) const
{
	SybErrInfo_t *pSybErrInfo = NULL;
	// get (allocated) user data where to return error info
	g_sybAPI.cs_config(
		m_handles.m_context, 
		CS_GET,
		CS_USERDATA,
		&pSybErrInfo,
		sizeof(SybErrInfo_t *),
		NULL);
	assert(pSybErrInfo);

	// clear
	memset(pSybErrInfo, 0, sizeof(SybErrInfo_t));

	return rcd;
}

SAString IsybConnection::ConvertToString(
	CS_INT srctype, CS_VOID	*src, CS_INT srclen)
{
	assert(m_handles.m_context != NULL);

	SAString sConverted;
	CS_INT destlen = sa_max(1024, srclen*2);
	CS_VOID *dest = new char[destlen];

	CS_DATAFMT srcfmt, destfmt;

	srcfmt.datatype = srctype;
	srcfmt.format = CS_FMT_UNUSED;
	srcfmt.maxlength = srclen;
	srcfmt.locale = NULL;

	destfmt.datatype = CS_CHAR_TYPE;
	destfmt.format = CS_FMT_UNUSED;
	destfmt.maxlength = destlen;
	destfmt.locale = NULL;

	CS_INT resultlen;
	Check(g_sybAPI.cs_convert(
		m_handles.m_context,
		&srcfmt,
		src,
		&destfmt,
		dest,
		&resultlen));

	sConverted = SAString((const char*)dest, resultlen);
	delete [] (char*)dest;

	return sConverted;
}

/*virtual */
void IsybConnection::CnvtInternalToDateTime(
	SADateTime &date_time,
	const void *pInternal,
	int	nInternalSize)
{
	assert(nInternalSize == sizeof(CS_DATETIME));
	if(nInternalSize != sizeof(CS_DATETIME))
		return;
	CnvtInternalToDateTime(date_time, *(const CS_DATETIME*)pInternal);
}

void IsybConnection::CnvtInternalToDateTime(
	SADateTime &date_time,
	const CS_DATETIME &Internal)
{
	assert(m_handles.m_context != NULL);

	struct tm &_tm = (struct tm&)date_time;

	CS_DATEREC rec;
	Check(g_sybAPI.cs_dt_crack(
		m_handles.m_context,
		CS_DATETIME_TYPE,
		(CS_VOID*)&Internal,
		&rec));

	_tm.tm_hour = rec.datehour;
	_tm.tm_mday = rec.datedmonth;
	_tm.tm_min = rec.dateminute;
	_tm.tm_mon = rec.datemonth;
	_tm.tm_sec = rec.datesecond;
	_tm.tm_year = rec.dateyear-1900;

	// complete structure
	_tm.tm_isdst = -1;
	// convert CS_DATEREC::datedweek 0 - 6 (Sun. - Sat.) 
	// to struct tm::tm_wday 0 - 6 (Sun. - Sat.)
   	_tm.tm_wday = rec.datedweek;
	// convert CS_DATEREC::datedyear 1-366
	// to struct tm::tm_yday 0-365
	_tm.tm_yday = rec.datedyear - 1;

	// convert SyBase milliseconds to SQLAPI++ nanoseconds
	date_time.Fraction() = rec.datemsecond * 1000000;
}

/*static */
void IsybConnection::CnvtDateTimeToInternal(
	const SADateTime &date_time,
	SAString &sInternal)
{
	// format should be 
	//    YYYYMMDD hh:mm:ss:mmm
	// or YYYYMMDD hh:mm:ss.mmm	- we use this currently
	// or YYYYMMDD hh:mm:ss		- and this
	if(date_time.Fraction())
		sInternal.Format("%.4d%.2d%.2d %.2d:%.2d:%.2d.%.3d",
			date_time.GetYear(), date_time.GetMonth(), date_time.GetDay(),
			date_time.GetHour(), date_time.GetMinute(), date_time.GetSecond(),
			(int)((double)date_time.Fraction() / 1.0e6 + 0.5e-6));
	else
		sInternal.Format("%.4d%.2d%.2d %.2d:%.2d:%.2d",
			date_time.GetYear(), date_time.GetMonth(), date_time.GetDay(),
			date_time.GetHour(), date_time.GetMinute(), date_time.GetSecond());
}

void IsybConnection::CnvtDateTimeToInternal(
	const SADateTime &date_time,
	CS_DATETIME *pInternal)
{
	assert(m_handles.m_context != NULL);

	SAString s;
	CnvtDateTimeToInternal(date_time, s);

	CS_DATAFMT srcfmt, destfmt;

	srcfmt.datatype = CS_CHAR_TYPE;
	srcfmt.format = CS_FMT_UNUSED;
	srcfmt.maxlength = s.GetLength();
	srcfmt.locale = NULL;

	destfmt.datatype = CS_DATETIME_TYPE;
	destfmt.format = CS_FMT_UNUSED;
	destfmt.maxlength = sizeof(CS_DATETIME);
	destfmt.locale = NULL;

	CS_INT resultlen;
	Check(g_sybAPI.cs_convert(
		m_handles.m_context,
		&srcfmt,
		(CS_VOID*)(const char*)s,
		&destfmt,
		pInternal,
		&resultlen));
}

/*virtual */
void IsybConnection::CnvtInternalToCursor(
	SACommand * /*pCursor*/,
	const void * /*pInternal*/)
{
	assert(false);
}

/*virtual */
long IsybConnection::GetClientVersion() const
{
	assert(m_handles.m_context != NULL);

	char sVer[1024];
	Check(g_sybAPI.ct_config(m_handles.m_context, CS_GET, CS_VER_STRING,
		sVer, sizeof(sVer), NULL));
	
	return SAExtractVersionFromString(sVer);
}

/*virtual */
long IsybConnection::GetServerVersion() const
{
	return SAExtractVersionFromString(GetServerVersionString());
}

/*virtual */
SAString IsybConnection::GetServerVersionString() const
{
	SACommand cmd(m_pSAConnection);
	
	bool bASA = false;
	try
	{
		// Check if we are on Adaptive Server Anywhere
		cmd.setCommandText("select dbo.xp_msver('FileDescription') || ' ' || dbo.xp_msver('ProductVersion')", SA_CmdSQLStmt);
		cmd.Execute();
		bASA = true;
	}
	catch(SAException &)
	{
	}

	if(!bASA)
	{
		// If we are on Adaptive Server Enterprise
		cmd.setCommandText("dbo.sp_server_info @attribute_id=2", SA_CmdSQLStmt);
		cmd.Execute();
	}

	cmd.FetchNext();
	SAString sVersion = cmd.Field(bASA? 1 : 3).asString();
	cmd.Close();

	return sVersion;
}

/*virtual */
bool IsybConnection::IsConnected() const
{
	return m_handles.m_connection != NULL;
}

/*virtual */
void IsybConnection::Connect(
	const SAString &sDBString,
	const SAString &sUserID,
	const SAString &sPassword)
{
	assert(m_handles.m_context != NULL);
	assert(m_handles.m_connection == NULL);

	CS_CONNECTION *connection = NULL;

	try
	{
		Check(g_sybAPI.ct_con_alloc(m_handles.m_context, &connection));

		Check(g_sybAPI.ct_con_props(
			connection, CS_SET,
			CS_USERNAME, (CS_VOID*)(const char*)sUserID, CS_NULLTERM, NULL));
		Check(g_sybAPI.ct_con_props(
			connection, CS_SET,
			CS_PASSWORD, (CS_VOID*)(const char*)sPassword, CS_NULLTERM, NULL));

		SAString sPacketSize = m_pSAConnection->Option("CS_PACKETSIZE");
		if(!sPacketSize.IsEmpty())
		{
			CS_INT nPacketSize = atoi(sPacketSize);
			Check(g_sybAPI.ct_con_props(
				connection, CS_SET,
				CS_PACKETSIZE, &nPacketSize, CS_UNUSED, NULL));
		}

		SAString sAppName = m_pSAConnection->Option("CS_APPNAME");
		if(!sAppName.IsEmpty())
			Check(g_sybAPI.ct_con_props(
				connection, CS_SET,
				CS_APPNAME, (CS_VOID*)(const char*)sAppName, CS_NULLTERM, NULL));

		SAString sHostName = m_pSAConnection->Option("CS_HOSTNAME");
		if(!sAppName.IsEmpty())
			Check(g_sybAPI.ct_con_props(
				connection, CS_SET,
				CS_HOSTNAME, (CS_VOID*)(const char*)sHostName, CS_NULLTERM, NULL));

		int iPos = sDBString.FindOneOf(":\\@");
		m_sServerName = sDBString.Left(iPos);
		m_sDatabase = sDBString.Mid(iPos+1);

		Check(g_sybAPI.ct_connect(
			connection,
			m_sServerName.IsEmpty()? NULL : (CS_CHAR*)(const char*)m_sServerName,
			m_sServerName.IsEmpty()? 0 : CS_NULLTERM));

		m_handles.m_connection = connection;

		CS_INT nTextSize = 2147483647;
		Check(g_sybAPI.ct_options(
			m_handles.m_connection,
			CS_SET, CS_OPT_TEXTSIZE, &nTextSize, CS_UNUSED, NULL));

		if(!m_sDatabase.IsEmpty())
		{
			SAString sCmd("use ");
			sCmd += m_sDatabase;
			SACommand cmd(getSAConnection(), sCmd, SA_CmdSQLStmt);
			cmd.Execute();
			cmd.Close();
		}

		// start new transaction if needed
		Commit();
	}
	catch(SAException &)
	{
		// clean up
		if(m_handles.m_connection)	// ct_options or use database failed
		{
			CS_RETCODE rcd = CheckSilent(g_sybAPI.ct_close(m_handles.m_connection, CS_UNUSED));
			if(rcd != CS_SUCCEED)
				CheckSilent(g_sybAPI.ct_close(m_handles.m_connection, CS_FORCE_CLOSE));
			m_handles.m_connection = NULL;
		}
		if(connection)
			CheckSilent(g_sybAPI.ct_con_drop(connection));

		throw;
	}
}

/*virtual */
void IsybConnection::Disconnect()
{
	assert(m_handles.m_connection);

	Check(g_sybAPI.ct_close(m_handles.m_connection, CS_UNUSED));
	Check(g_sybAPI.ct_con_drop(m_handles.m_connection));
	m_handles.m_connection	= NULL;

	m_sServerName.Empty();
	m_sDatabase.Empty();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -