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

📄 ibclient.cpp

📁 通用的数据库中间库
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			&blob_handle,
			sizeof(blob_items), blob_items,
			sizeof(blob_info), blob_info), m_StatusVector);
		int i = 0;
		unsigned long nBlobSize = 0;	// unknown
		while(blob_info[i] != isc_info_end)
		{
			char item = blob_info[i];
			++i;
			ISC_LONG item_length = g_ibAPI.isc_vax_integer(&blob_info[i], 2); i += 2;
			if(item == isc_info_blob_total_length)
			{
				nBlobSize = g_ibAPI.isc_vax_integer(&blob_info[i], (short)item_length);
				break;
			}
			i += item_length;
		}

		// Read and process nReaderWantedPieceSize bytes at a time.
		unsigned char* pBuf;
		unsigned int nPieceSize = vr.PrepareReader(
			nBlobSize,
			IibConnection::MaxBlobPiece,
			pBuf,
			fnReader,
			nReaderWantedPieceSize,
			pAddlData);
		assert(nPieceSize <= IibConnection::MaxBlobPiece);
		unsigned int nCnvtPieceSize = nPieceSize;

		// InterBase can return pieces of less size than asked,
		// so we might need buffering
		SABufferConverter BufferConverter;
		ISADataConverter *pIConverter = &BufferConverter;

		// read all the BLOB data by calling isc_get_segment() repeatedly to get each BLOB
		// segment and its length
		SAPieceType_t ePieceType = SA_FirstPiece;
		unsigned long nTotalRead = 0;
		unsigned long nTotalPassedToReader = 0;
		do
		{
			if(nBlobSize)	// known
				nPieceSize = sa_min(nPieceSize, nBlobSize - nTotalRead);

			unsigned short actual_seg_length;
			ISC_STATUS status = g_ibAPI.isc_get_segment(
				m_StatusVector,
				&blob_handle,
				&actual_seg_length,	// length of segment read
				(unsigned short)nPieceSize,			// length of segment buffer
				(char*)pBuf);				// segment buffer

			if(status != 0 && m_StatusVector[1] != isc_segment && m_StatusVector[1] != isc_segstr_eof)
				IibConnection::Check(status, m_StatusVector);

			assert(!(m_StatusVector[1] == isc_segstr_eof) || (actual_seg_length == 0));
			nTotalRead += actual_seg_length;
			if(nBlobSize)	// known
				assert(nTotalRead <= nBlobSize);

			if(nBlobSize)	// known
			{
				if(nTotalRead == nBlobSize)
				{
					if(ePieceType == SA_NextPiece)
						ePieceType = SA_LastPiece;
					else    // the whole BLob was read in one piece
					{
						assert(ePieceType == SA_FirstPiece);
						ePieceType = SA_OnePiece;
					}
				}
			}
			else
			{
				if(m_StatusVector[1] == isc_segstr_eof)
				{
					if(ePieceType == SA_NextPiece)
						ePieceType = SA_LastPiece;
					else    // the whole Long was read in one piece
					{
						assert(ePieceType == SA_FirstPiece);
						ePieceType = SA_OnePiece;
					}
				}
			}

			pIConverter->PutStream(pBuf, actual_seg_length, ePieceType);
			unsigned int nCnvtSize;
			SAPieceType_t eCnvtPieceType;
			// smart while: initialize nCnvtPieceSize before calling pIConverter->GetStream
			while(nCnvtPieceSize = (nBlobSize? // known
				sa_min(nCnvtPieceSize, nBlobSize - nTotalPassedToReader) : nCnvtPieceSize),
				pIConverter->GetStream(pBuf, nCnvtPieceSize, nCnvtSize, eCnvtPieceType))
			{
				vr.InvokeReader(eCnvtPieceType, pBuf, nCnvtSize);
				nTotalPassedToReader += nCnvtSize;

				if(nBlobSize)	// known
					nCnvtPieceSize = sa_min(nCnvtPieceSize, nBlobSize - nTotalPassedToReader);
			}

			if(ePieceType == SA_FirstPiece)
				ePieceType = SA_NextPiece;
		}
		while(ePieceType != SA_OnePiece && ePieceType != SA_LastPiece);
		assert(pIConverter->IsEmpty());
	}
	catch(SAException &)	// try to clean-up
	{
		g_ibAPI.isc_close_blob(m_StatusVector, &blob_handle);
		throw;
	}

	// close the Blob
	IibConnection::Check(g_ibAPI.isc_close_blob(
		m_StatusVector, &blob_handle), m_StatusVector);
}

