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

📄 sybclient.cpp

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

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