Example #1
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;
}
Example #2
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalPartitionSelector::PexprCombinedPartPred
//
//	@doc:
//		Return a single combined partition selection predicate
//
//---------------------------------------------------------------------------
CExpression *
CPhysicalPartitionSelector::PexprCombinedPartPred
	(
	IMemoryPool *pmp
	)
	const
{
	DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);

	const ULONG ulLevels = UlPartLevels();
	for (ULONG ul = 0; ul < ulLevels; ul++)
	{
		CExpression *pexpr = PexprPartPred(pmp, ul);
		if (NULL != pexpr)
		{
			pdrgpexpr->Append(pexpr);
		}
	}

	if (NULL != m_pexprResidual)
	{
		m_pexprResidual->AddRef();
		pdrgpexpr->Append(m_pexprResidual);
	}

	return CPredicateUtils::PexprConjunction(pmp, pdrgpexpr);
}
Example #3
0
//---------------------------------------------------------------------------
//	@function:
//		CConstraint::PexprScalarConjDisj
//
//	@doc:
//		Construct a conjunction or disjunction scalar expression from an
//		array of constraints
//
//---------------------------------------------------------------------------
CExpression *
CConstraint::PexprScalarConjDisj
(
    IMemoryPool *pmp,
    DrgPcnstr *pdrgpcnstr,
    BOOL fConj
)
const
{
    DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);

    const ULONG ulLen = pdrgpcnstr->UlLength();
    for (ULONG ul = 0; ul < ulLen; ul++)
    {
        CExpression *pexpr = (*pdrgpcnstr)[ul]->PexprScalar(pmp);
        pexpr->AddRef();
        pdrgpexpr->Append(pexpr);
    }

    if (fConj)
    {
        return CPredicateUtils::PexprConjunction(pmp, pdrgpexpr);
    }

    return CPredicateUtils::PexprDisjunction(pmp, pdrgpexpr);
}
CHashedDistributions::CHashedDistributions
		(
		IMemoryPool *pmp,
		DrgPcr *pdrgpcrOutput,
		DrgDrgPcr *pdrgpdrgpcrInput
		)
		:
		DrgPds(pmp)
{
	const ULONG ulCols = pdrgpcrOutput->UlLength();
	const ULONG ulArity = pdrgpdrgpcrInput->UlLength();
	for (ULONG ulChild = 0; ulChild < ulArity; ulChild++)
	{
		DrgPcr *pdrgpcr = (*pdrgpdrgpcrInput)[ulChild];
		DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
		for (ULONG ulCol = 0; ulCol < ulCols; ulCol++)
		{
			CColRef *pcr = (*pdrgpcr)[ulCol];
			CExpression *pexpr = CUtils::PexprScalarIdent(pmp, pcr);
			pdrgpexpr->Append(pexpr);
		}

		// create a hashed distribution on input columns of the current child
		BOOL fNullsColocated = true;
		CDistributionSpec *pdshashed = GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, fNullsColocated);
		Append(pdshashed);
	}
}
Example #5
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalUnionAll::PdsMatching
//
//	@doc:
//		Compute output hashed distribution based on the outer child's
//		hashed distribution
//---------------------------------------------------------------------------
CDistributionSpecHashed *
CPhysicalUnionAll::PdsMatching
	(
	IMemoryPool *pmp,
	const DrgPul *pdrgpulOuter
	)
	const
{
	GPOS_ASSERT(NULL != pdrgpulOuter);

	const ULONG ulCols = pdrgpulOuter->UlLength();

	GPOS_ASSERT(ulCols <= m_pdrgpcrOutput->UlLength());

	DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
	for (ULONG ulCol = 0; ulCol < ulCols; ulCol++)
	{
		ULONG ulIdx = *(*pdrgpulOuter)[ulCol];
		CExpression *pexpr = CUtils::PexprScalarIdent(pmp, (*m_pdrgpcrOutput)[ulIdx]);
		pdrgpexpr->Append(pexpr);
	}

	GPOS_ASSERT(0 < pdrgpexpr->UlLength());

	return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, true /*fNullsColocated*/);
}
Example #6
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PushThruSetOp
//
//	@doc:
//		Push a conjunct through set operation
//
//---------------------------------------------------------------------------
void
CNormalizer::PushThruSetOp
	(
	IMemoryPool *pmp,
	CExpression *pexprSetOp,
	CExpression *pexprConj,
	CExpression **ppexprResult
	)
{
	GPOS_ASSERT(NULL != pexprSetOp);
	GPOS_ASSERT(CUtils::FLogicalSetOp(pexprSetOp->Pop()));
	GPOS_ASSERT(NULL != pexprConj);
	GPOS_ASSERT(NULL != ppexprResult);

	CLogicalSetOp *popSetOp = CLogicalSetOp::PopConvert(pexprSetOp->Pop());
	DrgPcr *pdrgpcrOutput = popSetOp->PdrgpcrOutput();
	CColRefSet *pcrsOutput = GPOS_NEW(pmp) CColRefSet(pmp, pdrgpcrOutput);
	DrgDrgPcr *pdrgpdrgpcrInput = popSetOp->PdrgpdrgpcrInput();
	DrgPexpr *pdrgpexprNewChildren = GPOS_NEW(pmp) DrgPexpr(pmp);
	const ULONG ulArity = pexprSetOp->UlArity();
	for (ULONG ul = 0; ul < ulArity; ul++)
	{
		CExpression *pexprChild = (*pexprSetOp)[ul];
		DrgPcr *pdrgpcrChild = (*pdrgpdrgpcrInput)[ul];
		CColRefSet *pcrsChild =  GPOS_NEW(pmp) CColRefSet(pmp, pdrgpcrChild);

		pexprConj->AddRef();
		CExpression *pexprRemappedConj = pexprConj;
		if (!pcrsChild->FEqual(pcrsOutput))
		{
			// child columns are different from SetOp output columns,
			// we need to fix conjunct by mapping output columns to child columns,
			// columns that are not in the output of SetOp child need also to be re-mapped
			// to new columns,
			//
			// for example, if the conjunct looks like 'x > (select max(y) from T)'
			// and the SetOp child produces only column x, we need to create a new
			// conjunct that looks like 'x1 > (select max(y1) from T)'
			// where x1 is a copy of x, and y1 is a copy of y
			//
			// this is achieved by passing (fMustExist = True) flag below, which enforces
			// creating column copies for columns not already in the given map
			HMUlCr *phmulcr = CUtils::PhmulcrMapping(pmp, pdrgpcrOutput, pdrgpcrChild);
			pexprRemappedConj->Release();
			pexprRemappedConj = pexprConj->PexprCopyWithRemappedColumns(pmp, phmulcr, true /*fMustExist*/);
			phmulcr->Release();
		}

		CExpression *pexprNewChild = NULL;
		PushThru(pmp, pexprChild, pexprRemappedConj, &pexprNewChild);
		pdrgpexprNewChildren->Append(pexprNewChild);

		pexprRemappedConj->Release();
		pcrsChild->Release();
	}

	pcrsOutput->Release();
	popSetOp->AddRef();
	*ppexprResult = GPOS_NEW(pmp) CExpression(pmp, popSetOp, pdrgpexprNewChildren);
}
Example #7
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalUnionAll::BuildHashedDistributions
//
//	@doc:
//		Build hashed distributions used locally during distribution derivation,
//
//		the function builds an array of hashed distribution on input column
//		of each child, and an output hashed distribution on UnionAll output
//		columns
//
//
//---------------------------------------------------------------------------
void
CPhysicalUnionAll::BuildHashedDistributions
	(
	IMemoryPool *pmp
	)
{
	GPOS_ASSERT(NULL == m_pdrgpds);

	m_pdrgpds = GPOS_NEW(pmp) DrgPds(pmp);
	const ULONG ulCols = m_pdrgpcrOutput->UlLength();
	const ULONG ulArity = m_pdrgpdrgpcrInput->UlLength();
	for (ULONG ulChild = 0; ulChild < ulArity; ulChild++)
	{
		DrgPcr *pdrgpcr = (*m_pdrgpdrgpcrInput)[ulChild];
		DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
		for (ULONG ulCol = 0; ulCol < ulCols; ulCol++)
		{
			CExpression *pexpr = CUtils::PexprScalarIdent(pmp, (*pdrgpcr)[ulCol]);
			pdrgpexpr->Append(pexpr);
		}

		// create a hashed distribution on input columns of the current child
		CDistributionSpecHashed *pdshashed = GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, true /*fNullsColocated*/);
		m_pdrgpds->Append(pdshashed);
	}
}
Example #8
0
//---------------------------------------------------------------------------
//	@function:
//		CCNFConverter::Pdrgpdrgpexpr
//
//	@doc:
//		Create an array of arrays each holding the children of an expression
//		from the given array
//
//
//---------------------------------------------------------------------------
DrgPdrgPexpr *
CCNFConverter::Pdrgpdrgpexpr
	(
	IMemoryPool *pmp,
	DrgPexpr *pdrgpexpr
	)
{
	GPOS_ASSERT(NULL != pmp);
	GPOS_ASSERT(NULL != pdrgpexpr);

	DrgPdrgPexpr *pdrgpdrgpexpr = GPOS_NEW(pmp) DrgPdrgPexpr(pmp);
	const ULONG ulArity = pdrgpexpr->UlLength();
	for (ULONG ul = 0; ul < ulArity; ul++)
	{
		CExpression *pexpr = (*pdrgpexpr)[ul];
		DrgPexpr *pdrgpexprChild = NULL;

		if (CPredicateUtils::FAnd(pexpr))
		{
			pdrgpexprChild = pexpr->PdrgPexpr();
			pdrgpexprChild->AddRef();
		}
		else
		{
			pdrgpexprChild = GPOS_NEW(pmp) DrgPexpr(pmp);
			pexpr->AddRef();
			pdrgpexprChild->Append(pexpr);
		}
		pdrgpdrgpexpr->Append(pdrgpexprChild);
	}

	return pdrgpdrgpexpr;
}
//---------------------------------------------------------------------------
//	@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);
}
//---------------------------------------------------------------------------
//	@function:
//		CDistributionSpecHashed::PdsCopyWithRemappedColumns
//
//	@doc:
//		Return a copy of the distribution spec with remapped columns
//
//---------------------------------------------------------------------------
CDistributionSpec *
CDistributionSpecHashed::PdsCopyWithRemappedColumns
	(
	IMemoryPool *pmp,
	HMUlCr *phmulcr,
	BOOL fMustExist
	)
{
	DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
	const ULONG ulLen = m_pdrgpexpr->UlLength();
	for (ULONG ul = 0; ul < ulLen; ul++)
	{
		CExpression *pexpr = (*m_pdrgpexpr)[ul];
		pdrgpexpr->Append(pexpr->PexprCopyWithRemappedColumns(pmp, phmulcr, fMustExist));
	}

	if (NULL == m_pdshashedEquiv)
	{
		return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, m_fNullsColocated);
	}

	// copy equivalent distribution
	CDistributionSpec *pds = m_pdshashedEquiv->PdsCopyWithRemappedColumns(pmp, phmulcr, fMustExist);
	CDistributionSpecHashed *pdshashed = CDistributionSpecHashed::PdsConvert(pds);
	return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, m_fNullsColocated, pdshashed);
}
Example #11
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalUnionAll::PdshashedPassThru
//
//	@doc:
//		Compute required hashed distribution of the n-th child
//
//---------------------------------------------------------------------------
CDistributionSpecHashed *
CPhysicalUnionAll::PdshashedPassThru
	(
	IMemoryPool *pmp,
	CDistributionSpecHashed *pdshashedRequired,
	ULONG ulChildIndex
	)
	const
{
	DrgPexpr *pdrgpexprRequired = pdshashedRequired->Pdrgpexpr();
	DrgPcr *pdrgpcrChild = (*m_pdrgpdrgpcrInput)[ulChildIndex];
	const ULONG ulExprs = pdrgpexprRequired->UlLength();
	const ULONG ulOutputCols = m_pdrgpcrOutput->UlLength();

	DrgPexpr *pdrgpexprChildRequired = GPOS_NEW(pmp) DrgPexpr(pmp);
	for (ULONG ulExpr = 0; ulExpr < ulExprs; ulExpr++)
	{
		CExpression *pexpr = (*pdrgpexprRequired)[ulExpr];
		if (COperator::EopScalarIdent != pexpr->Pop()->Eopid())
		{
			// skip expressions that are not in form of scalar identifiers
			continue;
		}
		const CColRef *pcrHashed = CScalarIdent::PopConvert(pexpr->Pop())->Pcr();
		const IMDType *pmdtype = pcrHashed->Pmdtype();
		if (!pmdtype->FHashable())
		{
			// skip non-hashable columns
			continue;
		}

		for (ULONG ulCol = 0; ulCol < ulOutputCols; ulCol++)
		{
			const CColRef *pcrOutput = (*m_pdrgpcrOutput)[ulCol];
			if (pcrOutput == pcrHashed)
			{
				const CColRef *pcrInput = (*pdrgpcrChild)[ulCol];
				pdrgpexprChildRequired->Append(CUtils::PexprScalarIdent(pmp, pcrInput));
			}
		}
	}

	if (0 < pdrgpexprChildRequired->UlLength())
	{
		return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexprChildRequired, true /* fNullsCollocated */);
	}

	// failed to create a matching hashed distribution
	pdrgpexprChildRequired->Release();

	if (NULL != pdshashedRequired->PdshashedEquiv())
	{
		// try again with equivalent distribution
		return PdshashedPassThru(pmp, pdshashedRequired->PdshashedEquiv(), ulChildIndex);
	}

	// failed to create hashed distribution
	return NULL;
}
Example #12
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PushThru
//
//	@doc:
//		Push an array of conjuncts through a logical expression;
//		compute an array of unpushable conjuncts
//
//---------------------------------------------------------------------------
void
CNormalizer::PushThru
	(
	IMemoryPool *pmp,
	CExpression *pexprLogical,
	DrgPexpr *pdrgpexprConjuncts,
	CExpression **ppexprResult,
	DrgPexpr **ppdrgpexprRemaining
	)
{
	GPOS_ASSERT(NULL != pexprLogical);
	GPOS_ASSERT(NULL != pdrgpexprConjuncts);
	GPOS_ASSERT(NULL != ppexprResult);

	DrgPexpr *pdrgpexprPushable =  GPOS_NEW(pmp) DrgPexpr(pmp);
	DrgPexpr *pdrgpexprUnpushable =  GPOS_NEW(pmp) DrgPexpr(pmp);

	const ULONG ulSize = pdrgpexprConjuncts->UlLength();
	for (ULONG ul = 0; ul < ulSize; ul++)
	{
		CExpression *pexprConj = (*pdrgpexprConjuncts)[ul];
		pexprConj->AddRef();
		if (FPushable(pexprLogical, pexprConj))
		{
			pdrgpexprPushable->Append(pexprConj);
		}
		else
		{
			pdrgpexprUnpushable->Append(pexprConj);
		}
	}

	// push through a conjunction of all pushable predicates
	CExpression *pexprPred = CPredicateUtils::PexprConjunction(pmp, pdrgpexprPushable);
	if (FPushThruOuterChild(pexprLogical))
	{
		PushThruOuterChild(pmp, pexprLogical, pexprPred, ppexprResult);
	}
	else
	{
		PushThru(pmp, pexprLogical, pexprPred, ppexprResult);
	}
	pexprPred->Release();

	*ppdrgpexprRemaining = pdrgpexprUnpushable;
}
Example #13
0
//---------------------------------------------------------------------------
//	@function:
//		CCNFConverter::PexprNot2CNF
//
//	@doc:
//		Convert a NOT tree into CNF
//
//---------------------------------------------------------------------------
CExpression *
CCNFConverter::PexprNot2CNF
	(
	IMemoryPool *pmp,
	CExpression *pexpr
	)
{
	GPOS_ASSERT(NULL != pmp);
	GPOS_ASSERT(NULL != pexpr);
	GPOS_ASSERT(1 == pexpr->UlArity());

	CExpression *pexprNotChild = (*pexpr)[0];
	if (!FScalarBoolOp(pexprNotChild))
	{
		pexpr->AddRef();
		return pexpr;
	}

	CScalarBoolOp::EBoolOperator eboolopChild = CScalarBoolOp::PopConvert(pexprNotChild->Pop())->Eboolop();

	// apply DeMorgan laws

	// NOT(NOT(A)) ==> A
	if (CScalarBoolOp::EboolopNot == eboolopChild)
	{
		return Pexpr2CNF(pmp, (*pexprNotChild)[0]);
	}

	// Not child must be either an AND or an OR

	// NOT(A AND B) ==> NOT(A) OR  NOT(B)
	// NOT(A OR  B) ==> NOT(A) AND NOT(B)
	DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
	const ULONG ulArity = pexprNotChild->UlArity();
	for (ULONG ul = 0; ul < ulArity; ul++)
	{
		(*pexprNotChild)[ul]->AddRef();
		pdrgpexpr->Append(CUtils::PexprNegate(pmp, (*pexprNotChild)[ul]));
	}

	CScalarBoolOp::EBoolOperator eboolop = CScalarBoolOp::EboolopAnd;
	if (CScalarBoolOp::EboolopAnd == eboolopChild)
	{
		eboolop = CScalarBoolOp::EboolopOr;
	}

	CExpression *pexprScalarBoolOp =  CUtils::PexprScalarBoolOp(pmp, eboolop, pdrgpexpr);
	CExpression *pexprResult = Pexpr2CNF(pmp, pexprScalarBoolOp);
	pexprScalarBoolOp->Release();

	return pexprResult;
}
Example #14
0
//---------------------------------------------------------------------------
//	@function:
//		CJoinOrderDP::PexprBuildPred
//
//	@doc:
//		Build predicate connecting the two given sets
//
//---------------------------------------------------------------------------
CExpression *
CJoinOrderDP::PexprBuildPred
	(
	CBitSet *pbsFst,
	CBitSet *pbsSnd
	)
{
	// collect edges connecting the given sets
	CBitSet *pbsEdges = GPOS_NEW(m_pmp) CBitSet(m_pmp);
	CBitSet *pbs = GPOS_NEW(m_pmp) CBitSet(m_pmp, *pbsFst);
	pbs->Union(pbsSnd);

	for (ULONG ul = 0; ul < m_ulEdges; ul++)
	{
		SEdge *pedge = m_rgpedge[ul];
		if (
			pbs->FSubset(pedge->m_pbs) &&
			!pbsFst->FDisjoint(pedge->m_pbs) &&
			!pbsSnd->FDisjoint(pedge->m_pbs)
			)
		{
#ifdef GPOS_DEBUG
		BOOL fSet =
#endif // GPOS_DEBUG
			pbsEdges->FExchangeSet(ul);
			GPOS_ASSERT(!fSet);
		}
	}
	pbs->Release();

	CExpression *pexprPred = NULL;
	if (0 < pbsEdges->CElements())
	{
		DrgPexpr *pdrgpexpr = GPOS_NEW(m_pmp) DrgPexpr(m_pmp);
		CBitSetIter bsi(*pbsEdges);
		while (bsi.FAdvance())
		{
			ULONG ul = bsi.UlBit();
			SEdge *pedge = m_rgpedge[ul];
			pedge->m_pexpr->AddRef();
			pdrgpexpr->Append(pedge->m_pexpr);
		}

		pexprPred = CPredicateUtils::PexprConjunction(m_pmp, pdrgpexpr);
	}

	pbsEdges->Release();
	return pexprPred;
}
Example #15
0
//---------------------------------------------------------------------------
//	@function:
//		CPartitionPropagationSpec::PdrgpexprPredicatesOnKey
//
//	@doc:
//		Returns an array of predicates on the given partitioning key given
//		an array of predicates on all keys
//
//---------------------------------------------------------------------------
DrgPexpr *
CPartitionPropagationSpec::PdrgpexprPredicatesOnKey
	(
	IMemoryPool *pmp,
	DrgPexpr *pdrgpexpr,
	CColRef *pcr,
	CColRefSet *pcrsKeys,
	CBitSet **ppbs
	)
{
	GPOS_ASSERT(NULL != pdrgpexpr);
	GPOS_ASSERT(NULL != pcr);
	GPOS_ASSERT(NULL != ppbs);
	GPOS_ASSERT(NULL != *ppbs);

	DrgPexpr *pdrgpexprResult = GPOS_NEW(pmp) DrgPexpr(pmp);

	const ULONG ulLen = pdrgpexpr->UlLength();
	for (ULONG ul = 0; ul < ulLen; ul++)
	{
		if ((*ppbs)->FBit(ul))
		{
			// this expression has already been added for another column
			continue;
		}

		CExpression *pexpr = (*pdrgpexpr)[ul];
		GPOS_ASSERT(pexpr->Pop()->FScalar());

		CColRefSet *pcrsUsed = CDrvdPropScalar::Pdpscalar(pexpr->PdpDerive())->PcrsUsed();
		CColRefSet *pcrsUsedKeys = GPOS_NEW(pmp) CColRefSet(pmp, *pcrsUsed);
		pcrsUsedKeys->Intersection(pcrsKeys);

		if (1 == pcrsUsedKeys->CElements() && pcrsUsedKeys->FMember(pcr))
		{
			pexpr->AddRef();
			pdrgpexprResult->Append(pexpr);
			(*ppbs)->FExchangeSet(ul);
		}

		pcrsUsedKeys->Release();
	}

	return pdrgpexprResult;
}
Example #16
0
//---------------------------------------------------------------------------
//	@function:
//		CPhysicalHashJoin::CreateHashRedistributeRequests
//
//	@doc:
//		Create the set of redistribute requests to send to first
//		hash join child
//
//---------------------------------------------------------------------------
void
CPhysicalHashJoin::CreateHashRedistributeRequests
	(
	IMemoryPool *pmp
	)
{
	GPOS_ASSERT(NULL == m_pdrgpdsRedistributeRequests);
	GPOS_ASSERT(NULL != m_pdrgpexprOuterKeys);
	GPOS_ASSERT(NULL != m_pdrgpexprInnerKeys);

	DrgPexpr *pdrgpexpr = NULL;
	if (EceoRightToLeft == Eceo())
	{
		pdrgpexpr = m_pdrgpexprInnerKeys;
	}
	else
	{
		pdrgpexpr = m_pdrgpexprOuterKeys;
	}

	m_pdrgpdsRedistributeRequests = GPOS_NEW(pmp) DrgPds(pmp);
	const ULONG ulExprs = std::min((ULONG) GPOPT_MAX_HASH_DIST_REQUESTS, pdrgpexpr->UlLength());
	if (1 < ulExprs)
	{
		for (ULONG ul = 0; ul < ulExprs; ul++)
		{
			DrgPexpr *pdrgpexprCurrent = GPOS_NEW(pmp) DrgPexpr(pmp);
			CExpression *pexpr = (*pdrgpexpr)[ul];
			pexpr->AddRef();
			pdrgpexprCurrent->Append(pexpr);

			// add a separate request for each hash join key

			// TODO:  - Dec 30, 2011; change fNullsColocated to false when our
			// distribution matching can handle differences in NULL colocation
			CDistributionSpecHashed *pdshashedCurrent = GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexprCurrent, true /* fNullsCollocated */);
			m_pdrgpdsRedistributeRequests->Append(pdshashedCurrent);
		}
	}
	// add a request that contains all hash join keys
	pdrgpexpr->AddRef();
	CDistributionSpecHashed *pdshashed = GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, true /* fNullsCollocated */);
	m_pdrgpdsRedistributeRequests->Append(pdshashed);
}
Example #17
0
//---------------------------------------------------------------------------
//	@function:
//		CCNFConverter::Expand
//
//	@doc:
//		Recursively compute cross product over input array of arrays;
//		convert each cross product result to a conjunct and store it in
//		output array
//
//---------------------------------------------------------------------------
void
CCNFConverter::Expand
	(
	IMemoryPool *pmp,
	DrgPdrgPexpr *pdrgpdrgpexprInput, // input array of arrays
	DrgPexpr *pdrgpexprOutput, // output array
	DrgPexpr *pdrgpexprToExpand, // a cross product result to be expanded
	ULONG ulCurrent // index of current array to be used for expanding a cross product result
	)
{
	GPOS_CHECK_STACK_SIZE;
	GPOS_ASSERT(ulCurrent <= pdrgpdrgpexprInput->UlLength());

	if (ulCurrent == pdrgpdrgpexprInput->UlLength())
	{
		// exhausted input, add a new conjunct to output array
		pdrgpexprOutput->Append(CPredicateUtils::PexprDisjunction(pmp, pdrgpexprToExpand));

		return;
	}

	DrgPexpr *pdrgpexprCurrent = (*pdrgpdrgpexprInput)[ulCurrent];
	const ULONG ulArity = pdrgpexprCurrent->UlLength();
	for (ULONG ul = 0; ul < ulArity; ul++)
	{
		// append accumulated expressions to a new array
		DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
		CUtils::AddRefAppend<CExpression, CleanupRelease>(pdrgpexpr, pdrgpexprToExpand);

		// add an expression from current input array only if it's not equal to an existing one
		if (!CUtils::FEqualAny((*pdrgpexprCurrent)[ul], pdrgpexpr))
		{
			CExpression *pexpr = (*pdrgpexprCurrent)[ul];
			pexpr->AddRef();
			pdrgpexpr->Append(pexpr);
		}

		// recursively expand the resulting array
		Expand(pmp, pdrgpdrgpexprInput, pdrgpexprOutput, pdrgpexpr, ulCurrent + 1);
	}
	pdrgpexprToExpand->Release();
}
Example #18
0
//---------------------------------------------------------------------------
//	@function:
//		CXformExpandNAryJoin::Transform
//
//	@doc:
//		Actual transformation of n-ary join to cluster of inner joins
//
//---------------------------------------------------------------------------
void
CXformExpandNAryJoin::Transform
(
    CXformContext *pxfctxt,
    CXformResult *pxfres,
    CExpression *pexpr
)
const
{
    GPOS_ASSERT(NULL != pxfctxt);
    GPOS_ASSERT(NULL != pxfres);
    GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr));
    GPOS_ASSERT(FCheckPattern(pexpr));

    IMemoryPool *pmp = pxfctxt->Pmp();

    const ULONG ulArity = pexpr->UlArity();
    GPOS_ASSERT(ulArity >= 3);

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

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

    DrgPexpr *pdrgpexprPreds = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprScalar);

    // create a join order based on query-specified order of joins
    CJoinOrder jo(pmp, pdrgpexpr, pdrgpexprPreds);
    CExpression *pexprResult = jo.PexprExpand();

    // normalize resulting expression
    CExpression *pexprNormalized = CNormalizer::PexprNormalize(pmp, pexprResult);
    pexprResult->Release();
    pxfres->Add(pexprNormalized);

    AddSpecifiedJoinOrder(pmp, pexpr, pxfres);
}
Example #19
0
//---------------------------------------------------------------------------
//	@function:
//		CCNFConverter::PdrgpexprConvertChildren
//
//	@doc:
//		Call converter recursively on children array
//
//---------------------------------------------------------------------------
DrgPexpr *
CCNFConverter::PdrgpexprConvertChildren
	(
	IMemoryPool *pmp,
	CExpression *pexpr
	)
{
	GPOS_ASSERT(NULL != pmp);
	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 = Pexpr2CNF(pmp, (*pexpr)[ul]);
		pdrgpexpr->Append(pexprChild);
	}

	return pdrgpexpr;
}
Example #20
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);
}
//---------------------------------------------------------------------------
//	@function:
//		CDistributionSpecHashed::PdshashedExcludeColumns
//
//	@doc:
//		Return a copy of the distribution spec after excluding the given
//		columns, return NULL if all distribution expressions are excluded
//
//---------------------------------------------------------------------------
CDistributionSpecHashed *
CDistributionSpecHashed::PdshashedExcludeColumns
	(
	IMemoryPool *pmp,
	CColRefSet *pcrs
	)
{
	GPOS_ASSERT(NULL != pcrs);

	DrgPexpr *pdrgpexprNew = GPOS_NEW(pmp) DrgPexpr(pmp);
	const ULONG ulExprs = m_pdrgpexpr->UlLength();
	for (ULONG ul = 0; ul < ulExprs; ul++)
	{
		CExpression *pexpr = (*m_pdrgpexpr)[ul];
		COperator *pop = pexpr->Pop();
		if (COperator::EopScalarIdent == pop->Eopid())
		{
			// we only care here about column identifiers,
			// any more complicated expressions are copied to output
			const CColRef *pcr = CScalarIdent::PopConvert(pop)->Pcr();
			if (pcrs->FMember(pcr))
			{
				continue;
			}
		}

		pexpr->AddRef();
		pdrgpexprNew->Append(pexpr);
	}

	if (0 == pdrgpexprNew->UlLength())
	{
		pdrgpexprNew->Release();
		return NULL;
	}

	return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexprNew, m_fNullsColocated);
}
Example #22
0
//---------------------------------------------------------------------------
//	@function:
//		CPartitionPropagationSpec::PexprResidualFilter
//
//	@doc:
//		Return a residual filter given an array of predicates and a bitset
//		indicating which predicates have already been used
//
//---------------------------------------------------------------------------
CExpression *
CPartitionPropagationSpec::PexprResidualFilter
	(
	IMemoryPool *pmp,
	DrgPexpr *pdrgpexpr,
	CBitSet *pbsUsed
	)
{
	GPOS_ASSERT(NULL != pdrgpexpr);
	GPOS_ASSERT(NULL != pbsUsed);

	DrgPexpr *pdrgpexprUnused = GPOS_NEW(pmp) DrgPexpr(pmp);

	const ULONG ulLen = pdrgpexpr->UlLength();
	for (ULONG ul = 0; ul < ulLen; ul++)
	{
		if (pbsUsed->FBit(ul))
		{
			// predicate already considered
			continue;
		}

		CExpression *pexpr = (*pdrgpexpr)[ul];
		pexpr->AddRef();
		pdrgpexprUnused->Append(pexpr);
	}

	CExpression *pexprResult = CPredicateUtils::PexprConjunction(pmp, pdrgpexprUnused);
	if (CUtils::FScalarConstTrue(pexprResult))
	{
		pexprResult->Release();
		pexprResult = NULL;
	}

	return pexprResult;
}
//---------------------------------------------------------------------------
//	@function:
//		CXformSelect2PartialDynamicIndexGet::CreatePartialIndexGetPlan
//
//	@doc:
//		Create a plan as a union of the given partial index get candidates and 
//		possibly a dynamic table scan
//
//---------------------------------------------------------------------------
void
CXformSelect2PartialDynamicIndexGet::CreatePartialIndexGetPlan
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	DrgPpartdig *pdrgppartdig,
	const IMDRelation *pmdrel,
	CXformResult *pxfres
	)
	const
{ 
	CExpression *pexprRelational = (*pexpr)[0];
	CExpression *pexprScalar = (*pexpr)[1];

	CLogicalDynamicGet *popGet = CLogicalDynamicGet::PopConvert(pexprRelational->Pop());
	DrgPcr *pdrgpcrGet = popGet->PdrgpcrOutput();
	
	const ULONG ulPartialIndexes = pdrgppartdig->UlLength();
	
	DrgDrgPcr *pdrgpdrgpcrInput = GPOS_NEW(pmp) DrgDrgPcr(pmp);
	DrgPexpr *pdrgpexprInput = GPOS_NEW(pmp) DrgPexpr(pmp);
	for (ULONG ul = 0; ul < ulPartialIndexes; ul++)
	{
		SPartDynamicIndexGetInfo *ppartdig = (*pdrgppartdig)[ul];

		const IMDIndex *pmdindex = ppartdig->m_pmdindex;
		CPartConstraint *ppartcnstr = ppartdig->m_ppartcnstr;
		DrgPexpr *pdrgpexprIndex = ppartdig->m_pdrgpexprIndex;
		DrgPexpr *pdrgpexprResidual = ppartdig->m_pdrgpexprResidual;
		
		DrgPcr *pdrgpcrNew = pdrgpcrGet;

		if (0 < ul)
		{
			pdrgpcrNew = CUtils::PdrgpcrCopy(pmp, pdrgpcrGet);
		}
		else
		{
			pdrgpcrNew->AddRef();
		}

		CExpression *pexprDynamicScan = NULL;
		if (NULL != pmdindex)
		{
			pexprDynamicScan = CXformUtils::PexprPartialDynamicIndexGet
								(
								pmp,
								popGet,
								pexpr->Pop()->UlOpId(),
								pdrgpexprIndex,
								pdrgpexprResidual,
								pdrgpcrNew,
								pmdindex,
								pmdrel,
								ppartcnstr,
								NULL, // pcrsAcceptedOuterRefs
								NULL, // pdrgpcrOuter
								NULL // pdrgpcrNewOuter
								);
		}
		else
		{
			pexprDynamicScan = PexprSelectOverDynamicGet
								(
								pmp,
								popGet,
								pexprScalar,
								pdrgpcrNew,
								ppartcnstr
								);
		}
		GPOS_ASSERT(NULL != pexprDynamicScan);

		pdrgpdrgpcrInput->Append(pdrgpcrNew);
		pdrgpexprInput->Append(pexprDynamicScan);
	}

	ULONG ulInput = pdrgpexprInput->UlLength();
	if (0 < ulInput)
	{
		CExpression *pexprResult = NULL;
		if (1 < ulInput)
		{
			pdrgpcrGet->AddRef();
			DrgPcr *pdrgpcrOuter = pdrgpcrGet;

			// construct a new union all operator
			pexprResult = GPOS_NEW(pmp) CExpression
							(
							pmp,
							GPOS_NEW(pmp) CLogicalUnionAll(pmp, pdrgpcrOuter, pdrgpdrgpcrInput, popGet->UlScanId()),
							pdrgpexprInput
							);
		}
		else
		{
			pexprResult = (*pdrgpexprInput)[0];
			pexprResult->AddRef();

			// clean up
			pdrgpexprInput->Release();
			pdrgpdrgpcrInput->Release();
		}

		// if scalar expression involves the partitioning key, keep a SELECT node
		// on top for the purposes of partition selection
		DrgDrgPcr *pdrgpdrgpcrPartKeys = popGet->PdrgpdrgpcrPart();
		CExpression *pexprPredOnPartKey = CPredicateUtils::PexprExtractPredicatesOnPartKeys
											(
											pmp,
											pexprScalar,
											pdrgpdrgpcrPartKeys,
											NULL, /*pcrsAllowedRefs*/
											true /*fUseConstraints*/
											);
		
		if (NULL != pexprPredOnPartKey)
		{
			pexprResult = GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CLogicalSelect(pmp), pexprResult, pexprPredOnPartKey);
		}
		
		pxfres->Add(pexprResult);

		return;
	}

	// clean up
	pdrgpdrgpcrInput->Release();
	pdrgpexprInput->Release();
}
Example #24
0
//---------------------------------------------------------------------------
//	@function:
//		CNormalizer::PexprPullUpProjectElements
//
//	@doc:
//		Pull up project elements from the given projection expression that do not
//		exist in the given used columns set. The pulled up project elements must only
//		use columns that are in the output columns of the parent operator. Returns
//		a new expression that does not have the pulled up project elements. These
//		project elements are appended to the given array.
//
//---------------------------------------------------------------------------
CExpression *
CNormalizer::PexprPullUpProjectElements
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	CColRefSet *pcrsUsed,
	CColRefSet *pcrsOutput,
	DrgPexpr **ppdrgpexprPrElPullUp	// output: the pulled-up project elements
	)
{
	GPOS_ASSERT(NULL != pexpr);
	GPOS_ASSERT(COperator::EopLogicalProject == pexpr->Pop()->Eopid());
	GPOS_ASSERT(NULL != pcrsUsed);
	GPOS_ASSERT(NULL != ppdrgpexprPrElPullUp);
	GPOS_ASSERT(NULL != *ppdrgpexprPrElPullUp);

	if (2 != pexpr->UlArity())
	{
		// the project's children were not extracted as part of the pattern in this xform
		GPOS_ASSERT(0 == pexpr->UlArity());
		pexpr->AddRef();
		return pexpr;
	}

	DrgPexpr *pdrgpexprPrElNoPullUp = GPOS_NEW(pmp) DrgPexpr(pmp);
	CExpression *pexprPrL = (*pexpr)[1];

	const ULONG ulProjElements = pexprPrL->UlArity();
	for (ULONG ul = 0; ul < ulProjElements; ul++)
	{
		CExpression *pexprPrEl = (*pexprPrL)[ul];
		CScalarProjectElement *popPrEl = CScalarProjectElement::PopConvert(pexprPrEl->Pop());
		CColRef *pcrDefined = popPrEl->Pcr();
		CColRefSet *pcrsUsedByProjElem = CDrvdPropScalar::Pdpscalar(pexprPrEl->PdpDerive())->PcrsUsed();

		// a proj elem can be pulled up only if the defined column is not in
		// pcrsUsed and its used columns are in pcrOutput
		pexprPrEl->AddRef();
		if (!pcrsUsed->FMember(pcrDefined) && pcrsOutput->FSubset(pcrsUsedByProjElem))
		{
			(*ppdrgpexprPrElPullUp)->Append(pexprPrEl);
		}
		else
		{
			pdrgpexprPrElNoPullUp->Append(pexprPrEl);
		}
	}

	CExpression *pexprNew = (*pexpr)[0];
	pexprNew->AddRef();
	if (0 == pdrgpexprPrElNoPullUp->UlLength())
	{
		pdrgpexprPrElNoPullUp->Release();
	}
	else
	{
		// some project elements could not be pulled up - need a project here
		CExpression *pexprPrjList = GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CScalarProjectList(pmp), pdrgpexprPrElNoPullUp);
		pexprNew = GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CLogicalProject(pmp), pexprNew, pexprPrjList);
	}

	return pexprNew;
}
Example #25
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);
}
Example #26
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;
}
Example #27
0
//---------------------------------------------------------------------------
//	@function:
//		CDecorrelator::FProcessPredicate
//
//	@doc:
//		Decorrelate predicate
//
//---------------------------------------------------------------------------
BOOL
CDecorrelator::FProcessPredicate
	(
	IMemoryPool *pmp,
	CExpression *pexprLogical, // logical parent of predicate tree
	CExpression *pexprScalar,
	BOOL fEqualityOnly,
	CColRefSet *pcrsOutput,
	CExpression **ppexprDecorrelated,
	DrgPexpr *pdrgpexprCorrelations
	)
{
	GPOS_ASSERT(pexprLogical->Pop()->FLogical());
	GPOS_ASSERT(pexprScalar->Pop()->FScalar());

	*ppexprDecorrelated = NULL;
	
	DrgPexpr *pdrgpexprConj = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprScalar);
	DrgPexpr *pdrgpexprResiduals = GPOS_NEW(pmp) DrgPexpr(pmp);
	BOOL fSuccess = true;
	
	// divvy up the predicates in residuals (w/ no outer ref) and correlations (w/ outer refs)
	ULONG ulLength = pdrgpexprConj->UlLength();
	for(ULONG ul = 0; ul < ulLength && fSuccess; ul++)
	{
		CExpression *pexprConj = (*pdrgpexprConj)[ul];
		CColRefSet *pcrsUsed = CDrvdPropScalar::Pdpscalar(pexprConj->PdpDerive())->PcrsUsed();
		
		if (pcrsOutput->FSubset(pcrsUsed))
		{
			// no outer ref
			pexprConj->AddRef();
			pdrgpexprResiduals->Append(pexprConj);			

			continue;
		}
		
		fSuccess = FDelayable(pexprLogical, pexprConj, fEqualityOnly);
		if (fSuccess)
		{
			pexprConj->AddRef();
			pdrgpexprCorrelations->Append(pexprConj);
		}
		
	}

	pdrgpexprConj->Release();

	if (!fSuccess || 0 == pdrgpexprResiduals->UlLength())
	{
		// clean up
		pdrgpexprResiduals->Release();
	}
	else
	{
		// residuals become new predicate
		*ppexprDecorrelated = CPredicateUtils::PexprConjunction(pmp, pdrgpexprResiduals);
	}


	return fSuccess;
}
Example #28
0
//---------------------------------------------------------------------------
//	@function:
//		CJoinOrderTest::EresUnittest_Expand
//
//	@doc:
//		Simple expansion test
//
//---------------------------------------------------------------------------
GPOS_RESULT
CJoinOrderTest::EresUnittest_Expand()
{
	CAutoMemoryPool amp;
	IMemoryPool *pmp = amp.Pmp();

	// setup a file-based provider
	CMDProviderMemory *pmdp = CTestUtils::m_pmdpf;
	pmdp->AddRef();
	CMDAccessor mda(pmp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp);
	
	// install opt context in TLS
	CAutoOptCtxt aoc
				(
				pmp,
				&mda,
				NULL,  /* pceeval */
				CTestUtils::Pcm(pmp)
				);

	// build test case
	CExpression *pexpr = CTestUtils::PexprLogicalNAryJoin(pmp);
	DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
	ULONG ulArity = pexpr->UlArity();
	for (ULONG ul = 0; ul < ulArity - 1; ul++)
	{
		CExpression *pexprChild = (*pexpr)[ul];
		pexprChild->AddRef();
		pdrgpexpr->Append(pexprChild);
	}

	DrgPexpr *pdrgpexprConj = CPredicateUtils::PdrgpexprConjuncts(pmp, (*pexpr)[ulArity - 1]);

	// add predicates selectively to trigger special case of cross join
	DrgPexpr *pdrgpexprTest = GPOS_NEW(pmp) DrgPexpr(pmp);	
	for (ULONG ul = 0; ul < pdrgpexprConj->UlLength() - 1; ul++)
	{
		CExpression *pexprConjunct = (*pdrgpexprConj)[ul];
		pexprConjunct->AddRef();
		pdrgpexprTest->Append(pexprConjunct);
	}
	
	pdrgpexprConj->Release();

	// single-table predicate
	CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel((*pdrgpexpr)[ulArity - 2]->PdpDerive())->PcrsOutput();
	CExpression *pexprSingleton = CUtils::PexprScalarEqCmp(pmp, pcrsOutput->PcrAny(), pcrsOutput->PcrAny());
	
	pdrgpexprTest->Append(pexprSingleton);
	
	CJoinOrder jo(pmp, pdrgpexpr, pdrgpexprTest);
	CExpression *pexprResult = jo.PexprExpand();
	{
		CAutoTrace at(pmp);
		at.Os() << std::endl << "INPUT:" << std::endl << *pexpr << std::endl;
		at.Os() << std::endl << "OUTPUT:" << std::endl << *pexprResult << std::endl;
	}

	CRefCount::SafeRelease(pexprResult);

	pexpr->Release();

	return GPOS_OK;
}
Example #29
0
//---------------------------------------------------------------------------
//	@function:
//		CJoinOrderTest::EresUnittest_ExpandMinCard
//
//	@doc:
//		Expansion expansion based on cardinality of intermediate results
//
//---------------------------------------------------------------------------
GPOS_RESULT
CJoinOrderTest::EresUnittest_ExpandMinCard()
{
	CAutoMemoryPool amp;
	IMemoryPool *pmp = amp.Pmp();

	// array of relation names
	CWStringConst rgscRel[] =
	{
		GPOS_WSZ_LIT("Rel10"),
		GPOS_WSZ_LIT("Rel3"),
		GPOS_WSZ_LIT("Rel4"),
		GPOS_WSZ_LIT("Rel6"),
		GPOS_WSZ_LIT("Rel7"),
		GPOS_WSZ_LIT("Rel8"),
		GPOS_WSZ_LIT("Rel12"),
		GPOS_WSZ_LIT("Rel13"),
		GPOS_WSZ_LIT("Rel5"),
		GPOS_WSZ_LIT("Rel14"),
		GPOS_WSZ_LIT("Rel15"),
		GPOS_WSZ_LIT("Rel1"),
		GPOS_WSZ_LIT("Rel11"),
		GPOS_WSZ_LIT("Rel2"),
		GPOS_WSZ_LIT("Rel9"),
	};

	// array of relation IDs
	ULONG rgulRel[] =
	{
		GPOPT_TEST_REL_OID10,
		GPOPT_TEST_REL_OID3,
		GPOPT_TEST_REL_OID4,
		GPOPT_TEST_REL_OID6,
		GPOPT_TEST_REL_OID7,
		GPOPT_TEST_REL_OID8,
		GPOPT_TEST_REL_OID12,
		GPOPT_TEST_REL_OID13,
		GPOPT_TEST_REL_OID5,
		GPOPT_TEST_REL_OID14,
		GPOPT_TEST_REL_OID15,
		GPOPT_TEST_REL_OID1,
		GPOPT_TEST_REL_OID11,
		GPOPT_TEST_REL_OID2,
		GPOPT_TEST_REL_OID9,
	};

	const ULONG ulRels = GPOS_ARRAY_SIZE(rgscRel);
	GPOS_ASSERT(GPOS_ARRAY_SIZE(rgulRel) == ulRels);

	// setup a file-based provider
	CMDProviderMemory *pmdp = CTestUtils::m_pmdpf;
	pmdp->AddRef();
	CMDAccessor mda(pmp, CMDCache::Pcache());
	mda.RegisterProvider(CTestUtils::m_sysidDefault, pmdp);

	{
		// install opt context in TLS
		CAutoOptCtxt aoc
				(
				pmp,
				&mda,
				NULL,  /* pceeval */
				CTestUtils::Pcm(pmp)
				);

		CExpression *pexprNAryJoin =
				CTestUtils::PexprLogicalNAryJoin(pmp, rgscRel, rgulRel, ulRels, false /*fCrossProduct*/);

		// derive stats on input expression
		CExpressionHandle exprhdl(pmp);
		exprhdl.Attach(pexprNAryJoin);
		exprhdl.DeriveStats(pmp, pmp, NULL /*prprel*/, NULL /*pdrgpstatCtxt*/);

		DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp);
		for (ULONG ul = 0; ul < ulRels; ul++)
		{
			CExpression *pexprChild = (*pexprNAryJoin)[ul];
			pexprChild->AddRef();
			pdrgpexpr->Append(pexprChild);
		}
		DrgPexpr *pdrgpexprPred = CPredicateUtils::PdrgpexprConjuncts(pmp, (*pexprNAryJoin)[ulRels]);
		pdrgpexpr->AddRef();
		pdrgpexprPred->AddRef();
		CJoinOrderMinCard jomc(pmp, pdrgpexpr, pdrgpexprPred);
		CExpression *pexprResult = jomc.PexprExpand();
		{
			CAutoTrace at(pmp);
			at.Os() << std::endl << "INPUT:" << std::endl << *pexprNAryJoin << std::endl;
			at.Os() << std::endl << "OUTPUT:" << std::endl << *pexprResult << std::endl;
		}
		pexprResult->Release();
		pexprNAryJoin->Release();
		pdrgpexpr->Release();
		pdrgpexprPred->Release();
	}

	return GPOS_OK;
}
//---------------------------------------------------------------------------
//	@function:
//		CXformJoinAssociativity::CreatePredicates
//
//	@doc:
//		Extract all conjuncts and divvy them up between upper and lower join
//
//---------------------------------------------------------------------------
void
CXformJoinAssociativity::CreatePredicates
	(
	IMemoryPool *pmp,
	CExpression *pexpr,
	DrgPexpr *pdrgpexprLower,
	DrgPexpr *pdrgpexprUpper
	)
	const
{
	GPOS_CHECK_ABORT;

	// bind operators
	CExpression *pexprLeft = (*pexpr)[0];
	CExpression *pexprLeftLeft = (*pexprLeft)[0];
	CExpression *pexprRight = (*pexpr)[1];
	
	DrgPexpr *pdrgpexprJoins = GPOS_NEW(pmp) DrgPexpr(pmp);

	pexprLeft->AddRef();
	pdrgpexprJoins->Append(pexprLeft);
	
	pexpr->AddRef();
	pdrgpexprJoins->Append(pexpr);	
	
	// columns for new lower join
	CColRefSet *pcrsLower = GPOS_NEW(pmp) CColRefSet(pmp);
	pcrsLower->Union(CDrvdPropRelational::Pdprel(pexprLeftLeft->PdpDerive())->PcrsOutput());
	pcrsLower->Union(CDrvdPropRelational::Pdprel(pexprRight->PdpDerive())->PcrsOutput());
	
	// convert current predicates into arrays of conjuncts
	DrgPexpr *pdrgpexprOrig = GPOS_NEW(pmp) DrgPexpr(pmp);
	
	for (ULONG ul = 0; ul < 2; ul++)
	{
		DrgPexpr *pdrgpexprPreds = CPredicateUtils::PdrgpexprConjuncts(pmp, (*(*pdrgpexprJoins)[ul])[2]);
		ULONG ulLen = pdrgpexprPreds->UlLength();
		for (ULONG ulConj = 0; ulConj < ulLen; ulConj++)
		{	
			CExpression *pexprConj = (*pdrgpexprPreds)[ulConj];
			pexprConj->AddRef();
			
			pdrgpexprOrig->Append(pexprConj);
		}
		pdrgpexprPreds->Release();
	}

	// divvy up conjuncts for upper and lower join
	ULONG ulConj = pdrgpexprOrig->UlLength();
	for (ULONG ul = 0; ul < ulConj; ul++)
	{
		CExpression *pexprPred = (*pdrgpexprOrig)[ul];
		CColRefSet *pcrs = CDrvdPropScalar::Pdpscalar(pexprPred->PdpDerive())->PcrsUsed();
		
		pexprPred->AddRef();
		if (pcrsLower->FSubset(pcrs))
		{
			pdrgpexprLower->Append(pexprPred);
		}
		else 
		{
			pdrgpexprUpper->Append(pexprPred);			
		}
	}
	
	// No predicates indicate a cross join. And for that, ORCA expects
	// predicate to be a scalar const "true".
	if (pdrgpexprLower->UlLength() == 0)
	{
		CExpression *pexprCrossLowerJoinPred = CUtils::PexprScalarConstBool(pmp, true, false);
		pdrgpexprLower->Append(pexprCrossLowerJoinPred);
	}
	
	// Same for upper predicates
	if (pdrgpexprUpper->UlLength() == 0)
	{
		CExpression *pexprCrossUpperJoinPred = CUtils::PexprScalarConstBool(pmp, true, false);
		pdrgpexprUpper->Append(pexprCrossUpperJoinPred);
	}

	// clean up
	pcrsLower->Release();
	pdrgpexprOrig->Release();
	
	pdrgpexprJoins->Release();
}