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

📄 ibclient.cpp

📁 通用的数据库中间库
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		cFields = m_pOutXSQLDA->sqld;
		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);
		assert(m_pOutXSQLDA->sqld == cFields);
	}

	for(int iField = 0; iField < cFields; ++iField)
	{
		XSQLVAR &var = m_pOutXSQLDA->sqlvar[iField];

		int nFieldPrecision;

		switch(var.sqltype & ~1)
		{
		case SQL_ARRAY:
			nFieldPrecision = 0;
			break;
		case SQL_BLOB:
			nFieldPrecision = 0;
			break;
		case SQL_TEXT:
			nFieldPrecision = var.sqllen;
			break;
		case SQL_SHORT:
			if(var.sqlscale != 0)	// coerce to double
			{
				var.sqltype &= (~SQL_SHORT);
				var.sqltype |= SQL_DOUBLE;
				var.sqllen = sizeof(double);

				nFieldPrecision = 15;
			}
			else
				nFieldPrecision = 5;
			break;
		case SQL_LONG:
			if(var.sqlscale != 0)	// coerce to double
			{
				var.sqltype &= (~SQL_LONG);
				var.sqltype |= SQL_DOUBLE;
				var.sqllen = sizeof(double);

				nFieldPrecision = 15;
			}
			else
				nFieldPrecision = 10;
			break;
		case SQL_INT64:
			// coerce to double
			var.sqltype &= (~SQL_INT64);
			var.sqltype |= SQL_DOUBLE;
			var.sqllen = sizeof(double);

			nFieldPrecision = 15;
			break;
		case SQL_FLOAT:
			// coerce to double
			var.sqltype &= (~SQL_FLOAT);
			var.sqltype |= SQL_DOUBLE;
			var.sqllen = sizeof(double);

			nFieldPrecision = 15;
			break;
		case SQL_DOUBLE:
			nFieldPrecision = 15;
			break;
		case SQL_VARYING:
			nFieldPrecision = var.sqllen;
			break;
		case SQL_TYPE_DATE:
			// coerce to TIMESTAMP
			var.sqltype &= (~SQL_TYPE_DATE);
			var.sqltype |= SQL_TIMESTAMP;
			var.sqllen = sizeof(ISC_TIMESTAMP);

			nFieldPrecision = var.sqllen;
			break;
		case SQL_TYPE_TIME:
			// coerce to TIMESTAMP
			var.sqltype &= (~SQL_TYPE_DATE);
			var.sqltype |= SQL_TIMESTAMP;
			var.sqllen = sizeof(ISC_TIMESTAMP);

			nFieldPrecision = var.sqllen;
			break;
		case SQL_TIMESTAMP:
			nFieldPrecision = var.sqllen;
			break;

		case SQL_D_FLOAT:
		case SQL_QUAD:
		default:
			nFieldPrecision = 0;
			assert(false);	// unknown type
		}

		(m_pCommand->*fn)(
			SAString(var.aliasname, var.aliasname_length),
			CnvtNativeToStd(var.sqltype, var.sqlsubtype, var.sqllen, nFieldPrecision, var.sqlscale),
			(int)var.sqltype,
			var.sqllen,
			var.sqlscale,
			nFieldPrecision,
			!(var.sqltype & 1));
	}
}

/*
bool IibCursor::DescribeField(
	unsigned int nField,	// 1-based
	SAString &sName,
	SADataType_t &eFieldType,
	int &nNativeType,
	int &nFieldSize,
	int &nFieldPrecision,
	int &nFieldScale,
	bool &bFieldRequired)
{
	assert(nField == 1 || m_pOutXSQLDA != NULL);
	if(nField == 1)
	{
		short nFields = 1;
		DestroyXSQLDA(m_pOutXSQLDA);
		m_pOutXSQLDA = AllocXSQLDA(nFields);
		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)
		{
			nFields = m_pOutXSQLDA->sqld;
			DestroyXSQLDA(m_pOutXSQLDA);
			m_pOutXSQLDA = AllocXSQLDA(nFields);
			
			IibConnection::Check(g_ibAPI.isc_dsql_describe(
				m_StatusVector,
				&m_handles.m_stmt_handle, 1, m_pOutXSQLDA), m_StatusVector);
			assert(m_pOutXSQLDA->sqld == nFields);
		}
	}

	if((unsigned int)m_pOutXSQLDA->sqld < nField)
		return false;

	XSQLVAR &var = m_pOutXSQLDA->sqlvar[nField-1];
	sName = SAString(var.aliasname, var.aliasname_length);
	switch(var.sqltype & ~1)
	{
	case SQL_ARRAY:
		nFieldPrecision = 0;
		break;
	case SQL_BLOB:
		nFieldPrecision = 0;
		break;
	case SQL_TEXT:
		nFieldPrecision = var.sqllen;
		break;
	case SQL_SHORT:
		if(var.sqlscale != 0)	// coerce to double
		{
			var.sqltype &= (~SQL_SHORT);
			var.sqltype |= SQL_DOUBLE;
			var.sqllen = sizeof(double);

			nFieldPrecision = 15;
		}
		else
			nFieldPrecision = 5;
		break;
	case SQL_LONG:
		if(var.sqlscale != 0)	// coerce to double
		{
			var.sqltype &= (~SQL_LONG);
			var.sqltype |= SQL_DOUBLE;
			var.sqllen = sizeof(double);

			nFieldPrecision = 15;
		}
		else
			nFieldPrecision = 10;
		break;
	case SQL_INT64:
		// coerce to double
		var.sqltype &= (~SQL_INT64);
		var.sqltype |= SQL_DOUBLE;
		var.sqllen = sizeof(double);

		nFieldPrecision = 15;
		break;
	case SQL_FLOAT:
		// coerce to double
		var.sqltype &= (~SQL_FLOAT);
		var.sqltype |= SQL_DOUBLE;
		var.sqllen = sizeof(double);

		nFieldPrecision = 15;
		break;
	case SQL_DOUBLE:
		nFieldPrecision = 15;
		break;
	case SQL_VARYING:
		nFieldPrecision = var.sqllen;
		break;
	case SQL_TYPE_DATE:
		// coerce to TIMESTAMP
		var.sqltype &= (~SQL_TYPE_DATE);
		var.sqltype |= SQL_TIMESTAMP;
		var.sqllen = sizeof(ISC_TIMESTAMP);

		nFieldPrecision = var.sqllen;
		break;
	case SQL_TYPE_TIME:
		// coerce to TIMESTAMP
		var.sqltype &= (~SQL_TYPE_DATE);
		var.sqltype |= SQL_TIMESTAMP;
		var.sqllen = sizeof(ISC_TIMESTAMP);

		nFieldPrecision = var.sqllen;
		break;
	case SQL_TIMESTAMP:
		nFieldPrecision = var.sqllen;
		break;

	case SQL_D_FLOAT:
	case SQL_QUAD:
	default:
		assert(false);	// unknown type
	}

	eFieldType = CnvtNativeToStd(
		var.sqltype, var.sqlsubtype, var.sqllen, nFieldPrecision, var.sqlscale);
	nNativeType = (int)var.sqltype;
	nFieldSize = var.sqllen;
	nFieldScale = var.sqlscale;
	bFieldRequired = !(var.sqltype & 1);

	return true;
}
*/
/*virtual */
long IibCursor::GetRowsAffected()
{
	char type_item[1];
	char res_buffer[1048];

	type_item[0] = isc_info_sql_records;
	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_records)
	{
		switch(readStmtType())
		{
		case isc_info_sql_stmt_update:
			return g_ibAPI.isc_vax_integer(&res_buffer[6], 2);
		case isc_info_sql_stmt_delete:
			return g_ibAPI.isc_vax_integer(&res_buffer[13], 2);
		case isc_info_sql_stmt_insert:
			return g_ibAPI.isc_vax_integer(&res_buffer[27], 2);
		}
	}

	return -1;
}

/*virtual */
unsigned int IibCursor::OutputBufferSize(
	SADataType_t eDataType,
	unsigned int nDataSize) const
{
	switch(eDataType)
	{
		case SA_dtDateTime:
			return sizeof(ISC_TIMESTAMP);
		case SA_dtBLob:
		case SA_dtCLob:
			return sizeof(ISC_QUAD);
		default:
			break;
	}

	return ISACursor::OutputBufferSize(eDataType, nDataSize);
}


