greenplumn CMDAccessorUtils 源码

2022-08-18 浏览 (276)

greenplumn CMDAccessorUtils 代码

文件路径:/src/backend/gporca/libgpopt/src/mdcache/CMDAccessorUtils.cpp

/---------------------------------------------------------------------------
/	Greenplum Database
/	Copyright (C) 2012 EMC Corp.
/
/	@filename:
/		CMDAccessorUtils.cpp
/
/	@doc:
/		Implementation of the utility function associated with the metadata
/		accessor
/---------------------------------------------------------------------------

#include "gpopt/mdcache/CMDAccessorUtils.h"

#include "gpos/base.h"
#include "gpos/error/CErrorHandlerStandard.h"
#include "gpos/error/CException.h"
#include "gpos/task/CAutoTraceFlag.h"

#include "gpopt/base/COptCtxt.h"
#include "gpopt/base/CUtils.h"
#include "naucrates/dxl/gpdb_types.h"
#include "naucrates/exception.h"
#include "naucrates/md/CMDIdGPDB.h"
#include "naucrates/md/IMDAggregate.h"
#include "naucrates/md/IMDFunction.h"
#include "naucrates/md/IMDScCmp.h"
#include "naucrates/md/IMDScalarOp.h"

using namespace gpmd;
using namespace gpos;
using namespace gpopt;

/---------------------------------------------------------------------------
/	@function:
/		CMDAccessorUtils::PstrWindowFuncName
/
/	@doc:
/		Return the name of the window operation
/
/---------------------------------------------------------------------------
const CWStringConst *
CMDAccessorUtils::PstrWindowFuncName(CMDAccessor *md_accessor, IMDId *mdid_func)
{
	if (md_accessor->FAggWindowFunc(mdid_func))
	{
		const IMDAggregate *pmdagg = md_accessor->RetrieveAgg(mdid_func);

		return pmdagg->Mdname().GetMDName();
	}

	const IMDFunction *pmdfunc = md_accessor->RetrieveFunc(mdid_func);

	return pmdfunc->Mdname().GetMDName();
}

/---------------------------------------------------------------------------
/	@function:
/		CMDAccessorUtils::PmdidWindowReturnType
/
/	@doc:
/		Return the return type of the window function
/
/---------------------------------------------------------------------------
IMDId *
CMDAccessorUtils::PmdidWindowReturnType(CMDAccessor *md_accessor,
										IMDId *mdid_func)
{
	if (md_accessor->FAggWindowFunc(mdid_func))
	{
		const IMDAggregate *pmdagg = md_accessor->RetrieveAgg(mdid_func);
		return pmdagg->GetResultTypeMdid();
	}

	const IMDFunction *pmdfunc = md_accessor->RetrieveFunc(mdid_func);
	return pmdfunc->GetResultTypeMdid();
}

/ Does a scalar comparison object between given types exists
BOOL
CMDAccessorUtils::FCmpExists(CMDAccessor *md_accessor, IMDId *left_mdid,
							 IMDId *right_mdid, IMDType::ECmpType cmp_type)
{
	GPOS_ASSERT(nullptr != md_accessor);
	GPOS_ASSERT(nullptr != left_mdid);
	GPOS_ASSERT(nullptr != left_mdid);
	GPOS_ASSERT(IMDType::EcmptOther > cmp_type);

	GPOS_TRY
	{
		(void) GetScCmpMdid(md_accessor, left_mdid, right_mdid, cmp_type);

		return true;
	}
	GPOS_CATCH_EX(ex)
	{
		if (GPOS_MATCH_EX(ex, gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound))
		{
			GPOS_RESET_EX;
			return false;
		}
		GPOS_RETHROW(ex);
	}
	GPOS_CATCH_END;
}

