//--------------------------------------------------------------------------- // @function: // CXformImplementDynamicBitmapTableGet::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformImplementDynamicBitmapTableGet::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *pmp = pxfctxt->Pmp(); CLogicalDynamicBitmapTableGet *popLogical = CLogicalDynamicBitmapTableGet::PopConvert(pexpr->Pop()); CTableDescriptor *ptabdesc = popLogical->Ptabdesc(); ptabdesc->AddRef(); CName *pname = GPOS_NEW(pmp) CName(pmp, popLogical->Name()); DrgPcr *pdrgpcrOutput = popLogical->PdrgpcrOutput(); GPOS_ASSERT(NULL != pdrgpcrOutput); pdrgpcrOutput->AddRef(); DrgDrgPcr *pdrgpdrgpcrPart = popLogical->PdrgpdrgpcrPart(); pdrgpdrgpcrPart->AddRef(); CPartConstraint *ppartcnstr = popLogical->Ppartcnstr(); ppartcnstr->AddRef(); CPartConstraint *ppartcnstrRel = popLogical->PpartcnstrRel(); ppartcnstrRel->AddRef(); CPhysicalDynamicBitmapTableScan *popPhysical = GPOS_NEW(pmp) CPhysicalDynamicBitmapTableScan ( pmp, popLogical->FPartial(), ptabdesc, pexpr->Pop()->UlOpId(), pname, popLogical->UlScanId(), pdrgpcrOutput, pdrgpdrgpcrPart, popLogical->UlSecondaryScanId(), ppartcnstr, ppartcnstrRel ); CExpression *pexprCondition = (*pexpr)[0]; CExpression *pexprIndexPath = (*pexpr)[1]; pexprCondition->AddRef(); pexprIndexPath->AddRef(); CExpression *pexprPhysical = GPOS_NEW(pmp) CExpression(pmp, popPhysical, pexprCondition, pexprIndexPath); pxfres->Add(pexprPhysical); }
//--------------------------------------------------------------------------- // @function: // CPartConstraint::CopyPartConstraints // // @doc: // Copy the part constraints to the given destination part constraint map // //--------------------------------------------------------------------------- void CPartConstraint::CopyPartConstraints ( IMemoryPool *mp, UlongToPartConstraintMap *ppartcnstrmapDest, UlongToPartConstraintMap *ppartcnstrmapSource ) { GPOS_ASSERT(NULL != ppartcnstrmapDest); GPOS_ASSERT(NULL != ppartcnstrmapSource); UlongToPartConstraintMapIter pcmi(ppartcnstrmapSource); while (pcmi.Advance()) { ULONG ulKey = *(pcmi.Key()); CPartConstraint *ppartcnstrSource = const_cast<CPartConstraint *>(pcmi.Value()); CPartConstraint *ppartcnstrDest = ppartcnstrmapDest->Find(&ulKey); GPOS_ASSERT_IMP(NULL != ppartcnstrDest, ppartcnstrDest->FEquivalent(ppartcnstrSource)); if (NULL == ppartcnstrDest) { ppartcnstrSource->AddRef(); #ifdef GPOS_DEBUG BOOL result = #endif // GPOS_DEBUG ppartcnstrmapDest->Insert(GPOS_NEW(mp) ULONG(ulKey), ppartcnstrSource); GPOS_ASSERT(result && "Duplicate part constraints"); } } }
//--------------------------------------------------------------------------- // @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: // CPartIndexMap::CPartTableInfo::AddPartConstraint // // @doc: // Add a part constraint // //--------------------------------------------------------------------------- void CPartIndexMap::CPartTableInfo::AddPartConstraints ( IMemoryPool *pmp, PartCnstrMap *ppartcnstrmap ) { GPOS_ASSERT(NULL != ppartcnstrmap); PartCnstrMapIter partcnstriter(ppartcnstrmap); while (partcnstriter.FAdvance()) { ULONG ulScanId = *(partcnstriter.Pk()); CPartConstraint *ppartcnstr = const_cast<CPartConstraint*>(partcnstriter.Pt()); ppartcnstr->AddRef(); AddPartConstraint(pmp, ulScanId, ppartcnstr); } m_fPartialScans = m_fPartialScans || FDefinesPartialScans(ppartcnstrmap, m_ppartcnstrRel); }
//--------------------------------------------------------------------------- // @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: // CPartitionPropagationSpec::AppendEnforcers // // @doc: // Add required enforcers to dynamic array // //--------------------------------------------------------------------------- void CPartitionPropagationSpec::AppendEnforcers ( IMemoryPool *mp, CExpressionHandle &exprhdl, CReqdPropPlan * #ifdef GPOS_DEBUG prpp #endif // GPOS_DEBUG , CExpressionArray *pdrgpexpr, CExpression *pexpr ) { GPOS_ASSERT(NULL != prpp); GPOS_ASSERT(NULL != mp); GPOS_ASSERT(NULL != pdrgpexpr); GPOS_ASSERT(NULL != pexpr); ULongPtrArray *pdrgpul = m_ppim->PdrgpulScanIds(mp); const ULONG size = pdrgpul->Size(); for (ULONG ul = 0; ul < size; ul++) { ULONG scan_id = *((*pdrgpul)[ul]); GPOS_ASSERT(m_ppim->Contains(scan_id)); if (CPartIndexMap::EpimConsumer != m_ppim->Epim(scan_id) || 0 < m_ppim->UlExpectedPropagators(scan_id)) { continue; } if (!FRequiresPartitionPropagation(mp, pexpr, exprhdl, scan_id)) { continue; } CExpression *pexprResolver = NULL; IMDId *mdid = m_ppim->GetRelMdId(scan_id); CColRef2dArray *pdrgpdrgpcrKeys = NULL; CPartKeysArray *pdrgppartkeys = m_ppim->Pdrgppartkeys(scan_id); CPartConstraint *ppartcnstr = m_ppim->PpartcnstrRel(scan_id); UlongToPartConstraintMap *ppartcnstrmap = m_ppim->Ppartcnstrmap(scan_id); mdid->AddRef(); ppartcnstr->AddRef(); ppartcnstrmap->AddRef(); pexpr->AddRef(); // check if there is a predicate on this part index id UlongToExprMap *phmulexprEqFilter = GPOS_NEW(mp) UlongToExprMap(mp); UlongToExprMap *phmulexprFilter = GPOS_NEW(mp) UlongToExprMap(mp); CExpression *pexprResidual = NULL; if (m_ppfm->FContainsScanId(scan_id)) { CExpression *pexprScalar = PexprFilter(mp, scan_id); // find out which keys are used in the predicate, in case there are multiple // keys at this point (e.g. from a union of multiple CTE consumers) CColRefSet *pcrsUsed = CDrvdPropScalar::GetDrvdScalarProps(pexprScalar->PdpDerive())->PcrsUsed(); const ULONG ulKeysets = pdrgppartkeys->Size(); for (ULONG ulKey = 0; NULL == pdrgpdrgpcrKeys && ulKey < ulKeysets; ulKey++) { // get partition key CPartKeys *ppartkeys = (*pdrgppartkeys)[ulKey]; if (ppartkeys->FOverlap(pcrsUsed)) { pdrgpdrgpcrKeys = ppartkeys->Pdrgpdrgpcr(); } } // if we cannot find partition keys mapping the partition predicates, fall back to planner if (NULL == pdrgpdrgpcrKeys) { GPOS_RAISE(gpopt::ExmaGPOPT, gpopt::ExmiUnsatisfiedRequiredProperties); } pdrgpdrgpcrKeys->AddRef(); // split predicates and put them in the appropriate hashmaps SplitPartPredicates(mp, pexprScalar, pdrgpdrgpcrKeys, phmulexprEqFilter, phmulexprFilter, &pexprResidual); pexprScalar->Release(); } else { // doesn't matter which keys we use here since there is no filter GPOS_ASSERT(1 <= pdrgppartkeys->Size()); pdrgpdrgpcrKeys = (*pdrgppartkeys)[0]->Pdrgpdrgpcr(); pdrgpdrgpcrKeys->AddRef(); } pexprResolver = GPOS_NEW(mp) CExpression ( mp, GPOS_NEW(mp) CPhysicalPartitionSelector ( mp, scan_id, mdid, pdrgpdrgpcrKeys, ppartcnstrmap, ppartcnstr, phmulexprEqFilter, phmulexprFilter, pexprResidual ), pexpr ); pdrgpexpr->Append(pexprResolver); } pdrgpul->Release(); }
//--------------------------------------------------------------------------- // @function: // CXformSelect2PartialDynamicIndexGet::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformSelect2PartialDynamicIndexGet::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *pmp = pxfctxt->Pmp(); // extract components CExpression *pexprRelational = (*pexpr)[0]; CExpression *pexprScalar = (*pexpr)[1]; // get the indexes on this relation CLogicalDynamicGet *popGet = CLogicalDynamicGet::PopConvert(pexprRelational->Pop()); if (popGet->FPartial()) { // already a partial dynamic get; do not try to split further return; } CTableDescriptor *ptabdesc = popGet->Ptabdesc(); CMDAccessor *pmda = COptCtxt::PoctxtFromTLS()->Pmda(); const IMDRelation *pmdrel = pmda->Pmdrel(ptabdesc->Pmdid()); const ULONG ulIndices = pmdrel->UlIndices(); if (0 == ulIndices) { // no indexes on the table return; } // array of expressions in the scalar expression DrgPexpr *pdrgpexpr = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprScalar); GPOS_ASSERT(0 < pdrgpexpr->UlLength()); // derive the scalar and relational properties to build set of required columns CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel(pexpr->PdpDerive())->PcrsOutput(); CColRefSet *pcrsScalarExpr = CDrvdPropScalar::Pdpscalar(pexprScalar->PdpDerive())->PcrsUsed(); CColRefSet *pcrsReqd = GPOS_NEW(pmp) CColRefSet(pmp); pcrsReqd->Include(pcrsOutput); pcrsReqd->Include(pcrsScalarExpr); CPartConstraint *ppartcnstr = popGet->Ppartcnstr(); ppartcnstr->AddRef(); // find a candidate set of partial index combinations DrgPdrgPpartdig *pdrgpdrgppartdig = CXformUtils::PdrgpdrgppartdigCandidates ( pmp, pmda, pdrgpexpr, popGet->PdrgpdrgpcrPart(), pmdrel, ppartcnstr, popGet->PdrgpcrOutput(), pcrsReqd, pcrsScalarExpr, NULL // pcrsAcceptedOuterRefs ); // construct alternative partial index scan plans const ULONG ulCandidates = pdrgpdrgppartdig->UlLength(); for (ULONG ul = 0; ul < ulCandidates; ul++) { DrgPpartdig *pdrgppartdig = (*pdrgpdrgppartdig)[ul]; CreatePartialIndexGetPlan(pmp, pexpr, pdrgppartdig, pmdrel, pxfres); } ppartcnstr->Release(); pcrsReqd->Release(); pdrgpexpr->Release(); pdrgpdrgppartdig->Release(); }
//--------------------------------------------------------------------------- // @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: // 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); }