📄 sybclient.cpp
字号:
void IsybCursor::FetchParamResult()
{
// first bind all output params
int nOutputs = 0;
void *pBuf = m_pParamBuffer;
for(int i = 0; i < m_pCommand->ParamCount(); ++i)
{
SAParam &Param = m_pCommand->ParamByIndex(i);
void *pNull;
void *pSize;
unsigned int nDataBufSize;
void *pValue;
IncParamBuffer(pBuf, pNull, pSize, nDataBufSize, pValue);
if(!isOutputParam(Param))
continue;
if(Param.ParamDirType() == SA_ParamReturn)
continue;
else
{
++nOutputs;
}
ct_bind_Buffer(
nOutputs,
pNull, sizeof(CS_SMALLINT),
pSize, sizeof(CS_INT),
pValue, nDataBufSize,
Param.ParamType(), Param.Name(),
1);
}
// then fetch parameter row
CS_INT nRowsRead;
CS_RETCODE rcd = ((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_fetch(
m_handles.m_command,
CS_UNUSED,
CS_UNUSED,
CS_UNUSED,
&nRowsRead));
assert(nRowsRead == 1);
while(rcd != CS_END_DATA)
{
rcd = ((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_fetch(
m_handles.m_command,
CS_UNUSED,
CS_UNUSED,
CS_UNUSED,
NULL/*&nRowsRead*/));
}
}
void IsybCursor::FetchStatusResult()
{
// first bind return status
void *pBuf = m_pParamBuffer;
for(int i = 0; i < m_pCommand->ParamCount(); ++i)
{
SAParam &Param = m_pCommand->ParamByIndex(i);
void *pNull;
void *pSize;
unsigned int nDataBufSize;
void *pValue;
IncParamBuffer(pBuf, pNull, pSize, nDataBufSize, pValue);
if(Param.ParamDirType() != SA_ParamReturn)
continue;
ct_bind_Buffer(
1,
pNull, sizeof(CS_SMALLINT),
pSize, sizeof(CS_INT),
pValue, nDataBufSize,
Param.ParamType(), Param.Name(),
1);
}
// then fetch return status
CS_INT nRowsRead;
CS_RETCODE rcd = ((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_fetch(
m_handles.m_command,
CS_UNUSED,
CS_UNUSED,
CS_UNUSED,
&nRowsRead));
assert(nRowsRead == 1);
while(rcd != CS_END_DATA)
{
rcd = ((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_fetch(
m_handles.m_command,
CS_UNUSED,
CS_UNUSED,
CS_UNUSED,
NULL/*&nRowsRead*/));
}
}
/*virtual */
bool IsybCursor::FetchNext()
{
assert(m_bResultsPending == true);
if(m_cRowCurrent == m_cRowsObtained)
{
CS_RETCODE rcd = ((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_fetch(
m_handles.m_command,
CS_UNUSED,
CS_UNUSED,
CS_UNUSED,
&m_cRowsObtained));
if(rcd == CS_END_DATA)
m_cRowsObtained = 0;
m_cRowCurrent = 0;
}
if(m_cRowsObtained)
{
// use default helpers
ConvertSelectBufferToFields(m_cRowCurrent++);
}
else
ProcessBatchUntilEndOrResultSet();
return m_cRowsObtained != 0;
}
/*virtual */
void IsybCursor::ReadLongOrLOB(
ValueType_t /* eValueType*/,
SAValueRead &vr,
void * /*pValue*/,
unsigned int/* nBufSize*/,
saLongOrLobReader_t fnReader,
unsigned int nReaderWantedPieceSize,
void *pAddlData)
{
SAField &Field = (SAField &)vr;
// get long size
CS_IODESC iodesc;
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_data_info(
m_handles.m_command,
CS_GET,
Field.Pos(),
&iodesc));
CS_INT nLongLen = iodesc.total_txtlen;
assert(nLongLen > 0); // known
unsigned char* pBuf;
unsigned int nPortionSize = vr.PrepareReader(
nLongLen,
IsybConnection::MaxLongPiece,
pBuf,
fnReader,
nReaderWantedPieceSize,
pAddlData);
assert(nPortionSize <= IsybConnection::MaxLongPiece);
SAPieceType_t ePieceType = SA_FirstPiece;
unsigned int nTotalRead = 0;
do
{
nPortionSize =
sa_min(nPortionSize, nLongLen - nTotalRead);
CS_INT nActualRead;
((IsybConnection*)m_pISAConnection)->Check(g_sybAPI.ct_get_data(
m_handles.m_command,
Field.Pos(),
pBuf, nPortionSize,
&nActualRead));
nTotalRead += nActualRead;
if(nTotalRead == (unsigned int)nLongLen)
{
if(ePieceType == SA_NextPiece)
ePieceType = SA_LastPiece;
else // the whole BLob was read in one piece
{
assert(ePieceType == SA_FirstPiece);
ePieceType = SA_OnePiece;
}
}
vr.InvokeReader(ePieceType, pBuf, nActualRead);
if(ePieceType == SA_FirstPiece)
ePieceType = SA_NextPiece;
}
while(nTotalRead < (unsigned int)nLongLen);
assert((CS_INT)nTotalRead == nLongLen);
}
/*virtual */
void IsybCursor::DescribeParamSP()
{
SACommand cmd(m_pISAConnection->getSAConnection());
SAString sProcName = m_pCommand->CommandText();
SAString sSQL;
bool bASA = false;
try
{
// Check if we are on Adaptive Server Anywhere
sSQL.Format(
"select"
" spp.parm_name as name, spp.domain_id as type, spp.width as length, spp.width as prec, spp.scale,"
" spp.parm_mode_in || spp.parm_mode_out as parm_mode "
"from"
" sysobjects so,"
" sysprocedure sp, sysprocparm spp "
"where"
" so.id = object_id('%s') and so.type = 'P' and"
" so.name = sp.proc_name and so.uid = sp.creator and"
" spp.proc_id = sp.proc_id and"
" spp.parm_type = 0 "
"order by"
" spp.parm_id", (const char*)sProcName);
cmd.setCommandText(sSQL);
cmd.Execute();
bASA = true;
}
catch(SAException &)
{
}
if(!bASA)
{
// If we are on Adaptive Server Enterprise
sSQL.Format(
"select"
" sc.name, sc.type, sc.length, sc.prec, sc.scale,"
" 'YN' as parm_mode "
"from"
" dbo.sysobjects so, dbo.syscolumns sc "
"where"
" so.id = object_id('%s') and so.type = 'P' and"
" so.id = sc.id "
"order by"
" sc.colid", (const char*)sProcName);
cmd.setCommandText(sSQL);
cmd.Execute();
}
while(cmd.FetchNext())
{
SAString sName = cmd["name"].asString();
if(sName.Left(1) == "@")
sName.Delete(0);
int nParamSize = cmd["length"].asShort();
short nType = cmd["type"].asShort();
short nPrec = cmd["prec"].isNull()? (short)0 : cmd["prec"].asShort();
short nScale = cmd["scale"].isNull()? (short)0 : cmd["scale"].asShort();
SADataType_t eDataType = bASA?
CnvtNativeTypeFromASADomainIDToStd(
nType,
0, nParamSize,
nPrec,
nScale) :
CnvtNativeTypeFromASESysColumnsToStd(
nType,
0, nParamSize,
nPrec,
nScale);
SAParamDirType_t eDirType = SA_ParamInput;
SAString sParmMode = cmd["parm_mode"].asString();
if(sParmMode == "YN")
eDirType = SA_ParamInput;
else if(sParmMode == "YY")
eDirType = SA_ParamInputOutput;
else if(sParmMode == "NY")
eDirType = SA_ParamOutput;
else
assert(false);
m_pCommand->CreateParam(sName,
eDataType, IsybCursor::CnvtStdToNative(eDataType), nParamSize, eDirType);
}
// now check if SA_Param_Return parameter is described
// if not (currently true for Sybase ASE and ASA) add it manually
m_pCommand->CreateParam(
"RETURN_VALUE",
SA_dtLong,
IsybCursor::CnvtStdToNative(SA_dtLong),
sizeof(long),
SA_ParamReturn);
}
/*virtual */
saAPI *IsybConnection::NativeAPI() const
{
return &g_sybAPI;
}
/*virtual */
saConnectionHandles *IsybConnection::NativeHandles()
{
return &m_handles;
}
/*virtual */
saCommandHandles *IsybCursor::NativeHandles()
{
return &m_handles;
}
/*virtual */
void IsybConnection::setIsolationLevel(
SAIsolationLevel_t eIsolationLevel)
{
// if(false)
// {
// CS_INT level;
//
// switch(eIsolationLevel)
// {
// case SA_ReadUncommitted:
// level = CS_OPT_LEVEL0;
// break;
// case SA_ReadCommitted:
// level = CS_OPT_LEVEL1;
// break;
// case SA_RepeatableRead:
// level = 2; //CS_OPT_LEVEL2;
// break;
// case SA_Serializable:
// level = CS_OPT_LEVEL3;
// break;
// default:
// assert(false);
// return;
// }
//
// Check(g_sybAPI.ct_options(
// m_handles.m_connection,
// CS_SET, CS_OPT_ISOLATION, &level, CS_UNUSED, NULL));
//
// return;
// }
SAString sCmd("set transaction isolation level ");
SACommand cmd(m_pSAConnection);
switch(eIsolationLevel)
{
case SA_ReadUncommitted:
sCmd += "0\0read uncommitted";
break;
case SA_ReadCommitted:
sCmd += "1\0read committed";
break;
case SA_RepeatableRead:
sCmd += "2\0repeatable read";
break;
case SA_Serializable:
sCmd += "3\0serializable";
break;
default:
assert(false);
return;
}
cmd.setCommandText(sCmd, SA_CmdSQLStmt);
cmd.Execute();
cmd.Close();
}
/*virtual */
void IsybConnection::setAutoCommit(
SAAutoCommit_t eAutoCommit)
{
SACommand cmd(m_pSAConnection);
cmd.setCommandText("commit tran", SA_CmdSQLStmt);
cmd.Execute();
if(eAutoCommit == SA_AutoCommitOff)
{
cmd.setCommandText("begin tran", SA_CmdSQLStmt);
cmd.Execute();
}
cmd.Close();
}
//////////////////////////////////////////////////////////////////////
// sybExternalConnection Class
//////////////////////////////////////////////////////////////////////
sybExternalConnection::sybExternalConnection(
SAConnection *pCon,
CS_CONTEXT *context,
CS_CONNECTION *connection)
{
m_bAttached = false;
m_pCon = pCon;
m_context = context;
m_connection = connection;
m_pExternalUserData = ::malloc(sizeof(void *));
m_nExternalUserDataAllocated = sizeof(void *);
}
void sybExternalConnection::Attach()
{
Detach(); // if any
if(m_pCon->isConnected())
m_pCon->Disconnect();
m_pCon->setClient(SA_Sybase_Client);
sybAPI *psybAPI = (sybAPI *)m_pCon->NativeAPI();
sybConnectionHandles *psybConnectionHandles = (sybConnectionHandles *)
m_pCon->NativeHandles();
CS_RETCODE rc;
// save original callbacks for "external" handles
// we will later replace them with SQLAPI++ compatible ones
rc = psybAPI->ct_callback(
m_context, NULL, CS_GET, CS_CLIENTMSG_CB,
&m_ExternalContextClientMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
m_context, NULL, CS_GET, CS_SERVERMSG_CB,
&m_ExternalContextServerMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
NULL, m_connection, CS_GET, CS_CLIENTMSG_CB,
&m_ExternalConnectionClientMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
NULL, m_connection, CS_GET, CS_SERVERMSG_CB,
&m_ExternalConnectionServerMsg_cb);
assert(rc == CS_SUCCEED);
// disable original callbacks for "external" context
rc = psybAPI->ct_callback(
m_context, NULL, CS_SET, CS_CLIENTMSG_CB,
NULL);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
m_context, NULL, CS_SET, CS_SERVERMSG_CB,
NULL);
assert(rc == CS_SUCCEED);
// save original user data for "external" context handle
// we will later replace it with SQLAPI++ compatible
rc = psybAPI->cs_config(
m_context, CS_GET, CS_USERDATA,
m_pExternalUserData, m_nExternalUserDataAllocated,
&m_nExternalUserDataLen);
if(rc != CS_SUCCEED)
{
m_pExternalUserData = ::realloc(m_pExternalUserData, m_nExternalUserDataLen);
m_nExternalUserDataAllocated = m_nExternalUserDataLen;
rc = psybAPI->cs_config(
m_context, CS_GET, CS_USERDATA,
m_pExternalUserData, m_nExternalUserDataAllocated,
NULL);
assert(rc == CS_SUCCEED);
}
// get original callback handlers for client and server messages
// (context level callbacks)
CS_VOID *SQLAPIClientMsg_cb = NULL;
CS_VOID *SQLAPIServerMsg_cb = NULL;
rc = psybAPI->ct_callback(
psybConnectionHandles->m_context, NULL, CS_GET, CS_CLIENTMSG_CB,
&SQLAPIClientMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
psybConnectionHandles->m_context, NULL, CS_GET, CS_SERVERMSG_CB,
&SQLAPIServerMsg_cb);
assert(rc == CS_SUCCEED);
// replace "external" context user data with SQLAPI++ compatible
SybErrInfo_t *pSybErrInfo = &m_SybErrInfo;
memset(pSybErrInfo, 0, sizeof(SybErrInfo_t));
rc = psybAPI->cs_config(
m_context,
CS_SET,
CS_USERDATA,
&pSybErrInfo,
sizeof(SybErrInfo_t *),
NULL);
assert(rc == CS_SUCCEED);
// replace "external" callbacks with SQLAPI++ default ones
rc = psybAPI->ct_callback(
m_context, NULL, CS_SET, CS_CLIENTMSG_CB,
SQLAPIClientMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
m_context, NULL, CS_SET, CS_SERVERMSG_CB,
SQLAPIServerMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
NULL, m_connection, CS_SET, CS_CLIENTMSG_CB,
SQLAPIClientMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
NULL, m_connection, CS_SET, CS_SERVERMSG_CB,
SQLAPIServerMsg_cb);
assert(rc == CS_SUCCEED);
// save original SAConnection handles
m_contextSaved = psybConnectionHandles->m_context;
m_connectionSaved = psybConnectionHandles->m_connection;
// replace SAConnection handles with "external" ones
psybConnectionHandles->m_context = m_context;
psybConnectionHandles->m_connection = m_connection;
m_bAttached = true;
}
void sybExternalConnection::Detach()
{
if(!m_bAttached)
return;
assert(m_pCon->isConnected());
sybAPI *psybAPI = (sybAPI *)m_pCon->NativeAPI();
sybConnectionHandles *psybConnectionHandles = (sybConnectionHandles *)
m_pCon->NativeHandles();
// restore original SAConnection handles
psybConnectionHandles->m_context = m_contextSaved;
psybConnectionHandles->m_connection = m_connectionSaved;
CS_RETCODE rc;
// restore "external" context user data
if(m_nExternalUserDataLen)
rc = psybAPI->cs_config(
m_context,
CS_SET,
CS_USERDATA,
m_pExternalUserData,
m_nExternalUserDataLen,
NULL);
else
rc = psybAPI->cs_config(
m_context,
CS_CLEAR,
CS_USERDATA,
NULL,
CS_UNUSED,
NULL);
assert(rc == CS_SUCCEED);
// restore "external" handles callbacks
rc = psybAPI->ct_callback(
m_context, NULL, CS_SET, CS_CLIENTMSG_CB,
m_ExternalContextClientMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
m_context, NULL, CS_SET, CS_SERVERMSG_CB,
m_ExternalContextServerMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
NULL, m_connection, CS_SET, CS_CLIENTMSG_CB,
m_ExternalConnectionClientMsg_cb);
assert(rc == CS_SUCCEED);
rc = psybAPI->ct_callback(
NULL, m_connection, CS_SET, CS_SERVERMSG_CB,
m_ExternalConnectionServerMsg_cb);
assert(rc == CS_SUCCEED);
m_bAttached = false;
}
sybExternalConnection::~sybExternalConnection()
{
try
{
Detach();
}
catch(SAException &)
{
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -