//--------------------------------------------------------------------------- // @function: // CXformJoinCommutativity::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformJoinCommutativity::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *pmp = pxfctxt->Pmp(); // extract components CExpression *pexprLeft = (*pexpr)[0]; CExpression *pexprRight = (*pexpr)[1]; CExpression *pexprScalar = (*pexpr)[2]; // addref children pexprLeft->AddRef(); pexprRight->AddRef(); pexprScalar->AddRef(); // assemble transformed expression CExpression *pexprAlt = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(pmp, pexprRight, pexprLeft, pexprScalar); // add alternative to transformation result pxfres->Add(pexprAlt); }
//--------------------------------------------------------------------------- // @function: // CXformImplementDynamicBitmapTableGet::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformImplementDynamicBitmapTableGet::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *pmp = pxfctxt->Pmp(); CLogicalDynamicBitmapTableGet *popLogical = CLogicalDynamicBitmapTableGet::PopConvert(pexpr->Pop()); CTableDescriptor *ptabdesc = popLogical->Ptabdesc(); ptabdesc->AddRef(); CName *pname = GPOS_NEW(pmp) CName(pmp, popLogical->Name()); DrgPcr *pdrgpcrOutput = popLogical->PdrgpcrOutput(); GPOS_ASSERT(NULL != pdrgpcrOutput); pdrgpcrOutput->AddRef(); DrgDrgPcr *pdrgpdrgpcrPart = popLogical->PdrgpdrgpcrPart(); pdrgpdrgpcrPart->AddRef(); CPartConstraint *ppartcnstr = popLogical->Ppartcnstr(); ppartcnstr->AddRef(); CPartConstraint *ppartcnstrRel = popLogical->PpartcnstrRel(); ppartcnstrRel->AddRef(); CPhysicalDynamicBitmapTableScan *popPhysical = GPOS_NEW(pmp) CPhysicalDynamicBitmapTableScan ( pmp, popLogical->FPartial(), ptabdesc, pexpr->Pop()->UlOpId(), pname, popLogical->UlScanId(), pdrgpcrOutput, pdrgpdrgpcrPart, popLogical->UlSecondaryScanId(), ppartcnstr, ppartcnstrRel ); CExpression *pexprCondition = (*pexpr)[0]; CExpression *pexprIndexPath = (*pexpr)[1]; pexprCondition->AddRef(); pexprIndexPath->AddRef(); CExpression *pexprPhysical = GPOS_NEW(pmp) CExpression(pmp, popPhysical, pexprCondition, pexprIndexPath); pxfres->Add(pexprPhysical); }
//--------------------------------------------------------------------------- // @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: // CPartitionPropagationSpec::PexprFilter // // @doc: // Return the filter expression for the given Scan Id // //--------------------------------------------------------------------------- CExpression * CPartitionPropagationSpec::PexprFilter ( IMemoryPool *mp, ULONG scan_id ) { CExpression *pexprScalar = m_ppfm->Pexpr(scan_id); GPOS_ASSERT(NULL != pexprScalar); if (CUtils::FScalarIdent(pexprScalar)) { // condition of the form "pkey": translate into pkey = true pexprScalar->AddRef(); pexprScalar = CUtils::PexprScalarEqCmp(mp, pexprScalar, CUtils::PexprScalarConstBool(mp, true /*value*/, false /*is_null*/)); } else if (CPredicateUtils::FNot(pexprScalar) && CUtils::FScalarIdent((*pexprScalar)[0])) { // condition of the form "!pkey": translate into pkey = false CExpression *pexprId = (*pexprScalar)[0]; pexprId->AddRef(); pexprScalar = CUtils::PexprScalarEqCmp(mp, pexprId, CUtils::PexprScalarConstBool(mp, false /*value*/, false /*is_null*/)); } else { pexprScalar->AddRef(); } return pexprScalar; }
//--------------------------------------------------------------------------- // @function: // CJoinOrderDP::PexprJoin // // @doc: // Join expressions in the given two sets // //--------------------------------------------------------------------------- CExpression * CJoinOrderDP::PexprJoin ( CBitSet *pbsFst, CBitSet *pbsSnd ) { GPOS_ASSERT(NULL != pbsFst); GPOS_ASSERT(NULL != pbsSnd); CExpression *pexprFst = PexprLookup(pbsFst); GPOS_ASSERT(NULL != pexprFst); CExpression *pexprSnd = PexprLookup(pbsSnd); GPOS_ASSERT(NULL != pexprSnd); CExpression *pexprScalar = PexprPred(pbsFst, pbsSnd); GPOS_ASSERT(NULL != pexprScalar); pexprFst->AddRef(); pexprSnd->AddRef(); pexprScalar->AddRef(); return CUtils::PexprLogicalJoin<CLogicalInnerJoin>(m_mp, pexprFst, pexprSnd, pexprScalar); }
//--------------------------------------------------------------------------- // @function: // CStatsPredUtils::PstatspredLikeHandleCasting // // @doc: // Create a LIKE statistics filter //--------------------------------------------------------------------------- CStatsPred * CStatsPredUtils::PstatspredLike ( IMemoryPool *pmp, CExpression *pexprPred, CColRefSet *//pcrsOuterRefs, ) { GPOS_ASSERT(NULL != pexprPred); GPOS_ASSERT(CPredicateUtils::FLikePredicate(pexprPred)); CExpression *pexprLeft = (*pexprPred)[0]; CExpression *pexprRight = (*pexprPred)[1]; // we support LIKE predicate of the following patterns // CAST(ScIdent) LIKE Const // CAST(ScIdent) LIKE CAST(Const) // ScIdent LIKE Const // ScIdent LIKE CAST(Const) // CAST(Const) LIKE ScIdent // CAST(Const) LIKE CAST(ScIdent) // const LIKE ScIdent // const LIKE CAST(ScIdent) CExpression *pexprScIdent = NULL; CExpression *pexprScConst = NULL; CPredicateUtils::ExtractLikePredComponents(pexprPred, &pexprScIdent, &pexprScConst); if (NULL == pexprScIdent || NULL == pexprScConst) { return GPOS_NEW(pmp) CStatsPredUnsupported(ULONG_MAX, CStatsPred::EstatscmptLike); } CScalarIdent *popScalarIdent = CScalarIdent::PopConvert(pexprScIdent->Pop()); ULONG ulColId = popScalarIdent->Pcr()->UlId(); CScalarConst *popScalarConst = CScalarConst::PopConvert(pexprScConst->Pop()); IDatum *pdatumLiteral = popScalarConst->Pdatum(); const CColRef *pcr = popScalarIdent->Pcr(); if (!IMDType::FStatsComparable(pcr->Pmdtype(), pdatumLiteral)) { // unsupported stats comparison between the column and datum return GPOS_NEW(pmp) CStatsPredUnsupported(pcr->UlId(), CStatsPred::EstatscmptLike); } CDouble dDefaultScaleFactor(1.0); if (pdatumLiteral->FSupportLikePredicate()) { dDefaultScaleFactor = pdatumLiteral->DLikePredicateScaleFactor(); } pexprLeft->AddRef(); pexprRight->AddRef(); return GPOS_NEW(pmp) CStatsPredLike(ulColId, pexprLeft, pexprRight, dDefaultScaleFactor); }
//--------------------------------------------------------------------------- // @function: // CXformLeftSemiJoin2InnerJoin::Transform // // @doc: // actual transformation // //--------------------------------------------------------------------------- void CXformLeftSemiJoin2InnerJoin::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(); // extract components CExpression *pexprOuter = (*pexpr)[0]; CExpression *pexprInner = (*pexpr)[1]; CExpression *pexprScalar = (*pexpr)[2]; pexprOuter->AddRef(); pexprInner->AddRef(); pexprScalar->AddRef(); // construct grouping columns by collecting used columns in the join predicate // that come from join's inner child CColRefSet *pcrsOuterOutput = CDrvdPropRelational::GetRelationalProperties(pexprOuter->PdpDerive())->PcrsOutput(); CColRefSet *pcrsUsed = CDrvdPropScalar::GetDrvdScalarProps(pexprScalar->PdpDerive())->PcrsUsed(); CColRefSet *pcrsGb = GPOS_NEW(mp) CColRefSet(mp); pcrsGb->Include(pcrsUsed); pcrsGb->Difference(pcrsOuterOutput); GPOS_ASSERT(0 < pcrsGb->Size()); CKeyCollection *pkc = CDrvdPropRelational::GetRelationalProperties(pexprInner->PdpDerive())->Pkc(); if (NULL == pkc || (NULL != pkc && !pkc->FKey(pcrsGb, false /*fExactMatch*/))) { // grouping columns do not cover a key on the inner side, // we need to create a group by on inner side CColRefArray *colref_array = pcrsGb->Pdrgpcr(mp); CExpression *pexprGb = GPOS_NEW(mp) CExpression ( mp, GPOS_NEW(mp) CLogicalGbAgg(mp, colref_array, COperator::EgbaggtypeGlobal /*egbaggtype*/), pexprInner, GPOS_NEW(mp) CExpression(mp, GPOS_NEW(mp) CScalarProjectList(mp)) ); pexprInner = pexprGb; } CExpression *pexprInnerJoin = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(mp, pexprOuter, pexprInner, pexprScalar); pcrsGb->Release(); pxfres->Add(pexprInnerJoin); }
//--------------------------------------------------------------------------- // @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: // CXformGbAggDedup2HashAggDedup::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformGbAggDedup2HashAggDedup::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *pmp = pxfctxt->Pmp(); CLogicalGbAggDeduplicate *popAggDedup = CLogicalGbAggDeduplicate::PopConvert(pexpr->Pop()); DrgPcr *pdrgpcr = popAggDedup->Pdrgpcr(); pdrgpcr->AddRef(); DrgPcr *pdrgpcrKeys = popAggDedup->PdrgpcrKeys(); pdrgpcrKeys->AddRef(); // extract components CExpression *pexprRel = (*pexpr)[0]; CExpression *pexprScalar = (*pexpr)[1]; GPOS_ASSERT(0 == pexprScalar->UlArity()); // addref children pexprRel->AddRef(); pexprScalar->AddRef(); // create alternative expression CExpression *pexprAlt = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CPhysicalHashAggDeduplicate ( pmp, pdrgpcr, popAggDedup->PdrgpcrMinimal(), popAggDedup->Egbaggtype(), pdrgpcrKeys, popAggDedup->FGeneratesDuplicates(), CXformUtils::FMultiStageAgg(pexpr) ), pexprRel, pexprScalar ); // add alternative to transformation result pxfres->Add(pexprAlt); }
//--------------------------------------------------------------------------- // @function: // CNormalizer::FSimplifySelectOnOuterJoin // // @doc: // A SELECT on top of LOJ, where SELECT's predicate is NULL-filtering and // uses columns from LOJ's inner child, is simplified as Inner-Join // // Example: // // select * from (select * from R left join S on r1=s1) as foo where foo.s1>0; // // is converted to: // // select * from R inner join S on r1=s1 and s1>0; // // // //--------------------------------------------------------------------------- BOOL CNormalizer::FSimplifySelectOnOuterJoin ( IMemoryPool *pmp, CExpression *pexprOuterJoin, CExpression *pexprPred, // selection predicate CExpression **ppexprResult ) { GPOS_ASSERT(NULL != pmp); GPOS_ASSERT(COperator::EopLogicalLeftOuterJoin == pexprOuterJoin->Pop()->Eopid()); GPOS_ASSERT(pexprPred->Pop()->FScalar()); GPOS_ASSERT(NULL != ppexprResult); if (0 == pexprOuterJoin->UlArity()) { // exit early for leaf patterns extracted from memo *ppexprResult = NULL; return false; } CExpression *pexprOuterJoinOuterChild = (*pexprOuterJoin)[0]; CExpression *pexprOuterJoinInnerChild = (*pexprOuterJoin)[1]; CExpression *pexprOuterJoinPred = (*pexprOuterJoin)[2]; CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel(pexprOuterJoinInnerChild->PdpDerive())->PcrsOutput(); if (!GPOS_FTRACE(EopttraceDisableOuterJoin2InnerJoinRewrite) && CPredicateUtils::FNullRejecting(pmp, pexprPred, pcrsOutput)) { // we have a predicate on top of LOJ that uses LOJ's inner child, // if the predicate filters-out nulls, we can add it to the join // predicate and turn LOJ into Inner-Join pexprOuterJoinOuterChild->AddRef(); pexprOuterJoinInnerChild->AddRef(); *ppexprResult = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CLogicalInnerJoin(pmp), pexprOuterJoinOuterChild, pexprOuterJoinInnerChild, CPredicateUtils::PexprConjunction(pmp, pexprPred, pexprOuterJoinPred) ); return true; } // failed to convert LOJ to inner-join return false; }
//--------------------------------------------------------------------------- // @function: // CXformImplementLimit::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformImplementLimit::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *pmp = pxfctxt->Pmp(); // extract components CLogicalLimit *popLimit = CLogicalLimit::PopConvert(pexpr->Pop()); CExpression *pexprRelational = (*pexpr)[0]; CExpression *pexprScalarStart = (*pexpr)[1]; CExpression *pexprScalarRows = (*pexpr)[2]; COrderSpec *pos = popLimit->Pos(); // addref all components pexprRelational->AddRef(); pexprScalarStart->AddRef(); pexprScalarRows->AddRef(); popLimit->Pos()->AddRef(); // assemble physical operator CExpression *pexprLimit = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CPhysicalLimit ( pmp, pos, popLimit->FGlobal(), popLimit->FHasCount(), popLimit->FTopLimitUnderDML() ), pexprRelational, pexprScalarStart, pexprScalarRows ); // add alternative to results pxfres->Add(pexprLimit); }
//--------------------------------------------------------------------------- // @function: // CJoinOrderDP::PexprExpand // // @doc: // Create join order // //--------------------------------------------------------------------------- CExpression * CJoinOrderDP::PexprExpand() { CBitSet *pbs = GPOS_NEW(m_pmp) CBitSet(m_pmp); for (ULONG ul = 0; ul < m_ulComps; ul++) { (void) pbs->FExchangeSet(ul); } if (GPOPT_DP_JOIN_ORDERING_SIZE_THRESHOLD < m_ulComps && GPOPT_DP_JOIN_ORDERING_CONNECTEDNESS_THRESHOLD < DMaxConnectedness(pbs)) { // terminate early if computation cost is expected to be large pbs->Release(); return NULL; } CExpression *pexprResult = PexprBestJoinOrder(pbs); if (NULL != pexprResult) { pexprResult->AddRef(); } pbs->Release(); return pexprResult; }
//--------------------------------------------------------------------------- // @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: // CNormalizer::SplitConjunct // // @doc: // Split the given conjunct into pushable and unpushable predicates // // //--------------------------------------------------------------------------- void CNormalizer::SplitConjunct ( IMemoryPool *pmp, CExpression *pexpr, CExpression *pexprConj, DrgPexpr **ppdrgpexprPushable, DrgPexpr **ppdrgpexprUnpushable ) { GPOS_ASSERT(pexpr->Pop()->FLogical()); GPOS_ASSERT(pexprConj->Pop()->FScalar()); GPOS_ASSERT(NULL != ppdrgpexprPushable); GPOS_ASSERT(NULL != ppdrgpexprUnpushable); // collect pushable predicates from given conjunct *ppdrgpexprPushable = GPOS_NEW(pmp) DrgPexpr(pmp); *ppdrgpexprUnpushable = GPOS_NEW(pmp) DrgPexpr(pmp); DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprConj); const ULONG ulSize = pdrgpexprConjuncts->UlLength(); for (ULONG ul = 0; ul < ulSize; ul++) { CExpression *pexprScalar = (*pdrgpexprConjuncts)[ul]; pexprScalar->AddRef(); if (FPushable(pexpr, pexprScalar)) { (*ppdrgpexprPushable)->Append(pexprScalar); } else { (*ppdrgpexprUnpushable)->Append(pexprScalar); } } pdrgpexprConjuncts->Release(); }
//--------------------------------------------------------------------------- // @function: // CNormalizer::SplitConjunctForSeqPrj // // @doc: // Split the given conjunct into pushable and unpushable predicates // for a sequence project expression // //--------------------------------------------------------------------------- void CNormalizer::SplitConjunctForSeqPrj ( IMemoryPool *pmp, CExpression *pexprSeqPrj, CExpression *pexprConj, DrgPexpr **ppdrgpexprPushable, DrgPexpr **ppdrgpexprUnpushable ) { GPOS_ASSERT(NULL != pexprSeqPrj); GPOS_ASSERT(NULL != pexprConj); GPOS_ASSERT(NULL != ppdrgpexprPushable); GPOS_ASSERT(NULL != ppdrgpexprUnpushable); *ppdrgpexprPushable = GPOS_NEW(pmp) DrgPexpr(pmp); *ppdrgpexprUnpushable = GPOS_NEW(pmp) DrgPexpr(pmp); DrgPexpr *pdrgpexprPreds = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprConj); const ULONG ulPreds = pdrgpexprPreds->UlLength(); for (ULONG ul = 0; ul < ulPreds; ul++) { CExpression *pexprPred = (*pdrgpexprPreds)[ul]; pexprPred->AddRef(); if (FPushableThruSeqPrjChild(pexprSeqPrj, pexprPred)) { (*ppdrgpexprPushable)->Append(pexprPred); } else { (*ppdrgpexprUnpushable)->Append(pexprPred); } } pdrgpexprPreds->Release(); }
//--------------------------------------------------------------------------- // @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); }
//--------------------------------------------------------------------------- // @function: // CXformExpandNAryJoin::AddSpecifiedJoinOrder // // @doc: // Expand NAry join in the specified order of inputs // //--------------------------------------------------------------------------- void CXformExpandNAryJoin::AddSpecifiedJoinOrder ( IMemoryPool *pmp, CExpression *pexpr, CXformResult *pxfres ) { GPOS_ASSERT(COperator::EopLogicalNAryJoin == pexpr->Pop()->Eopid()); const ULONG ulArity = pexpr->UlArity(); if (4 > ulArity) { return; } // create a join order with same order of given relations (*pexpr)[0]->AddRef(); (*pexpr)[1]->AddRef(); CExpression *pexprJoin = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(pmp, (*pexpr)[0], (*pexpr)[1], CPredicateUtils::PexprConjunction(pmp, NULL)); for (ULONG ul = 2; ul < ulArity - 1; ul++) { (*pexpr)[ul]->AddRef(); pexprJoin = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(pmp, pexprJoin, (*pexpr)[ul], CPredicateUtils::PexprConjunction(pmp, NULL)); } CExpression *pexprScalar = (*pexpr)[ulArity - 1]; pexprScalar->AddRef(); CExpression *pexprSelect = CUtils::PexprLogicalSelect(pmp, pexprJoin, pexprScalar); CExpression *pexprNormalized = CNormalizer::PexprNormalize(pmp, pexprSelect); pexprSelect->Release(); pxfres->Add(pexprNormalized); }
//--------------------------------------------------------------------------- // @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; }
CExpression* COperator1Expr::CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks) { CExpression* newlhs = m_lhs->CheckLink(brokenlinks); if (newlhs) { if (newlhs==m_lhs) { // not changed } else { // changed //numchanges++; newlhs->AddRef(); //m_lhs->Release(); brokenlinks.push_back(new CBrokenLinkInfo(&m_lhs,m_lhs)); m_lhs = newlhs; } return this; } else { //numchanges++; AddRef(); return Release(); } }
//--------------------------------------------------------------------------- // @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: // CJoinOrderDP::PexprJoin // // @doc: // Join expressions in the given set // //--------------------------------------------------------------------------- CExpression * CJoinOrderDP::PexprJoin ( CBitSet *pbs ) { GPOS_ASSERT(2 == pbs->Size()); CBitSetIter bsi(*pbs); (void) bsi.Advance(); ULONG ulCompFst = bsi.Bit(); (void) bsi.Advance(); ULONG ulCompSnd = bsi.Bit(); GPOS_ASSERT(!bsi.Advance()); CBitSet *pbsFst = GPOS_NEW(m_mp) CBitSet(m_mp); (void) pbsFst->ExchangeSet(ulCompFst); CBitSet *pbsSnd = GPOS_NEW(m_mp) CBitSet(m_mp); (void) pbsSnd->ExchangeSet(ulCompSnd); CExpression *pexprScalar = PexprPred(pbsFst, pbsSnd); pbsFst->Release(); pbsSnd->Release(); if (NULL == pexprScalar) { return NULL; } CExpression *pexprLeft = m_rgpcomp[ulCompFst]->m_pexpr; CExpression *pexprRight = m_rgpcomp[ulCompSnd]->m_pexpr; pexprLeft->AddRef(); pexprRight->AddRef(); pexprScalar->AddRef(); CExpression *pexprJoin = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(m_mp, pexprLeft, pexprRight, pexprScalar); DeriveStats(pexprJoin); // store solution in DP table pbs->AddRef(); #ifdef GPOS_DEBUG BOOL fInserted = #endif // GPOS_DEBUG m_phmbsexpr->Insert(pbs, pexprJoin); GPOS_ASSERT(fInserted); return pexprJoin; }
//--------------------------------------------------------------------------- // @function: // CXformImplementSplit::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformImplementSplit::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); CLogicalSplit *popSplit = CLogicalSplit::PopConvert(pexpr->Pop()); IMemoryPool *pmp = pxfctxt->Pmp(); // extract components for alternative DrgPcr *pdrgpcrDelete = popSplit->PdrgpcrDelete(); pdrgpcrDelete->AddRef(); DrgPcr *pdrgpcrInsert = popSplit->PdrgpcrInsert(); pdrgpcrInsert->AddRef(); CColRef *pcrAction = popSplit->PcrAction(); CColRef *pcrCtid = popSplit->PcrCtid(); CColRef *pcrSegmentId = popSplit->PcrSegmentId(); CColRef *pcrTupleOid = popSplit->PcrTupleOid(); // child of Split operator CExpression *pexprChild = (*pexpr)[0]; CExpression *pexprProjList = (*pexpr)[1]; pexprChild->AddRef(); pexprProjList->AddRef(); // create physical Split CExpression *pexprAlt = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CPhysicalSplit(pmp, pdrgpcrDelete, pdrgpcrInsert, pcrCtid, pcrSegmentId, pcrAction, pcrTupleOid), pexprChild, pexprProjList ); // add alternative to transformation result pxfres->Add(pexprAlt); }
//--------------------------------------------------------------------------- // @function: // CScalarArrayCmp::PexprExpand // // @doc: // Expand array comparison expression into a conjunctive/disjunctive // expression // //--------------------------------------------------------------------------- CExpression * CScalarArrayCmp::PexprExpand ( IMemoryPool *mp, CExpression *pexprArrayCmp ) { GPOS_ASSERT(NULL != pexprArrayCmp); GPOS_ASSERT(EopScalarArrayCmp == pexprArrayCmp->Pop()->Eopid()); CExpression *pexprIdent = (*pexprArrayCmp)[0]; CExpression *pexprArray = CUtils::PexprScalarArrayChild(pexprArrayCmp); CScalarArrayCmp *popArrayCmp = CScalarArrayCmp::PopConvert(pexprArrayCmp->Pop()); ULONG ulArrayElems = 0; if (CUtils::FScalarArray(pexprArray)) { ulArrayElems = CUtils::UlScalarArrayArity(pexprArray); } // if this condition is true, we know the right child of ArrayCmp is a constant. if (0 == ulArrayElems) { // if right child is not an actual array (e.g., Const of type array), return input // expression without expansion pexprArrayCmp->AddRef(); return pexprArrayCmp; } CExpressionArray *pdrgpexpr = GPOS_NEW(mp) CExpressionArray(mp); for (ULONG ul = 0; ul < ulArrayElems; ul++) { CExpression *pexprArrayElem = CUtils::PScalarArrayExprChildAt(mp, pexprArray, ul); pexprIdent->AddRef(); const CWStringConst *str_opname = popArrayCmp->Pstr(); IMDId *mdid_op = popArrayCmp->MdIdOp(); GPOS_ASSERT(IMDId::IsValid(mdid_op)); mdid_op->AddRef(); CExpression *pexprCmp = CUtils::PexprScalarCmp(mp, pexprIdent, pexprArrayElem, *str_opname, mdid_op); pdrgpexpr->Append(pexprCmp); } GPOS_ASSERT(0 < pdrgpexpr->Size()); // deduplicate resulting array CExpressionArray *pdrgpexprDeduped = CUtils::PdrgpexprDedup(mp, pdrgpexpr); pdrgpexpr->Release(); EArrCmpType earrcmpt = popArrayCmp->Earrcmpt(); if (EarrcmpAny == earrcmpt) { return CPredicateUtils::PexprDisjunction(mp, pdrgpexprDeduped); } GPOS_ASSERT(EarrcmpAll == earrcmpt); return CPredicateUtils::PexprConjunction(mp, pdrgpexprDeduped); }
//--------------------------------------------------------------------------- // @function: // CXformImplementAssert::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformImplementAssert::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *pmp = pxfctxt->Pmp(); // extract components CLogicalAssert *popAssert = CLogicalAssert::PopConvert(pexpr->Pop()); CExpression *pexprRelational = (*pexpr)[0]; CExpression *pexprScalar = (*pexpr)[1]; CException *pexc = popAssert->Pexc(); // addref all children pexprRelational->AddRef(); pexprScalar->AddRef(); // assemble physical operator CPhysicalAssert *popPhysicalAssert = GPOS_NEW(pmp) CPhysicalAssert ( pmp, GPOS_NEW(pmp) CException(pexc->UlMajor(), pexc->UlMinor(), pexc->SzFilename(), pexc->UlLine()) ); CExpression *pexprAssert = GPOS_NEW(pmp) CExpression ( pmp, popPhysicalAssert, pexprRelational, pexprScalar ); // add alternative to results pxfres->Add(pexprAssert); }
//--------------------------------------------------------------------------- // @function: // CXformSimplifyLeftOuterJoin::Transform // // @doc: // Actual transformation to simplify left outer join // //--------------------------------------------------------------------------- void CXformSimplifyLeftOuterJoin::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 CExpression *pexprOuter = (*pexpr)[0]; CExpression *pexprInner = (*pexpr)[1]; CExpression *pexprScalar = (*pexpr)[2]; pexprOuter->AddRef(); pexprScalar->AddRef(); CExpression *pexprResult = NULL; // inner child of LOJ can be replaced with empty table GPOS_ASSERT(CUtils::FScalarConstFalse(pexprScalar)); // extract output columns of inner child DrgPcr *pdrgpcr = CDrvdPropRelational::Pdprel(pexprInner->PdpDerive())->PcrsOutput()->Pdrgpcr(pmp); // generate empty constant table with the same columns COperator *popCTG = GPOS_NEW(pmp) CLogicalConstTableGet(pmp, pdrgpcr, GPOS_NEW(pmp) DrgPdrgPdatum(pmp)); pexprResult = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CLogicalLeftOuterJoin(pmp), pexprOuter, GPOS_NEW(pmp) CExpression(pmp, popCTG), pexprScalar ); 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: // 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: // CXformImplementInnerIndexApply::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformImplementInnerIndexApply::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *pmp = pxfctxt->Pmp(); // extract components CExpression *pexprOuter = (*pexpr)[0]; CExpression *pexprInner = (*pexpr)[1]; CExpression *pexprScalar = (*pexpr)[2]; DrgPcr *pdrgpcr = CLogicalInnerIndexApply::PopConvert(pexpr->Pop())->PdrgPcrOuterRefs(); pdrgpcr->AddRef(); // addref all components pexprOuter->AddRef(); pexprInner->AddRef(); pexprScalar->AddRef(); // assemble physical operator CExpression *pexprResult = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CPhysicalInnerIndexNLJoin(pmp, pdrgpcr), pexprOuter, pexprInner, pexprScalar ); // add alternative to results pxfres->Add(pexprResult); }
//--------------------------------------------------------------------------- // @function: // CXformLeftAntiSemiJoin2CrossProduct::Transform // // @doc: // Anti semi join whose join predicate does not use columns from // join's inner child is equivalent to a Cross Product between outer // child (after pushing negated join predicate), and one tuple from // inner child // // //--------------------------------------------------------------------------- void CXformLeftAntiSemiJoin2CrossProduct::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *pmp = pxfctxt->Pmp(); // extract components CExpression *pexprOuter = (*pexpr)[0]; CExpression *pexprInner = (*pexpr)[1]; CExpression *pexprScalar = (*pexpr)[2]; pexprOuter->AddRef(); pexprInner->AddRef(); pexprScalar->AddRef(); CExpression *pexprNegatedScalar = CUtils::PexprNegate(pmp, pexprScalar); // create a (limit 1) on top of inner child CExpression *pexprLimitOffset = CUtils::PexprScalarConstInt8(pmp, 0 /*iVal*/); CExpression *pexprLimitCount = CUtils::PexprScalarConstInt8(pmp, 1 /*iVal*/); COrderSpec *pos = GPOS_NEW(pmp) COrderSpec(pmp); CLogicalLimit *popLimit = GPOS_NEW(pmp) CLogicalLimit(pmp, pos, true /*fGlobal*/, true /*fHasCount*/, false /*fNonRemovableLimit*/); CExpression *pexprLimit = GPOS_NEW(pmp) CExpression(pmp, popLimit, pexprInner, pexprLimitOffset, pexprLimitCount); // create cross product CExpression *pexprJoin = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(pmp, pexprOuter, pexprLimit, pexprNegatedScalar); CExpression *pexprNormalized = CNormalizer::PexprNormalize(pmp, pexprJoin); pexprJoin->Release(); pxfres->Add(pexprNormalized); }
//--------------------------------------------------------------------------- // @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; }