//--------------------------------------------------------------------------- // @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); }
//--------------------------------------------------------------------------- // @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; }
//--------------------------------------------------------------------------- // @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); }
//--------------------------------------------------------------------------- // @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; }
//--------------------------------------------------------------------------- // @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; }
//--------------------------------------------------------------------------- // @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); }
//--------------------------------------------------------------------------- // @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; }
//--------------------------------------------------------------------------- // @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; }
//--------------------------------------------------------------------------- // @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: // 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); }
//--------------------------------------------------------------------------- // @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(); }
//--------------------------------------------------------------------------- // @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); }
//--------------------------------------------------------------------------- // @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); }
//--------------------------------------------------------------------------- // @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; }
// 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; }