/*virtual */
unsigned int IibCursor::InputBufferSize(
	const SAParam &Param) const
{
	if(!Param.isNull())
	{
		switch(Param.DataType())
		{
		case SA_dtBool:
			// there is no "native" boolean type in InterBase,
			// so treat boolean as SQL_SHORT in InterBase
			return sizeof(short);
		case SA_dtDateTime:
			return sizeof(ISC_TIMESTAMP);
		case SA_dtLongBinary:
		case SA_dtLongChar:
		case SA_dtBLob:
		case SA_dtCLob:
			return sizeof(ISC_QUAD);
		default:
			break;
		}
	}
	
	return ISACursor::InputBufferSize(Param);
}

XSQLDA *IibCursor::AllocXSQLDA(short nVars)
{
	int nSize = XSQLDA_LENGTH(nVars);
	XSQLDA *pXSQLDA = (XSQLDA *)malloc(nSize);
	memset(pXSQLDA, 0, nSize);
	pXSQLDA->version = SQLDA_VERSION1;
	pXSQLDA->sqln = nVars;
	pXSQLDA->sqld = nVars;

	return pXSQLDA;
}

void IibCursor::DestroyXSQLDA(XSQLDA *&pXSQLDA)
{
	if(pXSQLDA == NULL)
		return;

	free(pXSQLDA);
	pXSQLDA = NULL;
}

/*virtual */
bool IibCursor::IsOpened()
{
	return m_handles.m_stmt_handle != NULL;
}

/*virtual */
void IibCursor::Open()
{
	assert(m_handles.m_stmt_handle == NULL);

	IibConnection::Check(g_ibAPI.isc_dsql_allocate_statement(
		m_StatusVector,
		&((IibConnection*)m_pISAConnection)->m_handles.m_db_handle,
		&m_handles.m_stmt_handle), m_StatusVector);
	assert(m_handles.m_stmt_handle != NULL);
}

/*virtual */
void IibCursor::Close()
{
	assert(m_handles.m_stmt_handle != NULL);
	IibConnection::Check(g_ibAPI.isc_dsql_free_statement(
		m_StatusVector,
		&m_handles.m_stmt_handle,
		DSQL_drop), m_StatusVector);
	assert(m_handles.m_stmt_handle == NULL);
}

/*virtual */
ISACursor *IibConnection::NewCursor(SACommand *m_pCommand)
{
	return new IibCursor(this, m_pCommand);
}

/*virtual */
void IibCursor::Prepare(
	const SAString &sCmd,
	SACommandType_t eCmdType,
	int nPlaceHolderCount,
	saPlaceHolder **ppPlaceHolders)
{
	// replace bind variables with '?' place holder
	SAString sStmtIB;
	int nPos = 0;
	int i;

	// these counts can be overiden in case of a stored proc
	short nInputParamCount = 0;
	short nOutputParamCount = 0;

	switch(eCmdType)
	{
	case SA_CmdSQLStmt:
		for(i = 0; i < nPlaceHolderCount; ++i)
		{
			sStmtIB += sCmd.Mid(nPos, ppPlaceHolders[i]->getStart()-nPos);
			sStmtIB += "?";
			nPos = ppPlaceHolders[i]->getEnd() + 1;
		}
		// copy tail
		if(nPos < sCmd.GetLength())
			sStmtIB += sCmd.Mid(nPos);
		break;
	case SA_CmdStoredProc:
		sStmtIB = "Execute Procedure ";
		sStmtIB += sCmd;
		for(i = 0; i < m_pCommand->ParamCount(); ++i)
		{
			SAParam &Param = m_pCommand->ParamByIndex(i);
			if(Param.ParamDirType() == SA_ParamInput
				|| Param.ParamDirType() == SA_ParamInputOutput)
			{
				if(++nInputParamCount > 1)
					sStmtIB += " ,?";
				else
					sStmtIB += " ?";
			}

			if(Param.ParamDirType() == SA_ParamOutput
				|| Param.ParamDirType() == SA_ParamInputOutput)
				++nOutputParamCount;
		}

		break;
	default:
		assert(false);
	}

	DestroyXSQLDA(m_pOutXSQLDA);
	if(nOutputParamCount)
		m_pOutXSQLDA = AllocXSQLDA(nOutputParamCount);

	IibConnection::Check(g_ibAPI.isc_dsql_prepare(
		m_StatusVector,
		&((IibConnection*)m_pISAConnection)->m_handles.m_tr_handle,
		&m_handles.m_stmt_handle,
		0,
		(char*)(const char*)sStmtIB,
		SQLDialect(), m_pOutXSQLDA), m_StatusVector);
}

