//--------------------------------------------------------------------------- // @function: // CPhysical::PpimDeriveCombineRelational // // @doc: // Common case of common case of combining partition index maps // of all logical children // //--------------------------------------------------------------------------- CPartIndexMap * CPhysical::PpimDeriveCombineRelational ( IMemoryPool *mp, CExpressionHandle &exprhdl ) { GPOS_ASSERT(0 < exprhdl.Arity()); CPartIndexMap *ppim = GPOS_NEW(mp) CPartIndexMap(mp); const ULONG arity = exprhdl.Arity(); for (ULONG ul = 0; ul < arity; ul++) { if (!exprhdl.FScalarChild(ul)) { CPartIndexMap *ppimChild = exprhdl.Pdpplan(ul)->Ppim(); GPOS_ASSERT(NULL != ppimChild); CPartIndexMap *ppimCombined = CPartIndexMap::PpimCombine(mp, *ppim, *ppimChild); ppim->Release(); ppim = ppimCombined; } } return ppim; }
//--------------------------------------------------------------------------- // @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: // CPhysicalScan::PpimDeriveFromDynamicScan // // @doc: // Derive partition index map from a dynamic scan operator // //--------------------------------------------------------------------------- CPartIndexMap * CPhysicalScan::PpimDeriveFromDynamicScan ( IMemoryPool *pmp, ULONG ulPartIndexId, IMDId *pmdidRel, DrgDrgPcr *pdrgpdrgpcrPart, ULONG ulSecondaryPartIndexId, CPartConstraint *ppartcnstr, CPartConstraint *ppartcnstrRel, ULONG ulExpectedPropagators ) { CPartIndexMap *ppim = GPOS_NEW(pmp) CPartIndexMap(pmp); PartCnstrMap *ppartcnstrmap = GPOS_NEW(pmp) PartCnstrMap(pmp); (void) ppartcnstrmap->FInsert(GPOS_NEW(pmp) ULONG(ulSecondaryPartIndexId), ppartcnstr); DrgPpartkeys *pdrgppartkeys = GPOS_NEW(pmp) DrgPpartkeys(pmp); pdrgppartkeys->Append(GPOS_NEW(pmp) CPartKeys(pdrgpdrgpcrPart)); ppim->Insert(ulPartIndexId, ppartcnstrmap, CPartIndexMap::EpimConsumer, ulExpectedPropagators, pmdidRel, pdrgppartkeys, ppartcnstrRel); return ppim; }
//--------------------------------------------------------------------------- // @function: // CPartIndexMap::FSatisfies // // @doc: // Check if part index map satisfies required partition propagation spec // //--------------------------------------------------------------------------- BOOL CPartIndexMap::FSatisfies ( const CPartitionPropagationSpec *ppps ) const { GPOS_ASSERT(NULL != ppps); CPartIndexMap *ppimReqd = ppps->Ppim(); if (NULL == ppimReqd || !ppimReqd->FContainsUnresolved()) { // no reqiurements specified return true; } // check if all required entries are satisfied PartIndexMapIter pimiReqd(ppimReqd->m_pim); while (pimiReqd.FAdvance()) { const CPartTableInfo *pptiReqd = pimiReqd.Pt(); CPartTableInfo *ppti = PptiLookup(pptiReqd->UlScanId()); if (NULL != ppti && !FSatisfiesEntry(pptiReqd, ppti)) { return false; } } return true; }
//--------------------------------------------------------------------------- // @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: // CPhysical::PpimPassThruOuter // // @doc: // Common case of common case of passing through partition index map // //--------------------------------------------------------------------------- CPartIndexMap * CPhysical::PpimPassThruOuter ( CExpressionHandle &exprhdl ) { CPartIndexMap *ppim = exprhdl.Pdpplan(0 /*child_index*/)->Ppim(); GPOS_ASSERT(NULL != ppim); ppim->AddRef(); return ppim; }
//--------------------------------------------------------------------------- // @function: // CPhysicalMotion::PppsRequired // // @doc: // Compute required partition propagation of the n-th child // //--------------------------------------------------------------------------- CPartitionPropagationSpec * CPhysicalMotion::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 *ppimReqd = pppsRequired->Ppim(); CPartFilterMap *ppfmReqd = pppsRequired->Ppfm(); DrgPul *pdrgpul = ppimReqd->PdrgpulScanIds(pmp); CPartIndexMap *ppimResult = GPOS_NEW(pmp) CPartIndexMap(pmp); CPartFilterMap *ppfmResult = GPOS_NEW(pmp) CPartFilterMap(pmp); /// get derived part consumers CPartInfo *ppartinfo = exprhdl.Pdprel(0)->Ppartinfo(); const ULONG ulPartIndexSize = pdrgpul->UlLength(); for (ULONG ul = 0; ul < ulPartIndexSize; ul++) { ULONG ulPartIndexId = *((*pdrgpul)[ul]); if (!ppartinfo->FContainsScanId(ulPartIndexId)) { // part index id does not exist in child nodes: do not push it below // the motion continue; } ppimResult->AddRequiredPartPropagation(ppimReqd, ulPartIndexId, CPartIndexMap::EppraPreservePropagators); (void) ppfmResult->FCopyPartFilter(m_pmp, ulPartIndexId, ppfmReqd); } pdrgpul->Release(); return GPOS_NEW(pmp) CPartitionPropagationSpec(ppimResult, ppfmResult); }
//--------------------------------------------------------------------------- // @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: // CPhysical::PppsRequiredPushThruUnresolvedUnary // // @doc: // Helper function for pushing unresolved partition propagation in unary // operators // //--------------------------------------------------------------------------- CPartitionPropagationSpec * CPhysical::PppsRequiredPushThruUnresolvedUnary ( IMemoryPool *mp, CExpressionHandle &exprhdl, CPartitionPropagationSpec *pppsRequired, EPropogatePartConstraint eppcPropogate ) { GPOS_ASSERT(NULL != pppsRequired); CPartInfo *ppartinfo = exprhdl.GetRelationalProperties(0)->Ppartinfo(); CPartIndexMap *ppimReqd = pppsRequired->Ppim(); CPartFilterMap *ppfmReqd = pppsRequired->Ppfm(); ULongPtrArray *pdrgpul = ppimReqd->PdrgpulScanIds(mp); CPartIndexMap *ppimResult = GPOS_NEW(mp) CPartIndexMap(mp); CPartFilterMap *ppfmResult = GPOS_NEW(mp) CPartFilterMap(mp); const ULONG ulPartIndexIds = pdrgpul->Size(); // iterate over required part index ids and decide which ones to push through for (ULONG ul = 0; ul < ulPartIndexIds; ul++) { ULONG part_idx_id = *((*pdrgpul)[ul]); GPOS_ASSERT(ppimReqd->Contains(part_idx_id)); // if part index id is defined in child, push it to the child if (ppartinfo->FContainsScanId(part_idx_id)) { // push requirements to child node ppimResult->AddRequiredPartPropagation(ppimReqd, part_idx_id, CPartIndexMap::EppraPreservePropagators); if (CPhysical::EppcAllowed == eppcPropogate) { // for some logical operators such as limit while we push the part index map, we cannot push the constraints // since they are NOT semantically equivalent. So only push the constraints when the operator asks this // utility function to do so (void) ppfmResult->FCopyPartFilter(mp, part_idx_id, ppfmReqd); } } } pdrgpul->Release(); return GPOS_NEW(mp) CPartitionPropagationSpec(ppimResult, ppfmResult); }
//--------------------------------------------------------------------------- // @function: // CPhysicalUnionAll::PpimDerive // // @doc: // Derive partition index map // //--------------------------------------------------------------------------- CPartIndexMap * CPhysicalUnionAll::PpimDerive ( IMemoryPool *pmp, CExpressionHandle &exprhdl, CDrvdPropCtxt *pdpctxt ) const { CPartIndexMap *ppim = PpimDeriveCombineRelational(pmp, exprhdl); if (FPartialIndex()) { GPOS_ASSERT(NULL != pdpctxt); ULONG ulExpectedPartitionSelectors = CDrvdPropCtxtPlan::PdpctxtplanConvert(pdpctxt)->UlExpectedPartitionSelectors(); ppim->SetExpectedPropagators(m_ulScanIdPartialIndex, ulExpectedPartitionSelectors); } return ppim; }
//--------------------------------------------------------------------------- // @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: // CPhysical::EpetPartitionPropagation // // @doc: // Compute the enforcing type for the operator // //--------------------------------------------------------------------------- CEnfdProp::EPropEnforcingType CPhysical::EpetPartitionPropagation ( CExpressionHandle &exprhdl, const CEnfdPartitionPropagation *pepp ) const { CPartIndexMap *ppimReqd = pepp->PppsRequired()->Ppim(); if (!ppimReqd->FContainsUnresolved()) { // no unresolved partition consumers left return CEnfdProp::EpetUnnecessary; } CPartIndexMap *ppimDrvd = CDrvdPropPlan::Pdpplan(exprhdl.Pdp())->Ppim(); GPOS_ASSERT(NULL != ppimDrvd); BOOL fInScope = pepp->FInScope(m_mp, ppimDrvd); BOOL fResolved = pepp->FResolved(m_mp, ppimDrvd); if (fResolved) { // all required partition consumers are resolved return CEnfdProp::EpetUnnecessary; } if (!fInScope) { // some partition consumers are not in scope of the operator: need to enforce these on top return CEnfdProp::EpetRequired; } // all partition resolvers are in scope of the operator: do not enforce them on top return CEnfdProp::EpetProhibited; }
//--------------------------------------------------------------------------- // @function: // CPartitionPropagationSpec::FRequiresPartitionPropagation // // @doc: // Check if given part index id needs to be enforced on top of the given // expression // //--------------------------------------------------------------------------- BOOL CPartitionPropagationSpec::FRequiresPartitionPropagation ( IMemoryPool *mp, CExpression *pexpr, CExpressionHandle &exprhdl, ULONG part_idx_id ) const { GPOS_ASSERT(m_ppim->Contains(part_idx_id)); // construct partition propagation spec with the given id only, and check if it needs to be // enforced on top CPartIndexMap *ppim = GPOS_NEW(mp) CPartIndexMap(mp); IMDId *mdid = m_ppim->GetRelMdId(part_idx_id); CPartKeysArray *pdrgppartkeys = m_ppim->Pdrgppartkeys(part_idx_id); CPartConstraint *ppartcnstr = m_ppim->PpartcnstrRel(part_idx_id); UlongToPartConstraintMap *ppartcnstrmap = m_ppim->Ppartcnstrmap(part_idx_id); mdid->AddRef(); pdrgppartkeys->AddRef(); ppartcnstr->AddRef(); ppartcnstrmap->AddRef(); ppim->Insert(part_idx_id, ppartcnstrmap, m_ppim->Epim(part_idx_id), m_ppim->UlExpectedPropagators(part_idx_id), mdid, pdrgppartkeys, ppartcnstr); CPartitionPropagationSpec *ppps = GPOS_NEW(mp) CPartitionPropagationSpec(ppim, GPOS_NEW(mp) CPartFilterMap(mp)); CEnfdPartitionPropagation *pepp = GPOS_NEW(mp) CEnfdPartitionPropagation(ppps, CEnfdPartitionPropagation::EppmSatisfy, GPOS_NEW(mp) CPartFilterMap(mp)); CEnfdProp::EPropEnforcingType epetPartitionPropagation = pepp->Epet(exprhdl, CPhysical::PopConvert(pexpr->Pop()), true /*fPartitionPropagationRequired*/); pepp->Release(); return CEnfdProp::FEnforce(epetPartitionPropagation); }
//--------------------------------------------------------------------------- // @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); }
//--------------------------------------------------------------------------- // @function: // CPhysicalUnionAll::EpetPartitionPropagation // // @doc: // Compute the enforcing type for the operator // //--------------------------------------------------------------------------- CEnfdProp::EPropEnforcingType CPhysicalUnionAll::EpetPartitionPropagation ( CExpressionHandle &exprhdl, const CEnfdPartitionPropagation *pepp ) const { CPartIndexMap *ppimReqd = pepp->PppsRequired()->Ppim(); if (!ppimReqd->FContainsUnresolved()) { // no unresolved partition consumers left return CEnfdProp::EpetUnnecessary; } CPartIndexMap *ppimDrvd = CDrvdPropPlan::Pdpplan(exprhdl.Pdp())->Ppim(); GPOS_ASSERT(NULL != ppimDrvd); BOOL fInScope = pepp->FInScope(m_pmp, ppimDrvd); BOOL fResolved = pepp->FResolved(m_pmp, ppimDrvd); if (fResolved) { // all required partition consumers are resolved return CEnfdProp::EpetUnnecessary; } if (!fInScope) { // some partition consumers are not covered downstream return CEnfdProp::EpetRequired; } DrgPul *pdrgpul = ppimReqd->PdrgpulScanIds(m_pmp); const ULONG ulScanIds = pdrgpul->UlLength(); const ULONG ulArity = exprhdl.UlNonScalarChildren(); for (ULONG ul = 0; ul < ulScanIds; ul++) { ULONG ulScanId = *((*pdrgpul)[ul]); ULONG ulChildrenWithConsumers = 0; for (ULONG ulChildIdx = 0; ulChildIdx < ulArity; ulChildIdx++) { if (exprhdl.Pdprel(ulChildIdx)->Ppartinfo()->FContainsScanId(ulScanId)) { ulChildrenWithConsumers++; } } if (1 < ulChildrenWithConsumers) { // partition consumer exists in more than one child, so enforce it here pdrgpul->Release(); return CEnfdProp::EpetRequired; } } pdrgpul->Release(); // required part propagation can be enforced here or passed to the children return CEnfdProp::EpetOptional; }
//--------------------------------------------------------------------------- // @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: // CPhysicalPartitionSelector::PppsRequired // // @doc: // Compute required partition propagation of the n-th child // //--------------------------------------------------------------------------- CPartitionPropagationSpec * CPhysicalPartitionSelector::PppsRequired ( IMemoryPool *mp, CExpressionHandle & exprhdl, CPartitionPropagationSpec *pppsRequired, ULONG #ifdef GPOS_DEBUG child_index #endif // GPOS_DEBUG , CDrvdProp2dArray *, //pdrgpdpCtxt, ULONG //ulOptReq ) { GPOS_ASSERT(0 == child_index); GPOS_ASSERT(NULL != pppsRequired); CPartIndexMap *ppimInput = pppsRequired->Ppim(); CPartFilterMap *ppfmInput = pppsRequired->Ppfm(); ULongPtrArray *pdrgpulInputScanIds = ppimInput->PdrgpulScanIds(mp); CPartIndexMap *ppim = GPOS_NEW(mp) CPartIndexMap(mp); CPartFilterMap *ppfm = GPOS_NEW(mp) CPartFilterMap(mp); CPartInfo *ppartinfo = exprhdl.GetRelationalProperties(0)->Ppartinfo(); const ULONG ulScanIds = pdrgpulInputScanIds->Size(); for (ULONG ul = 0; ul < ulScanIds; ul++) { ULONG scan_id = *((*pdrgpulInputScanIds)[ul]); ULONG ulExpectedPropagators = ppimInput->UlExpectedPropagators(scan_id); if (scan_id == m_scan_id) { // partition propagation resolved - do not need to require from children continue; } if (!ppartinfo->FContainsScanId(scan_id) && ppartinfo->FContainsScanId(m_scan_id)) { // dynamic scan for the required id not defined below, but the current one is: do not push request down continue; } IMDId *mdid = ppimInput->GetRelMdId(scan_id); CPartKeysArray *pdrgppartkeys = ppimInput->Pdrgppartkeys(scan_id); UlongToPartConstraintMap *ppartcnstrmap = ppimInput->Ppartcnstrmap(scan_id); CPartConstraint *ppartcnstr = ppimInput->PpartcnstrRel(scan_id); CPartIndexMap::EPartIndexManipulator epim = ppimInput->Epim(scan_id); mdid->AddRef(); pdrgppartkeys->AddRef(); ppartcnstrmap->AddRef(); ppartcnstr->AddRef(); ppim->Insert(scan_id, ppartcnstrmap, epim, ulExpectedPropagators, mdid, pdrgppartkeys, ppartcnstr); (void) ppfm->FCopyPartFilter(m_mp, scan_id, ppfmInput); } // cleanup pdrgpulInputScanIds->Release(); return GPOS_NEW(mp) 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: // CPhysical::PppsRequiredPushThruNAry // // @doc: // Helper for pushing required partition propagation to the children of // an n-ary operator // //--------------------------------------------------------------------------- CPartitionPropagationSpec * CPhysical::PppsRequiredPushThruNAry ( IMemoryPool *mp, CExpressionHandle &exprhdl, CPartitionPropagationSpec *pppsReqd, ULONG child_index ) { GPOS_ASSERT(NULL != pppsReqd); CPartIndexMap *ppimReqd = pppsReqd->Ppim(); CPartFilterMap *ppfmReqd = pppsReqd->Ppfm(); ULongPtrArray *pdrgpul = ppimReqd->PdrgpulScanIds(mp); CPartIndexMap *ppimResult = GPOS_NEW(mp) CPartIndexMap(mp); CPartFilterMap *ppfmResult = GPOS_NEW(mp) CPartFilterMap(mp); const ULONG ulPartIndexIds = pdrgpul->Size(); const ULONG arity = exprhdl.UlNonScalarChildren(); // iterate over required part index ids and decide which ones to push to the outer // and which to the inner side of the n-ary op for (ULONG ul = 0; ul < ulPartIndexIds; ul++) { ULONG part_idx_id = *((*pdrgpul)[ul]); GPOS_ASSERT(ppimReqd->Contains(part_idx_id)); CBitSet *pbsPartConsumer = GPOS_NEW(mp) CBitSet(mp); for (ULONG ulChildIdx = 0; ulChildIdx < arity; ulChildIdx++) { if (exprhdl.GetRelationalProperties(ulChildIdx)->Ppartinfo()->FContainsScanId(part_idx_id)) { (void) pbsPartConsumer->ExchangeSet(ulChildIdx); } } if (arity == pbsPartConsumer->Size() && COperator::EopPhysicalSequence == exprhdl.Pop()->Eopid() && (*(exprhdl.Pgexpr()))[0]->FHasCTEProducer()) { GPOS_ASSERT(2 == arity); // this is a part index id that comes from both sides of a sequence // with a CTE producer on the outer side, so pretend that part index // id is not defined the inner sides pbsPartConsumer->ExchangeClear(1); } if (!FCanPushPartReqToChild(pbsPartConsumer, child_index)) { // clean up pbsPartConsumer->Release(); continue; } // clean up pbsPartConsumer->Release(); CPartKeysArray *pdrgppartkeys = exprhdl.GetRelationalProperties(child_index)->Ppartinfo()->PdrgppartkeysByScanId(part_idx_id); GPOS_ASSERT(NULL != pdrgppartkeys); pdrgppartkeys->AddRef(); // push requirements to child node ppimResult->AddRequiredPartPropagation(ppimReqd, part_idx_id, CPartIndexMap::EppraPreservePropagators, pdrgppartkeys); // check if there is a filter on the part index id and propagate that further down if (ppfmReqd->FContainsScanId(part_idx_id)) { CExpression *pexpr = ppfmReqd->Pexpr(part_idx_id); // if the current child is inner child and the predicate is IsNull check and the parent is outer join, // don't push IsNull check predicate to the partition filter. // for all the other cases, push the filter down. if (!(1 == child_index && CUtils::FScalarNullTest(pexpr) && CUtils::FPhysicalOuterJoin(exprhdl.Pop())) ) { pexpr->AddRef(); ppfmResult->AddPartFilter(mp, part_idx_id, pexpr, NULL /*stats */); } } } pdrgpul->Release(); return GPOS_NEW(mp) CPartitionPropagationSpec(ppimResult, ppfmResult); }