greenplumn CJoinOrder 源码
greenplumn CJoinOrder 代码
文件路径:/src/backend/gporca/libgpopt/src/xforms/CJoinOrder.cpp
//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (C) 2011 EMC Corp.
//
// @filename:
// CJoinOrder.cpp
//
// @doc:
// Implementation of join order logic
//---------------------------------------------------------------------------
#include "gpopt/xforms/CJoinOrder.h"
#include "gpos/base.h"
#include "gpos/common/CBitSet.h"
#include "gpos/common/clibwrapper.h"
#include "gpos/io/COstreamString.h"
#include "gpos/string/CWStringDynamic.h"
#include "gpopt/base/CColRefSetIter.h"
#include "gpopt/base/CDrvdPropScalar.h"
#include "gpopt/operators/CLogicalInnerJoin.h"
#include "gpopt/operators/CLogicalJoin.h"
#include "gpopt/operators/CLogicalLeftOuterJoin.h"
#include "gpopt/operators/CPredicateUtils.h"
using namespace gpopt;
FORCE_GENERATE_DBGSTR(CJoinOrder);
FORCE_GENERATE_DBGSTR(CJoinOrder::SEdge);
FORCE_GENERATE_DBGSTR(CJoinOrder::SComponent);
// ctor
CJoinOrder::SComponent::SComponent(CMemoryPool *mp, CExpression *pexpr,
INT parent_loj_id, EPosition position)
: m_pbs(nullptr),
m_edge_set(nullptr),
m_pexpr(pexpr),
m_fUsed(false),
m_parent_loj_id(parent_loj_id),
m_position(position)
{
m_pbs = GPOS_NEW(mp) CBitSet(mp);
m_edge_set = GPOS_NEW(mp) CBitSet(mp);
GPOS_ASSERT_IMP(EpSentinel != m_position,
NON_LOJ_DEFAULT_ID < m_parent_loj_id);
}
// ctor
CJoinOrder::SComponent::SComponent(CExpression *pexpr, CBitSet *pbs,
CBitSet *edge_set, INT parent_loj_id,
EPosition position)
: m_pbs(pbs),
m_edge_set(edge_set),
m_pexpr(pexpr),
m_fUsed(false),
m_parent_loj_id(parent_loj_id),
m_position(position)
{
GPOS_ASSERT(nullptr != pbs);
GPOS_ASSERT_IMP(EpSentinel != m_position,
NON_LOJ_DEFAULT_ID < m_parent_loj_id);
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::SComponent::~SComponent
//
// @doc:
// Ctor
//
//---------------------------------------------------------------------------
CJoinOrder::SComponent::~SComponent()
{
m_pbs->Release();
m_edge_set->Release();
CRefCount::SafeRelease(m_pexpr);
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::SComponent::OsPrint
//
// @doc:
// Debug print
//
//---------------------------------------------------------------------------
IOstream &
CJoinOrder::SComponent::OsPrint(IOstream &os) const
{
CBitSet *pbs = m_pbs;
os << "Component: ";
os << (*pbs) << std::endl;
os << *m_pexpr << std::endl;
if (m_parent_loj_id > NON_LOJ_DEFAULT_ID)
{
GPOS_ASSERT(m_position != EpSentinel);
os << "Parent LOJ id: ";
os << m_parent_loj_id << std::endl;
os << "Child Position: ";
os << m_position << std::endl;
}
return os;
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::SEdge::SEdge
//
// @doc:
// Ctor
//
//---------------------------------------------------------------------------
CJoinOrder::SEdge::SEdge(CMemoryPool *mp, CExpression *pexpr, ULONG loj_num)
: m_pbs(nullptr), m_pexpr(pexpr), m_loj_num(loj_num), m_fUsed(false)
{
m_pbs = GPOS_NEW(mp) CBitSet(mp);
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::SEdge::~SEdge
//
// @doc:
// Ctor
//
//---------------------------------------------------------------------------
CJoinOrder::SEdge::~SEdge()
{
m_pbs->Release();
m_pexpr->Release();
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::SEdge::OsPrint
//
// @doc:
// Debug print
//
//---------------------------------------------------------------------------
IOstream &
CJoinOrder::SEdge::OsPrint(IOstream &os) const
{
return os << (m_loj_num > 0 ? "Edge (loj): " : "Edge : ") << (*m_pbs)
<< std::endl
<< (*m_pexpr) << std::endl;
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::CJoinOrder
//
// @doc:
// Ctor
//
//---------------------------------------------------------------------------
CJoinOrder::CJoinOrder(CMemoryPool *mp, CExpressionArray *all_components,
CExpressionArray *inner_join_conjuncts,
BOOL include_loj_childs)
: m_mp(mp),
m_rgpedge(nullptr),
m_ulEdges(0),
m_rgpcomp(nullptr),
m_ulComps(0),
m_include_loj_childs(include_loj_childs)
{
using Pcomp = SComponent *;
using Pedge = SEdge *;
const ULONG num_of_nary_children = all_components->Size();
INT num_of_lojs = 0;
// Since we are using a static array, we need to know size of the array before hand
// e.g.
// +--CLogicalNAryJoin
// |--CLogicalGet "t1"
// |--CLogicalLeftOuterJoin
// | |--CLogicalGet "t5"
// | |--CLogicalGet "t4"
// | +--CScalarCmp (=)
// +--CScalarCmp (=)
//
// In above case the pdrgpexpr comes with two elements in it:
// - CLogicalGet "t1"
// - CLogicalLeftOuterJoin
// We need to create components out of "t1", "t4", "t5" and store them
// in m_rgcomp.
if (m_include_loj_childs)
{
for (ULONG ul = 0; ul < num_of_nary_children; ul++)
{
CExpression *pexpr = (*all_components)[ul];
if (COperator::EopLogicalLeftOuterJoin == pexpr->Pop()->Eopid())
{
num_of_lojs++;
}
}
}
// total num of components = all_components + no of LOJs
// since each LOJ is replaced with two components: its left & right children
m_ulComps = num_of_nary_children + num_of_lojs;
m_rgpcomp = GPOS_NEW_ARRAY(mp, Pcomp, m_ulComps);
m_ulEdges = inner_join_conjuncts->Size() + num_of_lojs;
m_rgpedge = GPOS_NEW_ARRAY(mp, Pedge, m_ulEdges);
INT loj_id = 0;
INT comp_num = 0;
// add the inner join edges first
for (ULONG ul = 0; ul < inner_join_conjuncts->Size(); ul++)
{
CExpression *pexprEdge = (*inner_join_conjuncts)[ul];
pexprEdge->AddRef();
m_rgpedge[ul] = GPOS_NEW(mp) SEdge(mp, pexprEdge, 0 /* not an LOJ */);
}
// process LOJs & add components & LOJ edges
for (ULONG ul = 0; ul < num_of_nary_children; ul++)
{
CExpression *expr = (*all_components)[ul];
if (m_include_loj_childs &&
COperator::EopLogicalLeftOuterJoin == expr->Pop()->Eopid())
{
// counter for number of loj available in tree
++loj_id;
// add left child
AddComponent(mp, (*expr)[0], loj_id, EpLeft, comp_num);
// add right child.
AddComponent(mp, (*expr)[1], loj_id, EpRight, comp_num + 1);
// create the edge between the LOJ components right here - so as to
// capture the relevant components from the LOJ predicate in the ON
// clause; this is needed, later when assigning this edge to appropriate
// LOJ, especially in the case that the predicate doesn't include colrefs
// from both left & right components
CExpression *scalar_expr = (*expr)[2];
scalar_expr->AddRef();
ULONG edge_idx = inner_join_conjuncts->Size() + loj_id - 1;
m_rgpedge[edge_idx] =
GPOS_NEW(mp) SEdge(mp, scalar_expr, 1 /* is an LOJ */);
m_rgpcomp[comp_num]->m_edge_set->ExchangeSet(edge_idx);
m_rgpedge[edge_idx]->m_pbs->ExchangeSet(comp_num);
m_rgpcomp[comp_num + 1]->m_edge_set->ExchangeSet(edge_idx);
m_rgpedge[edge_idx]->m_pbs->ExchangeSet(comp_num + 1);
comp_num += 2;
}
else
{
AddComponent(mp, expr, NON_LOJ_DEFAULT_ID, EpSentinel, comp_num);
comp_num += 1;
}
}
ComputeEdgeCover();
all_components->Release();
inner_join_conjuncts->Release();
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::CJoinOrder
//
// @doc:
// Ctor
//
//---------------------------------------------------------------------------
CJoinOrder::CJoinOrder(CMemoryPool *mp, CExpressionArray *all_components,
CExpressionArray *innerJoinPredConjuncts,
CExpressionArray *onPreds,
ULongPtrArray *childPredIndexes)
: m_mp(mp),
m_rgpedge(nullptr),
m_ulEdges(0),
m_rgpcomp(nullptr),
m_ulComps(0),
m_include_loj_childs(false) // not used by CXformExpandNAryJoinDPv2
{
using Pcomp = SComponent *;
using Pedge = SEdge *;
const ULONG num_of_nary_children = all_components->Size();
m_ulComps = all_components->Size();
m_rgpcomp = GPOS_NEW_ARRAY(mp, Pcomp, m_ulComps);
m_ulEdges = innerJoinPredConjuncts->Size() + onPreds->Size();
m_rgpedge = GPOS_NEW_ARRAY(mp, Pedge, m_ulEdges);
ULONG innerJoinEdges = innerJoinPredConjuncts->Size();
// add the inner join edges first
for (ULONG ul = 0; ul < innerJoinEdges; ul++)
{
CExpression *pexprEdge = (*innerJoinPredConjuncts)[ul];
pexprEdge->AddRef();
m_rgpedge[ul] = GPOS_NEW(mp) SEdge(mp, pexprEdge, 0 /* not an LOJ */);
}
// add the left outer join edges
for (ULONG ul2 = 0; ul2 < onPreds->Size(); ul2++)
{
CExpression *pexprEdge = (*onPreds)[ul2];
// a 1-based id of the LOJ in this NAry join
ULONG lojId = ul2 + 1;
// the logical child index (right LOJ child) that belongs to our current predicate pexprEdge
ULONG logicalChildIndex = 0;
// search for number lojId in the childPredIndexes array, the
// entry that contains this number will be the logical child that
// is associated with our ON predicate pexprEdge
for (ULONG ci = 0; ci < childPredIndexes->Size(); ci++)
{
if (*(*childPredIndexes)[ci] == lojId)
{
logicalChildIndex = ci;
break;
}
}
GPOS_ASSERT(0 < logicalChildIndex);
pexprEdge->AddRef();
m_rgpedge[ul2 + innerJoinEdges] =
GPOS_NEW(mp) SEdge(mp, pexprEdge, lojId);
// this edge (ON predicate) is always associated with the right
// child of the LOJ, whether it refers to it in the ON pred or not
// Example: select * from t1 left outer join t2 on t1.a=5
// We still want to associate this ON predicate with t2
m_rgpedge[ul2 + innerJoinEdges]->m_pbs->ExchangeSet(logicalChildIndex);
}
// create the components (both inner and LOJs)
for (ULONG ul = 0; ul < num_of_nary_children; ul++)
{
CExpression *expr = (*all_components)[ul];
INT lojId =
(nullptr != childPredIndexes) ? *((*childPredIndexes)[ul]) : 0;
AddComponent(mp, expr, lojId, EpSentinel /*position not used in DPv2*/,
ul);
}
ComputeEdgeCover();
all_components->Release();
innerJoinPredConjuncts->Release();
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::~CJoinOrder
//
// @doc:
// Dtor
//
//---------------------------------------------------------------------------
CJoinOrder::~CJoinOrder()
{
for (ULONG ul = 0; ul < m_ulComps; ul++)
{
m_rgpcomp[ul]->Release();
}
GPOS_DELETE_ARRAY(m_rgpcomp);
for (ULONG ul = 0; ul < m_ulEdges; ul++)
{
m_rgpedge[ul]->Release();
}
GPOS_DELETE_ARRAY(m_rgpedge);
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::ComputeEdgeCover
//
// @doc:
// Compute cover for each edge and also the index of edges associated
// with each component
//
//---------------------------------------------------------------------------
void
CJoinOrder::ComputeEdgeCover()
{
for (ULONG ulEdge = 0; ulEdge < m_ulEdges; ulEdge++)
{
CExpression *pexpr = m_rgpedge[ulEdge]->m_pexpr;
CColRefSet *pcrsUsed = pexpr->DeriveUsedColumns();
for (ULONG ulComp = 0; ulComp < m_ulComps; ulComp++)
{
CExpression *pexprComp = m_rgpcomp[ulComp]->m_pexpr;
CColRefSet *pcrsOutput = pexprComp->DeriveOutputColumns();
if (!pcrsUsed->IsDisjoint(pcrsOutput))
{
(void) m_rgpcomp[ulComp]->m_edge_set->ExchangeSet(ulEdge);
(void) m_rgpedge[ulEdge]->m_pbs->ExchangeSet(ulComp);
}
}
}
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::PcompCombine
//
// @doc:
// Combine the two given components using applicable edges
//
//
//---------------------------------------------------------------------------
CJoinOrder::SComponent *
CJoinOrder::PcompCombine(SComponent *comp1, SComponent *comp2)
{
GPOS_ASSERT(IsValidJoinCombination(comp1, comp2));
CBitSet *pbs = GPOS_NEW(m_mp) CBitSet(m_mp);
CBitSet *edge_set = GPOS_NEW(m_mp) CBitSet(m_mp);
pbs->Union(comp1->m_pbs);
pbs->Union(comp2->m_pbs);
// edges connecting with the current component
edge_set->Union(comp1->m_edge_set);
edge_set->Union(comp2->m_edge_set);
// collect the list of conjuncts involved involved in the join from the list
// of edges, making sure to separate those that are derived from LOJs
CExpressionArray *loj_conjuncts = GPOS_NEW(m_mp) CExpressionArray(m_mp);
CExpressionArray *other_conjuncts = GPOS_NEW(m_mp) CExpressionArray(m_mp);
for (ULONG ul = 0; ul < m_ulEdges; ul++)
{
SEdge *pedge = m_rgpedge[ul];
if (pedge->m_fUsed)
{
// edge is already used in result component
continue;
}
if (pbs->ContainsAll(pedge->m_pbs))
{
// edge is subsumed by the cover of the combined component
CExpression *pexpr = pedge->m_pexpr;
pexpr->AddRef();
if (0 < pedge->m_loj_num)
{
loj_conjuncts->Append(pexpr);
}
else
{
other_conjuncts->Append(pexpr);
}
}
}
CExpression *pexprChild1 = comp1->m_pexpr;
CExpression *pexprChild2 = comp2->m_pexpr;
CExpression *pexpr = nullptr;
INT parent_loj_id = NON_LOJ_DEFAULT_ID;
EPosition position = EpSentinel;
if (nullptr == pexprChild1)
{
// first call to this function, we create a Select node
parent_loj_id = comp2->ParentLojId();
position = comp2->Position();
GPOS_ASSERT(loj_conjuncts->Size() == 0);
// combine all the conjuncts - since we are not creating a LOJ
CUtils::AddRefAppend(loj_conjuncts, other_conjuncts);
other_conjuncts->Release();
CExpression *predicate =
CPredicateUtils::PexprConjunction(m_mp, loj_conjuncts);
pexpr = CUtils::PexprCollapseSelect(m_mp, pexprChild2, predicate);
predicate->Release();
}
else
{
// not first call, we create an Inner Join or LOJ
GPOS_ASSERT(nullptr != pexprChild2);
pexprChild2->AddRef();
pexprChild1->AddRef();
if (IsChildOfSameLOJ(comp1, comp2))
{
// if both the components are child of the same LOJ, ensure that the left child
// stays left child and vice versa while creating the LOJ.
// for this component we need not track the parent_loj_id, as we are only
// concerned for joining LOJ childs with other non-LOJ components
CExpression *pexprLeft = comp1->Position() == CJoinOrder::EpLeft
? pexprChild1
: pexprChild2;
CExpression *pexprRight = comp1->Position() == CJoinOrder::EpLeft
? pexprChild2
: pexprChild1;
// construct a LOJ only using predicates from an original LOJ; mixing LOJ
// predicates with INNER join predicates could lead to wrong results
// since they change the semantics of the outer join.
CExpression *loj_predicate =
CPredicateUtils::PexprConjunction(m_mp, loj_conjuncts);
pexpr = CUtils::PexprLogicalJoin<CLogicalLeftOuterJoin>(
m_mp, pexprLeft, pexprRight, loj_predicate,
this->EOriginXForm());
// remaining predicates are place on top as a filter
CExpression *filter_predicate =
CPredicateUtils::PexprConjunction(m_mp, other_conjuncts);
pexpr = CUtils::PexprLogicalSelect(m_mp, pexpr, filter_predicate);
}
else
{
if (comp1->ParentLojId() > NON_LOJ_DEFAULT_ID ||
comp2->ParentLojId() > NON_LOJ_DEFAULT_ID)
{
// one of the component is the child of an LOJ, and can be joined with another relation
// to create an Inner Join. for other non LOJ childs of NAry join, the parent loj id is
// defaulted to 0, so assert the condition.
GPOS_ASSERT_IMP(comp1->ParentLojId() > NON_LOJ_DEFAULT_ID,
comp2->ParentLojId() == 0);
GPOS_ASSERT_IMP(comp2->ParentLojId() > NON_LOJ_DEFAULT_ID,
comp1->ParentLojId() == 0);
parent_loj_id = NON_LOJ_DEFAULT_ID < comp1->ParentLojId()
? comp1->ParentLojId()
: comp2->ParentLojId();
position = NON_LOJ_DEFAULT_ID < comp1->ParentLojId()
? comp1->Position()
: comp2->Position();
// since we only support joining the left child of LOJ to other relations in NAry Join,
// we must not get right child of LOJ here, as that join combination must have been isolated
// by IsValidJoinCombination earlier.
GPOS_ASSERT(CJoinOrder::EpLeft == position);
// we track if this join component contains the left child of LOJ,
// so the parent loj id must be some positive non-zero number (i.e > 0)
// for this join component
GPOS_ASSERT(NON_LOJ_DEFAULT_ID < parent_loj_id);
}
GPOS_ASSERT(loj_conjuncts->Size() == 0);
// combine all the conjuncts - since we are not creating a LOJ
CUtils::AddRefAppend(loj_conjuncts, other_conjuncts);
other_conjuncts->Release();
CExpression *predicate =
CPredicateUtils::PexprConjunction(m_mp, loj_conjuncts);
pexpr = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(
m_mp, pexprChild1, pexprChild2, predicate,
this->EOriginXForm());
}
}
// if the component has parent_loj_id > 0, it must be the left child or has the left child
// of loj id indicated by parent_loj_id
GPOS_ASSERT_IMP(NON_LOJ_DEFAULT_ID < parent_loj_id, EpLeft == position);
SComponent *join_comp = GPOS_NEW(m_mp)
SComponent(pexpr, pbs, edge_set, parent_loj_id, position);
return join_comp;
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::DeriveStats
//
// @doc:
// Helper function to derive stats on a given component
//
//---------------------------------------------------------------------------
void
CJoinOrder::DeriveStats(CExpression *pexpr)
{
GPOS_ASSERT(nullptr != pexpr);
if (nullptr == pexpr->Pstats())
{
CExpressionHandle exprhdl(m_mp);
exprhdl.Attach(pexpr);
exprhdl.DeriveStats(m_mp, m_mp, nullptr /*prprel*/,
nullptr /*pdrgpstatCtxt*/);
}
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::OsPrint
//
// @doc:
// Helper function to print a join order class
//
//---------------------------------------------------------------------------
// FIXME: the following function is completely unused even for the purpose of
// debugging, because all subclasses implement their own OsPrint
IOstream &
CJoinOrder::OsPrint(IOstream &os) const
{
os << "Join Order: " << std::endl << "Edges: " << m_ulEdges << std::endl;
for (ULONG ul = 0; ul < m_ulEdges; ul++)
{
m_rgpedge[ul]->OsPrint(os);
os << std::endl;
}
os << "Components: " << m_ulComps << std::endl;
for (ULONG ul = 0; ul < m_ulComps; ul++)
{
os << (void *) m_rgpcomp[ul] << " - " << std::endl;
m_rgpcomp[ul]->OsPrint(os);
}
return os;
}
BOOL
CJoinOrder::IsValidJoinCombination(SComponent *comp1, SComponent *comp2)
{
INT comp1_parent_loj_id = comp1->ParentLojId();
INT comp2_parent_loj_id = comp2->ParentLojId();
EPosition comp1_position = comp1->Position();
EPosition comp2_position = comp2->Position();
// Consider the below tree, for examples used:
//+--CLogicalNAryJoin
// |--CLogicalGet "t1"
// |--CLogicalGet "t2"
// |--CLogicalLeftOuterJoin => LOJ 1
// | |--CLogicalGet "t3" => {1, EpLeft}
// | |--CLogicalGet "t4" => {1, EpRight}
// | +--<Join Condition>
// |--CLogicalLeftOuterJoin => LOJ 2
// | |--CLogicalGet "t5" => {2, EpLeft}
// | |--CLogicalGet "t6" => {2, EpRight}
// | +--<Join Condition>
// +--<Join Condition>
if ((NON_LOJ_DEFAULT_ID == comp1_parent_loj_id &&
NON_LOJ_DEFAULT_ID == comp2_parent_loj_id))
{
// neither component contains any LOJs childs,
// this is valid
// example: CLogicalGet "t1" join CLogicalGet "t2"
return true;
}
if (NON_LOJ_DEFAULT_ID < comp1_parent_loj_id &&
NON_LOJ_DEFAULT_ID < comp2_parent_loj_id)
{
// both components contain LOJs child,
// check whether they are referring to same LOJ
if (comp1_parent_loj_id == comp2_parent_loj_id)
{
// one of them should be a left child and other one right child
// example: CLogicalGet "t3" join CLogicalGet "t4" is valid
GPOS_ASSERT(comp1_position != EpSentinel &&
comp2_position != EpSentinel);
if ((comp1_position == EpLeft && comp2_position == EpRight) ||
(comp1_position == EpRight && comp2_position == EpLeft))
{
return true;
}
}
// two components with children from different LOJs, this is not valid
// example: CLogicalGet "t3" join CLogicalGet "t5"
return false;
}
// one of the components contains one LOJ child without the sibling,
// this is allowed if it is a left LOJ child
// example 1: CLogicalGet "t1" join CLogicalGet "t3" is valid
// example 2: CLogicalGet "t1" join CLogicalGet "t4 is not valid
return comp1_position != EpRight && comp2_position != EpRight;
}
BOOL
CJoinOrder::IsChildOfSameLOJ(SComponent *comp1, SComponent *comp2)
{
// check if these components are inner and outer children of a same join
BOOL child_of_same_loj = comp1->ParentLojId() == comp2->ParentLojId() &&
comp1->ParentLojId() != NON_LOJ_DEFAULT_ID &&
((comp1->Position() == CJoinOrder::EpLeft &&
comp2->Position() == CJoinOrder::EpRight) ||
(comp1->Position() == CJoinOrder::EpRight &&
comp2->Position() == CJoinOrder::EpLeft));
return child_of_same_loj;
}
//---------------------------------------------------------------------------
// @function:
// CJoinOrder::MarkUsedEdges
//
// @doc:
// Mark edges used by result component
//
//---------------------------------------------------------------------------
void
CJoinOrder::MarkUsedEdges(SComponent *pcomponent)
{
GPOS_ASSERT(nullptr != pcomponent);
CExpression *pexpr = pcomponent->m_pexpr;
COperator::EOperatorId eopid = pexpr->Pop()->Eopid();
if (0 == pexpr->Arity() || (COperator::EopLogicalSelect != eopid &&
COperator::EopLogicalInnerJoin != eopid &&
COperator::EopLogicalLeftOuterJoin != eopid))
{
// result component does not have a scalar child, e.g. a Get node
return;
}
CBitSetIter edges_iter(*(pcomponent->m_edge_set));
while (edges_iter.Advance())
{
SEdge *pedge = m_rgpedge[edges_iter.Bit()];
if (pedge->m_fUsed)
{
continue;
}
if (pcomponent->m_pbs->ContainsAll(pedge->m_pbs))
{
pedge->m_fUsed = true;
}
}
}
void
CJoinOrder::AddComponent(CMemoryPool *mp, CExpression *expr, INT loj_id,
EPosition position, INT comp_num)
{
expr->AddRef();
SComponent *comp = GPOS_NEW(mp) SComponent(mp, expr, loj_id, position);
m_rgpcomp[comp_num] = comp;
// component always covers itself
(void) m_rgpcomp[comp_num]->m_pbs->ExchangeSet(comp_num);
}
// EOF
相关信息
相关文章
greenplumn CJoinOrderGreedy 源码
greenplumn CJoinOrderMinCard 源码
greenplumn CSubqueryHandler 源码
greenplumn CXformCTEAnchor2Sequence 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
7、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