/*virtual */
void IibCursor::UnExecute()
{
	if(m_bResultSet)
		closeResultSet();
}

void IibCursor::BindBlob(ISC_QUAD &BlobID, SAParam &Param)
{
	BlobID.gds_quad_high = 0;
	BlobID.gds_quad_low = 0;

	isc_blob_handle blob_handle = NULL;	// set handle to NULL before using it
	IibConnection::Check(g_ibAPI.isc_create_blob(
		m_StatusVector,
		&((IibConnection*)m_pISAConnection)->m_handles.m_db_handle,
		&((IibConnection*)m_pISAConnection)->m_handles.m_tr_handle,
		&blob_handle, &BlobID), m_StatusVector);

	unsigned int nActualWrite;
	SAPieceType_t ePieceType = SA_FirstPiece;
	void *pBuf;
	while((nActualWrite = Param.InvokeWriter(
		ePieceType,
		IibConnection::MaxBlobPiece, pBuf)) != 0)
	{
		IibConnection::Check(g_ibAPI.isc_put_segment(
			m_StatusVector, &blob_handle,
			(unsigned short)nActualWrite, (char*)pBuf), m_StatusVector);

		if(ePieceType == SA_LastPiece)
			break;
	}

	// Close the Blob
	IibConnection::Check(g_ibAPI.isc_close_blob(
		m_StatusVector,
		&blob_handle), m_StatusVector);
	assert(blob_handle == NULL);
}

