//--------------------------------------------------------------------------- // @function: // CXformCollapseGbAgg::Transform // // @doc: // Actual transformation to collapse two cascaded group by operators; // if the top Gb grouping columns are subset of bottom Gb grouping // columns AND both Gb operators do not define agg functions, we can // remove the bottom group by operator // // //--------------------------------------------------------------------------- void CXformCollapseGbAgg::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 *mp = pxfctxt->Pmp(); // extract components CLogicalGbAgg *popTopGbAgg = CLogicalGbAgg::PopConvert(pexpr->Pop()); GPOS_ASSERT(0 < popTopGbAgg->Pdrgpcr()->Size()); GPOS_ASSERT(popTopGbAgg->FGlobal()); CExpression *pexprRelational = (*pexpr)[0]; CExpression *pexprTopProjectList = (*pexpr)[1]; CLogicalGbAgg *popBottomGbAgg = CLogicalGbAgg::PopConvert(pexprRelational->Pop()); CExpression *pexprChild = (*pexprRelational)[0]; CExpression *pexprBottomProjectList = (*pexprRelational)[1]; if (!popBottomGbAgg->FGlobal()) { // bottom GbAgg must be global to prevent xform from getting applied to splitted GbAggs return; } if (0 < pexprTopProjectList->Arity() || 0 < pexprBottomProjectList->Arity()) { // exit if any of the Gb operators has an aggregate function return; } #ifdef GPOS_DEBUG // for two cascaded GbAgg ops with no agg functions, top grouping // columns must be a subset of bottom grouping columns CColRefSet *pcrsTopGrpCols = GPOS_NEW(mp) CColRefSet(mp, popTopGbAgg->Pdrgpcr()); CColRefSet *pcrsBottomGrpCols = GPOS_NEW(mp) CColRefSet(mp, popBottomGbAgg->Pdrgpcr()); GPOS_ASSERT(pcrsBottomGrpCols->ContainsAll(pcrsTopGrpCols)); pcrsTopGrpCols->Release(); pcrsBottomGrpCols->Release(); #endif // GPOS_DEBUG pexprChild->AddRef(); CExpression *pexprSelect = CUtils::PexprLogicalSelect(mp, pexprChild, CPredicateUtils::PexprConjunction(mp, NULL /*pdrgpexpr*/)); popTopGbAgg->AddRef(); pexprTopProjectList->AddRef(); CExpression *pexprGbAggNew = GPOS_NEW(mp) CExpression(mp, popTopGbAgg, pexprSelect, pexprTopProjectList); pxfres->Add(pexprGbAggNew); }
//--------------------------------------------------------------------------- // @function: // CQueryContext::MapComputedToUsedCols // // @doc: // Walk the expression and add the mapping between computed column // and its used columns // //--------------------------------------------------------------------------- void CQueryContext::MapComputedToUsedCols ( CColumnFactory *col_factory, CExpression *pexpr ) { GPOS_ASSERT(NULL != pexpr); if (COperator::EopLogicalProject == pexpr->Pop()->Eopid()) { CExpression *pexprPrL = (*pexpr)[1]; const ULONG arity = pexprPrL->Arity(); for (ULONG ul = 0; ul < arity; ul++) { CExpression *pexprPrEl = (*pexprPrL)[ul]; col_factory->AddComputedToUsedColsMap(pexprPrEl); } } // process children const ULONG ulChildren = pexpr->Arity(); for (ULONG ul = 0; ul < ulChildren; ul++) { MapComputedToUsedCols(col_factory, (*pexpr)[ul]); } }
//--------------------------------------------------------------------------- // @function: // CXformSubqJoin2Apply::Transform // // @doc: // Helper of transformation function // //--------------------------------------------------------------------------- void CXformSubqJoin2Apply::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr, BOOL fEnforceCorrelatedApply ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *mp = pxfctxt->Pmp(); CExpression *pexprSelect = CXformUtils::PexprSeparateSubqueryPreds(mp, pexpr); // attempt pushing subqueries to join children, // this optimization may not always succeed since unnested subqueries below joins // could hide columns needed to evaluate join condition CExpression *pexprSubqsPushedDown = PexprSubqueryPushDown(mp, pexprSelect, fEnforceCorrelatedApply); // check if join columns in join condition are still accessible after subquery pushdown CExpression *pexprJoin = (*pexprSubqsPushedDown)[0]; CExpression *pexprJoinCondition = (*pexprJoin)[pexprJoin->Arity() - 1]; CColRefSet *pcrsUsed = CDrvdPropScalar::GetDrvdScalarProps(pexprJoinCondition->PdpDerive())->PcrsUsed(); CColRefSet *pcrsJoinOutput = CDrvdPropRelational::GetRelationalProperties(pexprJoin->PdpDerive())->PcrsOutput(); if (!pcrsJoinOutput->ContainsAll(pcrsUsed)) { // discard expression after subquery push down pexprSubqsPushedDown->Release(); pexprSelect->AddRef(); pexprSubqsPushedDown = pexprSelect; } pexprSelect->Release(); CExpression *pexprResult = NULL; BOOL fHasSubquery = CDrvdPropScalar::GetDrvdScalarProps((*pexprSubqsPushedDown)[1]->PdpDerive())->FHasSubquery(); if (fHasSubquery) { // unnest subqueries remaining in the top Select expression pexprResult = PexprSubqueryUnnest(mp, pexprSubqsPushedDown, fEnforceCorrelatedApply); pexprSubqsPushedDown->Release(); } else { pexprResult = pexprSubqsPushedDown; } if (NULL == pexprResult) { // unnesting failed, return here return; } // normalize resulting expression and add it to xform results container CExpression *pexprNormalized = CNormalizer::PexprNormalize(mp, pexprResult); pexprResult->Release(); pxfres->Add(pexprNormalized); }
//--------------------------------------------------------------------------- // @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); }