greenplumn CMDAccessorUtils 源码

  • 2022-08-18
  • 浏览 (218)

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 源码

0  赞