📄 sybclient.cpp
字号:
// 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 + -