greenplumn CExpressionHandle 源码

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

greenplumn CExpressionHandle 代码

文件路径:/src/backend/gporca/libgpopt/src/operators/CExpressionHandle.cpp

//---------------------------------------------------------------------------
//	Greenplum Database
//	Copyright (C) 2009 Greenplum, Inc.
//
//	@filename:
//		CExpressionHandle.cpp
//
//	@doc:
//		Handle to an expression to abstract topology;
//
//		The handle provides access to an expression and the properties
//		of its children; regardless of whether the expression is a group
//		expression or a stand-alone tree;
//---------------------------------------------------------------------------

#include "gpopt/operators/CExpressionHandle.h"

#include "gpos/base.h"

#include "gpopt/base/CCTEReq.h"
#include "gpopt/base/CColRefSet.h"
#include "gpopt/base/CCostContext.h"
#include "gpopt/base/CDrvdPropCtxtPlan.h"
#include "gpopt/base/CDrvdPropScalar.h"
#include "gpopt/base/CKeyCollection.h"
#include "gpopt/base/COptCtxt.h"
#include "gpopt/base/CReqdPropPlan.h"
#include "gpopt/base/CUtils.h"
#include "gpopt/exception.h"
#include "gpopt/operators/CLogical.h"
#include "gpopt/operators/CLogicalCTEConsumer.h"
#include "gpopt/operators/CLogicalGbAgg.h"
#include "gpopt/operators/COperator.h"
#include "gpopt/operators/CPattern.h"
#include "gpopt/operators/CPhysicalCTEConsumer.h"
#include "gpopt/operators/CPhysicalScan.h"
#include "naucrates/statistics/CStatisticsUtils.h"

