//--------------------------------------------------------------------------- // @function: // CPartIndexMap::AddUnresolved // // @doc: // Helper to add part-index id's found in the first map and are // unresolved based on the second map // // For example, if the first and second map contain the following entries: // pimFst: // (partindexid: 1, consumer, part cnstr: 5->[1,3)), // (partindexid: 2, consumer, part cnstr: <>), // pimSnd: // (partindexid: 1, consumer, part cnstr: 6->(4,5))), // (partindexid: 2, producer, part cnstr: <>), // (partindexid: 3, producer, part cnstr: <>) // the result will be: // (partindexid: 1, consumer, part cnstr: 5->[1,3), 6->(4,5)), // part constraint get combined // (partindexid: 2, resolver, part cnstr: <>), // consumer+producer=resolver // (partindexid: 3, producer, part cnstr: <>) // no match for part index id 3: copy out // //--------------------------------------------------------------------------- void CPartIndexMap::AddUnresolved ( IMemoryPool *pmp, const CPartIndexMap &pimFst, const CPartIndexMap &pimSnd, CPartIndexMap* ppimResult ) { // iterate on first map and lookup entries in second map PartIndexMapIter pimiFst(pimFst.m_pim); while (pimiFst.FAdvance()) { const CPartTableInfo *pptiFst = pimiFst.Pt(); ULONG ulScanId = pptiFst->UlScanId(); EPartIndexManipulator epimFst = pptiFst->Epim(); ULONG ulPropagatorsFst = pptiFst->UlExpectedPropagators(); if (NULL != ppimResult->PptiLookup(ulScanId)) { // skip entries already in the result map continue; } // check if entry exists in second map CPartTableInfo *pptiSnd = pimSnd.PptiLookup(ulScanId); EPartIndexManipulator epimResult = epimFst; ULONG ulPropagatorsResult = ulPropagatorsFst; PartCnstrMap *ppartcnstrmapSnd = NULL; if (NULL != pptiSnd) { EPartIndexManipulator epimSnd = pptiSnd->Epim(); ULONG ulPropagatorsSnd = pptiSnd->UlExpectedPropagators(); GPOS_ASSERT_IMP(epimFst == EpimConsumer && epimSnd == EpimConsumer, ulPropagatorsFst == ulPropagatorsSnd); ResolvePropagator(epimFst, ulPropagatorsFst, epimSnd, ulPropagatorsSnd, &epimResult, &ulPropagatorsResult); ppartcnstrmapSnd = pptiSnd->Ppartcnstrmap(); } // copy mdid and partition columns from part index map entry IMDId *pmdid = pptiFst->Pmdid(); DrgPpartkeys *pdrgppartkeys = pptiFst->Pdrgppartkeys(); CPartConstraint *ppartcnstrRel = pptiFst->PpartcnstrRel(); PartCnstrMap *ppartcnstrmap = CPartConstraint::PpartcnstrmapCombine(pmp, pptiFst->Ppartcnstrmap(), ppartcnstrmapSnd); pmdid->AddRef(); pdrgppartkeys->AddRef(); ppartcnstrRel->AddRef(); ppimResult->Insert(ulScanId, ppartcnstrmap, epimResult, ulPropagatorsResult, pmdid, pdrgppartkeys, ppartcnstrRel); } }
//--------------------------------------------------------------------------- // @function: // CPartIndexMap::PpimPartitionSelector // // @doc: // Return a new part index map for a partition selector with the given // scan id, and the given number of expected selectors above it // //--------------------------------------------------------------------------- CPartIndexMap * CPartIndexMap::PpimPartitionSelector ( IMemoryPool *pmp, ULONG ulScanId, ULONG ulExpectedFromReq ) const { CPartIndexMap *ppimResult = GPOS_NEW(pmp) CPartIndexMap(pmp); PartIndexMapIter pimi(m_pim); while (pimi.FAdvance()) { const CPartTableInfo *ppti = pimi.Pt(); PartCnstrMap *ppartcnstrmap = ppti->Ppartcnstrmap(); IMDId *pmdid = ppti->Pmdid(); DrgPpartkeys *pdrgppartkeys = ppti->Pdrgppartkeys(); CPartConstraint *ppartcnstrRel = ppti->PpartcnstrRel(); ppartcnstrmap->AddRef(); pmdid->AddRef(); pdrgppartkeys->AddRef(); ppartcnstrRel->AddRef(); EPartIndexManipulator epim = ppti->Epim(); ULONG ulExpectedPropagators = ppti->UlExpectedPropagators(); if (ppti->UlScanId() == ulScanId) { if (0 == ulExpectedFromReq) { // this are no other expected partition selectors // so this scan id is resolved epim = EpimResolver; ulExpectedPropagators = 0; } else { // this is not resolved yet epim = EpimConsumer; ulExpectedPropagators = ulExpectedFromReq; } } ppimResult->Insert(ppti->UlScanId(), ppartcnstrmap, epim, ulExpectedPropagators, pmdid, pdrgppartkeys, ppartcnstrRel); } return ppimResult; }
//--------------------------------------------------------------------------- // @function: // CPartitionPropagationSpec::FRequiresPartitionPropagation // // @doc: // Check if given part index id needs to be enforced on top of the given // expression // //--------------------------------------------------------------------------- BOOL CPartitionPropagationSpec::FRequiresPartitionPropagation ( IMemoryPool *pmp, CExpression *pexpr, CExpressionHandle &exprhdl, ULONG ulPartIndexId ) const { GPOS_ASSERT(m_ppim->FContains(ulPartIndexId)); // construct partition propagation spec with the given id only, and check if it needs to be // enforced on top CPartIndexMap *ppim = GPOS_NEW(pmp) CPartIndexMap(pmp); IMDId *pmdid = m_ppim->PmdidRel(ulPartIndexId); DrgPpartkeys *pdrgppartkeys = m_ppim->Pdrgppartkeys(ulPartIndexId); CPartConstraint *ppartcnstr = m_ppim->PpartcnstrRel(ulPartIndexId); PartCnstrMap *ppartcnstrmap = m_ppim->Ppartcnstrmap(ulPartIndexId); pmdid->AddRef(); pdrgppartkeys->AddRef(); ppartcnstr->AddRef(); ppartcnstrmap->AddRef(); ppim->Insert(ulPartIndexId, ppartcnstrmap, m_ppim->Epim(ulPartIndexId), m_ppim->UlExpectedPropagators(ulPartIndexId), pmdid, pdrgppartkeys, ppartcnstr); CPartitionPropagationSpec *ppps = GPOS_NEW(pmp) CPartitionPropagationSpec(ppim, GPOS_NEW(pmp) CPartFilterMap(pmp)); CEnfdPartitionPropagation *pepp = GPOS_NEW(pmp) CEnfdPartitionPropagation(ppps, CEnfdPartitionPropagation::EppmSatisfy, GPOS_NEW(pmp) CPartFilterMap(pmp)); CEnfdProp::EPropEnforcingType epetPartitionPropagation = pepp->Epet(exprhdl, CPhysical::PopConvert(pexpr->Pop()), true /*fPartitionPropagationRequired*/); pepp->Release(); return CEnfdProp::FEnforce(epetPartitionPropagation); }
//--------------------------------------------------------------------------- // @function: // CPhysicalPartitionSelector::PppsRequired // // @doc: // Compute required partition propagation of the n-th child // //--------------------------------------------------------------------------- CPartitionPropagationSpec * CPhysicalPartitionSelector::PppsRequired ( IMemoryPool *pmp, CExpressionHandle & exprhdl, CPartitionPropagationSpec *pppsRequired, ULONG #ifdef GPOS_DEBUG ulChildIndex #endif // GPOS_DEBUG , DrgPdp *, //pdrgpdpCtxt, ULONG //ulOptReq ) { GPOS_ASSERT(0 == ulChildIndex); GPOS_ASSERT(NULL != pppsRequired); CPartIndexMap *ppimInput = pppsRequired->Ppim(); CPartFilterMap *ppfmInput = pppsRequired->Ppfm(); DrgPul *pdrgpulInputScanIds = ppimInput->PdrgpulScanIds(pmp); CPartIndexMap *ppim = GPOS_NEW(pmp) CPartIndexMap(pmp); CPartFilterMap *ppfm = GPOS_NEW(pmp) CPartFilterMap(pmp); CPartInfo *ppartinfo = exprhdl.Pdprel(0)->Ppartinfo(); const ULONG ulScanIds = pdrgpulInputScanIds->UlLength(); for (ULONG ul = 0; ul < ulScanIds; ul++) { ULONG ulScanId = *((*pdrgpulInputScanIds)[ul]); ULONG ulExpectedPropagators = ppimInput->UlExpectedPropagators(ulScanId); if (ulScanId == m_ulScanId) { // partition propagation resolved - do not need to require from children continue; } if (!ppartinfo->FContainsScanId(ulScanId) && ppartinfo->FContainsScanId(m_ulScanId)) { // dynamic scan for the required id not defined below, but the current one is: do not push request down continue; } IMDId *pmdid = ppimInput->PmdidRel(ulScanId); DrgPpartkeys *pdrgppartkeys = ppimInput->Pdrgppartkeys(ulScanId); PartCnstrMap *ppartcnstrmap = ppimInput->Ppartcnstrmap(ulScanId); CPartConstraint *ppartcnstr = ppimInput->PpartcnstrRel(ulScanId); CPartIndexMap::EPartIndexManipulator epim = ppimInput->Epim(ulScanId); pmdid->AddRef(); pdrgppartkeys->AddRef(); ppartcnstrmap->AddRef(); ppartcnstr->AddRef(); ppim->Insert(ulScanId, ppartcnstrmap, epim, ulExpectedPropagators, pmdid, pdrgppartkeys, ppartcnstr); (void) ppfm->FCopyPartFilter(m_pmp, ulScanId, ppfmInput); } // cleanup pdrgpulInputScanIds->Release(); return GPOS_NEW(pmp) CPartitionPropagationSpec(ppim, ppfm); }
//--------------------------------------------------------------------------- // @function: // CPhysicalNLJoin::PppsRequiredNLJoinChild // // @doc: // Compute required partition propagation of the n-th child // //--------------------------------------------------------------------------- CPartitionPropagationSpec * CPhysicalNLJoin::PppsRequiredNLJoinChild ( IMemoryPool *pmp, CExpressionHandle &exprhdl, CPartitionPropagationSpec *pppsRequired, ULONG ulChildIndex, DrgPdp *, //pdrgpdpCtxt, ULONG ulOptReq ) { GPOS_ASSERT(NULL != pppsRequired); if (1 == ulOptReq) { // request (1): push partition propagation requests to join's children, // do not consider possible dynamic partition elimination using join predicate here, // this is handled by optimization request (0) below return CPhysical::PppsRequiredPushThruNAry(pmp, exprhdl, pppsRequired, ulChildIndex); } GPOS_ASSERT(0 == ulOptReq); CPartIndexMap *ppim = pppsRequired->Ppim(); CPartFilterMap *ppfm = pppsRequired->Ppfm(); DrgPul *pdrgpul = ppim->PdrgpulScanIds(pmp); CPartIndexMap *ppimResult = GPOS_NEW(pmp) CPartIndexMap(pmp); CPartFilterMap *ppfmResult = GPOS_NEW(pmp) CPartFilterMap(pmp); CPartInfo *ppartinfoOuter = exprhdl.Pdprel(0)->Ppartinfo(); CColRefSet *pcrsOutputOuter = exprhdl.Pdprel(0)->PcrsOutput(); CColRefSet *pcrsOutputInner = exprhdl.Pdprel(1)->PcrsOutput(); const ULONG ulPartIndexIds = pdrgpul->UlLength(); for (ULONG ul = 0; ul < ulPartIndexIds; ul++) { ULONG ulPartIndexId = *((*pdrgpul)[ul]); if (ppfm->FContainsScanId(ulPartIndexId)) { GPOS_ASSERT(NULL != ppfm->Pexpr(ulPartIndexId)); // a selection-based propagation request pushed from above: do not propagate any // further as the join will reduce cardinality and thus may select more partitions // for scanning continue; } BOOL fOuterPartConsumer = ppartinfoOuter->FContainsScanId(ulPartIndexId); // in order to find interesting join predicates that can be used for DPE, // one side of the predicate must be the partition key, while the other side must only contain // references from the join child that does not have the partition consumer CColRefSet *pcrsAllowedRefs = pcrsOutputOuter; if (fOuterPartConsumer) { pcrsAllowedRefs = pcrsOutputInner; } if (0 == ulChildIndex && fOuterPartConsumer) { // always push through required partition propagation for consumers on the // outer side of the nested loop join DrgPpartkeys *pdrgppartkeys = ppartinfoOuter->PdrgppartkeysByScanId(ulPartIndexId); GPOS_ASSERT(NULL != pdrgppartkeys); pdrgppartkeys->AddRef(); ppimResult->AddRequiredPartPropagation(ppim, ulPartIndexId, CPartIndexMap::EppraPreservePropagators, pdrgppartkeys); } else { // check if there is an interesting condition involving the partition key CExpression *pexprScalar = exprhdl.PexprScalarChild(2 /*ulChildIndex*/); AddFilterOnPartKey(pmp, true /*fNLJoin*/, pexprScalar, ppim, ppfm, ulChildIndex, ulPartIndexId, fOuterPartConsumer, ppimResult, ppfmResult, pcrsAllowedRefs); } } pdrgpul->Release(); return GPOS_NEW(pmp) CPartitionPropagationSpec(ppimResult, ppfmResult); }
//--------------------------------------------------------------------------- // @function: // CPhysicalHashJoin::PppsRequiredCompute // // @doc: // Compute required partition propagation of the n-th child // //--------------------------------------------------------------------------- CPartitionPropagationSpec * CPhysicalHashJoin::PppsRequiredCompute ( IMemoryPool *pmp, CExpressionHandle &exprhdl, CPartitionPropagationSpec *pppsRequired, ULONG ulChildIndex ) { CPartIndexMap *ppim = pppsRequired->Ppim(); CPartFilterMap *ppfm = pppsRequired->Ppfm(); DrgPul *pdrgpul = ppim->PdrgpulScanIds(pmp); CPartIndexMap *ppimResult = GPOS_NEW(pmp) CPartIndexMap(pmp); CPartFilterMap *ppfmResult = GPOS_NEW(pmp) CPartFilterMap(pmp); // get outer partition consumers CPartInfo *ppartinfo = exprhdl.Pdprel(0)->Ppartinfo(); CColRefSet *pcrsOutputOuter = exprhdl.Pdprel(0)->PcrsOutput(); CColRefSet *pcrsOutputInner = exprhdl.Pdprel(1)->PcrsOutput(); const ULONG ulPartIndexIds = pdrgpul->UlLength(); for (ULONG ul = 0; ul < ulPartIndexIds; ul++) { ULONG ulPartIndexId = *((*pdrgpul)[ul]); if (ppfm->FContainsScanId(ulPartIndexId)) { GPOS_ASSERT(NULL != ppfm->Pexpr(ulPartIndexId)); // a selection-based propagation request pushed from above: do not propagate any // further as the join will reduce cardinality and thus may select more partitions // for scanning continue; } BOOL fOuterPartConsumer = ppartinfo->FContainsScanId(ulPartIndexId); // in order to find interesting join predicates that can be used for DPE, // one side of the predicate must be the partition key, while the other side must only contain // references from the join child that does not have the partition consumer CColRefSet *pcrsAllowedRefs = pcrsOutputOuter; if (fOuterPartConsumer) { pcrsAllowedRefs = pcrsOutputInner; } if (1 == ulChildIndex && !fOuterPartConsumer) { // always push through required partition propagation for consumers on the // inner side of the hash join DrgPpartkeys *pdrgppartkeys = exprhdl.Pdprel(1 /*ulChildIndex*/)->Ppartinfo()->PdrgppartkeysByScanId(ulPartIndexId); GPOS_ASSERT(NULL != pdrgppartkeys); pdrgppartkeys->AddRef(); ppimResult->AddRequiredPartPropagation(ppim, ulPartIndexId, CPartIndexMap::EppraPreservePropagators, pdrgppartkeys); } else { // look for a filter on the part key CExpression *pexprScalar = exprhdl.PexprScalarChild(2 /*ulChildIndex*/); AddFilterOnPartKey(pmp, false /*fNLJoin*/, pexprScalar, ppim, ppfm, ulChildIndex, ulPartIndexId, fOuterPartConsumer, ppimResult, ppfmResult, pcrsAllowedRefs); } } pdrgpul->Release(); return GPOS_NEW(pmp) CPartitionPropagationSpec(ppimResult, ppfmResult); }