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

📄 oraclient.cpp

📁 通用的数据库中间库
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	m_bPiecewiseFetchPending = false;
}

void Iora7Cursor::CheckPiecewiseNull(bool bAfterExecute)
{
	// to check if piecewise fetched column (output param) is null (or not)
	// we have to read at least one byte from piecewise stream
	ub1 piece;
	dvoid *ctxp;
	ub4 iter, index;

	sword rc;
	((Iora7Connection*)m_pISAConnection)->Check(g_ora7API.ogetpi(
		&m_handles.m_cda,
		&piece, &ctxp, &iter, &index), &m_handles.m_cda);
	LongContext_t *pLongContext = (LongContext_t *)ctxp;
	pLongContext->Len = sizeof(m_PiecewiseNullCheckPreFetch);
	((Iora7Connection*)m_pISAConnection)->Check(g_ora7API.osetpi(
		&m_handles.m_cda,
		piece, &m_PiecewiseNullCheckPreFetch[0], &pLongContext->Len), &m_handles.m_cda);

	if(bAfterExecute)
		rc = g_ora7API.oexec(&m_handles.m_cda);
	else
		rc = g_ora7API.ofetch(&m_handles.m_cda);

	if(m_handles.m_cda.rc != 3130)
	{
		((Iora7Connection*)m_pISAConnection)->Check(rc, &m_handles.m_cda);

		// cloumn was null or whole Long* was read
		m_bPiecewiseFetchPending = false;
	}

	// set null indicator manually
	// because Oracle set it only if null or whole read
	*(sb2*)pLongContext->pInd = (sb2)(pLongContext->Len? 0 : -1);

	// if column was not null then fetched piece is saved
	// in m_PiecewiseNullCheckPreFetch, it's len in pLongContext->Len
	// and we will use it when actual read request happen
}

/*virtual */
bool Iora7Cursor::FetchNext()
{
	if(m_bPiecewiseFetchPending)
		DiscardPiecewiseFetch();

	sword rc = g_ora7API.ofetch(&m_handles.m_cda);
	switch(m_handles.m_cda.rc)
	{
	case 1403:
		m_bResultSetExist = false;
		return false;
	case 3130:	// the buffer for the next Piece to be fetched is required
		assert(m_bPiecewiseFetchAllowed);
		m_bPiecewiseFetchPending = true;
		CheckPiecewiseNull();
		break;
	default:
		((Iora7Connection*)m_pISAConnection)->Check(rc, &m_handles.m_cda);
	}

	// use default helpers
	ConvertSelectBufferToFields(0);
	return true;
}

void Iora8Cursor::DestroyLobsReturnBinding()
{
	while(m_nLobReturnBindsColCount)
	{
		while(m_nBLobBindsRowCount)
		{
			OCILobLocator *&pLoc = m_pppBLobReturningLocs[m_nLobReturnBindsColCount-1][m_nBLobBindsRowCount-1];
			if(pLoc)
			{
				Iora8Connection::Check(g_ora8API.OCIDescriptorFree(
					pLoc, OCI_DTYPE_LOB), m_handles.m_pOCIError, OCI_HTYPE_ERROR);
				pLoc = NULL;
			}
			--m_nBLobBindsRowCount;
		}

		delete m_pppBLobReturningLocs[--m_nLobReturnBindsColCount];
		delete m_ppLobReturningLens[m_nLobReturnBindsColCount];
	}
	if(m_ppLobReturnPlaceHolders)
	{
		free(m_ppLobReturnPlaceHolders);
		m_ppLobReturnPlaceHolders = NULL;
	}
	delete m_pppBLobReturningLocs;
	m_pppBLobReturningLocs = NULL;
	delete m_ppLobReturningLens;
	m_ppLobReturningLens = NULL;
}