/*virtual */
void IibCursor::SetFieldBuffer(
	int nCol,	// 1-based
	void *pInd,
	unsigned int nIndSize,
	void * /*pSize*/,
	unsigned int nSizeSize,
	void *pValue,
	unsigned int nValueSize)
{
	assert(m_pOutXSQLDA != NULL);	// SetSelectBuffers should always be called after DescribeFields
	assert(nIndSize == sizeof(short));
	if(nIndSize != sizeof(short))
		return;
	assert(nSizeSize == sizeof(short));
	if(nSizeSize != sizeof(short))
		return;

	short &sqltype = m_pOutXSQLDA->sqlvar[nCol-1].sqltype;
	short *&sqlind = m_pOutXSQLDA->sqlvar[nCol-1].sqlind;
	short &sqllen = m_pOutXSQLDA->sqlvar[nCol-1].sqllen;
	char *&sqldata = m_pOutXSQLDA->sqlvar[nCol-1].sqldata;

	assert((unsigned int)sqllen == nValueSize);
	if((unsigned int)sqllen != nValueSize)
		return;

	assert(sqlind == NULL);
	assert(sqldata == NULL);

	if(!m_pCommand->Field(nCol).isFieldRequired())
	{
		assert((sqltype & 1) != 0);
		sqlind = (short*)pInd;
	}
	else
		assert((sqltype & 1) == 0);

	if((sqltype & ~1) == SQL_VARYING)
	{
		// short is reserverd for size returning 
		// just before the actual string
		sqldata = (char*)pValue - sizeof(short);
	}
	else
		sqldata = (char*)pValue;
}

/*virtual */
bool IibCursor::IndicatorIsNull(
	int nPos,	// 1-based
	SAValueRead &/*vr*/,
	ValueType_t/* eValueType*/,
	void * /*pInd*/,
	unsigned int nIndSize,
	void * /*pSize*/,
	unsigned int nSizeSize,
	unsigned int &nRealSize,
	int/* nBulkReadingBufPos*/) const
{
	assert(m_pOutXSQLDA != NULL);	// should always be called after DescribeFields
	assert(nIndSize == sizeof(short));
	if(nIndSize != sizeof(short))
		return true;
	assert(nSizeSize == sizeof(short));
	if(nSizeSize != sizeof(short))
		return true;

	XSQLVAR &var = m_pOutXSQLDA->sqlvar[nPos-1];
	// no indicator, field can not be NULL, or it is not null
	if(var.sqlind == NULL || *var.sqlind != -1)	
	{
		if((var.sqltype & ~1) == SQL_VARYING)
		{
			// short is reserverd for size returning 
			// just before the actual string
			nRealSize = *(short*)var.sqldata;
		}
		else
			nRealSize = var.sqllen;

		return false;
	}

	return true;
}

/*virtual */
void IibCursor::SetSelectBuffers()
{
	// use default helpers
	AllocSelectBuffer(sizeof(short), sizeof(short));
}

/*virtual */
bool IibCursor::FetchNext()
{
	ISC_STATUS Status;
	Status = g_ibAPI.isc_dsql_fetch(
		m_StatusVector,
		&m_handles.m_stmt_handle,
		1, m_pOutXSQLDA);
	if(Status != 100)
	{
		IibConnection::Check(Status, m_StatusVector);

		// use default helpers
		ConvertSelectBufferToFields(0);
	}

	return Status != 100;
}

/*static */
SAString IibConnection::FormatIdentifierValue(
	unsigned short nSQLDialect,
	const SAString &sValue)
{
	if(nSQLDialect == 1)
	{
		SAString sTemp = sValue;
		sTemp.TrimLeft();
		sTemp.TrimRight();

		return sTemp;
	}

	return sValue;
}

/*virtual */
void IibCursor::DescribeParamSP()
{
	SAString sProcName = m_pCommand->CommandText();
	SAString sStmtIB = "Execute Procedure ";
	sStmtIB += sProcName;
	
	// read sp parameters from system tables
	SAString sSQL =
		"SELECT RDB$PARAMETER_NAME,  RDB$PARAMETER_TYPE "
		"FROM RDB$PROCEDURE_PARAMETERS "
		"WHERE UPPER(RDB$PROCEDURE_NAME) = UPPER('";
	sSQL += IibConnection::FormatIdentifierValue(SQLDialect(), sProcName);
	sSQL += "') ORDER BY RDB$PARAMETER_NUMBER";
	
	SACommand cmd(m_pISAConnection->getSAConnection(), sSQL);
	cmd.Execute();
	int nTotal = 0;
	int nInput = 0;
	while(cmd.FetchNext())
	{
		SAString sName = cmd["RDB$PARAMETER_NAME"].asString();
		sName.TrimRight(" ");
		SAParamDirType_t eDirType = cmd["RDB$PARAMETER_TYPE"].asShort() == 0? SA_ParamInput : SA_ParamOutput;
		if(eDirType == SA_ParamInput)	// input
		{
			if(++nInput > 1)
				sStmtIB += " ,?";
			else
				sStmtIB += " ?";
		}
		else
		{
		}
		
		++nTotal;
		m_pCommand->CreateParam(sName, SA_dtUnknown, -1, 0, eDirType);
	}
	
	// query and set output parameters datatypes, native datatypes and sizes
	if(nTotal)
	{
		int nOutput = 0;
		cmd.setCommandText(sStmtIB);
		cmd.Prepare();
		for(int i = 0; i < nTotal; ++i)
		{
			SAParam &Param = m_pCommand->ParamByIndex(i);
			if(Param.ParamDirType() != SA_ParamOutput)
				continue;
			
			++nOutput;
			Param.setParamType(cmd.Field(nOutput).FieldType());
			Param.setParamNativeType(cmd.Field(nOutput).FieldNativeType());
			Param.setParamSize(cmd.Field(nOutput).FieldSize());
		}
		cmd.Close();
	}
}

