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

📄 isaclient.cpp

📁 通用的数据库中间库
💻 CPP
📖 第 1 页 / 共 3 页
字号:
}

/*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 + -