// There are can be several reasons to reparse (Prepare again)
// already prepared statement:
// 1) if we bind Lobs for update or insert and
//		temporary Lobs are not supported by client or server
//		then we have to add 'returning' clause
// 2) if statement was executed and we rebind with
//		different bind variable datatype (see ORA-01475 error)
void Iora8Cursor::CheckForReparseBeforeBinding(
	int nPlaceHolderCount,
	saPlaceHolder **ppPlaceHolders)
{
	// first check if we have to modify SQL statement and reparse
	// due to Lobs operations and lack of temporary Lobs support

	// quick check, if stmt type is not
	// Insert or Update then nothing to check
	if(m_nOraStmtType == OCI_STMT_UPDATE ||
		m_nOraStmtType == OCI_STMT_INSERT)
	{
		SAString sModifiedStmt;
		SAString sReturning;
		SAString sInto;

		saPlaceHolder **ppLobReturnPlaceHolders = NULL;
		int nLobReturnBindsColCount = 0;
		int nPos = 0;
		for(int i = 0; i < nPlaceHolderCount; ++i)
		{
			sModifiedStmt += m_sOriginalStmt.Mid(nPos, ppPlaceHolders[i]->getStart()-nPos);

			bool bNull = ppPlaceHolders[i]->getParam()->isNull();
			if(!bNull 
				&& ppPlaceHolders[i]->getParam()->DataType() == SA_dtBLob
				&& !((Iora8Connection*)m_pISAConnection)->IsTemporaryLobSupported())
			{
				// replace param marker with empty_blob() function
				sModifiedStmt += "empty_blob()";
				if(!sReturning.IsEmpty())
					sReturning += ", ";
				sReturning += ppPlaceHolders[i]->getParam()->Name();
				if(!sInto.IsEmpty())
					sInto += ", ";
				sInto += ":";
				sInto += ppPlaceHolders[i]->getParam()->Name();

				ppLobReturnPlaceHolders = (saPlaceHolder **)realloc(ppLobReturnPlaceHolders, sizeof(SAParam*)*(nLobReturnBindsColCount+1));
				ppLobReturnPlaceHolders[nLobReturnBindsColCount] = ppPlaceHolders[i];
				++nLobReturnBindsColCount;
			}
			else if(!bNull 
				&& ppPlaceHolders[i]->getParam()->DataType() == SA_dtCLob
				&& !((Iora8Connection*)m_pISAConnection)->IsTemporaryLobSupported())
			{
				// replace param marker with empty_clob() function
				sModifiedStmt += "empty_clob()";
				if(!sReturning.IsEmpty())
					sReturning += ", ";
				sReturning += ppPlaceHolders[i]->getParam()->Name();
				if(!sInto.IsEmpty())
					sInto += ", ";
				sInto += ":";
				sInto += ppPlaceHolders[i]->getParam()->Name();

				ppLobReturnPlaceHolders = (saPlaceHolder **)realloc(ppLobReturnPlaceHolders, sizeof(SAParam*)*(nLobReturnBindsColCount+1));
				ppLobReturnPlaceHolders[nLobReturnBindsColCount] = ppPlaceHolders[i];
				++nLobReturnBindsColCount;
			}
			else	// remain unmodified
				sModifiedStmt += m_sOriginalStmt.Mid(ppPlaceHolders[i]->getStart(), ppPlaceHolders[i]->getEnd()-ppPlaceHolders[i]->getStart()+1);

			nPos = ppPlaceHolders[i]->getEnd() + 1;
		}
		// copy tail
		if(nPos < m_sOriginalStmt.GetLength())
			sModifiedStmt += m_sOriginalStmt.Mid(nPos);

		if(nLobReturnBindsColCount)
		{
			// add/alter returning into clauses
			bool bAdd = true;
			if(bAdd)	// add
			{
				sModifiedStmt += " returning ";
				sModifiedStmt += sReturning;
				sModifiedStmt += " into ";
				sModifiedStmt += sInto;
			}
			else	// modify
			{
			}
		}

		if(nLobReturnBindsColCount	// we have returning clause
			|| m_nLobReturnBindsColCount)	// we had returning clause
		{
			try
			{
				InternalPrepare(sModifiedStmt);
			}
			catch(SAException &)
			{
				if(ppLobReturnPlaceHolders)
					free(ppLobReturnPlaceHolders);
				throw;
			}
		}

		if(nLobReturnBindsColCount)
		{
			m_ppLobReturnPlaceHolders = ppLobReturnPlaceHolders;

			m_pppBLobReturningLocs = new OCILobLocator**[nLobReturnBindsColCount];
			memset(m_pppBLobReturningLocs, 0, sizeof(OCILobLocator**)*nLobReturnBindsColCount);
			m_ppLobReturningLens = new ub4*[nLobReturnBindsColCount];
			memset(m_ppLobReturningLens, 0, sizeof(ub4*)*nLobReturnBindsColCount);
			m_nLobReturnBindsColCount = nLobReturnBindsColCount;
		}
	}

	// then check if we need to reparse to avoid ORA-01475
	if(m_pDTY)	// we bound before
	{
		for(int i = 0; i < m_pCommand->ParamCount(); ++i)
		{
			SAParam &Param = m_pCommand->ParamByIndex(i);

			SADataType_t eDataType = Param.DataType();
			ub2 dty = (ub2)(eDataType == SA_dtUnknown?
				SQLT_CHR : // VARCHAR2, some type should be set
				CnvtStdToNative(eDataType));

			if(m_pDTY[i] != dty)
			{
				InternalPrepare(m_sOriginalStmt);
				break;
			}
		}
	}
}