using namespace gpnaucrates;
using namespace gpopt;


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::CExpressionHandle
//
//	@doc:
//		ctor
//
//---------------------------------------------------------------------------
CExpressionHandle::CExpressionHandle(CMemoryPool *mp)
	: m_mp(mp),
	  m_pexpr(nullptr),
	  m_pgexpr(nullptr),
	  m_pcc(nullptr),
	  m_pdpplan(nullptr),
	  m_pstats(nullptr),
	  m_prp(nullptr),
	  m_pdrgpstat(nullptr),
	  m_pdrgprp(nullptr)
{
	GPOS_ASSERT(nullptr != mp);
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::~CExpressionHandle
//
//	@doc:
//		dtor
//
//		Since handles live on the stack this dtor will be called during
//		exceptions, hence, need to be defensive
//
//---------------------------------------------------------------------------
CExpressionHandle::~CExpressionHandle()
{
	CRefCount::SafeRelease(m_pexpr);
	CRefCount::SafeRelease(m_pgexpr);
	CRefCount::SafeRelease(m_pstats);
	CRefCount::SafeRelease(m_prp);
	CRefCount::SafeRelease(m_pdpplan);
	CRefCount::SafeRelease(m_pdrgpstat);
	CRefCount::SafeRelease(m_pdrgprp);
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::FStatsDerived
//
//	@doc:
//		Check if stats are derived for attached expression and its children
//
//---------------------------------------------------------------------------
BOOL
CExpressionHandle::FStatsDerived() const
{
	IStatistics *stats = nullptr;
	if (nullptr != m_pexpr)
	{
		stats = const_cast<IStatistics *>(m_pexpr->Pstats());
	}
	else
	{
		GPOS_ASSERT(nullptr != m_pgexpr);
		stats = m_pgexpr->Pgroup()->Pstats();
	}

	if (nullptr == stats)
	{
		// stats of attached expression have not been derived yet
		return false;
	}

	const ULONG arity = Arity();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		if (FScalarChild(ul))
		{
			// skip scalar children
			continue;
		}

		IStatistics *child_stats = nullptr;
		if (nullptr != m_pexpr)
		{
			child_stats = const_cast<IStatistics *>((*m_pexpr)[ul]->Pstats());
		}
		else
		{
			child_stats = (*m_pgexpr)[ul]->Pstats();
		}

		if (nullptr == child_stats)
		{
			// stats of attached expression child have not been derived yet
			return false;
		}
	}

	return true;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::CopyStats
//
//	@doc:
//		Copy stats from attached expression/group expression to local stats
//		members
//
//---------------------------------------------------------------------------
void
CExpressionHandle::CopyStats()
{
	if (!FStatsDerived())
	{
		// stats of attached expression (or its children) have not been derived yet
		return;
	}

	IStatistics *stats = nullptr;
	if (nullptr != m_pexpr)
	{
		stats = const_cast<IStatistics *>(m_pexpr->Pstats());
	}
	else
	{
		GPOS_ASSERT(nullptr != m_pgexpr);
		stats = m_pgexpr->Pgroup()->Pstats();
	}
	GPOS_ASSERT(nullptr != stats);

	// attach stats
	stats->AddRef();
	GPOS_ASSERT(nullptr == m_pstats);
	m_pstats = stats;

	// attach child stats
	GPOS_ASSERT(nullptr == m_pdrgpstat);
	m_pdrgpstat = GPOS_NEW(m_mp) IStatisticsArray(m_mp);
	const ULONG arity = Arity();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		IStatistics *child_stats = nullptr;
		if (nullptr != m_pexpr)
		{
			child_stats = const_cast<IStatistics *>((*m_pexpr)[ul]->Pstats());
		}
		else
		{
			child_stats = (*m_pgexpr)[ul]->Pstats();
		}

		if (nullptr != child_stats)
		{
			child_stats->AddRef();
		}
		else
		{
			GPOS_ASSERT(FScalarChild(ul));

			// create dummy stats for missing scalar children
			child_stats = CStatistics::MakeEmptyStats(m_mp);
		}

		m_pdrgpstat->Append(child_stats);
	}
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::Attach
//
//	@doc:
//		Attach to a given expression
//
//---------------------------------------------------------------------------
void
CExpressionHandle::Attach(CExpression *pexpr)
{
	GPOS_ASSERT(nullptr == m_pexpr);
	GPOS_ASSERT(nullptr == m_pgexpr);
	GPOS_ASSERT(nullptr != pexpr);

	// increment ref count on base expression
	pexpr->AddRef();
	m_pexpr = pexpr;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::Attach
//
//	@doc:
//		Attach to a given group expression
//
//---------------------------------------------------------------------------
void
CExpressionHandle::Attach(CGroupExpression *pgexpr)
{
	GPOS_ASSERT(nullptr == m_pexpr);
	GPOS_ASSERT(nullptr == m_pgexpr);
	GPOS_ASSERT(nullptr != pgexpr);

	// increment ref count on group expression
	pgexpr->AddRef();
	m_pgexpr = pgexpr;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::Attach
//
//	@doc:
//		Attach to a given cost context
//
//---------------------------------------------------------------------------
void
CExpressionHandle::Attach(CCostContext *pcc)
{
	GPOS_ASSERT(nullptr == m_pcc);
	GPOS_ASSERT(nullptr != pcc);

	m_pcc = pcc;
	Attach(pcc->Pgexpr());
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::DeriveProps
//
//	@doc:
//		Recursive property derivation
//
//---------------------------------------------------------------------------
void
CExpressionHandle::DeriveProps(CDrvdPropCtxt *pdpctxt)
{
	GPOS_CHECK_ABORT;

	if (nullptr != m_pgexpr)
	{
		return;
	}

	if (nullptr != m_pexpr->Pdp(m_pexpr->Ept()))
	{
		return;
	}

	// copy stats of attached expression
	CopyStats();

	m_pexpr->PdpDerive(pdpctxt);
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::PdrgpstatOuterRefs
//
//	@doc:
//		Given an array of stats objects and a child index, return an array
//		of stats objects starting from the first stats object referenced by
//		child
//
//---------------------------------------------------------------------------
IStatisticsArray *
CExpressionHandle::PdrgpstatOuterRefs(IStatisticsArray *statistics_array,
									  ULONG child_index)
{
	GPOS_ASSERT(nullptr != statistics_array);
	GPOS_ASSERT(child_index < Arity());

	if (FScalarChild(child_index) || !HasOuterRefs(child_index))
	{
		// if child is scalar or has no outer references, return empty array
		return GPOS_NEW(m_mp) IStatisticsArray(m_mp);
	}

	IStatisticsArray *pdrgpstatResult = GPOS_NEW(m_mp) IStatisticsArray(m_mp);
	CColRefSet *outer_refs = DeriveOuterReferences(child_index);
	GPOS_ASSERT(0 < outer_refs->Size());

	const ULONG size = statistics_array->Size();
	ULONG ulStartIndex = gpos::ulong_max;
	for (ULONG ul = 0; ul < size; ul++)
	{
		IStatistics *stats = (*statistics_array)[ul];
		CColRefSet *pcrsStats = stats->GetColRefSet(m_mp);
		BOOL fStatsColsUsed = !outer_refs->IsDisjoint(pcrsStats);
		pcrsStats->Release();
		if (fStatsColsUsed)
		{
			ulStartIndex = ul;
			break;
		}
	}

	if (gpos::ulong_max != ulStartIndex)
	{
		// copy stats starting from index of outer-most stats object referenced by child
		CUtils::AddRefAppend(pdrgpstatResult, statistics_array, ulStartIndex);
	}

	return pdrgpstatResult;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::FAttachedToLeafPattern
//
//	@doc:
//		Return True if handle is attached to a leaf pattern
//
//---------------------------------------------------------------------------
BOOL
CExpressionHandle::FAttachedToLeafPattern() const
{
	return 0 == Arity() && nullptr != m_pexpr && nullptr != m_pexpr->Pgexpr();
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::DeriveRootStats
//
//	@doc:
//		CheckState derivation at root operator where handle is attached
//
//---------------------------------------------------------------------------
void
CExpressionHandle::DeriveRootStats(IStatisticsArray *stats_ctxt)
{
	GPOS_ASSERT(nullptr == m_pstats);

	CLogical *popLogical = CLogical::PopConvert(Pop());
	IStatistics *pstatsRoot = nullptr;
	if (FAttachedToLeafPattern())
	{
		// for leaf patterns extracted from memo, trigger state derivation on origin group
		GPOS_ASSERT(nullptr != m_pexpr);
		GPOS_ASSERT(nullptr != m_pexpr->Pgexpr());

		pstatsRoot = m_pexpr->Pgexpr()->Pgroup()->PstatsRecursiveDerive(
			m_mp, m_mp, CReqdPropRelational::GetReqdRelationalProps(m_prp),
			stats_ctxt);
		pstatsRoot->AddRef();
	}
	else
	{
		// otherwise, derive stats using root operator
		pstatsRoot = popLogical->PstatsDerive(m_mp, *this, stats_ctxt);
	}
	GPOS_ASSERT(nullptr != pstatsRoot);

	m_pstats = pstatsRoot;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::DeriveStats
//
//	@doc:
//		Recursive stat derivation
//
//---------------------------------------------------------------------------
void
CExpressionHandle::DeriveStats(IStatisticsArray *stats_ctxt,
							   BOOL fComputeRootStats)
{
	GPOS_ASSERT(nullptr != stats_ctxt);
	GPOS_ASSERT(nullptr == m_pdrgpstat);
	GPOS_ASSERT(nullptr == m_pstats);
	GPOS_ASSERT(nullptr != m_pdrgprp);

	// copy input context
	IStatisticsArray *pdrgpstatCurrentCtxt =
		GPOS_NEW(m_mp) IStatisticsArray(m_mp);
	CUtils::AddRefAppend(pdrgpstatCurrentCtxt, stats_ctxt);

	// create array of children stats
	m_pdrgpstat = GPOS_NEW(m_mp) IStatisticsArray(m_mp);
	ULONG ulMaxChildRisk = 1;
	const ULONG arity = Arity();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		// create a new context for outer references used by current child
		IStatisticsArray *pdrgpstatChildCtxt =
			PdrgpstatOuterRefs(pdrgpstatCurrentCtxt, ul);

		IStatistics *stats = nullptr;
		if (nullptr != Pexpr())
		{
			// derive stats recursively on child expression
			stats = (*Pexpr())[ul]->PstatsDerive(GetReqdRelationalProps(ul),
												 pdrgpstatChildCtxt);
		}
		else
		{
			// derive stats recursively on child group
			stats = (*Pgexpr())[ul]->PstatsRecursiveDerive(
				m_mp, m_mp, GetReqdRelationalProps(ul), pdrgpstatChildCtxt);
		}
		GPOS_ASSERT(nullptr != stats);

		// add child stat to current context
		stats->AddRef();
		pdrgpstatCurrentCtxt->Append(stats);
		pdrgpstatChildCtxt->Release();

		// add child stat to children stat array
		stats->AddRef();
		m_pdrgpstat->Append(stats);
		if (stats->StatsEstimationRisk() > ulMaxChildRisk)
		{
			ulMaxChildRisk = stats->StatsEstimationRisk();
		}
	}

	if (fComputeRootStats)
	{
		// call stat derivation on operator to compute local stats
		GPOS_ASSERT(nullptr == m_pstats);

		DeriveRootStats(stats_ctxt);
		GPOS_ASSERT(nullptr != m_pstats);

		CLogical *popLogical = CLogical::PopConvert(Pop());
		ULONG risk = ulMaxChildRisk;
		if (CStatisticsUtils::IncreasesRisk(popLogical))
		{
			++risk;
		}
		m_pstats->SetStatsEstimationRisk(risk);
	}

	// clean up current stat context
	pdrgpstatCurrentCtxt->Release();
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::DeriveCostContextStats
//
//	@doc:
//		Stats derivation based on required plan properties
//
//---------------------------------------------------------------------------
void
CExpressionHandle::DeriveCostContextStats()
{
	GPOS_ASSERT(nullptr != m_pcc);
	GPOS_ASSERT(nullptr == m_pcc->Pstats());

	// copy group properties and stats
	CopyStats();

	if (nullptr != m_pstats && !m_pcc->FNeedsNewStats())
	{
		// there is no need to derive stats,
		// stats are copied from owner group
		// (note that m_pdrgpstat may not contain the correct DPE
		// stats of children, but it is used only for deriving the
		// stats, which we don't need to do anymore)

		return;
	}

	CEnfdPartitionPropagation *pepp = m_pcc->Poc()->Prpp()->Pepp();
	COperator *pop = Pop();
	if (CUtils::FPhysicalScan(pop) &&
		CPhysicalScan::PopConvert(pop)->FDynamicScan() &&
		pepp->PppsRequired()->ContainsAnyConsumers())
	{
		// derive stats on dynamic table scan using stats of part selector
		CPhysicalScan *popScan = CPhysicalScan::PopConvert(m_pgexpr->Pop());
		IStatistics *pstatsDS = popScan->PstatsDerive(
			m_mp, *this, m_pcc->Poc()->Prpp(), m_pcc->Poc()->Pdrgpstat());

		if (nullptr == m_pstats || m_pstats->Rows() > pstatsDS->Rows())
		{
			// Replace the group stats with our newly derived DPE stats
			CRefCount::SafeRelease(m_pstats);
			m_pstats = pstatsDS;
		}
		else
		{
			// Eliminating partitions can't possibly increase the row count. If the row
			// count is higher, that's likely due to some heuristics in the estimation.
			// If the row count is the same, there is no need to use DPE stats.
			pstatsDS->Release();
		}

		return;
	}

	// release current stats since we will derive new stats
	CRefCount::SafeRelease(m_pstats);
	m_pstats = nullptr;

	// load stats from child cost context(s) -- these may be different from child groups stats
	CRefCount::SafeRelease(m_pdrgpstat);
	m_pdrgpstat = nullptr;

	m_pdrgpstat = GPOS_NEW(m_mp) IStatisticsArray(m_mp);
	const ULONG arity = m_pcc->Pdrgpoc()->Size();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		COptimizationContext *pocChild = (*m_pcc->Pdrgpoc())[ul];
		CCostContext *pccChild = pocChild->PccBest();
		GPOS_ASSERT(nullptr != pccChild);
		GPOS_ASSERT(nullptr != pccChild->Pstats());

		pccChild->Pstats()->AddRef();
		m_pdrgpstat->Append(pccChild->Pstats());
	}

	if (CPhysical::PopConvert(m_pgexpr->Pop())->FPassThruStats())
	{
		GPOS_ASSERT(1 == m_pdrgpstat->Size());

		// copy stats from first child
		(*m_pdrgpstat)[0]->AddRef();
		m_pstats = (*m_pdrgpstat)[0];

		return;
	}

	// derive stats using the best logical expression with the same children as attached physical operator
	CGroupExpression *pgexprForStats = m_pcc->PgexprForStats();
	GPOS_ASSERT(nullptr != pgexprForStats);

	CExpressionHandle exprhdl(m_mp);
	exprhdl.Attach(pgexprForStats);
	exprhdl.DeriveProps(nullptr /*pdpctxt*/);
	m_pdrgpstat->AddRef();
	exprhdl.m_pdrgpstat = m_pdrgpstat;
	exprhdl.ComputeReqdProps(m_pcc->Poc()->GetReqdRelationalProps(),
							 0 /*ulOptReq*/);

	GPOS_ASSERT(nullptr == exprhdl.m_pstats);
	IStatistics *stats = m_pgexpr->Pgroup()->PstatsCompute(
		m_pcc->Poc(), exprhdl, pgexprForStats);

	// copy stats to main handle
	GPOS_ASSERT(nullptr == m_pstats);
	GPOS_ASSERT(nullptr != stats);

	stats->AddRef();
	m_pstats = stats;

	GPOS_ASSERT(m_pstats != nullptr);
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::DeriveStats
//
//	@doc:
//		CheckState derivation using given properties and context
//
//---------------------------------------------------------------------------
void
CExpressionHandle::DeriveStats(CMemoryPool *pmpLocal, CMemoryPool *pmpGlobal,
							   CReqdPropRelational *prprel,
							   IStatisticsArray *stats_ctxt) const
{
	CReqdPropRelational *prprelNew = prprel;
	if (nullptr == prprelNew)
	{
		// create empty property container
		CColRefSet *pcrs = GPOS_NEW(pmpGlobal) CColRefSet(pmpGlobal);
		prprelNew = GPOS_NEW(pmpGlobal) CReqdPropRelational(pcrs);
	}
	else
	{
		prprelNew->AddRef();
	}

	IStatisticsArray *pdrgpstatCtxtNew = stats_ctxt;
	if (nullptr == stats_ctxt)
	{
		// create empty context
		pdrgpstatCtxtNew = GPOS_NEW(pmpGlobal) IStatisticsArray(pmpGlobal);
	}
	else
	{
		pdrgpstatCtxtNew->AddRef();
	}

	if (nullptr != Pgexpr())
	{
		(void) Pgexpr()->Pgroup()->PstatsRecursiveDerive(
			pmpLocal, pmpGlobal, prprelNew, pdrgpstatCtxtNew);
	}
	else
	{
		GPOS_ASSERT(nullptr != Pexpr());

		(void) Pexpr()->PstatsDerive(prprelNew, pdrgpstatCtxtNew);
	}

	prprelNew->Release();
	pdrgpstatCtxtNew->Release();
}


// Derive the properties of the plan carried by attached cost context.
// Note that this re-derives the plan properties, instead of using those
// present in the gexpr, for cost contexts only and under the default
// CDrvdPropCtxtPlan.
// On the other hand, the properties in the gexpr may have been derived in
// other non-default contexts (e.g with cte info).
void
CExpressionHandle::DerivePlanPropsForCostContext()
{
	GPOS_ASSERT(nullptr != m_pcc);
	GPOS_ASSERT(nullptr != m_pgexpr);
	GPOS_CHECK_ABORT;

	CDrvdPropCtxtPlan *pdpctxtplan = GPOS_NEW(m_mp) CDrvdPropCtxtPlan(m_mp);
	CopyStats();


	COperator *pop = m_pgexpr->Pop();
	if (COperator::EopPhysicalCTEConsumer == pop->Eopid())
	{
		// copy producer plan properties to passed derived plan properties context
		ULONG ulCTEId = CPhysicalCTEConsumer::PopConvert(pop)->UlCTEId();
		CDrvdPropPlan *pdpplan =
			m_pcc->Poc()->Prpp()->Pcter()->Pdpplan(ulCTEId);
		if (nullptr != pdpplan)
		{
			pdpctxtplan->CopyCTEProducerProps(pdpplan, ulCTEId);
		}
	}

	// create/derive local properties
	m_pdpplan = Pop()->PdpCreate(m_mp);
	m_pdpplan->Derive(m_mp, *this, pdpctxtplan);
	pdpctxtplan->Release();
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::InitReqdProps
//
//	@doc:
//		Init required properties containers
//
//
//---------------------------------------------------------------------------
void
CExpressionHandle::InitReqdProps(CReqdProp *prpInput)
{
	GPOS_ASSERT(nullptr != prpInput);
	GPOS_ASSERT(nullptr == m_prp);
	GPOS_ASSERT(nullptr == m_pdrgprp);

	// set required properties of attached expr/gexpr
	m_prp = prpInput;
	m_prp->AddRef();

	// compute required properties of children
	m_pdrgprp = GPOS_NEW(m_mp) CReqdPropArray(m_mp);

	// initialize array with input requirements,
	// the initial requirements are only place holders in the array
	// and they are replaced when computing the requirements of each child
	const ULONG arity = Arity();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		m_prp->AddRef();
		m_pdrgprp->Append(m_prp);
	}
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::ComputeChildReqdProps
//
//	@doc:
//		Compute required properties of the n-th child
//
//
//---------------------------------------------------------------------------
void
CExpressionHandle::ComputeChildReqdProps(ULONG child_index,
										 CDrvdPropArray *pdrgpdpCtxt,
										 ULONG ulOptReq)
{
	GPOS_ASSERT(nullptr != m_prp);
	GPOS_ASSERT(nullptr != m_pdrgprp);
	GPOS_ASSERT(m_pdrgprp->Size() == Arity());
	GPOS_ASSERT(child_index < m_pdrgprp->Size() &&
				"uninitialized required child properties");
	GPOS_CHECK_ABORT;

	CReqdProp *prp = m_prp;
	if (FScalarChild(child_index))
	{
		// use local reqd properties to fill scalar child entry in children array
		prp->AddRef();
	}
	else
	{
		// compute required properties based on child type
		prp = Pop()->PrpCreate(m_mp);
		prp->Compute(m_mp, *this, m_prp, child_index, pdrgpdpCtxt, ulOptReq);
	}

	// replace required properties of given child
	m_pdrgprp->Replace(child_index, prp);
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::CopyChildReqdProps
//
//	@doc:
//		Copy required properties of the n-th child
//
//
//---------------------------------------------------------------------------
void
CExpressionHandle::CopyChildReqdProps(ULONG child_index, CReqdProp *prp)
{
	GPOS_ASSERT(nullptr != prp);
	GPOS_ASSERT(nullptr != m_pdrgprp);
	GPOS_ASSERT(m_pdrgprp->Size() == Arity());
	GPOS_ASSERT(child_index < m_pdrgprp->Size() &&
				"uninitialized required child properties");

	m_pdrgprp->Replace(child_index, prp);
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::ComputeChildReqdCols
//
//	@doc:
//		Compute required columns of the n-th child
//
//
//---------------------------------------------------------------------------
void
CExpressionHandle::ComputeChildReqdCols(ULONG child_index,
										CDrvdPropArray *pdrgpdpCtxt)
{
	GPOS_ASSERT(nullptr != m_prp);
	GPOS_ASSERT(nullptr != m_pdrgprp);
	GPOS_ASSERT(m_pdrgprp->Size() == Arity());
	GPOS_ASSERT(child_index < m_pdrgprp->Size() &&
				"uninitialized required child properties");

	CReqdProp *prp = m_prp;
	if (FScalarChild(child_index))
	{
		// use local reqd properties to fill scalar child entry in children array
		prp->AddRef();
	}
	else
	{
		// compute required columns
		prp = Pop()->PrpCreate(m_mp);
		CReqdPropPlan::Prpp(prp)->ComputeReqdCols(m_mp, *this, m_prp,
												  child_index, pdrgpdpCtxt);
	}

	// replace required properties of given child
	m_pdrgprp->Replace(child_index, prp);
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::ComputeReqdProps
//
//	@doc:
//		Set required properties of attached expr/gexpr, and compute required
//		properties of all children
//
//---------------------------------------------------------------------------
void
CExpressionHandle::ComputeReqdProps(CReqdProp *prpInput, ULONG ulOptReq)
{
	InitReqdProps(prpInput);
	const ULONG arity = Arity();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		ComputeChildReqdProps(ul, nullptr /*pdrgpdpCtxt*/, ulOptReq);
	}
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::FScalarChild
//
//	@doc:
//		Check if a given child is a scalar expression/group
//
//---------------------------------------------------------------------------
BOOL
CExpressionHandle::FScalarChild(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->Pop()->FScalar();
	}

	GPOS_ASSERT(nullptr != Pgexpr());

	return (*Pgexpr())[child_index]->FScalar();
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::Arity
//
//	@doc:
//		Return number of children of attached expression/group expression
//
//---------------------------------------------------------------------------
ULONG
CExpressionHandle::Arity() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->Arity();
	}

	GPOS_ASSERT(nullptr != Pgexpr());

	return Pgexpr()->Arity();
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::UlLastNonScalarChild
//
//	@doc:
//		Return the index of the last non-scalar child. This is only valid if
//		Arity() is greater than 0
//
//---------------------------------------------------------------------------
ULONG
CExpressionHandle::UlLastNonScalarChild() const
{
	const ULONG arity = Arity();
	if (0 == arity)
	{
		return gpos::ulong_max;
	}

	ULONG ulLastNonScalarChild = arity - 1;
	while (0 < ulLastNonScalarChild && FScalarChild(ulLastNonScalarChild))
	{
		ulLastNonScalarChild--;
	}

	if (!FScalarChild(ulLastNonScalarChild))
	{
		// we need to check again that index points to a non-scalar child
		// since operator's children may be all scalar (e.g. index-scan)
		return ulLastNonScalarChild;
	}

	return gpos::ulong_max;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::UlFirstNonScalarChild
//
//	@doc:
//		Return the index of the first non-scalar child. This is only valid if
//		Arity() is greater than 0
//
//---------------------------------------------------------------------------
ULONG
CExpressionHandle::UlFirstNonScalarChild() const
{
	const ULONG arity = Arity();
	if (0 == arity)
	{
		return gpos::ulong_max;
	}

	ULONG ulFirstNonScalarChild = 0;
	while (ulFirstNonScalarChild < arity - 1 &&
		   FScalarChild(ulFirstNonScalarChild))
	{
		ulFirstNonScalarChild++;
	}

	if (!FScalarChild(ulFirstNonScalarChild))
	{
		// we need to check again that index points to a non-scalar child
		// since operator's children may be all scalar (e.g. index-scan)
		return ulFirstNonScalarChild;
	}

	return gpos::ulong_max;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::UlNonScalarChildren
//
//	@doc:
//		Return number of non-scalar children
//
//---------------------------------------------------------------------------
ULONG
CExpressionHandle::UlNonScalarChildren() const
{
	const ULONG arity = Arity();
	ULONG ulNonScalarChildren = 0;
	for (ULONG ul = 0; ul < arity; ul++)
	{
		if (!FScalarChild(ul))
		{
			ulNonScalarChildren++;
		}
	}

	return ulNonScalarChildren;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::GetRelationalProperties
//
//	@doc:
//		Retrieve derived relational props of n-th child;
//		Assumes caller knows what properties to ask for;
//
//---------------------------------------------------------------------------
CDrvdPropRelational *
CExpressionHandle::GetRelationalProperties(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		// handle is used for required property computation
		if (Pexpr()->Pop()->FPhysical())
		{
			// relational props were copied from memo, return props directly
			return (*Pexpr())[child_index]->GetDrvdPropRelational();
		}

		// return props after calling derivation function
		return CDrvdPropRelational::GetRelationalProperties(
			(*Pexpr())[child_index]->PdpDerive());
	}

	GPOS_ASSERT(nullptr != m_pcc || nullptr != m_pgexpr);

	// handle is used for deriving plan properties, get relational props from child group
	CDrvdPropRelational *drvdProps =
		CDrvdPropRelational::GetRelationalProperties(
			(*Pgexpr())[child_index]->Pdp());
	GPOS_ASSERT(drvdProps->IsComplete());

	return drvdProps;
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::GetRelationalProperties
//
//	@doc:
//		Retrieve relational properties of attached expr/gexpr;
//
//---------------------------------------------------------------------------
CDrvdPropRelational *
CExpressionHandle::GetRelationalProperties() const
{
	if (nullptr != Pexpr())
	{
		if (Pexpr()->Pop()->FPhysical())
		{
			// relational props were copied from memo, return props directly
			CDrvdPropRelational *drvdProps = Pexpr()->GetDrvdPropRelational();
			GPOS_ASSERT(drvdProps->IsComplete());
			return drvdProps;
		}
		// return props after calling derivation function
		return CDrvdPropRelational::GetRelationalProperties(
			Pexpr()->PdpDerive());
	}

	GPOS_ASSERT(nullptr != m_pcc || nullptr != m_pgexpr);

	// get relational props from group
	CDrvdPropRelational *drvdProps =
		CDrvdPropRelational::GetRelationalProperties(Pgexpr()->Pgroup()->Pdp());
	GPOS_ASSERT(drvdProps->IsComplete());

	return drvdProps;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::Pstats
//
//	@doc:
//		Return derived stats of n-th child
//
//---------------------------------------------------------------------------
IStatistics *
CExpressionHandle::Pstats(ULONG child_index) const
{
	GPOS_ASSERT(child_index < m_pdrgpstat->Size());

	return (*m_pdrgpstat)[child_index];
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::Pdpplan
//
//	@doc:
//		Retrieve derived plan props of n-th child;
//		Assumes caller knows what properties to ask for;
//
//---------------------------------------------------------------------------
CDrvdPropPlan *
CExpressionHandle::Pdpplan(ULONG child_index) const
{
	if (nullptr != m_pexpr)
	{
		return CDrvdPropPlan::Pdpplan(
			(*m_pexpr)[child_index]->Pdp(CDrvdProp::EptPlan));
	}

	GPOS_ASSERT(nullptr != m_pcc || nullptr != m_pgexpr);

	COptimizationContext *pocChild = (*m_pcc->Pdrgpoc())[child_index];
	CDrvdPropPlan *pdpplan = pocChild->PccBest()->Pdpplan();

	return pdpplan;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::GetDrvdScalarProps
//
//	@doc:
//		Retrieve derived scalar props of n-th child;
//		Assumes caller knows what properties to ask for;
//
//---------------------------------------------------------------------------
CDrvdPropScalar *
CExpressionHandle::GetDrvdScalarProps(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		// handle is used for required property computation
		return CDrvdPropScalar::GetDrvdScalarProps(
			(*Pexpr())[child_index]->PdpDerive());
	}

	GPOS_ASSERT(nullptr != m_pcc || nullptr != m_pgexpr);

	// handle is used for deriving plan properties, get scalar props from child group
	return CDrvdPropScalar::GetDrvdScalarProps((*Pgexpr())[child_index]->Pdp());
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::GetReqdRelationalProps
//
//	@doc:
//		Retrieve required relational props of n-th child;
//		Assumes caller knows what properties to ask for;
//
//---------------------------------------------------------------------------
CReqdPropRelational *
CExpressionHandle::GetReqdRelationalProps(ULONG child_index) const
{
	GPOS_ASSERT(child_index < m_pdrgprp->Size());

	CReqdProp *prp = (*m_pdrgprp)[child_index];
	GPOS_ASSERT(prp->FRelational() && "Unexpected property type");

	return CReqdPropRelational::GetReqdRelationalProps(prp);
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::Prpp
//
//	@doc:
//		Retrieve required relational props of n-th child;
//		Assumes caller knows what properties to ask for;
//
//---------------------------------------------------------------------------
CReqdPropPlan *
CExpressionHandle::Prpp(ULONG child_index) const
{
	GPOS_ASSERT(child_index < m_pdrgprp->Size());

	CReqdProp *prp = (*m_pdrgprp)[child_index];
	GPOS_ASSERT(prp->FPlan() && "Unexpected property type");

	return CReqdPropPlan::Prpp(prp);
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::Pop
//
//	@doc:
//		Get operator from handle
//
//---------------------------------------------------------------------------
COperator *
CExpressionHandle::Pop() const
{
	if (nullptr != m_pexpr)
	{
		GPOS_ASSERT(nullptr == m_pgexpr);

		return m_pexpr->Pop();
	}

	if (nullptr != m_pgexpr)
	{
		return m_pgexpr->Pop();
	}

	GPOS_ASSERT(!"Handle was not attached properly");
	return nullptr;
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::Pop
//
//	@doc:
//		Get child operator from handle
//
//---------------------------------------------------------------------------
COperator *
CExpressionHandle::Pop(ULONG child_index) const
{
	GPOS_ASSERT(child_index < Arity());

	if (nullptr != m_pexpr)
	{
		GPOS_ASSERT(nullptr == m_pgexpr);

		return (*m_pexpr)[child_index]->Pop();
	}

	if (nullptr != m_pcc)
	{
		COptimizationContext *pocChild = (*m_pcc->Pdrgpoc())[child_index];
		GPOS_ASSERT(nullptr != pocChild);

		CCostContext *pccChild = pocChild->PccBest();
		GPOS_ASSERT(nullptr != pccChild);

		return pccChild->Pgexpr()->Pop();
	}

	return nullptr;
}

COperator *
CExpressionHandle::PopGrandchild(ULONG child_index, ULONG grandchild_index,
								 CCostContext **grandchildContext) const
{
	GPOS_ASSERT(child_index < Arity());

	if (grandchildContext)
	{
		*grandchildContext = nullptr;
	}

	if (nullptr != m_pexpr)
	{
		GPOS_ASSERT(nullptr == m_pcc);

		CExpression *childExpr = (*m_pexpr)[child_index];

		if (nullptr != childExpr)
		{
			return (*childExpr)[grandchild_index]->Pop();
		}

		return nullptr;
	}

	if (nullptr != m_pcc)
	{
		COptimizationContext *pocChild = (*m_pcc->Pdrgpoc())[child_index];
		GPOS_ASSERT(nullptr != pocChild);

		CCostContext *pccChild = pocChild->PccBest();
		GPOS_ASSERT(nullptr != pccChild);

		COptimizationContext *pocGrandchild =
			(*pccChild->Pdrgpoc())[grandchild_index];

		if (nullptr != pocGrandchild)
		{
			CCostContext *pccgrandchild = pocGrandchild->PccBest();

			if (grandchildContext)
			{
				*grandchildContext = pccgrandchild;
			}

			return pccgrandchild->Pgexpr()->Pop();
		}
	}

	return nullptr;
}



//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::DeriveProducerStats
//
//	@doc:
//		If the child (child_index) is a CTE consumer, then derive is corresponding
//		producer statistics.
//
//---------------------------------------------------------------------------
void
CExpressionHandle::DeriveProducerStats(ULONG child_index,
									   CColRefSet *pcrsStats) const
{
	// check to see if there are any CTE consumers in the group whose properties have
	// to be pushed to its corresponding CTE producer
	CGroupExpression *pgexpr = Pgexpr();
	if (nullptr != pgexpr)
	{
		CGroup *pgroupChild = (*pgexpr)[child_index];
		if (pgroupChild->FHasAnyCTEConsumer())
		{
			CGroupExpression *pgexprCTEConsumer =
				pgroupChild->PgexprAnyCTEConsumer();
			CLogicalCTEConsumer *popConsumer =
				CLogicalCTEConsumer::PopConvert(pgexprCTEConsumer->Pop());
			COptCtxt::PoctxtFromTLS()->Pcteinfo()->DeriveProducerStats(
				popConsumer, pcrsStats);
		}

		return;
	}

	// statistics are also derived on expressions representing the producer that may have
	// multiple CTE consumers. We should ensure that their properties are to pushed to their
	// corresponding CTE producer
	CExpression *pexpr = Pexpr();
	if (nullptr != pexpr)
	{
		CExpression *pexprChild = (*pexpr)[child_index];
		if (COperator::EopLogicalCTEConsumer == pexprChild->Pop()->Eopid())
		{
			CLogicalCTEConsumer *popConsumer =
				CLogicalCTEConsumer::PopConvert(pexprChild->Pop());
			COptCtxt::PoctxtFromTLS()->Pcteinfo()->DeriveProducerStats(
				popConsumer, pcrsStats);
		}
	}
}

//---------------------------------------------------------------------------
// CExpressionHandle::PexprScalarRepChild
//
// Get a representative (inexact) scalar child at given index. Subqueries
// in the child are replaced by a TRUE or NULL constant. Use this method
// where exactness is not required, e. g. for statistics derivation,
// costing, or for heuristics.
//
//---------------------------------------------------------------------------
CExpression *
CExpressionHandle::PexprScalarRepChild(ULONG child_index) const
{
	GPOS_ASSERT(child_index < Arity());

	if (nullptr != m_pgexpr)
	{
		// access scalar expression cached on the child scalar group
		GPOS_ASSERT((*m_pgexpr)[child_index]->FScalar());

		CExpression *pexprScalar = (*m_pgexpr)[child_index]->PexprScalarRep();
		GPOS_ASSERT(nullptr != pexprScalar);

		return pexprScalar;
	}

	if (nullptr != m_pexpr && nullptr != (*m_pexpr)[child_index]->Pgexpr())
	{
		// if the expression does not come from a group, but its child does then
		// get the scalar child from that group
		CGroupExpression *pgexpr = (*m_pexpr)[child_index]->Pgexpr();
		CExpression *pexprScalar = pgexpr->Pgroup()->PexprScalarRep();
		GPOS_ASSERT(nullptr != pexprScalar);

		return pexprScalar;
	}

	// access scalar expression from the child expression node
	GPOS_ASSERT((*m_pexpr)[child_index]->Pop()->FScalar());

	return (*m_pexpr)[child_index];
}


//---------------------------------------------------------------------------
// CExpressionHandle::PexprScalarRep
//
// Get a representative scalar expression attached to handle,
// return NULL if handle is not attached to a scalar expression.
// Note that this may be inexact if handle is attached to a
// CGroupExpression - subqueries will be replaced by a TRUE or NULL
// constant. Use this method where exactness is not required, e. g.
// for statistics derivation, costing, or for heuristics.
//
//---------------------------------------------------------------------------
CExpression *
CExpressionHandle::PexprScalarRep() const
{
	if (!Pop()->FScalar())
	{
		return nullptr;
	}

	if (nullptr != m_pexpr)
	{
		return m_pexpr;
	}

	if (nullptr != m_pgexpr)
	{
		return m_pgexpr->Pgroup()->PexprScalarRep();
	}

	return nullptr;
}


// return an exact scalar child at given index or return null if not possible
// (use this where exactness is required, e.g. for constraint derivation)
CExpression *
CExpressionHandle::PexprScalarExactChild(ULONG child_index,
										 BOOL error_on_null_return) const
{
	CExpression *result_expr = nullptr;
	if (nullptr != m_pgexpr && !(*m_pgexpr)[child_index]->FScalarRepIsExact())
	{
		result_expr = nullptr;
	}

	else if (nullptr != m_pexpr &&
			 nullptr != (*m_pexpr)[child_index]->Pgexpr() &&
			 !((*m_pexpr)[child_index]
				   ->Pgexpr()
				   ->Pgroup()
				   ->FScalarRepIsExact()))
	{
		// the expression does not come from a group, but its child does and
		// the child group does not have an exact expression
		result_expr = nullptr;
	}

	else
	{
		result_expr = PexprScalarRepChild(child_index);
	}
	if (nullptr == result_expr && error_on_null_return)
	{
		GPOS_RAISE(CException::ExmaInvalid, CException::ExmiInvalid,
				   GPOS_WSZ_LIT("Generated invalid plan with subquery"));
	}
	return result_expr;
}

// return an exact scalar expression attached to handle or null if not possible
// (use this where exactness is required, e.g. for constraint derivation)
CExpression *
CExpressionHandle::PexprScalarExact() const
{
	if (nullptr != m_pgexpr && !m_pgexpr->Pgroup()->FScalarRepIsExact())
	{
		return nullptr;
	}

	return PexprScalarRep();
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::PfpChild
//
//	@doc:
//		Retrieve derived function props of n-th child;
//
//---------------------------------------------------------------------------
CFunctionProp *
CExpressionHandle::PfpChild(ULONG child_index) const
{
	if (FScalarChild(child_index))
	{
		return DeriveScalarFunctionProperties(child_index);
	}

	return this->DeriveFunctionProperties(child_index);
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::FChildrenHaveVolatileFuncScan
//
//	@doc:
//		Check whether an expression's children have a volatile function scan
//
//---------------------------------------------------------------------------
BOOL
CExpressionHandle::FChildrenHaveVolatileFuncScan() const
{
	const ULONG arity = Arity();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		if (PfpChild(ul)->FHasVolatileFunctionScan())
		{
			return true;
		}
	}

	return false;
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::FChildrenHaveVolatileFunc
//
//	@doc:
//		Check whether an expression's children have a volatile function
//
//---------------------------------------------------------------------------
BOOL
CExpressionHandle::FChildrenHaveVolatileFunc() const
{
	const ULONG arity = Arity();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		if (PfpChild(ul)->Efs() == IMDFunction::EfsVolatile)
		{
			return true;
		}
	}

	return false;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::UlFirstOptimizedChildIndex
//
//	@doc:
//		Return the index of first child to be optimized
//
//---------------------------------------------------------------------------
ULONG
CExpressionHandle::UlFirstOptimizedChildIndex() const
{
	const ULONG arity = Arity();
	GPOS_ASSERT(0 < arity);

	CPhysical::EChildExecOrder eceo = CPhysical::PopConvert(Pop())->Eceo();
	if (CPhysical::EceoRightToLeft == eceo)
	{
		return arity - 1;
	}
	GPOS_ASSERT(CPhysical::EceoLeftToRight == eceo);

	return 0;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::UlLastOptimizedChildIndex
//
//	@doc:
//		Return the index of last child to be optimized
//
//---------------------------------------------------------------------------
ULONG
CExpressionHandle::UlLastOptimizedChildIndex() const
{
	const ULONG arity = Arity();
	GPOS_ASSERT(0 < arity);

	CPhysical::EChildExecOrder eceo = CPhysical::PopConvert(Pop())->Eceo();
	if (CPhysical::EceoRightToLeft == eceo)
	{
		return 0;
	}
	GPOS_ASSERT(CPhysical::EceoLeftToRight == eceo);

	return arity - 1;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::UlNextOptimizedChildIndex
//
//	@doc:
//		Return the index of child to be optimized next to the given child,
//		return gpos::ulong_max if there is no next child index
//
//
//---------------------------------------------------------------------------
ULONG
CExpressionHandle::UlNextOptimizedChildIndex(ULONG child_index) const
{
	CPhysical::EChildExecOrder eceo = CPhysical::PopConvert(Pop())->Eceo();

	ULONG ulNextChildIndex = gpos::ulong_max;
	if (CPhysical::EceoRightToLeft == eceo)
	{
		if (0 < child_index)
		{
			ulNextChildIndex = child_index - 1;
		}
	}
	else
	{
		GPOS_ASSERT(CPhysical::EceoLeftToRight == eceo);

		if (Arity() - 1 > child_index)
		{
			ulNextChildIndex = child_index + 1;
		}
	}

	return ulNextChildIndex;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::UlPreviousOptimizedChildIndex
//
//	@doc:
//		Return the index of child optimized before the given child,
//		return gpos::ulong_max if there is no previous child index
//
//
//---------------------------------------------------------------------------
ULONG
CExpressionHandle::UlPreviousOptimizedChildIndex(ULONG child_index) const
{
	CPhysical::EChildExecOrder eceo = CPhysical::PopConvert(Pop())->Eceo();

	ULONG ulPrevChildIndex = gpos::ulong_max;
	if (CPhysical::EceoRightToLeft == eceo)
	{
		if (Arity() - 1 > child_index)
		{
			ulPrevChildIndex = child_index + 1;
		}
	}
	else
	{
		GPOS_ASSERT(CPhysical::EceoLeftToRight == eceo);

		if (0 < child_index)
		{
			ulPrevChildIndex = child_index - 1;
		}
	}

	return ulPrevChildIndex;
}


//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::FNextChildIndex
//
//	@doc:
//		Get next child index based on child optimization order, return
//		true if such index could be found
//
//---------------------------------------------------------------------------
BOOL
CExpressionHandle::FNextChildIndex(ULONG *pulChildIndex) const
{
	GPOS_ASSERT(nullptr != pulChildIndex);

	const ULONG arity = Arity();
	if (0 == arity)
	{
		// operator does not have children
		return false;
	}

	ULONG ulNextChildIndex = UlNextOptimizedChildIndex(*pulChildIndex);
	if (gpos::ulong_max == ulNextChildIndex)
	{
		return false;
	}
	*pulChildIndex = ulNextChildIndex;

	return true;
}

//---------------------------------------------------------------------------
//	@function:
//		CExpressionHandle::PcrsUsedColumns
//
//	@doc:
//		Return the columns used by a logical operator and all its scalar children
//
//---------------------------------------------------------------------------
CColRefSet *
CExpressionHandle::PcrsUsedColumns(CMemoryPool *mp) const
{
	COperator *pop = Pop();
	GPOS_ASSERT(pop->FLogical());

	CColRefSet *pcrs = GPOS_NEW(mp) CColRefSet(mp);

	// get columns used by the operator itself
	pcrs->Include(CLogical::PopConvert(pop)->PcrsLocalUsed());

	// get columns used by the scalar children
	const ULONG arity = Arity();
	for (ULONG ul = 0; ul < arity; ul++)
	{
		if (FScalarChild(ul))
		{
			pcrs->Include(DeriveUsedColumns(ul));
		}
	}

	return pcrs;
}

CDrvdProp *
CExpressionHandle::Pdp() const
{
	if (nullptr != m_pcc)
	{
		GPOS_ASSERT(m_pdpplan != nullptr);
		return m_pdpplan;
	}

	if (nullptr != Pexpr())
	{
		return Pexpr()->Pdp(Pexpr()->Ept());
	}

	GPOS_ASSERT(nullptr != Pgexpr());
	return Pgexpr()->Pgroup()->Pdp();
}

IStatistics *
CExpressionHandle::Pstats()
{
	return m_pstats;
}

// The below functions use on-demand property derivation
// only if there is an expression associated with the expression handle.
// If there is only a group expression or a cost context assoicated with the handle,
// all properties must have already been derived as we can't derive anything.
CColRefSet *
CExpressionHandle::DeriveOuterReferences(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveOuterReferences();
	}

	return GetRelationalProperties(child_index)->GetOuterReferences();
}

CColRefSet *
CExpressionHandle::DeriveOuterReferences() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveOuterReferences();
	}

	return GetRelationalProperties()->GetOuterReferences();
}

CColRefSet *
CExpressionHandle::DeriveOutputColumns(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveOutputColumns();
	}

	return GetRelationalProperties(child_index)->GetOutputColumns();
}

CColRefSet *
CExpressionHandle::DeriveOutputColumns() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveOutputColumns();
	}

	return GetRelationalProperties()->GetOutputColumns();
}

CColRefSet *
CExpressionHandle::DeriveNotNullColumns(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveNotNullColumns();
	}

	return GetRelationalProperties(child_index)->GetNotNullColumns();
}

CColRefSet *
CExpressionHandle::DeriveNotNullColumns() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveNotNullColumns();
	}

	return GetRelationalProperties()->GetNotNullColumns();
}

CMaxCard
CExpressionHandle::DeriveMaxCard(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveMaxCard();
	}

	return GetRelationalProperties(child_index)->GetMaxCard();
}

CMaxCard
CExpressionHandle::DeriveMaxCard() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveMaxCard();
	}

	return GetRelationalProperties()->GetMaxCard();
}

CColRefSet *
CExpressionHandle::DeriveCorrelatedApplyColumns(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveCorrelatedApplyColumns();
	}

	return GetRelationalProperties(child_index)->GetCorrelatedApplyColumns();
}

CColRefSet *
CExpressionHandle::DeriveCorrelatedApplyColumns() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveCorrelatedApplyColumns();
	}

	return GetRelationalProperties()->GetCorrelatedApplyColumns();
}

CKeyCollection *
CExpressionHandle::DeriveKeyCollection(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveKeyCollection();
	}

	return GetRelationalProperties(child_index)->GetKeyCollection();
}

CKeyCollection *
CExpressionHandle::DeriveKeyCollection() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveKeyCollection();
	}

	return GetRelationalProperties()->GetKeyCollection();
}

CPropConstraint *
CExpressionHandle::DerivePropertyConstraint(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DerivePropertyConstraint();
	}

	return GetRelationalProperties(child_index)->GetPropertyConstraint();
}

CPropConstraint *
CExpressionHandle::DerivePropertyConstraint() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DerivePropertyConstraint();
	}

	return GetRelationalProperties()->GetPropertyConstraint();
}

ULONG
CExpressionHandle::DeriveJoinDepth(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveJoinDepth();
	}

	return GetRelationalProperties(child_index)->GetJoinDepth();
}

ULONG
CExpressionHandle::DeriveJoinDepth() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveJoinDepth();
	}

	return GetRelationalProperties()->GetJoinDepth();
}

CFunctionProp *
CExpressionHandle::DeriveFunctionProperties(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveFunctionProperties();
	}

	return GetRelationalProperties(child_index)->GetFunctionProperties();
}

CFunctionProp *
CExpressionHandle::DeriveFunctionProperties() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveFunctionProperties();
	}

	return GetRelationalProperties()->GetFunctionProperties();
}