/ Get the mdid of the scalar comparison between the given types.
/ Throws an exception if no such comparison exists! Use
/ CMDAccessorUtils::FCmpExists() to check that before calling this function.
IMDId *
CMDAccessorUtils::GetScCmpMdid(CMDAccessor *md_accessor, IMDId *left_mdid,
							   IMDId *right_mdid, IMDType::ECmpType cmp_type)
{
	GPOS_ASSERT(nullptr != md_accessor);
	GPOS_ASSERT(nullptr != left_mdid);
	GPOS_ASSERT(nullptr != left_mdid);
	GPOS_ASSERT(IMDType::EcmptOther > cmp_type);

	IMDId *sc_cmp_mdid;

	/ if the left & right are the same, first check the MDType
	if (left_mdid->Equals(right_mdid))
	{
		const IMDType *pmdtypeLeft = md_accessor->RetrieveType(left_mdid);
		sc_cmp_mdid = pmdtypeLeft->GetMdidForCmpType(cmp_type);

		if (IMDId::IsValid(sc_cmp_mdid))
		{
			return sc_cmp_mdid;
		}
	}

	/ then check for an explicit operator
	sc_cmp_mdid =
		md_accessor->Pmdsccmp(left_mdid, right_mdid, cmp_type)->MdIdOp();

	/ either sc_cmp_mdid is valid or an exception was raised during lookup
	GPOS_ASSERT(IMDId::IsValid(sc_cmp_mdid));

	return sc_cmp_mdid;
}


/ check is a comparison between given types or a comparison after casting one
/ side to an another exists
BOOL
CMDAccessorUtils::FCmpOrCastedCmpExists(IMDId *left_mdid, IMDId *right_mdid,
										IMDType::ECmpType cmp_type)
{
	CMDAccessor *md_accessor = COptCtxt::PoctxtFromTLS()->Pmda();

	GPOS_ASSERT(nullptr != md_accessor);
	GPOS_ASSERT(nullptr != left_mdid);
	GPOS_ASSERT(nullptr != left_mdid);
	GPOS_ASSERT(IMDType::EcmptOther > cmp_type);

	GPOS_TRY
	{
		(void) CMDAccessorUtils::GetScCmpMdIdConsiderCasts(
			md_accessor, left_mdid, right_mdid, cmp_type);

		return true;
	}
	GPOS_CATCH_EX(ex)
	{
		if (GPOS_MATCH_EX(ex, gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound))
		{
			GPOS_RESET_EX;
			return false;
		}
		GPOS_RETHROW(ex);
	}
	GPOS_CATCH_END;
}

/ return the scalar comparison operator id between the two types
/ Throws an exception if no such comparison exists! Use
/ CMDAccessorUtils::FCmpOrCastedCmpExists() to check that before calling this
/ function.
IMDId *
CMDAccessorUtils::GetScCmpMdIdConsiderCasts(CMDAccessor *md_accessor,
											IMDId *left_mdid, IMDId *right_mdid,
											IMDType::ECmpType cmp_type)
{
	GPOS_ASSERT(nullptr != left_mdid);
	GPOS_ASSERT(nullptr != right_mdid);
	GPOS_ASSERT(IMDType::EcmptOther > cmp_type);

	/ left op right
	if (CMDAccessorUtils::FCmpExists(md_accessor, left_mdid, right_mdid,
									 cmp_type))
	{
		return CMDAccessorUtils::GetScCmpMdid(md_accessor, left_mdid,
											  right_mdid, cmp_type);
	}

	/ left op cast(right)
	if (CMDAccessorUtils::FCmpExists(md_accessor, left_mdid, left_mdid,
									 cmp_type) &&
		CMDAccessorUtils::FCastExists(md_accessor, right_mdid, left_mdid))
	{
		return CMDAccessorUtils::GetScCmpMdid(md_accessor, left_mdid, left_mdid,
											  cmp_type);
	}

	/ cast(left) op right
	if (CMDAccessorUtils::FCmpExists(md_accessor, right_mdid, right_mdid,
									 cmp_type) &&
		CMDAccessorUtils::FCastExists(md_accessor, left_mdid, right_mdid))
	{
		return CMDAccessorUtils::GetScCmpMdid(md_accessor, right_mdid,
											  right_mdid, cmp_type);
	}

	/ call to raise an error on non-comparable data types
	return CMDAccessorUtils::GetScCmpMdid(md_accessor, left_mdid, right_mdid,
										  cmp_type);
}