void Iora8Cursor::InternalPrepare(
	const SAString &sStmt)
{
	// save because (extraction from Oracle docs):
	// "The pointer to the text of the statement must be available
	// as long as the statement is
	// executed, or data is fetched from it."
	m_sInternalPrepareStmt = sStmt;

	Iora8Connection::Check(g_ora8API.OCIStmtPrepare(
		m_handles.m_pOCIStmt,
		m_handles.m_pOCIError,
		(CONST text*)(const char*)m_sInternalPrepareStmt,
		(ub4)m_sInternalPrepareStmt.GetLength(),
		OCI_NTV_SYNTAX,
		OCI_DEFAULT), m_handles.m_pOCIError, OCI_HTYPE_ERROR);

	m_nOraStmtType = 0;	// unknown
	if(m_pDTY)
	{
		::free(m_pDTY);
		m_pDTY = NULL;
	}
	DestroyLobsReturnBinding();

	// readStmtType
	Iora8Connection::Check(g_ora8API.OCIAttrGet(
		m_handles.m_pOCIStmt, OCI_HTYPE_STMT, &m_nOraStmtType, NULL, OCI_ATTR_STMT_TYPE, m_handles.m_pOCIError), m_handles.m_pOCIError, OCI_HTYPE_ERROR);
}

/*virtual */
void Iora8Cursor::Prepare(
	const SAString &sStmt,
	SACommandType_t eCmdType,
	int /*nPlaceHolderCount*/,
	saPlaceHolder**	/*ppPlaceHolders*/)
{
	SAString sStmtOra;
	switch(eCmdType)
	{
		case SA_CmdSQLStmt:
			sStmtOra = sStmt;
			// save original, we will probably need to reprepare modified stmt if BLOBs will be bound in 8.0.x (not in 8i)
			m_sOriginalStmt = sStmt;
			break;
		case SA_CmdStoredProc:
			sStmtOra = CallSubProgramSQL();
			break;
		default:
			assert(false);
	}

	// always compile original to check errors
	InternalPrepare(sStmtOra);
}

void Iora8Cursor::CreateTemporaryLob(
	OCILobLocator **ppLob,
	SAParam &Param)
{
	ub1 lobtype;
	switch(Param.DataType())
	{
	case SA_dtBLob:
		lobtype = OCI_TEMP_BLOB;
		break;
	case SA_dtCLob:
		lobtype = OCI_TEMP_CLOB;
		break;
	default:
		assert(false);
		return;
	}

	Iora8Connection::Check(g_ora8API.OCIDescriptorAlloc(
		((Iora8Connection*)m_pISAConnection)->m_handles.m_pOCIEnv,
		(dvoid **)ppLob,
		OCI_DTYPE_LOB, 0,
		NULL), ((Iora8Connection*)m_pISAConnection)->m_handles.m_pOCIEnv, OCI_HTYPE_ENV);

	Iora8Connection::Check(g_ora8API.OCILobCreateTemporary(
		((Iora8Connection*)m_pISAConnection)->m_handles.m_pOCISvcCtx,
		m_handles.m_pOCIError,
		*ppLob,
		OCI_DEFAULT,
		OCI_DEFAULT,
		lobtype,
		OCI_ATTR_NOCACHE,
		OCI_DURATION_SESSION), m_handles.m_pOCIError, OCI_HTYPE_ERROR);

	++m_cTempLobs;
	m_ppTempLobs = (OCILobLocator **)::realloc(m_ppTempLobs, m_cTempLobs * sizeof(OCILobLocator *));
	m_ppTempLobs[m_cTempLobs-1] = *ppLob;

	BindLob(*ppLob, Param);
}