CFunctionalDependencyArray *
CExpressionHandle::Pdrgpfd(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveFunctionalDependencies();
	}

	return GetRelationalProperties(child_index)->GetFunctionalDependencies();
}

CFunctionalDependencyArray *
CExpressionHandle::Pdrgpfd() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveFunctionalDependencies();
	}

	return GetRelationalProperties()->GetFunctionalDependencies();
}

CPartInfo *
CExpressionHandle::DerivePartitionInfo(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DerivePartitionInfo();
	}

	return GetRelationalProperties(child_index)->GetPartitionInfo();
}

CPartInfo *
CExpressionHandle::DerivePartitionInfo() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DerivePartitionInfo();
	}

	return GetRelationalProperties()->GetPartitionInfo();
}

CTableDescriptor *
CExpressionHandle::DeriveTableDescriptor() const
{
	if (nullptr != Pexpr())
	{
		return Pexpr()->DeriveTableDescriptor();
	}

	return GetRelationalProperties()->GetTableDescriptor();
}

CTableDescriptor *
CExpressionHandle::DeriveTableDescriptor(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveTableDescriptor();
	}

	return GetRelationalProperties(child_index)->GetTableDescriptor();
}
// Scalar property accessors

CColRefSet *
CExpressionHandle::DeriveDefinedColumns(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveDefinedColumns();
	}

	return GetDrvdScalarProps(child_index)->GetDefinedColumns();
}

