//---------------------------------------------------------------------------
//	@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);
}
Пример #2
0
//---------------------------------------------------------------------------
//	@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");
		}
	}
}
Пример #3
0
//---------------------------------------------------------------------------
//	@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);
	}
}
Пример #4
0
//---------------------------------------------------------------------------
//	@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;
}
Пример #5
0
//---------------------------------------------------------------------------
//	@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);
}
Пример #6
0
//---------------------------------------------------------------------------
//	@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);
}
Пример #7
0
//---------------------------------------------------------------------------
//	@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();
}
Пример #9
0
//---------------------------------------------------------------------------
//	@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);
}
Пример #10
0
//---------------------------------------------------------------------------
//	@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);
}