/*virtual */
saAPI *IibConnection::NativeAPI() const
{
	return &g_ibAPI;
}

/*virtual */
saConnectionHandles *IibConnection::NativeHandles()
{
	return &m_handles;
}

/*virtual */
saCommandHandles *IibCursor::NativeHandles()
{
	return &m_handles;
}

void IibConnection::ConstructTPB(
	SAIsolationLevel_t eIsolationLevel,
	SAAutoCommit_t eAutoCommit)
{
	// Construct the transaction parameter buffer
	char *tpb = m_TPB_buffer;
	*tpb++ = isc_tpb_version3;
	*tpb++ = isc_tpb_write;
	switch(eIsolationLevel)
	{
	case SA_LevelUnknown:
		// use default values
		break;
	case SA_ReadUncommitted:
		*tpb++ = isc_tpb_read_committed;
		*tpb++ = isc_tpb_rec_version;
		break;
	case SA_ReadCommitted:
		*tpb++ = isc_tpb_read_committed;
		*tpb++ = isc_tpb_no_rec_version;
		break;
	case SA_RepeatableRead:
		*tpb++ = isc_tpb_consistency;
		break;
	case SA_Serializable:
		*tpb++ = isc_tpb_concurrency;
		break;
	default:
		assert(false);
	}
	*tpb++ = isc_tpb_wait;
	if(eAutoCommit == SA_AutoCommitOn)
		*tpb++ = isc_tpb_autocommit;

	m_TPB_buffer_length = (short)(tpb - m_TPB_buffer);
}

/*virtual */
void IibConnection::setIsolationLevel(
	SAIsolationLevel_t eIsolationLevel)
{
	// adjust isolation level and start new transaction
	ConstructTPB(
		eIsolationLevel,
		m_pSAConnection->AutoCommit());

	// for new settings to take affect we should start new transaction
	CommitTransaction();	// commit and close the transaction
	StartTransaction();		// reopen
}

/*virtual */
void IibConnection::setAutoCommit(
	SAAutoCommit_t eAutoCommit)
{
	ConstructTPB(
		m_pSAConnection->IsolationLevel(),
		eAutoCommit);

	// for new settings to take affect we should start new transaction
	CommitTransaction();	// commit and close the transaction
	StartTransaction();		// reopen
}

unsigned short IibCursor::SQLDialect() const
{
	SAString s = m_pCommand->Option("SQLDialect");
	if(s.IsEmpty())
		return 3;	// defaults to SQL dialect 3
	
	return (unsigned short)atoi((const char*)s);
}

static void TransactionClosed(ISACursor *pCursor, void *pAddlData)
{
	((IibCursor*)pCursor)->OnTransactionClosed(pAddlData);
}

void IibCursor::OnTransactionClosed(void * /*pAddlData*/)
{
	m_bResultSet = false;
}

void IibConnection::CommitTransaction()
{
	assert(m_handles.m_tr_handle != NULL);
	Check(g_ibAPI.isc_commit_transaction(
		m_StatusVector, &m_handles.m_tr_handle), m_StatusVector);
	assert(m_handles.m_tr_handle == NULL);

	EnumCursors(TransactionClosed, NULL);
}

void IibConnection::CommitRetaining()
{
	assert(m_handles.m_tr_handle != NULL);
	Check(g_ibAPI.isc_commit_retaining(
		m_StatusVector, &m_handles.m_tr_handle), m_StatusVector);
	assert(m_handles.m_tr_handle != NULL);
}

void IibConnection::RollbackTransaction()
{
	assert(m_handles.m_tr_handle != NULL);
	Check(g_ibAPI.isc_rollback_transaction(
		m_StatusVector, &m_handles.m_tr_handle), m_StatusVector);
	assert(m_handles.m_tr_handle == NULL);

	EnumCursors(TransactionClosed, NULL);
}

⌨️ 快捷键说明

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