CColRefSet *
CExpressionHandle::DeriveUsedColumns(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveUsedColumns();
	}

	return GetDrvdScalarProps(child_index)->GetUsedColumns();
}

CColRefSet *
CExpressionHandle::DeriveSetReturningFunctionColumns(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveSetReturningFunctionColumns();
	}

	return GetDrvdScalarProps(child_index)->GetSetReturningFunctionColumns();
}

BOOL
CExpressionHandle::DeriveHasSubquery(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveHasSubquery();
	}

	return GetDrvdScalarProps(child_index)->HasSubquery();
}

CPartInfo *
CExpressionHandle::DeriveScalarPartitionInfo(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveScalarPartitionInfo();
	}

	return GetDrvdScalarProps(child_index)->GetPartitionInfo();
}

CFunctionProp *
CExpressionHandle::DeriveScalarFunctionProperties(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveScalarFunctionProperties();
	}

	return GetDrvdScalarProps(child_index)->GetFunctionProperties();
}

BOOL
CExpressionHandle::DeriveHasNonScalarFunction(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveHasNonScalarFunction();
	}

	return GetDrvdScalarProps(child_index)->HasNonScalarFunction();
}

ULONG
CExpressionHandle::DeriveTotalDistinctAggs(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveTotalDistinctAggs();
	}

	return GetDrvdScalarProps(child_index)->GetTotalDistinctAggs();
}

BOOL
CExpressionHandle::DeriveHasMultipleDistinctAggs(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveHasMultipleDistinctAggs();
	}

	return GetDrvdScalarProps(child_index)->HasMultipleDistinctAggs();
}

BOOL
CExpressionHandle::DeriveHasScalarArrayCmp(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveHasScalarArrayCmp();
	}

	return GetDrvdScalarProps(child_index)->HasScalarArrayCmp();
}

BOOL
CExpressionHandle::DeriveHasScalarFuncProject(ULONG child_index) const
{
	if (nullptr != Pexpr())
	{
		return (*Pexpr())[child_index]->DeriveHasScalarFuncProject();
	}

	return GetDrvdScalarProps(child_index)->HasScalarFuncProject();
}
// EOF

相关信息

greenplumn 源码目录

相关文章

greenplumn CExpression 源码

greenplumn CExpressionFactorizer 源码

greenplumn CExpressionPreprocessor 源码

greenplumn CExpressionUtils 源码

greenplumn CHashedDistributions 源码

greenplumn CLogical 源码

greenplumn CLogicalApply 源码

greenplumn CLogicalAssert 源码

greenplumn CLogicalBitmapTableGet 源码

greenplumn CLogicalCTEAnchor 源码

0  赞