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 CExpressionFactorizer 源码
greenplumn CExpressionPreprocessor 源码
greenplumn CExpressionUtils 源码
greenplumn CHashedDistributions 源码