IMDId *
CMDAccessorUtils::GetScCmpMdIdConsiderCasts(CMDAccessor *md_accessor,
											CExpression *pexprLeft,
											CExpression *pexprRight,
											IMDType::ECmpType cmp_type)
{
	IMDId *left_mdid = CScalar::PopConvert(pexprLeft->Pop())->MdidType();
	IMDId *right_mdid = CScalar::PopConvert(pexprRight->Pop())->MdidType();

	return CMDAccessorUtils::GetScCmpMdIdConsiderCasts(md_accessor, left_mdid,
													   right_mdid, cmp_type);
}

void
CMDAccessorUtils::ApplyCastsForScCmp(CMemoryPool *mp, CMDAccessor *md_accessor,
									 CExpression *&pexprLeft,
									 CExpression *&pexprRight, IMDId *op_mdid)
{
	IMDId *left_mdid = CScalar::PopConvert(pexprLeft->Pop())->MdidType();
	IMDId *right_mdid = CScalar::PopConvert(pexprRight->Pop())->MdidType();

	const IMDScalarOp *op = md_accessor->RetrieveScOp(op_mdid);
	IMDId *op_left_mdid = op->GetLeftMdid();
	IMDId *op_right_mdid = op->GetRightMdid();

	/ Determine if casts need to be added (following is a description of what to
	/ do on the left side, for the right side it's analogous):

	/ GetScCmpMdIdConsiderCasts() has determined that
	/ a) there is a comparison operator with matching input types (left_mdid equals
	/    op_left_mdid); or
	/
	/ b) there is a common type t (either left_mdid or right_mdid) such that we
	/    can cast both left and right side to t, if needed, and that type t has a
	/    valid comparison operator.  Note that the input types of that operator
	/    may or may not be equal to t.  Note that we assume in this case that
	/    casts from t to the operators's input types "op_left_mdid" and
	/    "op_right_mdid" exist, otherwise this cannot be used to compare to
	/    values of type t (proposition A). Unfortunately, when we reach here, we
	/    don't know whether t is "left_mdid" or "right_mdid".
	/
	/    Case b) may require one or two casts. If a direct cast from "left_mdid"
	/    to "op_left_mdid" exists, we can use that directly. Otherwise,
	/    GetScCmpMdIdConsiderCasts() must have picked "right_mdid" as the common
	/    type t and it will have established that a cast from "left_mdid" to
	/    "right_mdid" must exist (proposition B). We know that we can cast from
	/    "left_mdid" to "right_mdid" and then, using the assumption above, from
	/    "right_mdid" to "op_left_mdid".

	if (!op_left_mdid->Equals(left_mdid))
	{
		/ We are in case b).
		if (CMDAccessorUtils::FCastExists(md_accessor, left_mdid, op_left_mdid))
		{
			/ The simple case, a direct cast exists
			pexprLeft =
				CUtils::PexprCast(mp, md_accessor, pexprLeft, op_left_mdid);
		}
		else
		{
			/ validate proposition B
			GPOS_ASSERT(CMDAccessorUtils::FCastExists(md_accessor, left_mdid,
													  right_mdid));
			/ Create the two casts described above, first from left to right type
			pexprLeft =
				CUtils::PexprCast(mp, md_accessor, pexprLeft, right_mdid);
			if (!right_mdid->Equals(op_left_mdid))
			{
				/ validate proposition A
				GPOS_ASSERT(CMDAccessorUtils::FCastExists(
					md_accessor, right_mdid, op_left_mdid));
				/ and then from right type to the type the comparison operator expects
				pexprLeft =
					CUtils::PexprCast(mp, md_accessor, pexprLeft, op_left_mdid);
			}
		}
	}

	if (!op_right_mdid->Equals(right_mdid))
	{
		/ We are in case b).
		if (CMDAccessorUtils::FCastExists(md_accessor, right_mdid,
										  op_right_mdid))
		{
			/ The simple case, a direct cast exists
			pexprRight =
				CUtils::PexprCast(mp, md_accessor, pexprRight, op_right_mdid);
		}
		else
		{
			/ validate proposition B
			GPOS_ASSERT(CMDAccessorUtils::FCastExists(md_accessor, right_mdid,
													  left_mdid));
			/ Create the two casts described above, first from right to left type
			pexprRight =
				CUtils::PexprCast(mp, md_accessor, pexprRight, left_mdid);
			if (!left_mdid->Equals(op_right_mdid))
			{
				/ validate proposition A
				GPOS_ASSERT(CMDAccessorUtils::FCastExists(
					md_accessor, left_mdid, op_right_mdid));
				/ and then from left type to the type the comparison operator expects
				pexprRight = CUtils::PexprCast(mp, md_accessor, pexprRight,
											   op_right_mdid);
			}
		}
	}
}

/---------------------------------------------------------------------------
/	@function:
/		CMDAccessorUtils::FCastExists
/
/	@doc:
/		Does if a cast object between given source and destination types exists
/
/---------------------------------------------------------------------------
BOOL
CMDAccessorUtils::FCastExists(CMDAccessor *md_accessor, IMDId *mdid_src,
							  IMDId *mdid_dest)
{
	GPOS_ASSERT(nullptr != md_accessor);
	GPOS_ASSERT(nullptr != mdid_src);
	GPOS_ASSERT(nullptr != mdid_dest);

	GPOS_TRY
	{
		(void) md_accessor->Pmdcast(mdid_src, mdid_dest);

		return true;
	}
	GPOS_CATCH_EX(ex)
	{
		if (GPOS_MATCH_EX(ex, gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound))
		{
			GPOS_RESET_EX;
			return false;
		}
		GPOS_RETHROW(ex);
	}
	GPOS_CATCH_END;
}


/---------------------------------------------------------------------------
/	@function:
/		CUtils::FScalarOpReturnsNullOnNullInput
/
/	@doc:
/		Does scalar operator return NULL on NULL input?
/
/---------------------------------------------------------------------------
BOOL
CMDAccessorUtils::FScalarOpReturnsNullOnNullInput(CMDAccessor *md_accessor,
												  IMDId *mdid_op)
{
	GPOS_ASSERT(nullptr != md_accessor);

	if (nullptr == mdid_op || !mdid_op->IsValid())
	{
		/ invalid mdid
		return false;
	}

	GPOS_TRY
	{
		const IMDScalarOp *md_scalar_op = md_accessor->RetrieveScOp(mdid_op);

		return md_scalar_op->ReturnsNullOnNullInput();
	}
	GPOS_CATCH_EX(ex)
	{
		if (GPOS_MATCH_EX(ex, gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryNotFound))
		{
			GPOS_RESET_EX;
			return false;
		}
		GPOS_RETHROW(ex);
	}
	GPOS_CATCH_END;

	return false;
}


/---------------------------------------------------------------------------
/	@function:
/		CUtils::FBoolType
/
/	@doc:
/		Return True if passed mdid is for BOOL type
/
/---------------------------------------------------------------------------
BOOL
CMDAccessorUtils::FBoolType(CMDAccessor *md_accessor, IMDId *mdid_type)
{
	GPOS_ASSERT(nullptr != md_accessor);

	if (nullptr != mdid_type && mdid_type->IsValid())
	{
		return (IMDType::EtiBool ==
				md_accessor->RetrieveType(mdid_type)->GetDatumType());
	}

	return false;
}

/---------------------------------------------------------------------------
/	@function:
/		CMDAccessorUtils::FCommutativeScalarOp
/
/	@doc:
/		Is scalar operator commutative? This can be used with ScalarOp and ScalarCmp
/
/---------------------------------------------------------------------------
BOOL
CMDAccessorUtils::FCommutativeScalarOp(CMDAccessor *md_accessor, IMDId *mdid_op)
{
	GPOS_ASSERT(nullptr != md_accessor);
	GPOS_ASSERT(nullptr != mdid_op);

	const IMDScalarOp *md_scalar_op = md_accessor->RetrieveScOp(mdid_op);

	return mdid_op->Equals(md_scalar_op->GetCommuteOpMdid());
}


/ EOF

相关信息

greenplumn 源码目录

相关文章

greenplumn CMDAccessor 源码

greenplumn CMDCache 源码

greenplumn CMDKey 源码

^