void IibCursor::Bind(
		int nPlaceHolderCount,
		saPlaceHolder**	ppPlaceHolders)
{
	// we should bind for every place holder ('?') associated with input or input/output param
	short nInputCount = ParamDirCount(
		nPlaceHolderCount, ppPlaceHolders, 1, SA_ParamInput);
	short nOutputCount = ParamDirCount(
		nPlaceHolderCount, ppPlaceHolders, 1, SA_ParamOutput);
	assert(nInputCount + nOutputCount == nPlaceHolderCount);
	if(nInputCount + nOutputCount != nPlaceHolderCount)
		return;

	AllocBindBuffer(nPlaceHolderCount, ppPlaceHolders, sizeof(short), sizeof(short));
	void *pBuf = m_pParamBuffer;

	DestroyXSQLDA(m_pInXSQLDA);
	m_pInXSQLDA = AllocXSQLDA(nInputCount);
	assert(!nOutputCount || (nOutputCount == m_pOutXSQLDA->sqld));
	assert(!nOutputCount || (nOutputCount == m_pOutXSQLDA->sqln));

	int nInput = 0;
	int nOutput = 0;
	for(int i = 0; i < nPlaceHolderCount; ++i)
	{
		SAParam &Param = *ppPlaceHolders[i]->getParam();
		
		void *pNull;
		void *pSize;
		unsigned int nDataBufSize;
		void *pValue;
		IncParamBuffer(pBuf, pNull, pSize, nDataBufSize, pValue);
		
		if(Param.ParamDirType() == SA_ParamInput)
		{
			short &sqltype = m_pInXSQLDA->sqlvar[nInput].sqltype;
			short &sqlsubtype = m_pInXSQLDA->sqlvar[nInput].sqlsubtype;
			short *&sqlind = m_pInXSQLDA->sqlvar[nInput].sqlind;
			short &sqllen = m_pInXSQLDA->sqlvar[nInput].sqllen;
			char *&sqldata = m_pInXSQLDA->sqlvar[nInput].sqldata;
			
			assert(sqlind == NULL);
			assert(sqldata == NULL);
			sqldata = (char*)pValue;
			sqllen = (short)nDataBufSize;
			
			if(Param.isNull())
			{
				sqlind = (short*)pNull;
				sqltype = SQL_TEXT+1;	// some type should be set
				assert(sqllen == 0);
				*sqlind = -1;
			}
			else
			{
				switch(Param.DataType())
				{
				case SA_dtUnknown:
					throw SAException(SA_Library_Error, -1, -1, IDS_UNKNOWN_PARAMETER_TYPE, (const char*)Param.Name());
				case SA_dtBool:
					// there is no "native" boolean type in InterBase,
					// so treat boolean as SQL_SHORT in InterBase
					sqltype = SQL_SHORT;
					assert(sqllen == sizeof(short));
					*(short*)sqldata = (short)Param.asBool();
					break;
				case SA_dtShort:
					sqltype = SQL_SHORT;
					assert(sqllen == sizeof(short));
					*(short*)sqldata = Param.asShort();
					break;
				case SA_dtLong:
					sqltype = SQL_LONG;
					assert(sqllen == sizeof(long));
					*(long*)sqldata = Param.asLong();
					break;
				case SA_dtDouble:
					sqltype = SQL_DOUBLE;
					assert(sqllen == sizeof(double));
					*(double*)sqldata = Param.asDouble();
					break;
				case SA_dtDateTime:
					sqltype = SQL_DATE;
					assert(sqllen == sizeof(ISC_QUAD));
					IibConnection::CnvtDateTimeToInternal(
						Param.asDateTime(), *(ISC_QUAD*)sqldata);
					break;
				case SA_dtString:
					sqltype = SQL_TEXT;
					assert(sqllen == Param.asString().GetLength());
					memcpy(sqldata, (const char*)Param.asString(), sqllen);
					break;
				case SA_dtBytes:
					sqltype = SQL_TEXT;
					assert(sqllen == Param.asBytes().GetLength());
					memcpy(sqldata, (const char*)Param.asBytes(), sqllen);
					break;
				case SA_dtLongBinary:
				case SA_dtBLob:
					sqltype = SQL_BLOB;
					sqlsubtype = 0;	// binary
					assert(sqllen == sizeof(ISC_QUAD));
					BindBlob(*(ISC_QUAD*)sqldata, Param);
					break;
				case SA_dtLongChar:
				case SA_dtCLob:
					sqltype = SQL_BLOB;
					sqlsubtype = 1;	// text
					assert(sqllen == sizeof(ISC_QUAD));
					BindBlob(*(ISC_QUAD*)sqldata, Param);
					break;
				default:
					assert(false);
				}
			}
			
			++nInput;
		}
		else
		{
			assert(Param.ParamDirType() == SA_ParamOutput);
			
			short &sqltype = m_pOutXSQLDA->sqlvar[nOutput].sqltype;
			short *&sqlind = m_pOutXSQLDA->sqlvar[nOutput].sqlind;
			short &sqllen = m_pOutXSQLDA->sqlvar[nOutput].sqllen;
			char *&sqldata = m_pOutXSQLDA->sqlvar[nOutput].sqldata;
			
			assert(sqlind == NULL);
			assert(sqldata == NULL);
			
			assert((sqltype & 1) != 0);
			sqlind = (short*)pNull;
			if((sqltype & ~1) == SQL_VARYING)
				sqldata = (char*)pSize;
			else
				sqldata = (char*)pValue;
			
			if((sqltype & ~1) == SQL_FLOAT)
			{
				assert(sqllen == sizeof(float));
				// coerce to double
				sqltype &= (~SQL_FLOAT);
				sqltype |= SQL_DOUBLE;
				sqllen = sizeof(double);
			}
			assert(sqllen == Param.ParamSize());
			
			++nOutput;
		}
	}
}

