greenplumn CExpression 源码
greenplumn CExpression 代码
文件路径:/src/backend/gporca/libgpopt/src/operators/CExpression.cpp
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2009 Greenplum, Inc.
//
// @filename:
// CExpression.cpp
//
// @doc:
// Implementation of expressions
//---------------------------------------------------------------------------
#include "gpos/base.h"
#include "gpos/error/CAutoTrace.h"
#include "gpos/io/COstreamString.h"
#include "gpos/string/CWStringDynamic.h"
#include "gpos/task/CAutoSuspendAbort.h"
#include "gpos/task/CAutoTraceFlag.h"
#include "gpos/task/CWorker.h"
#include "gpopt/base/CAutoOptCtxt.h"
#include "gpopt/base/CColRefSet.h"
#include "gpopt/base/CDistributionSpec.h"
#include "gpopt/base/CDrvdPropCtxtPlan.h"
#include "gpopt/base/CDrvdPropCtxtRelational.h"
#include "gpopt/base/CDrvdPropRelational.h"
#include "gpopt/base/CPrintPrefix.h"
#include "gpopt/base/CReqdPropRelational.h"
#include "gpopt/base/CUtils.h"
#include "gpopt/exception.h"
#include "gpopt/metadata/CTableDescriptor.h"
#include "gpopt/operators/CExpressionHandle.h"
#include "gpopt/operators/COperator.h"
#include "gpopt/operators/CPattern.h"
#include "gpopt/operators/CPatternNode.h"
#include "gpopt/operators/CPhysicalCTEProducer.h"
#include "gpopt/search/CGroupExpression.h"
#include "naucrates/statistics/CStatistics.h"
#include "naucrates/traceflags/traceflags.h"
using namespace gpnaucrates;
using namespace gpopt;
static CHAR szExprLevelWS[] = " ";
static CHAR szExprBarLevelWS[] = "| ";
static CHAR szExprBarOpPrefix[] = "|--";
static CHAR szExprPlusOpPrefix[] = "+--";
//---------------------------------------------------------------------------
// @function:
// CExpression::CExpression
//
// @doc:
// Ctor for leaf nodes
//
//---------------------------------------------------------------------------
CExpression::CExpression(CMemoryPool *mp, COperator *pop,
CGroupExpression *pgexpr)
: m_mp(mp),
m_pop(pop),
m_pdrgpexpr(nullptr),
m_pdprel(nullptr),
m_pstats(nullptr),
m_prpp(nullptr),
m_pdpplan(nullptr),
m_pdpscalar(nullptr),
m_pgexpr(pgexpr),
m_cost(GPOPT_INVALID_COST),
m_ulOriginGrpId(gpos::ulong_max),
m_ulOriginGrpExprId(gpos::ulong_max)
{
GPOS_ASSERT(nullptr != mp);
GPOS_ASSERT(nullptr != pop);
m_pdprel = GPOS_NEW(m_mp) CDrvdPropRelational(m_mp);
m_pdpscalar = GPOS_NEW(m_mp) CDrvdPropScalar(m_mp);
if (nullptr != pgexpr)
{
CopyGroupPropsAndStats(nullptr /*input_stats*/);
}
}
//---------------------------------------------------------------------------
// @function:
// CExpression::CExpression
//
// @doc:
// Ctor, unary
//
//---------------------------------------------------------------------------
CExpression::CExpression(CMemoryPool *mp, COperator *pop, CExpression *pexpr)
: m_mp(mp),
m_pop(pop),
m_pdrgpexpr(nullptr),
m_pdprel(nullptr),
m_pstats(nullptr),
m_prpp(nullptr),
m_pdpplan(nullptr),
m_pdpscalar(nullptr),
m_pgexpr(nullptr),
m_cost(GPOPT_INVALID_COST),
m_ulOriginGrpId(gpos::ulong_max),
m_ulOriginGrpExprId(gpos::ulong_max)
{
GPOS_ASSERT(nullptr != mp);
GPOS_ASSERT(nullptr != pop);
GPOS_ASSERT(nullptr != pexpr);
m_pdprel = GPOS_NEW(m_mp) CDrvdPropRelational(m_mp);
m_pdpscalar = GPOS_NEW(m_mp) CDrvdPropScalar(m_mp);
m_pdrgpexpr = GPOS_NEW(mp) CExpressionArray(mp, 1);
m_pdrgpexpr->Append(pexpr);
GPOS_ASSERT(m_pdrgpexpr->Size() == 1);
}
//---------------------------------------------------------------------------
// @function:
// CExpression::CExpression
//
// @doc:
// Ctor, binary
//
//---------------------------------------------------------------------------
CExpression::CExpression(CMemoryPool *mp, COperator *pop,
CExpression *pexprChildFirst,
CExpression *pexprChildSecond)
: m_mp(mp),
m_pop(pop),
m_pdrgpexpr(nullptr),
m_pdprel(nullptr),
m_pstats(nullptr),
m_prpp(nullptr),
m_pdpplan(nullptr),
m_pdpscalar(nullptr),
m_pgexpr(nullptr),
m_cost(GPOPT_INVALID_COST),
m_ulOriginGrpId(gpos::ulong_max),
m_ulOriginGrpExprId(gpos::ulong_max)
{
GPOS_ASSERT(nullptr != mp);
GPOS_ASSERT(nullptr != pop);
GPOS_ASSERT(nullptr != pexprChildFirst);
GPOS_ASSERT(nullptr != pexprChildSecond);
m_pdprel = GPOS_NEW(m_mp) CDrvdPropRelational(m_mp);
m_pdpscalar = GPOS_NEW(m_mp) CDrvdPropScalar(m_mp);
m_pdrgpexpr = GPOS_NEW(mp) CExpressionArray(mp, 2);
m_pdrgpexpr->Append(pexprChildFirst);
m_pdrgpexpr->Append(pexprChildSecond);
GPOS_ASSERT(m_pdrgpexpr->Size() == 2);
}
//---------------------------------------------------------------------------
// @function:
// CExpression::CExpression
//
// @doc:
// Ctor, ternary
//
//---------------------------------------------------------------------------
CExpression::CExpression(CMemoryPool *mp, COperator *pop,
CExpression *pexprChildFirst,
CExpression *pexprChildSecond,
CExpression *pexprChildThird)
: m_mp(mp),
m_pop(pop),
m_pdrgpexpr(nullptr),
m_pdprel(nullptr),
m_pstats(nullptr),
m_prpp(nullptr),
m_pdpplan(nullptr),
m_pdpscalar(nullptr),
m_pgexpr(nullptr),
m_cost(GPOPT_INVALID_COST),
m_ulOriginGrpId(gpos::ulong_max),
m_ulOriginGrpExprId(gpos::ulong_max)
{
GPOS_ASSERT(nullptr != mp);
GPOS_ASSERT(nullptr != pop);
GPOS_ASSERT(nullptr != pexprChildFirst);
GPOS_ASSERT(nullptr != pexprChildSecond);
GPOS_ASSERT(nullptr != pexprChildThird);
m_pdprel = GPOS_NEW(m_mp) CDrvdPropRelational(m_mp);
m_pdpscalar = GPOS_NEW(m_mp) CDrvdPropScalar(m_mp);
m_pdrgpexpr = GPOS_NEW(mp) CExpressionArray(mp, 3);
m_pdrgpexpr->Append(pexprChildFirst);
m_pdrgpexpr->Append(pexprChildSecond);
m_pdrgpexpr->Append(pexprChildThird);
GPOS_ASSERT(m_pdrgpexpr->Size() == 3);
}
//---------------------------------------------------------------------------
// @function:
// CExpression::CExpression
//
// @doc:
// Ctor, generic n-ary
//
//---------------------------------------------------------------------------
CExpression::CExpression(CMemoryPool *mp, COperator *pop,
CExpressionArray *pdrgpexpr)
: m_mp(mp),
m_pop(pop),
m_pdrgpexpr(pdrgpexpr),
m_pdprel(nullptr),
m_pstats(nullptr),
m_prpp(nullptr),
m_pdpplan(nullptr),
m_pdpscalar(nullptr),
m_pgexpr(nullptr),
m_cost(GPOPT_INVALID_COST),
m_ulOriginGrpId(gpos::ulong_max),
m_ulOriginGrpExprId(gpos::ulong_max)
{
GPOS_ASSERT(nullptr != mp);
GPOS_ASSERT(nullptr != pop);
GPOS_ASSERT(nullptr != pdrgpexpr);
m_pdprel = GPOS_NEW(m_mp) CDrvdPropRelational(m_mp);
m_pdpscalar = GPOS_NEW(m_mp) CDrvdPropScalar(m_mp);
}
//---------------------------------------------------------------------------
// @function:
// CExpression::CExpression
//
// @doc:
// Ctor, generic n-ary with origin group expression
//
//---------------------------------------------------------------------------
CExpression::CExpression(CMemoryPool *mp, COperator *pop,
CGroupExpression *pgexpr, CExpressionArray *pdrgpexpr,
CReqdPropPlan *prpp, IStatistics *input_stats,
CCost cost)
: m_mp(mp),
m_pop(pop),
m_pdrgpexpr(pdrgpexpr),
m_pdprel(nullptr),
m_pstats(nullptr),
m_prpp(prpp),
m_pdpplan(nullptr),
m_pdpscalar(nullptr),
m_pgexpr(pgexpr),
m_cost(cost),
m_ulOriginGrpId(gpos::ulong_max),
m_ulOriginGrpExprId(gpos::ulong_max)
{
GPOS_ASSERT(nullptr != mp);
GPOS_ASSERT(nullptr != pop);
GPOS_ASSERT(pgexpr->Arity() ==
(pdrgpexpr == nullptr ? 0 : pdrgpexpr->Size()));
GPOS_ASSERT(nullptr != pgexpr->Pgroup());
m_pdprel = GPOS_NEW(m_mp) CDrvdPropRelational(m_mp);
m_pdpscalar = GPOS_NEW(m_mp) CDrvdPropScalar(m_mp);
CopyGroupPropsAndStats(input_stats);
}
//---------------------------------------------------------------------------
// @function:
// CExpression::~CExpression
//
// @doc:
// Dtor
//
//---------------------------------------------------------------------------
CExpression::~CExpression()
{
{
CAutoSuspendAbort asa;
CRefCount::SafeRelease(m_pdprel);
CRefCount::SafeRelease(m_pstats);
CRefCount::SafeRelease(m_prpp);
CRefCount::SafeRelease(m_pdpplan);
CRefCount::SafeRelease(m_pdpscalar);
CRefCount::SafeRelease(m_pdrgpexpr);
m_pop->Release();
}
}
//---------------------------------------------------------------------------
// @function:
// CExpression::CopyGroupPropsAndStats
//
// @doc:
// Copy group properties and stats to expression
//
//---------------------------------------------------------------------------
void
CExpression::CopyGroupPropsAndStats(IStatistics *input_stats)
{
GPOS_ASSERT(nullptr != m_pgexpr);
CDrvdProp *pdp = m_pgexpr->Pgroup()->Pdp();
GPOS_ASSERT(nullptr != pdp);
// copy properties
pdp->AddRef();
if (m_pgexpr->Pgroup()->FScalar())
{
m_pdpscalar->Release();
m_pdpscalar = CDrvdPropScalar::GetDrvdScalarProps(pdp);
}
else
{
m_pdprel->Release();
m_pdprel = CDrvdPropRelational::GetRelationalProperties(pdp);
}
IStatistics *stats = nullptr;
if (nullptr != input_stats)
{
// copy stats from input
stats = input_stats;
}
else
{
// copy stats from group
stats = m_pgexpr->Pgroup()->Pstats();
}
if (nullptr != stats)
{
stats->AddRef();
m_pstats = stats;
}
m_ulOriginGrpExprId = m_pgexpr->Id();
m_ulOriginGrpId = m_pgexpr->Pgroup()->Id();
}
//---------------------------------------------------------------------------
// @function:
// CExpression::Pdp
//
// @doc:
// Get derivable property based on operator type;
// only used internally during property derivation
//
//---------------------------------------------------------------------------
CDrvdProp *
CExpression::Pdp(const CDrvdProp::EPropType ept) const
{
switch (ept)
{
case CDrvdProp::EptRelational:
return m_pdprel;
case CDrvdProp::EptPlan:
return m_pdpplan;
case CDrvdProp::EptScalar:
return m_pdpscalar;
default:
break;
}
GPOS_ASSERT(!"Invalid property type");
return nullptr;
}
CDrvdPropRelational *
CExpression::GetDrvdPropRelational() const
{
GPOS_RTL_ASSERT(m_pdprel->IsComplete());
return m_pdprel;
}
CDrvdPropPlan *
CExpression::GetDrvdPropPlan() const
{
GPOS_RTL_ASSERT(m_pdpplan->IsComplete());
return m_pdpplan;
}
CDrvdPropScalar *
CExpression::GetDrvdPropScalar() const
{
GPOS_RTL_ASSERT(m_pdpscalar->IsComplete());
return m_pdpscalar;
}
#ifdef GPOS_DEBUG
//---------------------------------------------------------------------------
// @function:
// CExpression::AssertValidPropDerivation
//
// @doc:
// Assert valid property derivation
//
//---------------------------------------------------------------------------
void
CExpression::AssertValidPropDerivation(const CDrvdProp::EPropType ept)
{
COperator *pop = Pop();
GPOS_ASSERT_IMP(pop->FScalar(), CDrvdProp::EptScalar == ept);
GPOS_ASSERT_IMP(pop->FLogical(), CDrvdProp::EptRelational == ept);
GPOS_ASSERT_IMP(pop->FPattern(), CDrvdProp::EptRelational == ept ||
CDrvdProp::EptScalar == ept);
GPOS_ASSERT_IMP(pop->FPhysical(), CDrvdProp::EptRelational == ept ||
CDrvdProp::EptPlan == ept);
GPOS_ASSERT_IMP(pop->FPhysical() && CDrvdProp::EptRelational == ept,
nullptr != m_pdprel &&
"Relational properties were not copied from Memo");
}
#endif // GPOS_DEBUG
//---------------------------------------------------------------------------
// @function:
// CExpression::Ept
//
// @doc:
// Get the suitable derived property type based on operator
//
//---------------------------------------------------------------------------
CDrvdProp::EPropType
CExpression::Ept() const
{
if (Pop()->FLogical())
{
return CDrvdProp::EptRelational;
}
if (Pop()->FPhysical())
{
GPOS_ASSERT(nullptr != m_pdprel &&
"Relational properties were not copied from Memo");
return CDrvdProp::EptPlan;
}
if (Pop()->FScalar())
{
return CDrvdProp::EptScalar;
}
GPOS_ASSERT(!"Unexpected operator type");
return CDrvdProp::EptInvalid;
}
// Derive all properties immediately. The suitable derived property is
// determined internally. To derive properties on an on-demand bases, use
// DeriveXXX() methods.
CDrvdProp *
CExpression::PdpDerive(
CDrvdPropCtxt *pdpctxt // derivation context, passed by caller
)
{
GPOS_CHECK_STACK_SIZE;
GPOS_CHECK_ABORT;
const CDrvdProp::EPropType ept = Ept();
#ifdef GPOS_DEBUG
AssertValidPropDerivation(ept);
#endif // GPOS_DEBUG
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
// see if suitable prop is already cached. This only applies to plan properties.
// relational properties are never null and are handled in the next case
if (nullptr == Pdp(ept))
{
GPOS_ASSERT(CDrvdProp::EptRelational != ept);
GPOS_ASSERT(CDrvdProp::EptScalar != ept);
const ULONG arity = Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CExpression *pexprChild = (*m_pdrgpexpr)[ul];
CDrvdProp *pdp = pexprChild->PdpDerive(pdpctxt);
// add child props to derivation context
CDrvdPropCtxt::AddDerivedProps(pdp, pdpctxt);
}
exprhdl.CopyStats();
switch (ept)
{
case CDrvdProp::EptPlan:
m_pdpplan = GPOS_NEW(m_mp) CDrvdPropPlan();
break;
default:
break;
}
Pdp(ept)->Derive(m_mp, exprhdl, pdpctxt);
}
// If we havn't derived all properties, do that now. If we've derived some
// of the properties, this will only derive properties that have not yet been derived.
else if (!Pdp(ept)->IsComplete())
{
Pdp(ept)->Derive(m_mp, exprhdl, pdpctxt);
}
// Otherwise, we've already derived all properties and can simply return them
GPOS_ASSERT(Pdp(ept)->IsComplete());
return Pdp(ept);
}
//---------------------------------------------------------------------------
// @function:
// CExpression::PstatsDerive
//
// @doc:
// Derive statistics
//
//---------------------------------------------------------------------------
IStatistics *
CExpression::PstatsDerive(CReqdPropRelational *prprel,
IStatisticsArray *stats_ctxt)
{
GPOS_CHECK_STACK_SIZE;
GPOS_ASSERT(nullptr != prprel);
GPOS_ASSERT(prprel->FRelational());
GPOS_CHECK_ABORT;
if (Pop()->FScalar())
{
if (nullptr == m_pstats)
{
// create an empty statistics container
m_pstats = CStatistics::MakeEmptyStats(m_mp);
}
return m_pstats;
}
prprel->AddRef();
CReqdPropRelational *prprelInput = prprel;
// if expression has derived statistics, check if requirements are covered
// by what's already derived
if (nullptr != m_pstats)
{
prprelInput->Release();
CReqdPropRelational *prprelExisting =
m_pstats->GetReqdRelationalProps(m_mp);
prprelInput = prprel->PrprelDifference(m_mp, prprelExisting);
prprelExisting->Release();
if (prprelInput->IsEmpty())
{
// required statistics columns are already covered by existing statistics
// clean up
prprelInput->Release();
return m_pstats;
}
}
IStatisticsArray *pdrgpstatCtxtNew = stats_ctxt;
if (nullptr == stats_ctxt)
{
// create an empty context
pdrgpstatCtxtNew = GPOS_NEW(m_mp) IStatisticsArray(m_mp);
}
else
{
pdrgpstatCtxtNew->AddRef();
}
// trigger recursive property derivation
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
CDrvdPropCtxtRelational *pdpctxtrel =
GPOS_NEW(m_mp) CDrvdPropCtxtRelational(m_mp);
exprhdl.DeriveProps(pdpctxtrel);
// compute required relational properties of expression's children
exprhdl.ComputeReqdProps(prprelInput, 0 /*ulOptReq*/);
// trigger recursive statistics derivation
exprhdl.DeriveStats(pdrgpstatCtxtNew);
// cache derived stats on expression
IStatistics *stats = exprhdl.Pstats();
GPOS_ASSERT(nullptr != stats);
if (nullptr == m_pstats)
{
stats->AddRef();
m_pstats = stats;
}
else
{
IStatistics *stats_copy = stats->CopyStats(m_mp);
stats_copy->AppendStats(m_mp, m_pstats);
m_pstats->Release();
m_pstats = nullptr;
m_pstats = stats_copy;
}
GPOS_ASSERT(nullptr != m_pstats);
// clean up
prprelInput->Release();
pdrgpstatCtxtNew->Release();
pdpctxtrel->Release();
return m_pstats;
}
//---------------------------------------------------------------------------
// @function:
// CExpression::ResetDerivedProperty
//
// @doc:
// Reset a derived property
//
//---------------------------------------------------------------------------
void
CExpression::ResetDerivedProperty(CDrvdProp::EPropType ept)
{
switch (ept)
{
case CDrvdProp::EptRelational:
CRefCount::SafeRelease(m_pdprel);
m_pdprel = GPOS_NEW(m_mp) CDrvdPropRelational(m_mp);
break;
case CDrvdProp::EptPlan:
CRefCount::SafeRelease(m_pdpplan);
m_pdpplan = nullptr;
break;
case CDrvdProp::EptScalar:
CRefCount::SafeRelease(m_pdpscalar);
m_pdpscalar = GPOS_NEW(m_mp) CDrvdPropScalar(m_mp);
break;
default:
GPOS_ASSERT(!"Invalid property type");
break;
}
}
//---------------------------------------------------------------------------
// @function:
// CExpression::ResetDerivedProperties
//
// @doc:
// Reset all derived properties
//
//---------------------------------------------------------------------------
void
CExpression::ResetDerivedProperties()
{
// protect against stack overflow during recursion
GPOS_CHECK_STACK_SIZE;
CDrvdProp::EPropType rgept[] = {CDrvdProp::EptRelational,
CDrvdProp::EptScalar, CDrvdProp::EptPlan};
for (ULONG i = 0; i < GPOS_ARRAY_SIZE(rgept); i++)
{
// reset self
ResetDerivedProperty(rgept[i]);
}
for (ULONG i = 0; i < Arity(); i++)
{
// reset children
(*this)[i]->ResetDerivedProperties();
}
}
//---------------------------------------------------------------------------
// @function:
// CExpression::ResetStats
//
// @doc:
// Reset stats on expression tree
//
//---------------------------------------------------------------------------
void
CExpression::ResetStats()
{
// protect against stack overflow during recursion
GPOS_CHECK_STACK_SIZE;
// reset stats on self
CRefCount::SafeRelease(m_pstats);
m_pstats = nullptr;
const ULONG arity = Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
// reset children stats
(*this)[ul]->ResetStats();
}
}
//---------------------------------------------------------------------------
// @function:
// CExpression::HasOuterRefs
//
// @doc:
// Check for outer references
//
//
//---------------------------------------------------------------------------
BOOL
CExpression::HasOuterRefs()
{
return (0 < DeriveOuterReferences()->Size());
}
//---------------------------------------------------------------------------
// @function:
// CExpression::FMatchPattern
//
// @doc:
// Check a pattern expression against a given group;
// shallow, do not match its children, check only arity of the root
//
//---------------------------------------------------------------------------
BOOL
CExpression::FMatchPattern(CGroupExpression *pgexpr) const
{
GPOS_ASSERT(nullptr != pgexpr);
if (this->Pop()->FPattern())
{
if (COperator::EopPatternNode == this->Pop()->Eopid())
{
return CPatternNode::PopConvert(this->Pop())
->MatchesOperator(pgexpr->Pop()->Eopid());
}
// a pattern operator other than a CPatternNode matches any group expression
return true;
}
else
{
ULONG arity = Arity();
BOOL fMultiNode =
((1 == arity || 2 == arity) && // has 2 or fewer children
CPattern::FMultiNode(
(*this)[0]->Pop()) // child is multileaf or a multitree
);
// match operator id and arity
if (this->Pop()->Eopid() == pgexpr->Pop()->Eopid() &&
(this->Arity() == pgexpr->Arity() ||
(fMultiNode && pgexpr->Arity() > 1)))
{
return true;
}
}
return false;
}
//---------------------------------------------------------------------------
// @function:
// CExpression::Matches
//
// @doc:
// Recursive comparison of this expression against another given one
//
//---------------------------------------------------------------------------
BOOL
CExpression::Matches(CExpression *pexpr) const
{
GPOS_CHECK_STACK_SIZE;
// check local operator
if (!Pop()->Matches(pexpr->Pop()))
{
return false;
}
ULONG arity = Arity();
if (arity != pexpr->Arity())
{
return false;
}
// decend into children
for (ULONG ul = 0; ul < arity; ul++)
{
if (!(*this)[ul]->Matches((*pexpr)[ul]))
{
return false;
}
}
return true;
}
//---------------------------------------------------------------------------
// @function:
// CExpression::PexprCopyWithRemappedColumns
//
// @doc:
// Return a copy of the expression with remapped columns
//
//---------------------------------------------------------------------------
CExpression *
CExpression::PexprCopyWithRemappedColumns(CMemoryPool *mp,
UlongToColRefMap *colref_mapping,
BOOL must_exist) const
{
GPOS_ASSERT(nullptr != m_pop);
// this is only valid for logical and scalar expressions
GPOS_ASSERT(m_pop->FLogical() || m_pop->FScalar());
// copy children
CExpressionArray *pdrgpexpr = GPOS_NEW(mp) CExpressionArray(mp);
const ULONG arity = Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
CExpression *pexprChild = (*m_pdrgpexpr)[ul];
pdrgpexpr->Append(pexprChild->PexprCopyWithRemappedColumns(
mp, colref_mapping, must_exist));
}
COperator *pop =
m_pop->PopCopyWithRemappedColumns(mp, colref_mapping, must_exist);
if (0 == arity)
{
pdrgpexpr->Release();
return GPOS_NEW(mp) CExpression(mp, pop);
}
return GPOS_NEW(mp) CExpression(mp, pop, pdrgpexpr);
}
#ifdef GPOS_DEBUG
//---------------------------------------------------------------------------
// @function:
// CExpression::FMatchPattern
//
// @doc:
// Check expression against a given pattern;
//
//---------------------------------------------------------------------------
BOOL
CExpression::FMatchPattern(CExpression *pexprPattern) const
{
GPOS_CHECK_STACK_SIZE;
GPOS_ASSERT(nullptr != pexprPattern);
COperator::EOperatorId op_id = pexprPattern->Pop()->Eopid();
if (COperator::EopPatternLeaf == op_id ||
COperator::EopPatternTree == op_id)
{
// leaf and tree operators always match
return true;
}
if (Pop()->Eopid() == op_id ||
(COperator::EopPatternNode == op_id &&
CPatternNode::PopConvert(pexprPattern->Pop())
->MatchesOperator(Pop()->Eopid())))
{
// check arity, children
return FMatchPatternChildren(pexprPattern);
}
return false;
}
//---------------------------------------------------------------------------
// @function:
// CExpression::FMatchPatternChildren
//
// @doc:
// Check expression's children against a given pattern's children;
//
//---------------------------------------------------------------------------
BOOL
CExpression::FMatchPatternChildren(CExpression *pexprPattern) const
{
GPOS_CHECK_STACK_SIZE;
ULONG arity = Arity();
ULONG ulArityPattern = pexprPattern->Arity();
BOOL fMultiNode = ((1 == ulArityPattern || 2 == ulArityPattern) &&
CPattern::FMultiNode((*pexprPattern)[0]->Pop()));
if (fMultiNode)
{
// match if there are multiple children;
// allow only-children to match multi children against its own pattern in asserts;
if (1 == ulArityPattern)
{
return arity > 0;
}
else
{
// check last child explicitly
CExpression *pexpr = (*this)[arity - 1];
return arity > 1 &&
pexpr->FMatchPattern((*pexprPattern)[ulArityPattern - 1]);
}
}
// all other matches must have same arity
if (arity != ulArityPattern)
{
return false;
}
BOOL fMatch = true;
for (ULONG ul = 0; ul < arity && fMatch; ul++)
{
CExpression *pexpr = (*this)[ul];
fMatch = fMatch && pexpr->FMatchPattern((*pexprPattern)[ul]);
}
return fMatch;
}
//---------------------------------------------------------------------------
// @function:
// CExpression::FMatchDebug
//
// @doc:
// Recursive comparison of this expression against another given one
//
//---------------------------------------------------------------------------
BOOL
CExpression::FMatchDebug(CExpression *pexpr) const
{
GPOS_CHECK_STACK_SIZE;
// check local operator
if (!Pop()->Matches(pexpr->Pop()))
{
GPOS_ASSERT(Pop()->HashValue() == pexpr->Pop()->HashValue());
return false;
}
// operator match must be commutative
GPOS_ASSERT(pexpr->Pop()->Matches(Pop()));
// scalar operators must agree on return type
GPOS_ASSERT_IMP(Pop()->FScalar() &&
CScalar::EopScalarProjectList != Pop()->Eopid() &&
CScalar::EopScalarProjectElement != Pop()->Eopid(),
CScalar::PopConvert(pexpr->Pop())
->MdidType()
->Equals(CScalar::PopConvert(Pop())->MdidType()));
ULONG arity = Arity();
if (arity != pexpr->Arity())
{
return false;
}
// inner nodes have same sensitivity
GPOS_ASSERT_IMP(0 < arity, Pop()->FInputOrderSensitive() ==
pexpr->Pop()->FInputOrderSensitive());
// decend into children
for (ULONG ul = 0; ul < arity; ul++)
{
if (!(*this)[ul]->FMatchDebug((*pexpr)[ul]))
{
return false;
}
}
return true;
}
//---------------------------------------------------------------------------
// @function:
// CExpression::PrintProperties
//
// @doc:
// Print expression properties;
//
//---------------------------------------------------------------------------
void
CExpression::PrintProperties(IOstream &os, CPrintPrefix &pfx) const
{
GPOS_CHECK_ABORT;
if (nullptr != m_pdprel && m_pdprel->IsComplete())
{
os << pfx << "DrvdRelProps:{" << *m_pdprel << "}" << std::endl;
}
if (nullptr != m_pdpscalar && m_pdpscalar->IsComplete())
{
os << pfx << "DrvdScalarProps:{" << *m_pdpscalar << "}" << std::endl;
}
if (nullptr != m_pdpplan)
{
os << pfx << "DrvdPlanProps:{" << *m_pdpplan << "}" << std::endl;
}
if (nullptr != m_prpp)
{
os << pfx << "ReqdPlanProps:{" << *m_prpp << "}" << std::endl;
}
}
// ----------------------------------------------------------------
// Print driving functions for use in interactive debugging;
// always prints to stderr.
// ----------------------------------------------------------------
// Prints expression along with it's properties
void
CExpression::DbgPrintWithProperties() const
{
CAutoTraceFlag atf(EopttracePrintExpressionProperties, true);
CAutoTrace at(m_mp);
(void) this->OsPrint(at.Os());
}
#endif // GPOS_DEBUG
FORCE_GENERATE_DBGSTR(gpopt::CExpression);
//---------------------------------------------------------------------------
// @function:
// CExpression::OsPrint
//
// @doc:
// Print driving function
//
//---------------------------------------------------------------------------
IOstream &
CExpression::OsPrint(IOstream &os) const
{
CPrintPrefix ppref(nullptr, "");
return OsPrintExpression(os, &ppref);
}
//---------------------------------------------------------------------------
// @function:
// CExpression::OsPrintExpression
//
// @doc:
// Print driving function, customized for CExpression
//
//---------------------------------------------------------------------------
IOstream &
CExpression::OsPrintExpression(IOstream &os, const CPrintPrefix *ppfx,
BOOL fLast) const
{
// recursive, check stack depth
GPOS_CHECK_STACK_SIZE;
GPOS_CHECK_ABORT;
if (nullptr != ppfx)
{
(void) ppfx->OsPrint(os);
}
CHAR *szChildPrefix = nullptr;
if (fLast)
{
os << szExprPlusOpPrefix;
szChildPrefix = szExprLevelWS;
}
else
{
os << szExprBarOpPrefix;
szChildPrefix = szExprBarLevelWS;
}
(void) m_pop->OsPrint(os);
if (!m_pop->FScalar() && nullptr != m_pstats)
{
os << " rows:" << LINT(m_pstats->Rows().Get())
<< " width:" << LINT(m_pstats->Width().Get())
<< " rebinds:" << LINT(m_pstats->NumRebinds().Get());
}
if (m_pop->FPhysical())
{
os << " cost:" << m_cost;
}
if (gpos::ulong_max != m_ulOriginGrpId)
{
os << " origin: [Grp:" << m_ulOriginGrpId
<< ", GrpExpr:" << m_ulOriginGrpExprId << "]";
}
os << std::endl;
CPrintPrefix pfx(ppfx, szChildPrefix);
#ifdef GPOS_DEBUG
if (GPOS_FTRACE(EopttracePrintExpressionProperties))
{
PrintProperties(os, pfx);
}
#endif // GPOS_DEBUG
const ULONG ulChildren = this->Arity();
for (ULONG i = 0; i < ulChildren; i++)
{
(*this)[i]->OsPrintExpression(os, &pfx, i == (ulChildren - 1));
}
return os;
}
//---------------------------------------------------------------------------
// @function:
// CExpression::HashValue
//
// @doc:
// Hash function
//
//---------------------------------------------------------------------------
ULONG
CExpression::HashValue(const CExpression *pexpr)
{
GPOS_CHECK_STACK_SIZE;
ULONG ulHash = pexpr->Pop()->HashValue();
const ULONG arity = pexpr->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
ulHash = CombineHashes(ulHash, HashValue((*pexpr)[ul]));
}
return ulHash;
}
// Less strict hash function to support expressions that are not order
// sensitive. This hash function specifically used in CUtils::PdrgpexprDedup
// for deduping the expressions in a given list.
ULONG
CExpression::UlHashDedup(const CExpression *pexpr)
{
GPOS_CHECK_STACK_SIZE;
ULONG ulHash = pexpr->Pop()->HashValue();
const ULONG arity = pexpr->Arity();
for (ULONG ul = 0; ul < arity; ul++)
{
if (pexpr->Pop()->FInputOrderSensitive())
{
// If the two expressions are order sensitive, then even though
// thir inputs are the same, if the order of the inputs are not the
// same, hash function puts two different expressions into separate
// buckets.
// e.g logically a < b is not equal to b < a
ulHash = CombineHashes(ulHash, HashValue((*pexpr)[ul]));
}
else
{
// If the two expressions are not order sensitive and their
// inputs are the same, the expressions are considered as equal
// and fall into the same bucket in the hash map.
// e.g logically a = b is equal to b = a
ulHash ^= HashValue((*pexpr)[ul]);
}
}
return ulHash;
}
//---------------------------------------------------------------------------
// @function:
// CExpression::PexprRehydrate
//
// @doc:
// Rehydrate expression from a given cost context and child expressions
//
//---------------------------------------------------------------------------
CExpression *
CExpression::PexprRehydrate(CMemoryPool *mp, CCostContext *pcc,
CExpressionArray *pdrgpexpr,
CDrvdPropCtxtPlan *pdpctxtplan)
{
GPOS_ASSERT(nullptr != pcc);
GPOS_ASSERT(nullptr != pdpctxtplan);
CGroupExpression *pgexpr = pcc->Pgexpr();
COperator *pop = pgexpr->Pop();
pop->AddRef();
CCost cost = pcc->Cost();
if (pop->FPhysical())
{
const ULONG arity = pgexpr->Arity();
CCostArray *pdrgpcost = GPOS_NEW(mp) CCostArray(mp);
for (ULONG ul = 0; ul < arity; ul++)
{
CExpression *pexprChild = (*pdrgpexpr)[ul];
CCost costChild = pexprChild->Cost();
pdrgpcost->Append(GPOS_NEW(mp) CCost(costChild));
}
cost = pcc->CostCompute(mp, pdrgpcost);
pdrgpcost->Release();
}
pcc->Poc()->Prpp()->AddRef();
CExpression *pexpr =
GPOS_NEW(mp) CExpression(mp, pop, pgexpr, pdrgpexpr, pcc->Poc()->Prpp(),
pcc->Pstats(), CCost(cost));
if (pop->FPhysical() && !pexpr->FValidPlan(pcc->Poc()->Prpp(), pdpctxtplan))
{
#ifdef GPOS_DEBUG
{
CAutoTrace at(mp);
IOstream &os = at.Os();
os << std::endl << "INVALID EXPRESSION: " << std::endl << *pexpr;
os << std::endl
<< "REQUIRED PROPERTIES: " << std::endl
<< *(pcc->Poc()->Prpp());
os << std::endl
<< "DERIVED PROPERTIES: " << std::endl
<< *CDrvdPropPlan::Pdpplan(pexpr->PdpDerive()) << std::endl;
}
#endif // GPOS_DEBUG
GPOS_RAISE(gpopt::ExmaGPOPT, gpopt::ExmiUnsatisfiedRequiredProperties);
}
return pexpr;
}
//---------------------------------------------------------------------------
// @function:
// CExpression::FValidPlan
//
// @doc:
// Check if the expression satisfies given required properties.
//
//---------------------------------------------------------------------------
BOOL
CExpression::FValidPlan(const CReqdPropPlan *prpp,
CDrvdPropCtxtPlan *pdpctxtplan)
{
GPOS_ASSERT(Pop()->FPhysical());
GPOS_ASSERT(nullptr != prpp);
GPOS_ASSERT(nullptr != pdpctxtplan);
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
exprhdl.DeriveProps(pdpctxtplan);
CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan(exprhdl.Pdp());
if (COperator::EopPhysicalCTEProducer == m_pop->Eopid())
{
ULONG ulCTEId = CPhysicalCTEProducer::PopConvert(m_pop)->UlCTEId();
pdpctxtplan->CopyCTEProducerProps(pdpplan, ulCTEId);
}
CDrvdPropRelational *pdprel = GetDrvdPropRelational();
// GPDB_12_MERGE_FIXME: Also check FValidPartEnforcers()
return prpp->FCompatible(exprhdl, CPhysical::PopConvert(m_pop), pdprel,
pdpplan) &&
FValidChildrenDistribution(pdpctxtplan);
}
//---------------------------------------------------------------------------
// @function:
// CExpression::FValidChildrenDistribution
//
// @doc:
// Check if the distributions of all children are compatible.
//
//---------------------------------------------------------------------------
BOOL
CExpression::FValidChildrenDistribution(CDrvdPropCtxtPlan *pdpctxtplan)
{
GPOS_ASSERT(Pop()->FPhysical());
CPhysical *pop = CPhysical::PopConvert(Pop());
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
exprhdl.DeriveProps(pdpctxtplan);
if (!pop->FCompatibleChildrenDistributions(exprhdl))
{
return false;
}
// we cannot enforce a motion gather if the input is already on the master
if (COperator::EopPhysicalMotionGather == Pop()->Eopid())
{
CExpression *pexprChild = (*this)[0];
CDrvdPropPlan *pdpplanChild =
CDrvdPropPlan::Pdpplan(pexprChild->PdpDerive(pdpctxtplan));
if (CDistributionSpec::EdtSingleton == pdpplanChild->Pds()->Edt() ||
CDistributionSpec::EdtStrictSingleton == pdpplanChild->Pds()->Edt())
{
return false;
}
}
return true;
}
#if 0
//---------------------------------------------------------------------------
// @function:
// CExpression::FValidPartEnforcers
//
// @doc:
// Check if the expression is valid with respect to the partition enforcers.
//
//---------------------------------------------------------------------------
BOOL
CExpression::FValidPartEnforcers(CDrvdPropCtxtPlan *pdpctxtplan)
{
GPOS_ASSERT(Pop()->FPhysical());
CPartInfo *ppartinfo = DerivePartitionInfo();
GPOS_ASSERT(NULL != ppartinfo);
if (0 == ppartinfo->UlConsumers())
{
// no part consumers found
return true;
}
// retrieve plan properties
CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan(PdpDerive(pdpctxtplan));
if (CUtils::FPhysicalMotion(Pop()) &&
pdpplan->Ppim()->FContainsUnresolved())
{
// prohibit Motion on top of unresolved partition consumers
return false;
}
return true;
}
#endif
CColRefSet *
CExpression::DeriveOuterReferences()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveOuterReferences(exprhdl);
}
CColRefSet *
CExpression::DeriveOutputColumns()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveOutputColumns(exprhdl);
}
CColRefSet *
CExpression::DeriveNotNullColumns()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveNotNullColumns(exprhdl);
}
CColRefSet *
CExpression::DeriveCorrelatedApplyColumns()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveCorrelatedApplyColumns(exprhdl);
}
CMaxCard
CExpression::DeriveMaxCard()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveMaxCard(exprhdl);
}
CKeyCollection *
CExpression::DeriveKeyCollection()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveKeyCollection(exprhdl);
}
CPropConstraint *
CExpression::DerivePropertyConstraint()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DerivePropertyConstraint(exprhdl);
}
ULONG
CExpression::DeriveJoinDepth()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveJoinDepth(exprhdl);
}
CFunctionProp *
CExpression::DeriveFunctionProperties()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveFunctionProperties(exprhdl);
}
CFunctionalDependencyArray *
CExpression::DeriveFunctionalDependencies()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveFunctionalDependencies(exprhdl);
}
CPartInfo *
CExpression::DerivePartitionInfo()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DerivePartitionInfo(exprhdl);
}
CTableDescriptor *
CExpression::DeriveTableDescriptor()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdprel->DeriveTableDescriptor(exprhdl);
}
// Scalar property accessors - derived as needed
CColRefSet *
CExpression::DeriveDefinedColumns()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveDefinedColumns(exprhdl);
}
CColRefSet *
CExpression::DeriveUsedColumns()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveUsedColumns(exprhdl);
}
CColRefSet *
CExpression::DeriveSetReturningFunctionColumns()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveSetReturningFunctionColumns(exprhdl);
}
BOOL
CExpression::DeriveHasSubquery()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveHasSubquery(exprhdl);
}
CPartInfo *
CExpression::DeriveScalarPartitionInfo()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DerivePartitionInfo(exprhdl);
}
CFunctionProp *
CExpression::DeriveScalarFunctionProperties()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveFunctionProperties(exprhdl);
}
BOOL
CExpression::DeriveHasNonScalarFunction()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveHasNonScalarFunction(exprhdl);
}
ULONG
CExpression::DeriveTotalDistinctAggs()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveTotalDistinctAggs(exprhdl);
}
BOOL
CExpression::DeriveHasMultipleDistinctAggs()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveHasMultipleDistinctAggs(exprhdl);
}
BOOL
CExpression::DeriveHasScalarArrayCmp()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveHasScalarArrayCmp(exprhdl);
}
BOOL
CExpression::DeriveHasScalarFuncProject()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveHasScalarFuncProject(exprhdl);
}
ULONG
CExpression::DeriveTotalOrderedAggs()
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(this);
return m_pdpscalar->DeriveTotalOrderedAggs(exprhdl);
}
// EOF
相关信息
相关文章
greenplumn CExpressionFactorizer 源码
greenplumn CExpressionHandle 源码
greenplumn CExpressionPreprocessor 源码
greenplumn CExpressionUtils 源码
greenplumn CHashedDistributions 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