//---------------------------------------------------------------------------
//	@function:
//		CGroupExpression::FCostContextExists
//
//	@doc:
//		Check if cost context already exists in group expression hash table
//
//---------------------------------------------------------------------------
BOOL
CGroupExpression::FCostContextExists
	(
	COptimizationContext *poc,
	DrgPoc *pdrgpoc
	)
{
	GPOS_ASSERT(NULL != poc);

	// lookup context based on required properties
	CCostContext *pccFound = NULL;
	{
		ShtAcc shta(Sht(), poc);
		pccFound = shta.PtLookup();
	}

	while (NULL != pccFound)
	{
		if (COptimizationContext::FEqualContextIds(pdrgpoc, pccFound->Pdrgpoc()))
		{
			// a cost context, matching required properties and child contexts, was already created
			return true;
		}

		{
			ShtAcc shta(Sht(), poc);
			pccFound = shta.PtNext(pccFound);
		}
	}

	return false;
}
//---------------------------------------------------------------------------
//	@function:
//		COptimizationContext::PrppCTEProducer
//
//	@doc:
//		Compute required properties to CTE producer based on plan properties
//		of CTE consumer
//
//---------------------------------------------------------------------------
CReqdPropPlan *
COptimizationContext::PrppCTEProducer
	(
	IMemoryPool *mp,
	COptimizationContext *poc,
	ULONG ulSearchStages
	)
{
	GPOS_ASSERT(NULL != poc);
	GPOS_ASSERT(NULL != poc->PccBest());

	CCostContext *pccBest = poc->PccBest();
	CGroupExpression *pgexpr = pccBest->Pgexpr();
	BOOL fOptimizeCTESequence =
			(
			COperator::EopPhysicalSequence == pgexpr->Pop()->Eopid() &&
			(*pgexpr)[0]->FHasCTEProducer()
			);

	if (!fOptimizeCTESequence)
	{
		// best group expression is not a CTE sequence
		return NULL;
	}

	COptimizationContext *pocProducer = (*pgexpr)[0]->PocLookupBest(mp, ulSearchStages, (*pccBest->Pdrgpoc())[0]->Prpp());
	if (NULL == pocProducer)
	{
		return NULL;
	}

	CCostContext *pccProducer = pocProducer->PccBest();
	if (NULL == pccProducer)
	{
		return NULL;
	}
	COptimizationContext *pocConsumer = (*pgexpr)[1]->PocLookupBest(mp, ulSearchStages, (*pccBest->Pdrgpoc())[1]->Prpp());
	if (NULL == pocConsumer)
	{
		return NULL;
	}

	CCostContext *pccConsumer = pocConsumer->PccBest();
	if (NULL == pccConsumer)
	{
		return NULL;
	}

	CColRefSet *pcrsInnerOutput = CDrvdPropRelational::GetRelationalProperties((*pgexpr)[1]->Pdp())->PcrsOutput();
	CPhysicalCTEProducer *popProducer = CPhysicalCTEProducer::PopConvert(pccProducer->Pgexpr()->Pop());
	UlongToColRefMap *colref_mapping = COptCtxt::PoctxtFromTLS()->Pcteinfo()->PhmulcrConsumerToProducer(mp, popProducer->UlCTEId(), pcrsInnerOutput, popProducer->Pdrgpcr());
	CReqdPropPlan *prppProducer = CReqdPropPlan::PrppRemap(mp, pocProducer->Prpp(), pccConsumer->Pdpplan(), colref_mapping);
	colref_mapping->Release();

	if (prppProducer->Equals(pocProducer->Prpp()))
	{
		prppProducer->Release();

		return NULL;
	}

	return prppProducer;
}