/*virtual */
void IibCursor::Execute(
	int nPlaceHolderCount,
	saPlaceHolder **ppPlaceHolders)
{
	if(nPlaceHolderCount)
		Bind(nPlaceHolderCount, ppPlaceHolders);

	XSQLDA *pOutXSQLDA =
		m_pCommand->CommandType() == SA_CmdStoredProc? m_pOutXSQLDA : NULL;

	IibConnection::Check(g_ibAPI.isc_dsql_execute2(
		m_StatusVector,
		&((IibConnection*)m_pISAConnection)->m_handles.m_tr_handle,
		&m_handles.m_stmt_handle,
		1,
		m_pInXSQLDA,
		pOutXSQLDA), m_StatusVector);

	m_bResultSet = ResultSetExists();
	if(readStmtType() == isc_info_sql_stmt_exec_procedure && m_pOutXSQLDA)
		ConvertOutputParams();
}

/*virtual */
void IibCursor::Cancel()
{
}

ISC_LONG IibCursor::readStmtType()
{
	char type_item[1];
	char res_buffer[8];
	ISC_LONG nLength;

	type_item[0] = isc_info_sql_stmt_type;
	IibConnection::Check(g_ibAPI.isc_dsql_sql_info(
		m_StatusVector,
		&m_handles.m_stmt_handle,
		sizeof(type_item)/sizeof(char), type_item,
		sizeof(res_buffer)/sizeof(char), res_buffer), m_StatusVector);
	if(res_buffer[0] == isc_info_sql_stmt_type)
	{
		nLength = g_ibAPI.isc_vax_integer(&res_buffer[1], 2);
		return g_ibAPI.isc_vax_integer(&res_buffer[3], (short)nLength);
	}

	return 0;
}

void IibCursor::closeResultSet()
{
	assert(m_bResultSet);
	IibConnection::Check(g_ibAPI.isc_dsql_free_statement(
		m_StatusVector,
		&m_handles.m_stmt_handle,
		DSQL_close), m_StatusVector);
	m_bResultSet = false;

	DestroyXSQLDA(m_pOutXSQLDA);
}

/*virtual */
bool IibCursor::ResultSetExists()
{
	switch(readStmtType())
	{
	case isc_info_sql_stmt_select:
	case isc_info_sql_stmt_select_for_upd:
		return true;
	case isc_info_sql_stmt_insert:
		return false;
	case isc_info_sql_stmt_update:
		return false;
	case isc_info_sql_stmt_delete:
		return false;
	case isc_info_sql_stmt_ddl:
		return false;
	case isc_info_sql_stmt_get_segment:
	case isc_info_sql_stmt_put_segment:
	case isc_info_sql_stmt_exec_procedure:
	case isc_info_sql_stmt_start_trans:
	case isc_info_sql_stmt_commit:
	case isc_info_sql_stmt_rollback:
	case isc_info_sql_stmt_set_generator:
		return false;
	}

	return false;
}

/*virtual */
SADataType_t IibCursor::CnvtNativeToStd(
	int nNativeType,
	int nNativeSubType,
	int/* nSize*/,
	int/* nPrec*/,
	int/* nScale*/) const
{
	switch(nNativeType & ~1)
	{
	case SQL_ARRAY:
		return SA_dtBLob;
	case SQL_BLOB:
		if(nNativeSubType == 1)
			return SA_dtCLob;
		else
			return SA_dtBLob;
	case SQL_TEXT:
		return SA_dtString;
	case SQL_SHORT:
		return SA_dtShort;
	case SQL_LONG:
		return SA_dtLong;
	case SQL_FLOAT:
		return SA_dtDouble;
	case SQL_DOUBLE:
		return SA_dtDouble;
	case SQL_VARYING:
		return SA_dtString;

	case SQL_TYPE_DATE:
		return SA_dtDateTime;
	case SQL_TYPE_TIME:
		return SA_dtDateTime;
	case SQL_TIMESTAMP:
		return SA_dtDateTime;

	default:
		assert(false);	// unknown type
	}

	return SA_dtUnknown;
}

/*virtual */
void IibCursor::DescribeFields(
	DescribeFields_cb_t fn)
{
	short cFields = 1;
	DestroyXSQLDA(m_pOutXSQLDA);
	m_pOutXSQLDA = AllocXSQLDA(cFields);
	IibConnection::Check(g_ibAPI.isc_dsql_describe(
		m_StatusVector,
		&m_handles.m_stmt_handle, 1, m_pOutXSQLDA), m_StatusVector);

	if(m_pOutXSQLDA->sqld > m_pOutXSQLDA->sqln)
	{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -