Beispiel #1
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PushThruUnaryWithScalarChild
//
//	@doc:
//		Push a conjunct through a unary operator with scalar child
//
//---------------------------------------------------------------------------
void
CNormalizer::PushThruUnaryWithScalarChild
	(
	IMemoryPool *pmp,
	CExpression *pexprLogical,
	CExpression *pexprConj,
	CExpression **ppexprResult
	)
{
	GPOS_ASSERT(NULL != pexprLogical);
	GPOS_ASSERT(2 == pexprLogical->UlArity());
	GPOS_ASSERT(NULL != pexprConj);
	GPOS_ASSERT(NULL != ppexprResult);

	// get logical and scalar children
	CExpression *pexprLogicalChild = (*pexprLogical)[0];
	CExpression *pexprScalarChild = (*pexprLogical)[1];

	// push conjuncts through the logical child
	CExpression *pexprNewLogicalChild = NULL;
	DrgPexpr *pdrgpexprUnpushable = NULL;

	// break scalar expression to conjuncts
	DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprConj);

	PushThru(pmp, pexprLogicalChild, pdrgpexprConjuncts, &pexprNewLogicalChild, &pdrgpexprUnpushable);
	pdrgpexprConjuncts->Release();

	// create a new logical expression based on recursion results
	COperator *pop = pexprLogical->Pop();
	pop->AddRef();
	pexprScalarChild->AddRef();
	CExpression *pexprNewLogical = GPOS_NEW(pmp) CExpression(pmp, pop, pexprNewLogicalChild, pexprScalarChild);
	*ppexprResult = PexprSelect(pmp, pexprNewLogical, pdrgpexprUnpushable);
}
//---------------------------------------------------------------------------
//	@function:
//		CXformSubqJoin2Apply::PexprReplaceSubqueries
//
//	@doc:
//		Replace subqueries with scalar identifiers based on given map
//
//---------------------------------------------------------------------------
CExpression *
CXformSubqJoin2Apply::PexprReplaceSubqueries
	(
	IMemoryPool *mp,
	CExpression *pexprScalar,
	ExprToColRefMap *phmexprcr
	)
{
	GPOS_CHECK_STACK_SIZE;
	GPOS_ASSERT(NULL != pexprScalar);
	GPOS_ASSERT(NULL != phmexprcr);

	CColRef *colref = phmexprcr->Find(pexprScalar);
	if (NULL != colref)
	{
		// look-up succeeded on root operator, we return here
		return CUtils::PexprScalarIdent(mp, colref);
	}

	// recursively process children
	const ULONG arity = pexprScalar->Arity();
	CExpressionArray *pdrgpexprChildren = GPOS_NEW(mp) CExpressionArray(mp);
	for (ULONG ul = 0; ul < arity; ul++)
	{
		CExpression *pexprChild = PexprReplaceSubqueries(mp, (*pexprScalar)[ul], phmexprcr);
		pdrgpexprChildren->Append(pexprChild);
	}

	COperator *pop = pexprScalar->Pop();
	pop->AddRef();

	return GPOS_NEW(mp) CExpression(mp, pop, pdrgpexprChildren);
}
Beispiel #3
0
//---------------------------------------------------------------------------
//	@function:
//		CDecorrelator::FProcessMaxOneRow
//
//	@doc:
//		Decorrelate max one row operator
//
//---------------------------------------------------------------------------
BOOL
CDecorrelator::FProcessMaxOneRow
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	BOOL fEqualityOnly,
	CExpression **ppexprDecorrelated,
	DrgPexpr *pdrgpexprCorrelations
	)
{
	GPOS_ASSERT(NULL != pexpr);

	COperator *pop = pexpr->Pop();
	GPOS_ASSERT(COperator::EopLogicalMaxOneRow == pop->Eopid());

	// fail if MaxOneRow expression has outer references
	if (CUtils::FHasOuterRefs(pexpr))
	{
		return false;
	}

	// decorrelate relational child
	CExpression *pexprRelational = NULL;
	if (!FProcess(pmp, (*pexpr)[0], fEqualityOnly, &pexprRelational, pdrgpexprCorrelations))
	{
		GPOS_ASSERT(NULL == pexprRelational);
		return false;
	}

	// assemble new project
	pop->AddRef();
	*ppexprDecorrelated = GPOS_NEW(pmp) CExpression(pmp, pop, pexprRelational);

	return true;
}
Beispiel #4
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PexprNormalize
//
//	@doc:
//		Main driver
//
//---------------------------------------------------------------------------
CExpression *
CNormalizer::PexprNormalize
	(
	IMemoryPool *pmp,
	CExpression *pexpr
	)
{
	GPOS_CHECK_STACK_SIZE;
	GPOS_ASSERT(NULL != pexpr);

	if (0 == pexpr->UlArity())
	{
		// end recursion early for leaf patterns extracted from memo
		pexpr->AddRef();
		return pexpr;
	}

	CExpression *pexprResult = NULL;
	COperator *pop = pexpr->Pop();
	if (pop->FLogical() && CLogical::PopConvert(pop)->FSelectionOp())
	{
		if (FPushThruOuterChild(pexpr))
		{
			CExpression *pexprConstTrue = CUtils::PexprScalarConstBool(pmp, true /*fVal*/);
			PushThru(pmp, pexpr, pexprConstTrue, &pexprResult);
			pexprConstTrue->Release();
		}
		else
		{
			// add-ref all children except scalar predicate
			const ULONG ulArity = pexpr->UlArity();
			DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
			for (ULONG ul = 0; ul < ulArity - 1; ul++)
			{
				CExpression *pexprChild = (*pexpr)[ul];
				pexprChild->AddRef();
				pdrgpexpr->Append(pexprChild);
			}

			// normalize scalar predicate and construct a new expression
			CExpression *pexprPred = (*pexpr)[pexpr->UlArity() - 1];
			CExpression *pexprPredNormalized = PexprRecursiveNormalize(pmp, pexprPred);
			pdrgpexpr->Append(pexprPredNormalized);
			COperator *pop = pexpr->Pop();
			pop->AddRef();
			CExpression *pexprNew = GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexpr);

			// push normalized predicate through
			PushThru(pmp, pexprNew, pexprPredNormalized, &pexprResult);
			pexprNew->Release();
		}
	}
	else
	{
		pexprResult = PexprRecursiveNormalize(pmp, pexpr);
	}
	GPOS_ASSERT(NULL != pexprResult);

	return pexprResult;
}
//---------------------------------------------------------------------------
//	@function:
//		CXformGbAggWithMDQA2Join::PexprTransform
//
//	@doc:
//		Main transformation driver
//
//---------------------------------------------------------------------------
CExpression *
CXformGbAggWithMDQA2Join::PexprTransform
	(
	IMemoryPool *pmp,
	CExpression *pexpr
	)
{
	// protect against stack overflow during recursion
	GPOS_CHECK_STACK_SIZE;
	GPOS_ASSERT(NULL != pmp);
	GPOS_ASSERT(NULL != pexpr);

	COperator *pop = pexpr->Pop();
	if (COperator::EopLogicalGbAgg == pop->Eopid())
	{
		CExpression *pexprResult = PexprExpandMDQAs(pmp, pexpr);
		if (NULL != pexprResult)
		{
			return pexprResult;
		}
	}

	// recursively process child expressions
	const ULONG ulArity = pexpr->UlArity();
	DrgPexpr *pdrgpexprChildren = GPOS_NEW(pmp) DrgPexpr(pmp);
	for (ULONG ul = 0; ul < ulArity; ul++)
	{
		CExpression *pexprChild = PexprTransform(pmp, (*pexpr)[ul]);
		pdrgpexprChildren->Append(pexprChild);
	}

	pop->AddRef();
	return GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexprChildren);
}
Beispiel #6
0
//---------------------------------------------------------------------------
//	@function:
//		CDecorrelator::FProcessProject
//
//	@doc:
//		Decorrelate project/sequence project
//
//---------------------------------------------------------------------------
BOOL
CDecorrelator::FProcessProject
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	BOOL fEqualityOnly,
	CExpression **ppexprDecorrelated,
	DrgPexpr *pdrgpexprCorrelations
	)
{
	COperator::EOperatorId eopid = pexpr->Pop()->Eopid();

	GPOS_ASSERT(COperator::EopLogicalProject == eopid ||
			COperator::EopLogicalSequenceProject == eopid);

	CExpression *pexprPrjList = (*pexpr)[1];

	// fail if project elements have outer references
	CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel((*pexpr)[0]->PdpDerive())->PcrsOutput();
	CColRefSet *pcrsUsed = CDrvdPropScalar::Pdpscalar(pexprPrjList->PdpDerive())->PcrsUsed();
	if (!pcrsOutput->FSubset(pcrsUsed))
	{
		return false;
	}

	if (COperator::EopLogicalSequenceProject == eopid)
	{
		(void) pexpr->PdpDerive();
		CExpressionHandle exprhdl(pmp);
		exprhdl.Attach(pexpr);
		exprhdl.DeriveProps(NULL /*pdpctxt*/);
		if (CLogicalSequenceProject::PopConvert(pexpr->Pop())->FHasLocalOuterRefs(exprhdl))
		{
			// fail if a SequenceProject has local outer references
			return false;
		}
	}

	// decorrelate relational child
	CExpression *pexprRelational = NULL;
	if (!FProcess(pmp, (*pexpr)[0], fEqualityOnly, &pexprRelational, pdrgpexprCorrelations))
	{
		GPOS_ASSERT(NULL == pexprRelational);
		return false;
	}
	
	// assemble new project
	COperator *pop = pexpr->Pop();
	pop->AddRef();
	pexprPrjList->AddRef();
	
	*ppexprDecorrelated = GPOS_NEW(pmp) CExpression(pmp, pop, pexprRelational, pexprPrjList);
	
	return true;
}
Beispiel #7
0
//---------------------------------------------------------------------------
//	@function:
//		CBinding::PexprFinalize
//
//	@doc:
//		Assemble expression; substitute operator with pattern as necessary
//
//---------------------------------------------------------------------------
CExpression *
CBinding::PexprFinalize
	(
	IMemoryPool *pmp,
	CGroupExpression *pgexpr,
	DrgPexpr *pdrgpexpr
	)
{
	COperator *pop = pgexpr->Pop();
	
	pop->AddRef();
	CExpression *pexpr = GPOS_NEW(pmp) CExpression(pmp, pop, pgexpr, pdrgpexpr, NULL /*pstatsInput*/);
	
	return pexpr;
}
Beispiel #8
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PushThruSeqPrj
//
//	@doc:
//		Push a conjunct through a sequence project expression
//
//---------------------------------------------------------------------------
void
CNormalizer::PushThruSeqPrj
	(
	IMemoryPool *pmp,
	CExpression *pexprSeqPrj,
	CExpression *pexprConj,
	CExpression **ppexprResult
	)
{
	GPOS_ASSERT(NULL != pexprSeqPrj);
	GPOS_ASSERT(CLogical::EopLogicalSequenceProject == pexprSeqPrj->Pop()->Eopid());
	GPOS_ASSERT(NULL != pexprConj);
	GPOS_ASSERT(NULL != ppexprResult);

	// get logical and scalar children
	CExpression *pexprLogicalChild = (*pexprSeqPrj)[0];
	CExpression *pexprScalarChild = (*pexprSeqPrj)[1];

	// break scalar expression to pushable and unpushable conjuncts
	DrgPexpr *pdrgpexprPushable = NULL;
	DrgPexpr *pdrgpexprUnpushable = NULL;
	SplitConjunctForSeqPrj(pmp, pexprSeqPrj, pexprConj, &pdrgpexprPushable, &pdrgpexprUnpushable);

	CExpression *pexprNewLogicalChild = NULL;
	if (0 < pdrgpexprPushable->UlLength())
	{
		CExpression *pexprPushableConj = CPredicateUtils::PexprConjunction(pmp, pdrgpexprPushable);
		PushThru(pmp, pexprLogicalChild, pexprPushableConj, &pexprNewLogicalChild);
		pexprPushableConj->Release();
	}
	else
	{
		// no pushable predicates on top of sequence project,
		// we still need to process child recursively to push-down child's own predicates
		pdrgpexprPushable->Release();
		pexprNewLogicalChild = PexprNormalize(pmp, pexprLogicalChild);
	}

	// create a new logical expression based on recursion results
	COperator *pop = pexprSeqPrj->Pop();
	pop->AddRef();
	pexprScalarChild->AddRef();
	CExpression *pexprNewLogical = GPOS_NEW(pmp) CExpression(pmp, pop, pexprNewLogicalChild, pexprScalarChild);

	// create a select node for remaining predicates, if any
	*ppexprResult = PexprSelect(pmp, pexprNewLogical, pdrgpexprUnpushable);
}
Beispiel #9
0
//---------------------------------------------------------------------------
//	@function:
//		CDecorrelator::FProcessAssert
//
//	@doc:
//		Decorrelate assert operator
//
//---------------------------------------------------------------------------
BOOL
CDecorrelator::FProcessAssert
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	BOOL fEqualityOnly,
	CExpression **ppexprDecorrelated,
	DrgPexpr *pdrgpexprCorrelations
	)
{
	GPOS_ASSERT(NULL != pexpr);

	COperator *pop = pexpr->Pop();
	GPOS_ASSERT(COperator::EopLogicalAssert == pop->Eopid());

	CExpression *pexprScalar = (*pexpr)[1];

	// fail if assert expression has outer references
	CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel((*pexpr)[0]->PdpDerive())->PcrsOutput();
	CColRefSet *pcrsUsed = CDrvdPropScalar::Pdpscalar(pexprScalar->PdpDerive())->PcrsUsed();
	if (!pcrsOutput->FSubset(pcrsUsed))
	{
		return false;
	}

	// decorrelate relational child
	CExpression *pexprRelational = NULL;
	if (!FProcess(pmp, (*pexpr)[0], fEqualityOnly, &pexprRelational, pdrgpexprCorrelations))
	{
		GPOS_ASSERT(NULL == pexprRelational);
		return false;
	}

	// assemble new project
	pop->AddRef();
	pexprScalar->AddRef();
	*ppexprDecorrelated = GPOS_NEW(pmp) CExpression(pmp, pop, pexprRelational, pexprScalar);

	return true;
}
Beispiel #10
0
//---------------------------------------------------------------------------
//	@function:
//		CDecorrelator::FProcessLimit
//
//	@doc:
//		Decorrelate limit
//
//---------------------------------------------------------------------------
BOOL
CDecorrelator::FProcessLimit
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	BOOL fEqualityOnly,
	CExpression **ppexprDecorrelated,
	DrgPexpr *pdrgpexprCorrelations
	)
{
	GPOS_ASSERT(COperator::EopLogicalLimit == pexpr->Pop()->Eopid());

	CExpression *pexprOffset = (*pexpr)[1];
	CExpression *pexprRowCount = (*pexpr)[2];

	// fail if there are any outer references below Limit
	if (CUtils::FHasOuterRefs(pexpr))
	{
		return false;
	}

	// decorrelate relational child
	CExpression *pexprRelational = NULL;
	if (!FProcess(pmp, (*pexpr)[0], fEqualityOnly, &pexprRelational, pdrgpexprCorrelations))
	{
		GPOS_ASSERT(NULL == pexprRelational);
		return false;
	}

	// assemble new project
	COperator *pop = pexpr->Pop();
	pop->AddRef();
	pexprOffset->AddRef();
	pexprRowCount->AddRef();

	*ppexprDecorrelated = GPOS_NEW(pmp) CExpression(pmp, pop, pexprRelational, pexprOffset, pexprRowCount);

	return true;
}
Beispiel #11
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PexprRecursiveNormalize
//
//	@doc:
//		Call normalizer recursively on children array
//
//
//---------------------------------------------------------------------------
CExpression *
CNormalizer::PexprRecursiveNormalize
	(
	IMemoryPool *pmp,
	CExpression *pexpr
	)
{
	GPOS_ASSERT(NULL != pexpr);

	const ULONG ulArity = pexpr->UlArity();
	DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
	for (ULONG ul = 0; ul < ulArity; ul++)
	{
		CExpression *pexprChild = PexprNormalize(pmp, (*pexpr)[ul]);
		pdrgpexpr->Append(pexprChild);
	}

	COperator *pop = pexpr->Pop();
	pop->AddRef();

	return GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexpr);
}
Beispiel #12
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PushThruJoin
//
//	@doc:
//		Push a conjunct through a join
//
//
//---------------------------------------------------------------------------
void
CNormalizer::PushThruJoin
	(
	IMemoryPool *pmp,
	CExpression *pexprJoin,
	CExpression *pexprConj,
	CExpression **ppexprResult
	)
{
	GPOS_ASSERT(NULL != pexprConj);
	GPOS_ASSERT(NULL != ppexprResult);

	COperator *pop = pexprJoin->Pop();
	const ULONG ulArity = pexprJoin->UlArity();
	BOOL fLASApply = CUtils::FLeftAntiSemiApply(pop);
	COperator::EOperatorId eopid = pop->Eopid();
	BOOL fOuterJoin =
		COperator::EopLogicalLeftOuterJoin == eopid ||
		COperator::EopLogicalLeftOuterApply == eopid ||
		COperator::EopLogicalLeftOuterCorrelatedApply == eopid;

	if (fOuterJoin && !CUtils::FScalarConstTrue(pexprConj))
	{
		// whenever possible, push incoming predicate through outer join's outer child,
		// recursion will eventually reach the rest of PushThruJoin() to process join predicates
		PushThruOuterChild(pmp, pexprJoin, pexprConj, ppexprResult);

		return;
	}

	// combine conjunct with join predicate
	CExpression *pexprScalar = (*pexprJoin)[ulArity - 1];
	CExpression *pexprPred =  CPredicateUtils::PexprConjunction(pmp, pexprScalar, pexprConj);

	// break predicate to conjuncts
	DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprPred);
	pexprPred->Release();

	// push predicates through children and compute new child expressions
	DrgPexpr *pdrgpexprChildren =  GPOS_NEW(pmp) DrgPexpr(pmp);

	for (ULONG ul = 0; ul < ulArity - 1; ul++)
	{
		CExpression *pexprChild = (*pexprJoin)[ul];
		CExpression *pexprNewChild = NULL;
		if (fLASApply)
		{
			// do not push anti-semi-apply predicates to any of the children
			pexprNewChild = PexprNormalize(pmp, pexprChild);
			pdrgpexprChildren->Append(pexprNewChild);
			continue;
		}

		if (0 == ul && fOuterJoin)
		{
			// do not push outer join predicates through outer child
			// otherwise, we will throw away outer child's tuples that should
			// be part of the join result
			pexprNewChild = PexprNormalize(pmp, pexprChild);
			pdrgpexprChildren->Append(pexprNewChild);
			continue;
		}

		DrgPexpr *pdrgpexprRemaining = NULL;
		PushThru(pmp, pexprChild, pdrgpexprConjuncts, &pexprNewChild, &pdrgpexprRemaining);
		pdrgpexprChildren->Append(pexprNewChild);

		pdrgpexprConjuncts->Release();
		pdrgpexprConjuncts = pdrgpexprRemaining;
	}

	// remaining conjuncts become the new join predicate
	CExpression *pexprNewScalar = CPredicateUtils::PexprConjunction(pmp, pdrgpexprConjuncts);
	pdrgpexprChildren->Append(pexprNewScalar);

	// create a new join expression
	pop->AddRef();
	*ppexprResult = GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexprChildren);
}
Beispiel #13
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PushThruOuterChild
//
//	@doc:
//		Push scalar expression through left outer join children;
//		this only handles the case of a SELECT on top of LEFT OUTER JOIN;
//		pushing down join predicates is handled in PushThruJoin();
//		here, we push predicates of the top SELECT node through LEFT OUTER JOIN's
//		outer child
//
//---------------------------------------------------------------------------
void
CNormalizer::PushThruOuterChild
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	CExpression *pexprConj,
	CExpression **ppexprResult
	)
{
	GPOS_ASSERT(NULL != pexpr);
	GPOS_ASSERT(FPushThruOuterChild(pexpr));
	GPOS_ASSERT(NULL != pexprConj);
	GPOS_ASSERT(NULL != ppexprResult);

	if (0 == pexpr->UlArity())
	{
		// end recursion early for leaf patterns extracted from memo
		pexpr->AddRef();
		pexprConj->AddRef();
		*ppexprResult = CUtils::PexprSafeSelect(pmp, pexpr, pexprConj);

		return;
	}

	CExpression *pexprOuter = (*pexpr)[0];
	CExpression *pexprInner = (*pexpr)[1];
	CExpression *pexprPred = (*pexpr)[2];

	DrgPexpr *pdrgpexprPushable = NULL;
	DrgPexpr *pdrgpexprUnpushable = NULL;
	SplitConjunct(pmp, pexprOuter, pexprConj, &pdrgpexprPushable, &pdrgpexprUnpushable);

	if (0 < pdrgpexprPushable->UlLength())
	{
		pdrgpexprPushable->AddRef();
		CExpression *pexprNewConj = CPredicateUtils::PexprConjunction(pmp, pdrgpexprPushable);

		// create a new select node on top of the outer child
		pexprOuter->AddRef();
		CExpression *pexprNewSelect =
			GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CLogicalSelect(pmp), pexprOuter, pexprNewConj);

		// push predicate through the new select to create a new outer child
		CExpression *pexprNewOuter = NULL;
		PushThru(pmp, pexprNewSelect, pexprNewConj, &pexprNewOuter);
		pexprNewSelect->Release();

		// create a new outer join using the new outer child and the new inner child
		COperator *pop = pexpr->Pop();
		pop->AddRef();
		pexprInner->AddRef();
		pexprPred->AddRef();
		CExpression *pexprNew = GPOS_NEW(pmp) CExpression(pmp, pop, pexprNewOuter, pexprInner, pexprPred);

		// call push down predicates on the new outer join
		CExpression *pexprConstTrue = CUtils::PexprScalarConstBool(pmp, true /*fVal*/);
		PushThru(pmp, pexprNew, pexprConstTrue, ppexprResult);
		pexprConstTrue->Release();
		pexprNew->Release();
	}

	if (0 < pdrgpexprUnpushable->UlLength())
	{
		CExpression *pexprOuterJoin = pexpr;
		if (0 < pdrgpexprPushable->UlLength())
		{
			pexprOuterJoin = *ppexprResult;
			GPOS_ASSERT(NULL != pexprOuterJoin);
		}

		// call push down on the outer join predicates
		CExpression *pexprNew = NULL;
		CExpression *pexprConstTrue = CUtils::PexprScalarConstBool(pmp, true /*fVal*/);
		PushThru(pmp, pexprOuterJoin, pexprConstTrue, &pexprNew);
		if (pexprOuterJoin != pexpr)
		{
			pexprOuterJoin->Release();
		}
		pexprConstTrue->Release();

		// create a SELECT on top of the new outer join
		pdrgpexprUnpushable->AddRef();
		*ppexprResult = PexprSelect(pmp, pexprNew, pdrgpexprUnpushable);
	}

	pdrgpexprPushable->Release();
	pdrgpexprUnpushable->Release();
}
Beispiel #14
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PexprPullUpAndCombineProjects
//
//	@doc:
//		Pulls up logical projects as far as possible, and combines consecutive
//		projects if possible
//
//---------------------------------------------------------------------------
CExpression *
CNormalizer::PexprPullUpAndCombineProjects
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	BOOL *pfSuccess		// output to indicate whether anything was pulled up
	)
{
	GPOS_ASSERT(NULL != pexpr);
	GPOS_ASSERT(NULL != pfSuccess);

	COperator *pop = pexpr->Pop();
	const ULONG ulArity = pexpr->UlArity();
	if (!pop->FLogical() || 0 == ulArity)
	{
		pexpr->AddRef();
		return pexpr;
	}

	DrgPexpr *pdrgpexprChildren = GPOS_NEW(pmp) DrgPexpr(pmp);
	DrgPexpr *pdrgpexprPrElPullUp = GPOS_NEW(pmp) DrgPexpr(pmp);
	CExpressionHandle exprhdl(pmp);
	exprhdl.Attach(pexpr);

	CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel(pexpr->PdpDerive())->PcrsOutput();

	// extract the columns used by the scalar expression and the operator itself (for grouping, sorting, etc.)
	CColRefSet *pcrsUsed = exprhdl.PcrsUsedColumns(pmp);
	for (ULONG ul = 0; ul < ulArity; ul++)
	{
		CExpression *pexprChild = PexprPullUpAndCombineProjects(pmp, (*pexpr)[ul], pfSuccess);
		if (pop->FLogical() && CLogical::PopConvert(pop)->FCanPullProjectionsUp(ul) &&
			COperator::EopLogicalProject == pexprChild->Pop()->Eopid())
		{
			// this child is a project - see if any project elements can be pulled up
			CExpression *pexprNewChild = PexprPullUpProjectElements
											(
											pmp,
											pexprChild,
											pcrsUsed,
											pcrsOutput,
											&pdrgpexprPrElPullUp
											);

			pexprChild->Release();
			pexprChild = pexprNewChild;
		}

		pdrgpexprChildren->Append(pexprChild);
	}

	pcrsUsed->Release();
	pop->AddRef();

	if (0 < pdrgpexprPrElPullUp->UlLength() && COperator::EopLogicalProject == pop->Eopid())
	{
		// some project elements have been pulled up and the original expression
		// was a project - combine its project list with the pulled up project elements
		GPOS_ASSERT(2 == pdrgpexprChildren->UlLength());
		*pfSuccess = true;
		CExpression *pexprRelational = (*pdrgpexprChildren)[0];
		CExpression *pexprPrLOld = (*pdrgpexprChildren)[1];
		pexprRelational->AddRef();

		CUtils::AddRefAppend(pdrgpexprPrElPullUp, pexprPrLOld->PdrgPexpr());
		pdrgpexprChildren->Release();
		CExpression *pexprPrjList = GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CScalarProjectList(pmp), pdrgpexprPrElPullUp);
		GPOS_ASSERT(CDrvdPropRelational::Pdprel(pexprRelational->PdpDerive())->PcrsOutput()->FSubset(CDrvdPropScalar::Pdpscalar(pexprPrjList->PdpDerive())->PcrsUsed()));

		return GPOS_NEW(pmp) CExpression(pmp, pop, pexprRelational, pexprPrjList);
	}

	CExpression *pexprOutput = GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexprChildren);

	if (0 == pdrgpexprPrElPullUp->UlLength())
	{
		// no project elements were pulled up
		pdrgpexprPrElPullUp->Release();
		return pexprOutput;
	}

	// some project elements were pulled - add a project on top of output expression
	*pfSuccess = true;
	CExpression *pexprPrjList = GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CScalarProjectList(pmp), pdrgpexprPrElPullUp);
	GPOS_ASSERT(CDrvdPropRelational::Pdprel(pexprOutput->PdpDerive())->PcrsOutput()->FSubset(CDrvdPropScalar::Pdpscalar(pexprPrjList->PdpDerive())->PcrsUsed()));

	return GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CLogicalProject(pmp), pexprOutput, pexprPrjList);
}
Beispiel #15
0
//---------------------------------------------------------------------------
//	@function:
//		CXformSubqJoin2Apply::PexprSubqueryPushdown
//
//	@doc:
//		Push down subquery below join
//
//---------------------------------------------------------------------------
CExpression *
CXformSubqJoin2Apply::PexprSubqueryPushDown
	(
	IMemoryPool *mp,
	CExpression *pexpr,
	BOOL fEnforceCorrelatedApply
	)
{
	GPOS_ASSERT(NULL != pexpr);
	GPOS_ASSERT(COperator::EopLogicalSelect == pexpr->Pop()->Eopid());

	CExpression *pexprJoin = (*pexpr)[0];
	const ULONG arity = pexprJoin->Arity();
	CExpression *pexprScalar = (*pexpr)[1];
	CExpression *join_pred_expr = (*pexprJoin)[arity - 1];

	// collect output columns of all logical children
	CColRefSetArray *pdrgpcrs = GPOS_NEW(mp) CColRefSetArray(mp);
	CExpressionArrays *pdrgpdrgpexprSubqs = GPOS_NEW(mp) CExpressionArrays(mp);
	for (ULONG ul = 0; ul < arity - 1; ul++)
	{
		CExpression *pexprChild = (*pexprJoin)[ul];
		CColRefSet *pcrsOutput = CDrvdPropRelational::GetRelationalProperties(pexprChild->PdpDerive())->PcrsOutput();
		pcrsOutput->AddRef();
		pdrgpcrs->Append(pcrsOutput);

		pdrgpdrgpexprSubqs->Append(GPOS_NEW(mp) CExpressionArray(mp));
	}

	// collect subqueries that exclusively use columns from each join child
	CollectSubqueries(mp, pexprScalar, pdrgpcrs, pdrgpdrgpexprSubqs);

	// create new join children by pushing subqueries to Project nodes on top
	// of corresponding join children
	CExpressionArray *pdrgpexprNewChildren = GPOS_NEW(mp) CExpressionArray(mp);
	ExprToColRefMap *phmexprcr = GPOS_NEW(mp) ExprToColRefMap(mp);
	for (ULONG ulChild = 0; ulChild < arity - 1; ulChild++)
	{
		CExpression *pexprChild = (*pexprJoin)[ulChild];
		pexprChild->AddRef();
		CExpression *pexprNewChild = pexprChild;

		CExpressionArray *pdrgpexprSubqs = (*pdrgpdrgpexprSubqs)[ulChild];
		const ULONG ulSubqs = pdrgpexprSubqs->Size();
		if (0 < ulSubqs)
		{
			// join child has pushable subqueries
			pexprNewChild = CUtils::PexprAddProjection(mp, pexprChild, pdrgpexprSubqs);
			CExpression *pexprPrjList = (*pexprNewChild)[1];

			// add pushed subqueries to map
			for (ULONG ulSubq = 0; ulSubq < ulSubqs; ulSubq++)
			{
				CExpression *pexprSubq = (*pdrgpexprSubqs)[ulSubq];
				pexprSubq->AddRef();
				CColRef *colref = CScalarProjectElement::PopConvert((*pexprPrjList)[ulSubq]->Pop())->Pcr();
	#ifdef GPOS_DEBUG
				BOOL fInserted =
	#endif // GPOS_DEBUG
					phmexprcr->Insert(pexprSubq, colref);
				GPOS_ASSERT(fInserted);
			}

			// unnest subqueries in newly created child
			CExpression *pexprUnnested = PexprSubqueryUnnest(mp, pexprNewChild, fEnforceCorrelatedApply);
			if (NULL != pexprUnnested)
			{
				pexprNewChild->Release();
				pexprNewChild = pexprUnnested;
			}
		}

		pdrgpexprNewChildren->Append(pexprNewChild);
	}

	join_pred_expr->AddRef();
	pdrgpexprNewChildren->Append(join_pred_expr);

	// replace subqueries in the original scalar expression with
	// scalar identifiers based on constructed map
	CExpression *pexprNewScalar = PexprReplaceSubqueries(mp, pexprScalar, phmexprcr);

	phmexprcr->Release();
	pdrgpcrs->Release();
	pdrgpdrgpexprSubqs->Release();

	// build the new join expression
	COperator *pop = pexprJoin->Pop();
	pop->AddRef();
	CExpression *pexprNewJoin = GPOS_NEW(mp) CExpression(mp, pop, pdrgpexprNewChildren);

	// return a new Select expression
	pop = pexpr->Pop();
	pop->AddRef();
	return GPOS_NEW(mp) CExpression(mp, pop, pexprNewJoin, pexprNewScalar);
}
Beispiel #16
0
//---------------------------------------------------------------------------
//	@function:
//		CDecorrelator::FProcessJoin
//
//	@doc:
//		Decorrelate a join expression;
//
//---------------------------------------------------------------------------
BOOL
CDecorrelator::FProcessJoin
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	BOOL fEqualityOnly,
	CExpression **ppexprDecorrelated,
	DrgPexpr *pdrgpexprCorrelations
	)
{
	GPOS_ASSERT(CUtils::FLogicalJoin(pexpr->Pop()) || CUtils::FApply(pexpr->Pop()));

	ULONG ulArity = pexpr->UlArity();	
	DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp, ulArity);
	CColRefSet *pcrsOutput = GPOS_NEW(pmp) CColRefSet(pmp);

	// decorrelate all relational children
	for (ULONG ul = 0; ul < ulArity - 1; ul++)
	{
		CExpression *pexprInput = NULL;
		if (FProcess(pmp, (*pexpr)[ul], fEqualityOnly, &pexprInput, pdrgpexprCorrelations))
		{
			pdrgpexpr->Append(pexprInput);
			pcrsOutput->Union(CDrvdPropRelational::Pdprel(pexprInput->PdpDerive())->PcrsOutput());
		}
		else
		{
			pdrgpexpr->Release();
			pcrsOutput->Release();
			
			return false;
		}
	}

	// check for valid semi join correlations
	if (!FPullableCorrelations(pmp, pexpr, pdrgpexpr, pdrgpexprCorrelations))
	{
		pdrgpexpr->Release();
		pcrsOutput->Release();

		return false;
	 }

	// decorrelate predicate and build new join operator
	CExpression *pexprPredicate = NULL;
	BOOL fSuccess = FProcessPredicate(pmp, pexpr, (*pexpr)[ulArity - 1], fEqualityOnly, pcrsOutput, &pexprPredicate, pdrgpexprCorrelations);
	pcrsOutput->Release();

	if (fSuccess)
	{
		// in case entire predicate is being deferred, plug in a 'true'
		if (NULL == pexprPredicate)
		{
			pexprPredicate = CUtils::PexprScalarConstBool(pmp, true /*fVal*/);
		}
		
		pdrgpexpr->Append(pexprPredicate);
		
		COperator *pop = pexpr->Pop();
		pop->AddRef();
		*ppexprDecorrelated = GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexpr);
	}
	else
	{
		pdrgpexpr->Release();
		CRefCount::SafeRelease(pexprPredicate);
	}
	
	return fSuccess;
}
Beispiel #17
0
// results:
// decorrelated expression, ppexprDecorrelated
//     +--CLogicalSequenceProject
//        |--CLogicalGet "b" ("b"), Columns: [...]
//        +--CScalarProjectList   origin: [Grp:8, GrpExpr:0]
//           +--CScalarProjectElement "avg" (18)   origin: [Grp:7, GrpExpr:0]
//              +--CScalarWindowFunc (avg , Agg: true , Distinct: false , StarArgument: false , SimpleAgg: true)   origin: [Grp:6, GrpExpr:0]
//              +--CScalarIdent "i" (9)   origin: [Grp:3, GrpExpr:0]
// array of quals
// pdrgpexprCorrelations
//         +--CScalarCmp (=)   origin: [Grp:4, GrpExpr:0]
//            |--CScalarIdent "i" (0)   origin: [Grp:2, GrpExpr:0]
//            +--CScalarIdent "i" (9)   origin: [Grp:3, GrpExpr:0]
// clang-format on
BOOL
CDecorrelator::FProcessProject
	(
	IMemoryPool *mp,
	CExpression *pexpr,
	BOOL fEqualityOnly,
	CExpression **ppexprDecorrelated,
	CExpressionArray *pdrgpexprCorrelations
	)
{
	COperator::EOperatorId op_id = pexpr->Pop()->Eopid();

	GPOS_ASSERT(COperator::EopLogicalProject == op_id ||
			COperator::EopLogicalSequenceProject == op_id);

	CExpression *pexprPrjList = (*pexpr)[1];

	// fail if project elements have outer references
	CColRefSet *pcrsOutput = CDrvdPropRelational::GetRelationalProperties((*pexpr)[0]->PdpDerive())->PcrsOutput();
	CColRefSet *pcrsUsed = CDrvdPropScalar::GetDrvdScalarProps(pexprPrjList->PdpDerive())->PcrsUsed();
	if (!pcrsOutput->ContainsAll(pcrsUsed))
	{
		return false;
	}

	if (COperator::EopLogicalSequenceProject == op_id)
	{
		(void) pexpr->PdpDerive();
		CExpressionHandle exprhdl(mp);
		exprhdl.Attach(pexpr);
		exprhdl.DeriveProps(NULL /*pdpctxt*/);
		
		// fail decorrelation in the following two cases;
		// 1. if the LogicalSequenceProject node has local outer references in order by or partition by or window frame
		// of a window function
		// ex: select C.j from C where C.i in (select rank() over (order by C.i) from B where B.i=C.i);
		// 2. if the relational child of LogicalSequenceProject node does not have any aggregate window function

		// if the project list contains aggregrate on window function, then
		// we can decorrelate it as the aggregate is performed over a column or count(*).
		// The IN condition will be translated to a join instead of a correlated plan.
		// ex: select C.j from C where C.i in (select avg(i) over (partition by B.i) from B where B.i=C.i);
		// ===> (resulting join condition) b.i = c.i and c.i = avg(i)
		if (CLogicalSequenceProject::PopConvert(pexpr->Pop())->FHasLocalOuterRefs(exprhdl)
			|| !CUtils::FHasAggWindowFunc(pexprPrjList))
		{
			return false;
		}
	}

	// decorrelate relational child
	CExpression *pexprRelational = NULL;
	if (!FProcess(mp, (*pexpr)[0], fEqualityOnly, &pexprRelational, pdrgpexprCorrelations))
	{
		GPOS_ASSERT(NULL == pexprRelational);
		return false;
	}
	
	// assemble new project
	COperator *pop = pexpr->Pop();
	pop->AddRef();
	pexprPrjList->AddRef();
	
	*ppexprDecorrelated = GPOS_NEW(mp) CExpression(mp, pop, pexprRelational, pexprPrjList);
	
	return true;
}