📄 isaclient.cpp
字号:
}
/*static */
bool ISACursor::isLob(SADataType_t eDataType)
{
switch(eDataType)
{
case SA_dtBLob:
case SA_dtCLob:
return true;
default:
break;
}
return false;
}
/*static */
bool ISACursor::isLongOrLob(SADataType_t eDataType)
{
return isLong(eDataType) || isLob(eDataType);
}
/*static */
bool ISACursor::isInputParam(const SAParam& Param)
{
switch(Param.ParamDirType())
{
case SA_ParamInput:
case SA_ParamInputOutput:
return true;
case SA_ParamOutput:
case SA_ParamReturn:
break;
default:
assert(false);
}
return false;
}
/*static */
bool ISACursor::isOutputParam(const SAParam& Param)
{
switch(Param.ParamDirType())
{
case SA_ParamInputOutput:
case SA_ParamOutput:
case SA_ParamReturn:
return true;
case SA_ParamInput:
break;
default:
assert(false);
}
return false;
}
int ISACursor::BulkReadingBufSize() const
{
SAString s = m_pCommand->Option("BulkReadingBufSize");
if(s.IsEmpty())
return 0; // defaults to non bulk reading
return sa_toi(s);
}
void ISACursor::WriteLongOrLobToInternalValue(SAValue &value)
{
if(value.m_fnWriter != saDefaultLongOrLobWriter)
{
value.m_pString->Empty();
unsigned int nActualWrite;
SAPieceType_t ePieceType = SA_FirstPiece;
void *pBuf;
while((nActualWrite = value.InvokeWriter(
ePieceType, 0xffff, pBuf)) != 0)
{
// for non-binary (text) data:
// nActualWrite is in bytes not characters,
// so binary processing is used always
//(*value.m_pString) += SAString(pBuf, nActualWrite);
int nBinaryLen = value.m_pString->GetBinaryLength();
memcpy((unsigned char*)value.m_pString->GetBinaryBuffer(nBinaryLen + nActualWrite) + nBinaryLen, pBuf, nActualWrite);
value.m_pString->ReleaseBinaryBuffer(nBinaryLen + nActualWrite);
if(ePieceType == SA_LastPiece)
break;
}
}
}
//////////////////////////////////////////////////////////////////////
// SADummyConverter Class
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
SADummyConverter::SADummyConverter()
{
m_nExternalDataSize = 0;
m_bEmptyFinalPiecePending = false;
m_eCnvtPieceType = SA_OnePiece; // assumption only
}
//////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////
void SADummyConverter::FlushExternalData(
unsigned char *
#ifndef NDEBUG
pData
#endif
, unsigned int &nDataSize)
{
assert(!SADummyConverter::IsEmpty());
assert(pData == m_pExternalData); // we are just a repeater, we are not expected to copy data into pData
nDataSize = m_nExternalDataSize;
// we've given all the data, we are empty
m_nExternalDataSize = 0;
m_bEmptyFinalPiecePending = false;
}
void SADummyConverter::SetExternalData(unsigned char *pExternalData, unsigned int nExternalDataSize)
{
m_pExternalData = pExternalData;
m_nExternalDataSize = nExternalDataSize;
}
//////////////////////////////////////////////////////////////////////
// Overides
//////////////////////////////////////////////////////////////////////
/*virtual */
void SADummyConverter::PutStream(unsigned char *pExternalData, unsigned int nExternalDataSize, SAPieceType_t eExternalPieceType)
{
// we do not support several PutStream calls one by one (no buffering)
// if buffering is required, it should be implemented transparently by
// inherited classes
assert(SADummyConverter::IsEmpty());
SetExternalData(pExternalData, nExternalDataSize);
m_eExternalPieceType = eExternalPieceType;
// special case
if(nExternalDataSize == 0 && (eExternalPieceType == SA_OnePiece || eExternalPieceType == SA_LastPiece))
m_bEmptyFinalPiecePending = true;
}
bool SADummyConverter::StreamIsEnough(
unsigned int nWantedSize, unsigned int nExternalDataSize) const
{
assert(nExternalDataSize <= nWantedSize);
bool bFinalExternalPiece = m_eExternalPieceType == SA_OnePiece || m_eExternalPieceType == SA_LastPiece;
// check if there isn't enough data
if(!bFinalExternalPiece && nExternalDataSize < nWantedSize)
return false;
return true;
}
/*virtual */
bool SADummyConverter::GetStream(unsigned char *pData, unsigned int nWantedSize, unsigned int &nDataSize, SAPieceType_t &eCnvtPieceType)
{
// we do not support buffering
// if buffering is required, it should be implemented transparently
// by inherited classes
if(SADummyConverter::IsEmpty())
return false;
assert(m_nExternalDataSize <= nWantedSize);
bool bFinalExternalPiece = m_eExternalPieceType == SA_OnePiece || m_eExternalPieceType == SA_LastPiece;
// check if there isn't enough data
if(!bFinalExternalPiece && m_nExternalDataSize < nWantedSize)
return false;
// we have enough data to return, let do it
FlushExternalData(pData, nDataSize);
// virtual call, this shows if inherited class caches some data
bool bEmptyAfterFlush = IsEmpty();
// adjust m_eCnvtPieceType
switch(m_eCnvtPieceType)
{
case SA_OnePiece:
if(!bEmptyAfterFlush || !bFinalExternalPiece)
m_eCnvtPieceType = SA_FirstPiece;
break;
case SA_FirstPiece:
case SA_NextPiece:
m_eCnvtPieceType = bFinalExternalPiece? (bEmptyAfterFlush? SA_LastPiece : SA_NextPiece) : SA_NextPiece;
break;
default:
assert(false);
}
eCnvtPieceType = m_eCnvtPieceType;
return true;
}
/*virtual */
bool SADummyConverter::IsEmpty() const
{
return m_nExternalDataSize == 0 && !m_bEmptyFinalPiecePending;
}
//////////////////////////////////////////////////////////////////////
// SABufferConverter Class
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
SABufferConverter::SABufferConverter()
{
}
/*virtual */
SABufferConverter::~SABufferConverter()
{
}
//////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////
unsigned char *SABufferConverter::GetAppendBuffer(int nAppendBytesMaxCount)
{
int nBytes = m_Buffer.GetBinaryLength();
void *pBuf = m_Buffer.GetBinaryBuffer(nBytes + nAppendBytesMaxCount);
return (unsigned char*)pBuf + nBytes;
}
void SABufferConverter::ReleaseAppendBuffer(int nAppendBytesCount)
{
int nBytes = m_Buffer.GetBinaryLength();
m_Buffer.ReleaseBinaryBuffer(nBytes + nAppendBytesCount);
}
//////////////////////////////////////////////////////////////////////
// Overides
//////////////////////////////////////////////////////////////////////
/*virtual */
bool SABufferConverter::GetStream(unsigned char *pData, unsigned int nWantedSize, unsigned int &nDataSize, SAPieceType_t &eCnvtPieceType)
{
if(SABufferConverter::IsEmpty())
return false;
if(m_Buffer.IsEmpty())
{
bool bRes = SADummyConverter::GetStream(pData, nWantedSize, nDataSize, eCnvtPieceType);
if(bRes)
return bRes;
// we need to save data (buffering)
FlushExternalData(pData, nDataSize);
void *pBuf = m_Buffer.GetBinaryBuffer(nDataSize);
memcpy(pBuf, pData, nDataSize);
m_Buffer.ReleaseBinaryBuffer(nDataSize);
return false;
}
// extend the buffer
// concatenate old buffer with new data
int nCurSize = m_Buffer.GetBinaryLength();
if(SADummyConverter::IsEmpty())
nDataSize = 0;
else
FlushExternalData(pData, nDataSize);
unsigned char *pBuf = (unsigned char*)m_Buffer.GetBinaryBuffer(nCurSize + nDataSize);
memcpy(pBuf+nCurSize, pData, nDataSize);
int nSizeToReturn = sa_min(nCurSize + nDataSize, nWantedSize);
if(StreamIsEnough(nWantedSize, nSizeToReturn))
{
memcpy(pData, pBuf, nSizeToReturn);
SetExternalData(pData, nSizeToReturn);
// use memmove, areas can overlap
memmove(pBuf, pBuf + nSizeToReturn, nCurSize + nDataSize - nSizeToReturn);
m_Buffer.ReleaseBinaryBuffer(nCurSize + nDataSize - nSizeToReturn);
bool bRes = SADummyConverter::GetStream(pData, nWantedSize, nDataSize, eCnvtPieceType);
assert(bRes);
return bRes;
}
// !StreamIsEnough(...)
m_Buffer.ReleaseBinaryBuffer(nCurSize + nDataSize);
return false;
}
/*virtual */
bool SABufferConverter::IsEmpty() const
{
if(m_Buffer.IsEmpty())
return SADummyConverter::IsEmpty();
return false;
}
//////////////////////////////////////////////////////////////////////
// SAUnicode2MultibyteConverter Class
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
SAUnicode2MultibyteConverter::SAUnicode2MultibyteConverter()
{
m_ReminderBytesCount = 0;
}
/*virtual */
SAUnicode2MultibyteConverter::~SAUnicode2MultibyteConverter()
{
}
//////////////////////////////////////////////////////////////////////
// Overides
//////////////////////////////////////////////////////////////////////
/*virtual */
bool SAUnicode2MultibyteConverter::GetStream(
unsigned char *pData,
unsigned int nWantedSize,
unsigned int &nDataSize,
SAPieceType_t &eDataPieceType)
{
if(SAUnicode2MultibyteConverter::IsEmpty())
return false;
// very simple trick: convert all the data and put it
// into parent class' buffer, then let it deal with it
if(SADummyConverter::IsEmpty())
nDataSize = 0;
else
FlushExternalData(pData, nDataSize);
// chek if we have a reminder from previous conversion
unsigned char *pNewData = pData;
if(m_ReminderBytesCount)
{
assert(m_ReminderBytesCount < sizeof(wchar_t));
// try to complete one Unicode character
while(m_ReminderBytesCount < sizeof(wchar_t) && nDataSize > 0)
{
m_chReminderBytes[m_ReminderBytesCount] = *pNewData;
++m_ReminderBytesCount;
--nDataSize;
++pNewData;
}
}
assert(m_ReminderBytesCount <= sizeof(wchar_t));
int nNewUnicodeChars = nDataSize/sizeof(wchar_t);
if(m_ReminderBytesCount == sizeof(wchar_t) || nNewUnicodeChars)
{
// assume that each Unicode character can be converted to max four-byte character
int nNewMultiByteBytesMax = 4*(nNewUnicodeChars + (m_ReminderBytesCount? 1 :0));
void *pMultiByteBuffer = GetAppendBuffer(nNewMultiByteBytesMax);
int nNewReminderMultiByteBytes = 0;
if(m_ReminderBytesCount)
{
assert(m_ReminderBytesCount == sizeof(wchar_t));
nNewReminderMultiByteBytes = SAWideCharToMultiByte(
(char*)pMultiByteBuffer,
(wchar_t*)m_chReminderBytes, 1);
// reminder has been converted, flush it
m_ReminderBytesCount = 0;
}
int nNewDataMultiByteBytes = 0;
if(nNewUnicodeChars)
{
nNewDataMultiByteBytes =
SAWideCharToMultiByte(
(char*)pMultiByteBuffer + nNewReminderMultiByteBytes,
(wchar_t*)pNewData, nNewUnicodeChars);
}
assert(nNewReminderMultiByteBytes+nNewDataMultiByteBytes <= nNewMultiByteBytesMax);
ReleaseAppendBuffer(nNewReminderMultiByteBytes+nNewDataMultiByteBytes);
}
// save new reminder bytes if any
unsigned int NewReminderBytesCount = nDataSize%sizeof(wchar_t);
if(NewReminderBytesCount)
{
assert(m_ReminderBytesCount == 0);
while(m_ReminderBytesCount < NewReminderBytesCount)
{
m_chReminderBytes[m_ReminderBytesCount] = pNewData[nNewUnicodeChars*sizeof(wchar_t)+m_ReminderBytesCount];
++m_ReminderBytesCount;
}
}
return SABufferConverter::GetStream(
pData,
nWantedSize,
nDataSize,
eDataPieceType);
}
/*virtual */
bool SAUnicode2MultibyteConverter::IsEmpty() const
{
if(!m_ReminderBytesCount)
return SABufferConverter::IsEmpty();
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -