//---------------------------------------------------------------------------
//	@function:
//		CPhysicalStreamAgg::PosCovering
//
//	@doc:
//		Construct order spec on grouping column so that it covers required
//		order spec, the function returns NULL if no covering order spec
//		can be created
//
//---------------------------------------------------------------------------
COrderSpec *
CPhysicalStreamAgg::PosCovering
	(
	IMemoryPool *mp,
	COrderSpec *posRequired,
	CColRefArray *pdrgpcrGrp
	)
	const
{
	GPOS_ASSERT(NULL != posRequired);

	if (0 == posRequired->UlSortColumns())
	{
		// required order must be non-empty
		return NULL;
	}

	// create a set of required sort columns
	CColRefSet *pcrsReqd = posRequired->PcrsUsed(mp);

	COrderSpec *pos = NULL;

	CColRefSet *pcrsGrpCols = GPOS_NEW(mp) CColRefSet(mp, pdrgpcrGrp);
	if (pcrsGrpCols->ContainsAll(pcrsReqd))
	{
		// required order columns are included in grouping columns, we can
		// construct a covering order spec
		pos = GPOS_NEW(mp) COrderSpec(mp);

		// extract order expressions from required order
		const ULONG ulReqdSortCols = posRequired->UlSortColumns();
		for (ULONG ul = 0; ul < ulReqdSortCols; ul++)
		{
			CColRef *colref = const_cast<CColRef *>(posRequired->Pcr(ul));
			IMDId *mdid = posRequired->GetMdIdSortOp(ul);
			COrderSpec::ENullTreatment ent = posRequired->Ent(ul);
			mdid->AddRef();
			pos->Append(mdid, colref, ent);
		}

		// augment order with remaining grouping columns
		const ULONG size = pdrgpcrGrp->Size();
		for (ULONG ul = 0; ul < size; ul++)
		{
			CColRef *colref = (*pdrgpcrGrp)[ul];
			if (!pcrsReqd->FMember(colref))
			{
				IMDId *mdid = colref->RetrieveType()->GetMdidForCmpType(IMDType::EcmptL);
				mdid->AddRef();
				pos->Append(mdid, colref, COrderSpec::EntLast);
			}
		}
	}
	pcrsGrpCols->Release();
	pcrsReqd->Release();

	return pos;
}
Exemple #2
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalDML::PosComputeRequired
//
//	@doc:
//		Compute required sort order based on the key information in the table 
//		descriptor:
//		1. If a table has no keys, no sort order is necessary.
//
//		2. If a table has keys, but they are not modified in the update, no sort
//		order is necessary. This relies on the fact that Split always produces
//		Delete tuples before Insert tuples, so we cannot have two versions of the
//		same tuple on the same time. Consider for example tuple (A: 1, B: 2), where
//		A is key and an update "set B=B+1". Since there cannot be any other tuple 
//		with A=1, and the tuple (1,2) is deleted before tuple (1,3) gets inserted,
//		we don't need to enforce specific order of deletes and inserts.
//
//		3. If the update changes a key column, enforce order on the Action column
//		to deliver Delete tuples before Insert tuples. This is done to avoid a
//		conflict between a newly inserted tuple and an old tuple that is about to be
//		deleted. Consider table with tuples (A: 1),(A: 2), where A is key, and 
//		update "set A=A+1". Split will generate tuples (1,"D"), (2,"I"), (2,"D"), (3,"I").
//		If (2,"I") happens before (2,"D") we will have a violation of the key constraint.
//		Therefore we need to enforce sort order on Action to get all old tuples
//		tuples deleted before the new ones are inserted.
//
//---------------------------------------------------------------------------
COrderSpec *
CPhysicalDML::PosComputeRequired
	(
	IMemoryPool *pmp,
	CTableDescriptor *ptabdesc
	)
{
	COrderSpec *pos = GPOS_NEW(pmp) COrderSpec(pmp);

	const DrgPbs *pdrgpbsKeys = ptabdesc->PdrgpbsKeys();
	if (1 < pdrgpbsKeys->UlLength() && CLogicalDML::EdmlUpdate == m_edmlop)
	{
		// if this is an update on the target table's keys, enforce order on 
		// the action column, see explanation in function's comment		
		const ULONG ulKeySets = pdrgpbsKeys->UlLength();
		BOOL fNeedsSort = false;
		for (ULONG ul = 0; ul < ulKeySets && !fNeedsSort; ul++)
		{
			CBitSet *pbs = (*pdrgpbsKeys)[ul];
			if (!pbs->FDisjoint(m_pbsModified))
			{
				fNeedsSort = true;
				break;
			}
		}
		
		if (fNeedsSort)
		{
			IMDId *pmdid = m_pcrAction->Pmdtype()->PmdidCmp(IMDType::EcmptL);
			pmdid->AddRef();
			pos->Append(pmdid, m_pcrAction, COrderSpec::EntAuto);
		}
	}
	else if (m_ptabdesc->FPartitioned())
	{
		COptimizerConfig *poconf = COptCtxt::PoctxtFromTLS()->Poconf();

		BOOL fInsertSortOnParquet = FInsertSortOnParquet();
		BOOL fInsertSortOnRows = FInsertSortOnRows(poconf);

		if (fInsertSortOnParquet || fInsertSortOnRows)
		{
			GPOS_ASSERT(CLogicalDML::EdmlInsert == m_edmlop);
			m_fInputSorted = true;
			// if this is an INSERT over a partitioned Parquet or Row-oriented table,
			// sort tuples by their table oid
			IMDId *pmdid = m_pcrTableOid->Pmdtype()->PmdidCmp(IMDType::EcmptL);
			pmdid->AddRef();
			pos->Append(pmdid, m_pcrTableOid, COrderSpec::EntAuto);
		}
	}
	
	return pos;
}
Exemple #3
0
//---------------------------------------------------------------------------
//	@function:
//		CLogical::PosFromIndex
//
//	@doc:
//		Compute an order spec based on an index
//
//---------------------------------------------------------------------------
COrderSpec *
CLogical::PosFromIndex
	(
	IMemoryPool *pmp,
	const IMDIndex *pmdindex,
	DrgPcr *pdrgpcr
	)
{
	// compute the order spec
	COrderSpec *pos = GPOS_NEW(pmp) COrderSpec(pmp);
	const ULONG ulLenIncludeCols = pmdindex->UlKeys();
	for (ULONG  ul = 0; ul < ulLenIncludeCols; ul++)
	{
		ULONG ulPos = pmdindex->UlKey(ul);
		CColRef *pcr = (*pdrgpcr)[ulPos];
	
		IMDId *pmdid = pcr->Pmdtype()->PmdidCmp(IMDType::EcmptL);
		pmdid->AddRef();
	
		// TODO:  March 27th 2012; we hard-code NULL treatment
		// need to revisit
		pos->Append(pmdid, pcr, COrderSpec::EntLast);
	}
	
	return pos;
}
//---------------------------------------------------------------------------
//	@function:
//		CParseHandlerScalarSubPlanParamList::EndElement
//
//	@doc:
//		Processes a Xerces end element event
//
//---------------------------------------------------------------------------
void
CParseHandlerScalarSubPlanParamList::EndElement
	(
	const XMLCh* const, // xmlszUri,
	const XMLCh* const xmlszLocalname,
	const XMLCh* const // xmlszQname
	)
{
	if(0 != XMLString::compareString(CDXLTokens::XmlstrToken(EdxltokenScalarSubPlanParamList), xmlszLocalname) && NULL != m_pdxln)
	{
		CWStringDynamic *pstr = CDXLUtils::PstrFromXMLCh(m_pphm->Pmm(), xmlszLocalname);
		GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXLUnexpectedTag, pstr->Wsz());
	}

	const ULONG ulSize = this->UlLength();
	// add constructed children from child parse handlers
	for (ULONG ul = 0; ul < ulSize; ul++)
	{
		CParseHandlerScalarSubPlanParam *pphParam = dynamic_cast<CParseHandlerScalarSubPlanParam *>((*this)[ul]);

		CDXLColRef *pdxlcr = pphParam->Pdxlcr();
		IMDId *pmdid = pphParam->Pmdid();
		pdxlcr->AddRef();
		pmdid->AddRef();
		m_pdrgdxlcr->Append(pdxlcr);
		m_pdrgmdid->Append(pmdid);
	}

	// deactivate handler
	m_pphm->DeactivateHandler();
}
Exemple #5
0
//---------------------------------------------------------------------------
//	@function:
//		CScalarAggFunc::CScalarAggFunc
//
//	@doc:
//		Ctor
//
//---------------------------------------------------------------------------
CScalarAggFunc::CScalarAggFunc
	(
	IMemoryPool *pmp,
	IMDId *pmdidAggFunc,
	IMDId *pmdidResolvedRetType,
	const CWStringConst *pstrAggFunc,
	BOOL fDistinct,
	EAggfuncStage eaggfuncstage,
	BOOL fSplit
	)
	:
	CScalar(pmp),
	m_pmdidAggFunc(pmdidAggFunc),
	m_pmdidResolvedRetType(pmdidResolvedRetType),
	m_pmdidRetType(NULL),
	m_pstrAggFunc(pstrAggFunc),
	m_fDistinct(fDistinct),
	m_eaggfuncstage(eaggfuncstage),
	m_fSplit(fSplit)
{
	GPOS_ASSERT(NULL != pmdidAggFunc);
	GPOS_ASSERT(NULL != pstrAggFunc);
	GPOS_ASSERT(pmdidAggFunc->FValid());
	GPOS_ASSERT_IMP(NULL != pmdidResolvedRetType, pmdidResolvedRetType->FValid());
	GPOS_ASSERT(EaggfuncstageSentinel > eaggfuncstage);

	// store id of type obtained by looking up MD cache
	IMDId *pmdid = PmdidLookupReturnType(m_pmdidAggFunc, (EaggfuncstageGlobal == m_eaggfuncstage));
	pmdid->AddRef();
	m_pmdidRetType = pmdid;
}
Exemple #6
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);
	}
}
Exemple #7
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;
}
//---------------------------------------------------------------------------
//	@function:
//		CLogicalDynamicGetBase::PpartinfoDerive
//
//	@doc:
//		Derive partition consumer info
//
//---------------------------------------------------------------------------
CPartInfo *
CLogicalDynamicGetBase::PpartinfoDerive
	(
	IMemoryPool *pmp,
	CExpressionHandle & // exprhdl
	)
	const
{
	IMDId *pmdid = m_ptabdesc->Pmdid();
	pmdid->AddRef();
	m_pdrgpdrgpcrPart->AddRef();
	m_ppartcnstrRel->AddRef(); 
	
	CPartInfo *ppartinfo = GPOS_NEW(pmp) CPartInfo(pmp);
	ppartinfo->AddPartConsumer(pmp, m_ulScanId, pmdid, m_pdrgpdrgpcrPart, m_ppartcnstrRel);
	
	return ppartinfo;
}
//---------------------------------------------------------------------------
//	@function:
//		CMDProviderMemory::LoadMetadataObjectsFromArray
//
//	@doc:
//		Loads the metadata objects from the given file
//
//---------------------------------------------------------------------------
void
CMDProviderMemory::LoadMetadataObjectsFromArray
	(
	IMemoryPool *pmp,
	DrgPimdobj *pdrgpmdobj
	)
{
	GPOS_ASSERT(NULL != pdrgpmdobj);

	// load metadata objects from the file
	CAutoRef<MDMap> a_pmdmap;
	m_pmdmap = GPOS_NEW(pmp) MDMap(pmp);
	a_pmdmap = m_pmdmap;

	const ULONG ulSize = pdrgpmdobj->UlLength();

	// load objects into the hash map
	for (ULONG ul = 0; ul < ulSize; ul++)
	{
		GPOS_CHECK_ABORT;

		IMDCacheObject *pmdobj = (*pdrgpmdobj)[ul];
		IMDId *pmdidKey = pmdobj->Pmdid();
		pmdidKey->AddRef();
		CAutoRef<IMDId> a_pmdidKey;
		a_pmdidKey = pmdidKey;
		
		CAutoP<CWStringDynamic> a_pstr;
		a_pstr = CDXLUtils::PstrSerializeMDObj(pmp, pmdobj, true /*fSerializeHeaders*/, false /*findent*/);
		
		GPOS_CHECK_ABORT;
		BOOL fInserted = m_pmdmap->FInsert(pmdidKey, a_pstr.Pt());
		if (!fInserted)
		{
			
			GPOS_RAISE(gpdxl::ExmaMD, gpdxl::ExmiMDCacheEntryDuplicate, pmdidKey->Wsz());
		}
		(void) a_pmdidKey.PtReset();
		(void) a_pstr.PtReset();
	}
	
	// safely completed loading
	(void) a_pmdmap.PtReset();
}
Exemple #10
0
//---------------------------------------------------------------------------
//	@function:
//		CPartInfo::CPartInfoEntry::PpartinfoentryCopy
//
//	@doc:
//		Copy part info entry into given memory pool
//
//---------------------------------------------------------------------------
CPartInfo::CPartInfoEntry *
CPartInfo::CPartInfoEntry::PpartinfoentryCopy
	(
	IMemoryPool *pmp
	)
{
	IMDId *pmdid = Pmdid();
	pmdid->AddRef();

	// copy part keys
	DrgPpartkeys *pdrgppartkeysCopy = CPartKeys::PdrgppartkeysCopy(pmp, Pdrgppartkeys());

	// copy part constraint using empty remapping to get exact copy
	HMUlCr *phmulcr = GPOS_NEW(pmp) HMUlCr(pmp);
	CPartConstraint *ppartcnstrRel = PpartcnstrRel()->PpartcnstrCopyWithRemappedColumns(pmp, phmulcr, false /*fMustExist*/);
	phmulcr->Release();

	return GPOS_NEW(pmp) CPartInfoEntry(UlScanId(), pmdid, pdrgppartkeysCopy, ppartcnstrRel);
}
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalDynamicScan::PpimDerive
//
//	@doc:
//		Derive partition index map
//
//---------------------------------------------------------------------------
CPartIndexMap *
CPhysicalDynamicScan::PpimDerive
	(
	IMemoryPool *pmp,
	CExpressionHandle &, //exprhdl
	CDrvdPropCtxt *pdpctxt
	)
	const
{
	GPOS_ASSERT(NULL != pdpctxt);
	IMDId *pmdid = m_ptabdesc->Pmdid();
	pmdid->AddRef();
	m_pdrgpdrgpcrPart->AddRef();
	m_ppartcnstr->AddRef();
	m_ppartcnstrRel->AddRef();
	ULONG ulExpectedPartitionSelectors = CDrvdPropCtxtPlan::PdpctxtplanConvert(pdpctxt)->UlExpectedPartitionSelectors();

	return PpimDeriveFromDynamicScan(pmp, m_ulScanId, pmdid, m_pdrgpdrgpcrPart, m_ulSecondaryScanId, m_ppartcnstr, m_ppartcnstrRel, ulExpectedPartitionSelectors);
}
Exemple #12
0
//---------------------------------------------------------------------------
//	@function:
//		CDatumBoolGPDB::CDatumBoolGPDB
//
//	@doc:
//		Ctor
//
//---------------------------------------------------------------------------
CDatumBoolGPDB::CDatumBoolGPDB
	(
	CSystemId sysid,
	BOOL fVal,
	BOOL fNull
	)
	:
	m_fVal(fVal),
	m_fNull(fNull)
{
	CMDAccessor *pmda = COptCtxt::PoctxtFromTLS()->Pmda();
	IMDId *pmdid = dynamic_cast<const CMDTypeBoolGPDB *>(pmda->PtMDType<IMDTypeBool>(sysid))->Pmdid();
	pmdid->AddRef();
	
	m_pmdid = pmdid;

	if (FNull())
	{
		// needed for hash computation
		m_fVal = false;
	}
}
Exemple #13
0
//---------------------------------------------------------------------------
//	@function:
//		CDatumInt4GPDB::CDatumInt4GPDB
//
//	@doc:
//		Ctor
//
//---------------------------------------------------------------------------
CDatumInt4GPDB::CDatumInt4GPDB
	(
	CSystemId sysid,
	INT iVal,
	BOOL fNull
	)
	:
	m_pmdid(NULL),
	m_iVal(iVal),
	m_fNull(fNull)
{
	CMDAccessor *pmda = COptCtxt::PoctxtFromTLS()->Pmda();
	IMDId *pmdid = dynamic_cast<const CMDTypeInt4GPDB *>(pmda->PtMDType<IMDTypeInt4>(sysid))->Pmdid();
	pmdid->AddRef();
	
	m_pmdid = pmdid;

	if (FNull())
	{
		// needed for hash computation
		m_iVal = INT_MAX;
	}
}
Exemple #14
0
//---------------------------------------------------------------------------
//	@function:
//		CDatumInt4GPDB::CDatumInt4GPDB
//
//	@doc:
//		Ctor
//
//---------------------------------------------------------------------------
CDatumInt4GPDB::CDatumInt4GPDB
	(
	CSystemId sysid,
	INT val,
	BOOL is_null
	)
	:
	m_mdid(NULL),
	m_val(val),
	m_is_null(is_null)
{
	CMDAccessor *md_accessor = COptCtxt::PoctxtFromTLS()->Pmda();
	IMDId *mdid = dynamic_cast<const CMDTypeInt4GPDB *>(md_accessor->PtMDType<IMDTypeInt4>(sysid))->MDId();
	mdid->AddRef();
	
	m_mdid = mdid;

	if (IsNull())
	{
		// needed for hash computation
		m_val = gpos::int_max;
	}
}
//---------------------------------------------------------------------------
//	@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:
//		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:
//		CXformImplementPartitionSelector::Transform
//
//	@doc:
//		Actual transformation
//
//---------------------------------------------------------------------------
void
CXformImplementPartitionSelector::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
	CLogicalPartitionSelector *popSelector = CLogicalPartitionSelector::PopConvert(pexpr->Pop());
	CExpression *pexprRelational = (*pexpr)[0];

	IMDId *pmdid = popSelector->Pmdid();

	// addref all components
	pexprRelational->AddRef();
	pmdid->AddRef();

	HMUlExpr *phmulexprFilter = GPOS_NEW(pmp) HMUlExpr(pmp);

	const ULONG ulLevels = popSelector->UlPartLevels();
	for (ULONG ul = 0; ul < ulLevels; ul++)
	{
		CExpression *pexprFilter = popSelector->PexprPartFilter(ul);
		GPOS_ASSERT(NULL != pexprFilter);
		pexprFilter->AddRef();
#ifdef GPOS_DEBUG
		BOOL fInserted =
#endif
		phmulexprFilter->FInsert(GPOS_NEW(pmp) ULONG(ul), pexprFilter);
		GPOS_ASSERT(fInserted);
	}

	// assemble physical operator
	CPhysicalPartitionSelectorDML *popPhysicalPartitionSelector =
			GPOS_NEW(pmp) CPhysicalPartitionSelectorDML
						(
						pmp,
						pmdid,
						phmulexprFilter,
						popSelector->PcrOid()
						);

	CExpression *pexprPartitionSelector =
		GPOS_NEW(pmp) CExpression
					(
					pmp,
					popPhysicalPartitionSelector,
					pexprRelational
					);

	// add alternative to results
	pxfres->Add(pexprPartitionSelector);
}
//---------------------------------------------------------------------------
//	@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);
}