//--------------------------------------------------------------------------- // @function: // CPhysicalPartitionSelector::PpimDerive // // @doc: // Derive partition index map // //--------------------------------------------------------------------------- CPartIndexMap * CPhysicalPartitionSelector::PpimDerive ( IMemoryPool *mp, CExpressionHandle &exprhdl, CDrvdPropCtxt *pdpctxt ) const { GPOS_ASSERT(NULL != pdpctxt); CDrvdPropPlan *pdpplan = exprhdl.Pdpplan(0 /*child_index*/); CPartIndexMap *ppimInput = pdpplan->Ppim(); GPOS_ASSERT(NULL != ppimInput); ULONG ulExpectedPartitionSelectors = CDrvdPropCtxtPlan::PdpctxtplanConvert(pdpctxt)->UlExpectedPartitionSelectors(); CPartIndexMap *ppim = ppimInput->PpimPartitionSelector(mp, m_scan_id, ulExpectedPartitionSelectors); if (!ppim->Contains(m_scan_id)) { // the consumer of this scan id does not come from the child, i.e. it // is on the other side of a join MDId()->AddRef(); m_pdrgpdrgpcr->AddRef(); m_ppartcnstrmap->AddRef(); m_part_constraint->AddRef(); CPartKeysArray *pdrgppartkeys = GPOS_NEW(mp) CPartKeysArray(mp); pdrgppartkeys->Append(GPOS_NEW(mp) CPartKeys(m_pdrgpdrgpcr)); ppim->Insert(m_scan_id, m_ppartcnstrmap, CPartIndexMap::EpimPropagator, 0 /*ulExpectedPropagators*/, MDId(), pdrgppartkeys, m_part_constraint); } return ppim; }
//--------------------------------------------------------------------------- // @function: // CPhysicalPartitionSelector::EpetDistribution // // @doc: // Return the enforcing type for distribution property based on this operator // //--------------------------------------------------------------------------- CEnfdProp::EPropEnforcingType CPhysicalPartitionSelector::EpetDistribution ( CExpressionHandle &exprhdl, const CEnfdDistribution *ped ) const { CDrvdPropPlan *pdpplan = exprhdl.Pdpplan(0 /* child_index */); if (ped->FCompatible(pdpplan->Pds())) { // required distribution established by the operator return CEnfdProp::EpetUnnecessary; } CPartIndexMap *ppimDrvd = pdpplan->Ppim(); if (!ppimDrvd->Contains(m_scan_id)) { // part consumer is defined above: prohibit adding a motion on top of the // part resolver as this will create two slices return CEnfdProp::EpetProhibited; } GPOS_ASSERT(CPartIndexMap::EpimConsumer == ppimDrvd->Epim(m_scan_id)); // part consumer found below: enforce distribution on top of part resolver return CEnfdProp::EpetRequired; }
//--------------------------------------------------------------------------- // @function: // CDrvdPropCtxtPlan::PdpctxtCopy // // @doc: // Copy function // //--------------------------------------------------------------------------- CDrvdPropCtxt * CDrvdPropCtxtPlan::PdpctxtCopy ( IMemoryPool *pmp ) const { CDrvdPropCtxtPlan *pdpctxtplan = GPOS_NEW(pmp) CDrvdPropCtxtPlan(pmp); pdpctxtplan->m_ulExpectedPartitionSelectors = m_ulExpectedPartitionSelectors; HMUlPdpIter hmulpdpiter(m_phmulpdpCTEs); while (hmulpdpiter.FAdvance()) { ULONG ulId = *(hmulpdpiter.Pk()); CDrvdPropPlan *pdpplan = const_cast<CDrvdPropPlan *>(hmulpdpiter.Pt()); pdpplan->AddRef(); #ifdef GPOS_DEBUG BOOL fInserted = #endif // GPOS_DEBUG pdpctxtplan->m_phmulpdpCTEs->FInsert(GPOS_NEW(m_pmp) ULONG(ulId), pdpplan); GPOS_ASSERT(fInserted); } return pdpctxtplan; }
//--------------------------------------------------------------------------- // @function: // CCTEReq::PcterUnresolved // // @doc: // Unresolved CTE requirements given a derived CTE map // //--------------------------------------------------------------------------- CCTEReq * CCTEReq::PcterUnresolved ( IMemoryPool *pmp, CCTEMap *pcm ) { GPOS_ASSERT(NULL != pcm); CCTEReq *pcterUnresolved = GPOS_NEW(pmp) CCTEReq(pmp); HMCteReqIter hmcri(m_phmcter); while (hmcri.FAdvance()) { // if a cte is marked as required and it is not found in the given map // then keep it as required, else make it optional const CCTEReqEntry *pcre = hmcri.Pt(); ULONG ulId = pcre->UlId(); BOOL fRequired = pcre->FRequired() && CCTEMap::EctSentinel == pcm->Ect(ulId); CDrvdPropPlan *pdpplan = pcre->PdpplanProducer(); if (NULL != pdpplan) { pdpplan->AddRef(); } pcterUnresolved->Insert(ulId, pcre->Ect(), fRequired, pdpplan); } return pcterUnresolved; }
//--------------------------------------------------------------------------- // @function: // CDrvdPropCtxtPlan::AddProps // // @doc: // Add props to context // //--------------------------------------------------------------------------- void CDrvdPropCtxtPlan::AddProps ( CDrvdProp *pdp ) { if (CDrvdProp::EptPlan != pdp->Ept()) { // passed property is not a plan property container return; } CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan(pdp); ULONG ulProducerId = ULONG_MAX; CDrvdPropPlan *pdpplanProducer = pdpplan->Pcm()->PdpplanProducer(&ulProducerId); if (NULL == pdpplanProducer) { return; } if (m_fUpdateCTEMap) { pdpplanProducer->AddRef(); #ifdef GPOS_DEBUG BOOL fInserted = #endif // GPOS_DEBUG m_phmulpdpCTEs->FInsert(GPOS_NEW(m_pmp) ULONG(ulProducerId), pdpplanProducer); GPOS_ASSERT(fInserted); } }
//--------------------------------------------------------------------------- // @function: // CExpressionHandle::DerivePlanProps // // @doc: // Derive the properties of the plan carried by attached cost context // //--------------------------------------------------------------------------- void CExpressionHandle::DerivePlanProps ( CDrvdPropCtxtPlan *pdpctxtplan ) { GPOS_ASSERT(NULL != m_pcc); GPOS_ASSERT(NULL != m_pgexpr); GPOS_ASSERT(NULL == m_pdrgpdp); GPOS_ASSERT(NULL == m_pdp); GPOS_CHECK_ABORT; // check if properties have been already derived if (NULL != m_pcc->Pdpplan()) { CopyCostCtxtProps(); return; } GPOS_ASSERT(NULL != pdpctxtplan); // extract children's properties m_pdrgpdp = GPOS_NEW(m_pmp) DrgPdp(m_pmp); const ULONG ulArity = m_pcc->Pdrgpoc()->UlLength(); for (ULONG ul = 0; ul < ulArity; ul++) { COptimizationContext *pocChild = (*m_pcc->Pdrgpoc())[ul]; CDrvdPropPlan *pdpplan = pocChild->PccBest()->Pdpplan(); GPOS_ASSERT(NULL != pdpplan); pdpplan->AddRef(); m_pdrgpdp->Append(pdpplan); // add child props to derivation context CDrvdPropCtxt::AddDerivedProps(pdpplan, pdpctxtplan); } 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 (NULL != pdpplan) { pdpctxtplan->CopyCTEProducerProps(pdpplan, ulCTEId); } } // set the number of expected partition selectors in the context pdpctxtplan->SetExpectedPartitionSelectors(pop, m_pcc); // create/derive local properties m_pdp = Pop()->PdpCreate(m_pmp); m_pdp->Derive(m_pmp, *this, pdpctxtplan); }
//--------------------------------------------------------------------------- // @function: // CCTEReq::InsertConsumer // // @doc: // Insert a new consumer entry. with the given id. The plan properties are // taken from the given context // //--------------------------------------------------------------------------- void CCTEReq::InsertConsumer ( ULONG ulId, DrgPdp *pdrgpdpCtxt ) { ULONG ulProducerId = ULONG_MAX; CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan((*pdrgpdpCtxt)[0])->Pcm()->PdpplanProducer(&ulProducerId); GPOS_ASSERT(NULL != pdpplan); GPOS_ASSERT(ulProducerId == ulId && "unexpected CTE producer plan properties"); pdpplan->AddRef(); Insert(ulId, CCTEMap::EctConsumer, true /*fRequired*/, pdpplan); }
//--------------------------------------------------------------------------- // @function: // CDrvdPropPlan::CopyCTEProducerPlanProps // // @doc: // Copy CTE producer plan properties from given context to current object // //--------------------------------------------------------------------------- void CDrvdPropPlan::CopyCTEProducerPlanProps ( IMemoryPool *pmp, CDrvdPropCtxt *pdpctxt, COperator *pop ) { CDrvdPropCtxtPlan *pdpctxtplan = CDrvdPropCtxtPlan::PdpctxtplanConvert(pdpctxt); CPhysicalCTEConsumer *popCTEConsumer = CPhysicalCTEConsumer::PopConvert(pop); ULONG ulCTEId = popCTEConsumer->UlCTEId(); HMUlCr *phmulcr = popCTEConsumer->Phmulcr(); CDrvdPropPlan *pdpplan = pdpctxtplan->PdpplanCTEProducer(ulCTEId); if (NULL != pdpplan) { // copy producer plan properties after remapping columns m_pos = pdpplan->Pos()->PosCopyWithRemappedColumns(pmp, phmulcr, true /*fMustExist*/); m_pds = pdpplan->Pds()->PdsCopyWithRemappedColumns(pmp, phmulcr, true /*fMustExist*/); // rewindability and partition filter map do not need column remapping, // we add-ref producer's properties directly pdpplan->Prs()->AddRef(); m_prs = pdpplan->Prs(); pdpplan->Ppfm()->AddRef(); m_ppfm = pdpplan->Ppfm(); // no need to copy the part index map. return an empty one. This is to // distinguish between a CTE consumer and the inlined expression m_ppim = GPOS_NEW(pmp) CPartIndexMap(pmp); GPOS_ASSERT(CDistributionSpec::EdtAny != m_pds->Edt() && "CDistributionAny is a require-only, cannot be derived"); } }
//--------------------------------------------------------------------------- // @function: // CPhysical::FChildrenHaveCompatibleDistributions // // @doc: // Returns true iff the delivered distributions of the children are // compatible among themselves. // //--------------------------------------------------------------------------- BOOL CPhysical::FCompatibleChildrenDistributions ( const CExpressionHandle &exprhdl ) const { GPOS_ASSERT(exprhdl.Pop() == this); BOOL fSingletonOrUniversalChild = false; BOOL fNotSingletonOrUniversalDistributedChild = false; const ULONG arity = exprhdl.Arity(); for (ULONG ul = 0; ul < arity; ul++) { if (!exprhdl.FScalarChild(ul)) { CDrvdPropPlan *pdpplanChild = exprhdl.Pdpplan(ul); // an operator cannot have a singleton or universal distributed child // and one distributed on multiple nodes // this assumption is safe for all current operators, but it can be // too conservative: we could allow for instance the following cases // * LeftOuterJoin (universal, distributed) // * AntiSemiJoin (universal, distributed) // These cases can be enabled if considered necessary by overriding // this function. if (CDistributionSpec::EdtUniversal == pdpplanChild->Pds()->Edt() || pdpplanChild->Pds()->FSingletonOrStrictSingleton()) { fSingletonOrUniversalChild = true; } else { fNotSingletonOrUniversalDistributedChild = true; } if (fSingletonOrUniversalChild && fNotSingletonOrUniversalDistributedChild) { return false; } } } return true; }
//--------------------------------------------------------------------------- // @function: // CPhysicalMotion::FValidContext // // @doc: // Check if optimization context is valid // //--------------------------------------------------------------------------- BOOL CPhysicalMotion::FValidContext ( IMemoryPool *pmp, COptimizationContext *poc, DrgPoc *pdrgpocChild ) const { GPOS_ASSERT(NULL != pdrgpocChild); GPOS_ASSERT(1 == pdrgpocChild->UlLength()); COptimizationContext *pocChild = (*pdrgpocChild)[0]; CCostContext *pccBest = pocChild->PccBest(); GPOS_ASSERT(NULL != pccBest); CDrvdPropPlan *pdpplanChild = pccBest->Pdpplan(); if (pdpplanChild->Ppim()->FContainsUnresolved()) { return false; } CExpressionHandle exprhdl(pmp); exprhdl.Attach(pccBest); exprhdl.DeriveProps(NULL /*CDrvdPropCtxt*/); if (exprhdl.FHasOuterRefs()) { // disallow plans with outer references below motion operator return false; } CEnfdDistribution *ped = poc->Prpp()->Ped(); if (ped->FCompatible(this->Pds()) && ped->FCompatible(pdpplanChild->Pds())) { // required distribution is compatible with the distribution delivered by Motion and its child plan, // in this case, Motion is redundant since child plan delivers the required distribution return false; } return true; }
//--------------------------------------------------------------------------- // @function: // CCTEReq::PcterAllOptional // // @doc: // Create a copy of the current requirement where all the entries are marked optional // //--------------------------------------------------------------------------- CCTEReq * CCTEReq::PcterAllOptional ( IMemoryPool *pmp ) { CCTEReq *pcter = GPOS_NEW(pmp) CCTEReq(pmp); HMCteReqIter hmcri(m_phmcter); while (hmcri.FAdvance()) { const CCTEReqEntry *pcre = hmcri.Pt(); CDrvdPropPlan *pdpplan = pcre->PdpplanProducer(); if (NULL != pdpplan) { pdpplan->AddRef(); } pcter->Insert(pcre->UlId(), pcre->Ect(), false /*fRequired*/, pdpplan); } return pcter; }
//--------------------------------------------------------------------------- // @function: // CCostContext::DerivePlanProps // // @doc: // Derive properties of the plan carried by cost context // //--------------------------------------------------------------------------- void CCostContext::DerivePlanProps ( IMemoryPool *pmp ) { GPOS_ASSERT(NULL != m_pdrgpoc); if (NULL == m_pdpplan) { // derive properties of the plan carried by cost context CExpressionHandle exprhdl(pmp); exprhdl.Attach(this); exprhdl.DerivePlanProps(); CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan(exprhdl.Pdp()); GPOS_ASSERT(NULL != pdpplan); // set derived plan properties pdpplan->AddRef(); m_pdpplan = pdpplan; GPOS_ASSERT(NULL != m_pdpplan); } }
//--------------------------------------------------------------------------- // @function: // CCTEReq::PcterUnresolvedSequence // // @doc: // Unresolved CTE requirements given a derived CTE map for a sequence // operator // //--------------------------------------------------------------------------- CCTEReq * CCTEReq::PcterUnresolvedSequence ( IMemoryPool *pmp, CCTEMap *pcm, DrgPdp *pdrgpdpCtxt // context contains derived plan properties of producer tree ) { GPOS_ASSERT(NULL != pcm); CCTEReq *pcterUnresolved = GPOS_NEW(pmp) CCTEReq(pmp); HMCteReqIter hmcri(m_phmcter); while (hmcri.FAdvance()) { const CCTEReqEntry *pcre = hmcri.Pt(); ULONG ulId = pcre->UlId(); CCTEMap::ECteType ect = pcre->Ect(); BOOL fRequired = pcre->FRequired(); CCTEMap::ECteType ectDrvd = pcm->Ect(ulId); if (fRequired && CCTEMap::EctSentinel != ectDrvd) { GPOS_ASSERT(CCTEMap::EctConsumer == ect); GPOS_ASSERT(CCTEMap::EctConsumer == ectDrvd); // already found, so mark it as optional CDrvdPropPlan *pdpplan = pcre->PdpplanProducer(); GPOS_ASSERT(NULL != pdpplan); pdpplan->AddRef(); pcterUnresolved->Insert(ulId, ect, false /*fReqiored*/, pdpplan); } else if (!fRequired && CCTEMap::EctProducer == ect && CCTEMap::EctSentinel != ectDrvd) { GPOS_ASSERT(CCTEMap::EctProducer == ectDrvd); // found a producer. require the corresponding consumer and // extract producer plan properties from passed context pcterUnresolved->InsertConsumer(ulId, pdrgpdpCtxt); } else { // either required and not found yet, or optional // in both cases, pass it down as is CDrvdPropPlan *pdpplan = pcre->PdpplanProducer(); GPOS_ASSERT_IMP(NULL == pdpplan, CCTEMap::EctProducer == ect); if (NULL != pdpplan) { pdpplan->AddRef(); } pcterUnresolved->Insert(ulId, ect, fRequired, pdpplan); } } // if something is in pcm and not in the requirments, it has to be a producer // in which case, add the corresponding consumer as unresolved DrgPul *pdrgpulProducers = pcm->PdrgpulAdditionalProducers(pmp, this); const ULONG ulLen = pdrgpulProducers->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { ULONG *pulId = (*pdrgpulProducers)[ul]; pcterUnresolved->InsertConsumer(*pulId, pdrgpdpCtxt); } pdrgpulProducers->Release(); return pcterUnresolved; }
BOOL CPhysicalSpool::FValidContext ( IMemoryPool *, COptimizationContext *poc, COptimizationContextArray *pdrgpocChild ) const { GPOS_ASSERT(NULL != pdrgpocChild); GPOS_ASSERT(1 == pdrgpocChild->Size()); COptimizationContext *pocChild = (*pdrgpocChild)[0]; CCostContext *pccBest = pocChild->PccBest(); GPOS_ASSERT(NULL != pccBest); // partition selections that happen outside of a physical spool does not do // any good on rescan: a physical spool blocks the rescan from the entire // subtree (in particular, any dynamic scan) underneath it. That means when // we have a dynamic scan under a spool, and a corresponding partition // selector outside the spool, we run the risk of materializing the wrong // results. // For example, the following plan is invalid because the partition selector // won't be able to influence inner side of the nested loop join as intended // ("blocked" by the spool): // +--CPhysicalMotionGather(master) // +--CPhysicalInnerNLJoin // |--CPhysicalPartitionSelector // | +--CPhysicalMotionBroadcast // | +--CPhysicalTableScan "foo" ("foo") // |--CPhysicalSpool // | +--CPhysicalLeftOuterHashJoin // | |--CPhysicalDynamicTableScan "pt" ("pt") // | |--CPhysicalMotionHashDistribute // | | +--CPhysicalTableScan "bar" ("bar") // | +--CScalarCmp (=) // | |--CScalarIdent "d" (19) // | +--CScalarIdent "dk" (9) // +--CScalarCmp (<) // |--CScalarIdent "a" (0) // +--CScalarIdent "partkey" (10) CDrvdPropPlan *pdpplanChild = pccBest->Pdpplan(); if (pdpplanChild->Ppim()->FContainsUnresolved()) { return false; } // Discard any context that is requesting for rewindability with motion hazard handling and // the physical spool is streaming with a motion underneath it. // We do not want to add a blocking spool over a spool as spooling twice will be expensive, // hence invalidate this context. CEnfdRewindability *per = poc->Prpp()->Per(); if(per->PrsRequired()->HasMotionHazard() && pdpplanChild->Prs()->HasMotionHazard()) { return FEager(); } return true; }
//--------------------------------------------------------------------------- // @function: // CPhysicalSequence::PdsRequired // // @doc: // Compute required distribution of the n-th child // //--------------------------------------------------------------------------- CDistributionSpec * CPhysicalSequence::PdsRequired ( IMemoryPool *pmp, CExpressionHandle & #ifdef GPOS_DEBUG exprhdl #endif // GPOS_DEBUG , CDistributionSpec *pdsRequired, ULONG ulChildIndex, DrgPdp *pdrgpdpCtxt, ULONG ulOptReq ) const { GPOS_ASSERT(2 == exprhdl.UlArity()); GPOS_ASSERT(ulChildIndex < exprhdl.UlArity()); GPOS_ASSERT(ulOptReq < UlDistrRequests()); if (0 == ulOptReq) { if (CDistributionSpec::EdtSingleton == pdsRequired->Edt() || CDistributionSpec::EdtStrictSingleton == pdsRequired->Edt()) { // incoming request is a singleton, request singleton on all children CDistributionSpecSingleton *pdss = CDistributionSpecSingleton::PdssConvert(pdsRequired); return GPOS_NEW(pmp) CDistributionSpecSingleton(pdss->Est()); } // incoming request is a non-singleton, request non-singleton on all children return GPOS_NEW(pmp) CDistributionSpecNonSingleton(); } GPOS_ASSERT(1 == ulOptReq); if (0 == ulChildIndex) { // no distribution requirement on first child return GPOS_NEW(pmp) CDistributionSpecAny(this->Eopid()); } // get derived plan properties of first child CDrvdPropPlan *pdpplan = CDrvdPropPlan::Pdpplan((*pdrgpdpCtxt)[0]); CDistributionSpec *pds = pdpplan->Pds(); if (pds->FSingletonOrStrictSingleton()) { // first child is singleton, request singleton distribution on second child CDistributionSpecSingleton *pdss = CDistributionSpecSingleton::PdssConvert(pds); return GPOS_NEW(pmp) CDistributionSpecSingleton(pdss->Est()); } if (CDistributionSpec::EdtUniversal == pds->Edt()) { // first child is universal, impose no requirements on second child return GPOS_NEW(pmp) CDistributionSpecAny(this->Eopid()); } // first child is non-singleton, request a non-singleton distribution on second child return GPOS_NEW(pmp) CDistributionSpecNonSingleton(); }