void Iora8Cursor::Bind(
		int nPlaceHolderCount,
		saPlaceHolder**	ppPlaceHolders)
{
	CheckForReparseBeforeBinding(nPlaceHolderCount, ppPlaceHolders);

	m_pDTY = (ub2*)::realloc(m_pDTY, sizeof(ub2) * m_pCommand->ParamCount());

	// we should bind all params, not place holders in Oracle
	AllocBindBuffer(sizeof(sb2), sizeof(ub2));
	void *pBuf = m_pParamBuffer;

	ub4 nLobReturnBindsColCount = 0;

	for(int i = 0; i < m_pCommand->ParamCount(); ++i)
	{
		SAParam &Param = m_pCommand->ParamByIndex(i);

		void *pInd;
		void *pSize;
		unsigned int nDataBufSize;
		void *pValue;
		IncParamBuffer(pBuf, pInd, pSize, nDataBufSize, pValue);

		SADataType_t eDataType = Param.DataType();
		ub2 dty = (ub2)(eDataType == SA_dtUnknown?
			SQLT_CHR : // VARCHAR2, some type should be set
			CnvtStdToNative(eDataType));
		m_pDTY[i] = dty;

		sb2 *indp = (sb2 *)pInd;	// bind null indicator
		dvoid *valuep = pValue;
		sb4 value_sz = nDataBufSize;	// allocated
		ub2 *alenp = (ub2 *)pSize;

		// this will be adjusted if Param is input
		*alenp = (ub2)nDataBufSize;

		// special code for ref cursors
		if(eDataType == SA_dtCursor)
		{
			*indp = OCI_IND_NOTNULL;	// field is not null

			assert(nDataBufSize == sizeof(OCIStmt *));
			memset(valuep, 0, nDataBufSize);

			Iora8Connection::Check(
				g_ora8API.OCIHandleAlloc(((Iora8Connection*)m_pISAConnection)->m_handles.m_pOCIEnv, (dvoid**)valuep, OCI_HTYPE_STMT, 0, NULL),
				((Iora8Connection*)m_pISAConnection)->m_handles.m_pOCIEnv, OCI_HTYPE_ENV);

			if(!Param.isNull() && isInputParam(Param))
			{
				SACommand *pCursor = Param.asCursor();
				assert(pCursor);

				const ora8CommandHandles *pH = (ora8CommandHandles *)pCursor->NativeHandles();
				memcpy(valuep, &pH->m_pOCIStmt, sizeof(OCIStmt *));

				*alenp = (ub2)InputBufferSize(Param);
			}
		}
		else
		{
			*indp = OCI_IND_NULL;
			if(isInputParam(Param))
			{
				if(Param.isNull())
					*indp = OCI_IND_NULL;		// field is null
				else
					*indp = OCI_IND_NOTNULL;	// field is not null

				*alenp = (ub2)InputBufferSize(Param);
				assert(value_sz >= *alenp);

				if(!Param.isNull())
				{
					switch(eDataType)
					{
					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 Oracle,
						// so treat boolean as 16-bit signed INTEGER in Oracle
						assert(*alenp == sizeof(short));
						*(short*)valuep = (short)Param.asBool();
						break;
					case SA_dtShort:
						assert(*alenp == sizeof(short));
						*(short*)valuep = Param.asShort();
						break;
					case SA_dtLong:
						assert(*alenp == sizeof(long));
						*(long*)valuep = Param.asLong();
						break;
					case SA_dtDouble:
						assert(*alenp == sizeof(double));
						*(double*)valuep = Param.asDouble();
						break;
					case SA_dtDateTime:
						assert(*alenp == sizeof(OraDate_t));	// Oracle internal date/time representation
						IoraConnection::CnvtDateTimeToInternal(
							Param.asDateTime(),
							(OraDate_t*)valuep);
						break;
					case SA_dtString:
						assert(*alenp == (ub2)Param.asString().GetLength());
						memcpy(valuep, (const char*)Param.asString(), *alenp);
						break;
					case SA_dtBytes:
						assert(*alenp == (ub2)Param.asBytes().GetLength());
						memcpy(valuep, (const char*)Param.asBytes(), *alenp);
						break;
					case SA_dtLongBinary:
						assert(*alenp == sizeof(LongContext_t));
						break;
					case SA_dtLongChar:
						assert(*alenp == sizeof(LongContext_t));
						break;
					case SA_dtBLob:
					case SA_dtCLob:
						assert(*alenp == sizeof(OCILobLocator *)
							|| *alenp == sizeof(BlobReturningContext_t));
						break;
					case SA_dtCursor:
						assert(false);	// already handled
						break;
					default:
						assert(false);
					}
				}
			}
		}

		bool bLongPiecewise = isLong(eDataType);
		bool bLob = !Param.isNull() && isLob(eDataType);
		bool bLobReturning = bLob && !((Iora8Connection*)m_pISAConnection)->IsTemporaryLobSupported();

		OCIBind* pOCIBind = NULL;
		if(bLongPiecewise)
		{
			Iora8Connection::Check(g_ora8API.OCIBindByName(
				m_handles.m_pOCIStmt,
				&pOCIBind,
				m_handles.m_pOCIError,
				(CONST text*)(const char*)Param.Name(),
				Param.Name().GetLength(),
				valuep, SB4MAXVAL, dty,
				indp, NULL,
				NULL, 0, NULL, OCI_DATA_AT_EXEC), m_handles.m_pOCIError, OCI_HTYPE_ERROR);

			LongContext_t *pLongContext = (LongContext_t *)pValue;
			pLongContext->pReader = &Param;
			pLongContext->pWriter = &Param;
			pLongContext->pInd = indp;

			OCICallbackInBind icbfp = LongInBind;	// always assign InBind, otherwise OutBind is not used and Oracle do piecewise instead of callbacks
			OCICallbackOutBind ocbfp = NULL;
			if(isOutputParam(Param))
				ocbfp = LongOutBind;
			Iora8Connection::Check(

⌨️ 快捷键说明

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