//--------------------------------------------------------------------------- // @function: // CXformPushGbWithHavingBelowJoin::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformPushGbWithHavingBelowJoin::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *mp = pxfctxt->Pmp(); CExpression *pexprGb = (*pexpr)[0]; CLogicalGbAgg *popGbAgg = CLogicalGbAgg::PopConvert(pexprGb->Pop()); if (!popGbAgg->FGlobal()) { // xform only applies to global aggs return; } CExpression *pexprResult = CXformUtils::PexprPushGbBelowJoin(mp, pexpr); if (NULL != pexprResult) { // add alternative to results pxfres->Add(pexprResult); } }
//--------------------------------------------------------------------------- // @function: // CDecorrelator::FProcessGbAgg // // @doc: // Decorrelate GbAgg operator // //--------------------------------------------------------------------------- BOOL CDecorrelator::FProcessGbAgg ( IMemoryPool *pmp, CExpression *pexpr, BOOL, // fEqualityOnly CExpression **ppexprDecorrelated, DrgPexpr *pdrgpexprCorrelations ) { CLogicalGbAgg *popAggOriginal = CLogicalGbAgg::PopConvert(pexpr->Pop()); // fail if agg has outer references if (CUtils::FHasOuterRefs(pexpr) && !CUtils::FHasOuterRefs((*pexpr)[0])) { return false; } // TODO: 12/20/2012 - ; check for strictness of agg function // decorrelate relational child CExpression *pexprRelational = NULL; if (!FProcess(pmp, (*pexpr)[0], true /*fEqualityOnly*/, &pexprRelational, pdrgpexprCorrelations)) { GPOS_ASSERT(NULL == pexprRelational); return false; } // get the output columns of decorrelated child CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel(pexprRelational->PdpDerive())->PcrsOutput(); // create temp expression of correlations to determine inner columns pdrgpexprCorrelations->AddRef(); CExpression *pexprTemp = CPredicateUtils::PexprConjunction(pmp, pdrgpexprCorrelations); CColRefSet *pcrs = GPOS_NEW(pmp) CColRefSet(pmp, *(CDrvdPropScalar::Pdpscalar(pexprTemp->PdpDerive())->PcrsUsed())); pcrs->Intersection(pcrsOutput); pexprTemp->Release(); // add grouping columns from original agg pcrs->Include(popAggOriginal->Pdrgpcr()); // assemble grouping columns DrgPcr *pdrgpcr = pcrs->Pdrgpcr(pmp); pcrs->Release(); // assemble agg CExpression *pexprProjList = (*pexpr)[1]; pexprProjList->AddRef(); CLogicalGbAgg *popAgg = GPOS_NEW(pmp) CLogicalGbAgg(pmp, pdrgpcr, popAggOriginal->Egbaggtype()); *ppexprDecorrelated = GPOS_NEW(pmp) CExpression(pmp, popAgg, pexprRelational, pexprProjList); return true; }
//--------------------------------------------------------------------------- // @function: // CXformSimplifyGbAgg::FDropGbAgg // // @doc: // Return true if GbAgg operator can be dropped because grouping // columns include a key // //--------------------------------------------------------------------------- BOOL CXformSimplifyGbAgg::FDropGbAgg ( IMemoryPool *pmp, CExpression *pexpr, CXformResult *pxfres ) { CLogicalGbAgg *popAgg = CLogicalGbAgg::PopConvert(pexpr->Pop()); CExpression *pexprRelational = (*pexpr)[0]; CExpression *pexprProjectList = (*pexpr)[1]; if (0 < pexprProjectList->UlArity()) { // GbAgg cannot be dropped if Agg functions are computed return false; } CKeyCollection *pkc = CDrvdPropRelational::Pdprel(pexprRelational->PdpDerive())->Pkc(); if (NULL == pkc) { // relational child does not have key return false; } const ULONG ulKeys = pkc->UlKeys(); BOOL fDrop = false; for (ULONG ul = 0; !fDrop && ul < ulKeys; ul++) { DrgPcr *pdrgpcrKey = pkc->PdrgpcrKey(pmp, ul); CColRefSet *pcrs = GPOS_NEW(pmp) CColRefSet(pmp, pdrgpcrKey); pdrgpcrKey->Release(); CColRefSet *pcrsGrpCols = GPOS_NEW(pmp) CColRefSet(pmp); pcrsGrpCols->Include(popAgg->Pdrgpcr()); BOOL fGrpColsHasKey = pcrsGrpCols->FSubset(pcrs); pcrs->Release(); pcrsGrpCols->Release(); if (fGrpColsHasKey) { // Gb operator can be dropped pexprRelational->AddRef(); CExpression *pexprResult = CUtils::PexprLogicalSelect(pmp, pexprRelational, CPredicateUtils::PexprConjunction(pmp, NULL)); pxfres->Add(pexprResult); fDrop = true; } } return fDrop; }
//--------------------------------------------------------------------------- // @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 *pmp = pxfctxt->Pmp(); // extract components CLogicalGbAgg *popTopGbAgg = CLogicalGbAgg::PopConvert(pexpr->Pop()); GPOS_ASSERT(0 < popTopGbAgg->Pdrgpcr()->UlLength()); 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->UlArity() || 0 < pexprBottomProjectList->UlArity()) { // 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(pmp) CColRefSet(pmp, popTopGbAgg->Pdrgpcr()); CColRefSet *pcrsBottomGrpCols = GPOS_NEW(pmp) CColRefSet(pmp, popBottomGbAgg->Pdrgpcr()); GPOS_ASSERT(pcrsBottomGrpCols->FSubset(pcrsTopGrpCols)); pcrsTopGrpCols->Release(); pcrsBottomGrpCols->Release(); #endif // GPOS_DEBUG pexprChild->AddRef(); CExpression *pexprSelect = CUtils::PexprLogicalSelect(pmp, pexprChild, CPredicateUtils::PexprConjunction(pmp, NULL /*pdrgpexpr*/)); popTopGbAgg->AddRef(); pexprTopProjectList->AddRef(); CExpression *pexprGbAggNew = GPOS_NEW(pmp) CExpression(pmp, popTopGbAgg, pexprSelect, pexprTopProjectList); pxfres->Add(pexprGbAggNew); }
//--------------------------------------------------------------------------- // @function: // CXformCollapseGbAgg::Exfp // // @doc: // Compute xform promise for a given expression handle; // GbAgg must be global and have non empty grouping columns // //--------------------------------------------------------------------------- CXform::EXformPromise CXformCollapseGbAgg::Exfp ( CExpressionHandle &exprhdl ) const { CLogicalGbAgg *popAgg = CLogicalGbAgg::PopConvert(exprhdl.Pop()); if (!popAgg->FGlobal() || 0 == popAgg->Pdrgpcr()->UlLength()) { return CXform::ExfpNone; } return CXform::ExfpHigh; }
//--------------------------------------------------------------------------- // @function: // CXformPushGbBelowJoin::Exfp // // @doc: // Compute xform promise for a given expression handle; // we only push down global aggregates // //--------------------------------------------------------------------------- CXform::EXformPromise CXformPushGbBelowJoin::Exfp ( CExpressionHandle &exprhdl ) const { CLogicalGbAgg *popGbAgg = CLogicalGbAgg::PopConvert(exprhdl.Pop()); if (!popGbAgg->FGlobal()) { return CXform::ExfpNone; } return CXform::ExfpHigh; }
//--------------------------------------------------------------------------- // @function: // CXformGbAgg2Apply::Exfp // // @doc: // Compute xform promise for a given expression handle; // scalar child must have subquery // //--------------------------------------------------------------------------- CXform::EXformPromise CXformGbAgg2Apply::Exfp ( CExpressionHandle &exprhdl ) const { CLogicalGbAgg *popGbAgg = CLogicalGbAgg::PopConvert(exprhdl.Pop()); if (popGbAgg->FGlobal() && exprhdl.Pdpscalar(1)->FHasSubquery()) { return CXform::ExfpHigh; } return CXform::ExfpNone; }
//--------------------------------------------------------------------------- // @function: // CXformSimplifyGbAgg::Exfp // // @doc: // Compute xform promise for a given expression handle; // aggregate must have grouping columns // //--------------------------------------------------------------------------- CXform::EXformPromise CXformSimplifyGbAgg::Exfp ( CExpressionHandle &exprhdl ) const { CLogicalGbAgg *popAgg = CLogicalGbAgg::PopConvert(exprhdl.Pop()); GPOS_ASSERT(COperator::EgbaggtypeGlobal == popAgg->Egbaggtype()); if (0 == popAgg->Pdrgpcr()->UlLength() || NULL != popAgg->PdrgpcrMinimal()) { return CXform::ExfpNone; } return CXform::ExfpHigh; }
//--------------------------------------------------------------------------- // @function: // CXformGbAggWithMDQA2Join::Exfp // // @doc: // Compute xform promise for a given expression handle; // //--------------------------------------------------------------------------- CXform::EXformPromise CXformGbAggWithMDQA2Join::Exfp ( CExpressionHandle &exprhdl ) const { CAutoMemoryPool amp; CLogicalGbAgg *popAgg = CLogicalGbAgg::PopConvert(exprhdl.Pop()); if (COperator::EgbaggtypeGlobal == popAgg->Egbaggtype() && exprhdl.Pdpscalar(1 /*ulChildIndex*/)->FHasMultipleDistinctAggs()) { return CXform::ExfpHigh; } return CXform::ExfpNone; }
//--------------------------------------------------------------------------- // @function: // CXformGbAgg2StreamAgg::Exfp // // @doc: // Compute xform promise for a given expression handle; // grouping columns must be non-empty // //--------------------------------------------------------------------------- CXform::EXformPromise CXformGbAgg2StreamAgg::Exfp ( CExpressionHandle &exprhdl ) const { CLogicalGbAgg *popAgg = CLogicalGbAgg::PopConvert(exprhdl.Pop()); if (0 == popAgg->Pdrgpcr()->UlLength() || !CUtils::FComparisonPossible(popAgg->Pdrgpcr(), IMDType::EcmptL) || exprhdl.Pdpscalar(1 /*ulChildIndex*/)->FHasSubquery()) { // no grouping columns, or no sort operators are available for grouping columns, or // agg functions use subquery arguments return CXform::ExfpNone; } return CXform::ExfpHigh; }
//--------------------------------------------------------------------------- // @function: // CXformGbAgg2StreamAgg::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformGbAgg2StreamAgg::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); CLogicalGbAgg *popAgg = CLogicalGbAgg::PopConvert(pexpr->Pop()); IMemoryPool *pmp = pxfctxt->Pmp(); DrgPcr *pdrgpcr = popAgg->Pdrgpcr(); pdrgpcr->AddRef(); // extract components CExpression *pexprRel = (*pexpr)[0]; CExpression *pexprScalar = (*pexpr)[1]; // addref children pexprRel->AddRef(); pexprScalar->AddRef(); DrgPcr *pdrgpcrArgDQA = popAgg->PdrgpcrArgDQA(); if (0 != pdrgpcrArgDQA->UlSafeLength()) { GPOS_ASSERT(NULL != pdrgpcrArgDQA); pdrgpcrArgDQA->AddRef(); } // create alternative expression CExpression *pexprAlt = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CPhysicalStreamAgg ( pmp, pdrgpcr, popAgg->PdrgpcrMinimal(), popAgg->Egbaggtype(), popAgg->FGeneratesDuplicates(), pdrgpcrArgDQA, CXformUtils::FMultiStageAgg(pexpr) ), pexprRel, pexprScalar ); // add alternative to transformation result pxfres->Add(pexprAlt); }
//--------------------------------------------------------------------------- // @function: // CXformSubqueryUnnest::PexprSubqueryUnnest // // @doc: // Helper for unnesting subquery under a given context // //--------------------------------------------------------------------------- CExpression * CXformSubqueryUnnest::PexprSubqueryUnnest ( IMemoryPool *pmp, CExpression *pexpr, BOOL fEnforceCorrelatedApply ) { GPOS_ASSERT(NULL != pexpr); if (GPOS_FTRACE(EopttraceEnforceCorrelatedExecution) && !fEnforceCorrelatedApply) { // if correlated execution is enforced, we cannot generate an expression // that does not use correlated Apply return NULL; } // extract components CExpression *pexprOuter = (*pexpr)[0]; CExpression *pexprScalar = (*pexpr)[1]; // we add-ref the logical child since the resulting expression must re-use it pexprOuter->AddRef(); CExpression *pexprNewOuter = NULL; CExpression *pexprResidualScalar = NULL; CSubqueryHandler::ESubqueryCtxt esqctxt = CSubqueryHandler::EsqctxtFilter; if (COperator::EopScalarProjectList == pexprScalar->Pop()->Eopid()) { esqctxt = CSubqueryHandler::EsqctxtValue; } // calling the handler removes subqueries and sets new logical and scalar expressions CSubqueryHandler sh(pmp, fEnforceCorrelatedApply); if (!CSubqueryHandler::FProcess ( sh, pexprOuter, pexprScalar, false /* fDisjunctionOrNegation */, esqctxt, &pexprNewOuter, &pexprResidualScalar ) ) { CRefCount::SafeRelease(pexprNewOuter); CRefCount::SafeRelease(pexprResidualScalar); return NULL; } // create a new alternative using the new logical and scalar expressions CExpression *pexprResult = NULL; if (CSubqueryHandler::EsqctxtFilter == esqctxt) { pexprResult = CUtils::PexprLogicalSelect(pmp, pexprNewOuter, pexprResidualScalar); } else { GPOS_ASSERT(CSubqueryHandler::EsqctxtValue == esqctxt); CLogicalSequenceProject *popSeqPrj = NULL; CLogicalGbAgg *popGbAgg = NULL; COperator::EOperatorId eopid = pexpr->Pop()->Eopid(); switch (eopid) { case COperator::EopLogicalProject: pexprResult = CUtils::PexprLogicalProject(pmp, pexprNewOuter, pexprResidualScalar, false /*fNewComputedCol*/); break; case COperator::EopLogicalGbAgg: popGbAgg = CLogicalGbAgg::PopConvert(pexpr->Pop()); popGbAgg->Pdrgpcr()->AddRef(); pexprResult = CUtils::PexprLogicalGbAgg(pmp, popGbAgg->Pdrgpcr(), pexprNewOuter, pexprResidualScalar, popGbAgg->Egbaggtype()); break; case COperator::EopLogicalSequenceProject: popSeqPrj = CLogicalSequenceProject::PopConvert(pexpr->Pop()); popSeqPrj->Pds()->AddRef(); popSeqPrj->Pdrgpos()->AddRef(); popSeqPrj->Pdrgpwf()->AddRef(); pexprResult = CUtils::PexprLogicalSequenceProject(pmp, popSeqPrj->Pds(), popSeqPrj->Pdrgpos(), popSeqPrj->Pdrgpwf(), pexprNewOuter, pexprResidualScalar); break; default: GPOS_ASSERT(!"Unnesting subqueries for an invalid operator"); break; } } // normalize resulting expression CExpression *pexprNormalized = CNormalizer::PexprNormalize(pmp, pexprResult); pexprResult->Release(); // pull up projections CExpression *pexprPullUpProjections = CNormalizer::PexprPullUpProjections(pmp, pexprNormalized); pexprNormalized->Release(); return pexprPullUpProjections; }
//--------------------------------------------------------------------------- // @function: // CXformSimplifyGbAgg::Transform // // @doc: // Actual transformation to simplify a aggregate expression // //--------------------------------------------------------------------------- void CXformSimplifyGbAgg::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(); if (FDropGbAgg(pmp, pexpr,pxfres)) { // grouping columns could be dropped, GbAgg is transformed to a Select return; } // extract components CLogicalGbAgg *popAgg = CLogicalGbAgg::PopConvert(pexpr->Pop()); CExpression *pexprRelational = (*pexpr)[0]; CExpression *pexprProjectList = (*pexpr)[1]; DrgPcr *pdrgpcr = popAgg->Pdrgpcr(); CColRefSet *pcrsGrpCols = GPOS_NEW(pmp) CColRefSet(pmp); pcrsGrpCols->Include(pdrgpcr); CColRefSet *pcrsCovered = GPOS_NEW(pmp) CColRefSet(pmp); // set of grouping columns covered by FD's CColRefSet *pcrsMinimal = GPOS_NEW(pmp) CColRefSet(pmp); // a set of minimal grouping columns based on FD's DrgPfd *pdrgpfd = CDrvdPropRelational::Pdprel(pexpr->PdpDerive())->Pdrgpfd(); // collect grouping columns FD's const ULONG ulSize = pdrgpfd->UlSafeLength(); for (ULONG ul = 0; ul < ulSize; ul++) { CFunctionalDependency *pfd = (*pdrgpfd)[ul]; if (pfd->FIncluded(pcrsGrpCols)) { pcrsCovered->Include(pfd->PcrsDetermined()); pcrsCovered->Include(pfd->PcrsKey()); pcrsMinimal->Include(pfd->PcrsKey()); } } BOOL fCovered = pcrsCovered->FEqual(pcrsGrpCols); pcrsGrpCols->Release(); pcrsCovered->Release(); if (!fCovered) { // the union of RHS of collected FD's does not cover all grouping columns pcrsMinimal->Release(); return; } // create a new Agg with minimal grouping columns pdrgpcr->AddRef(); CLogicalGbAgg *popAggNew = GPOS_NEW(pmp) CLogicalGbAgg(pmp, pdrgpcr, pcrsMinimal->Pdrgpcr(pmp), popAgg->Egbaggtype()); pcrsMinimal->Release(); GPOS_ASSERT(!popAgg->FMatch(popAggNew) && "Simplified aggregate matches original aggregate"); pexprRelational->AddRef(); pexprProjectList->AddRef(); CExpression *pexprResult = GPOS_NEW(pmp) CExpression(pmp, popAggNew, pexprRelational, pexprProjectList); pxfres->Add(pexprResult); }