//--------------------------------------------------------------------------- // @function: // CPhysicalUnionAll::PdshashedPassThru // // @doc: // Compute required hashed distribution of the n-th child // //--------------------------------------------------------------------------- CDistributionSpecHashed * CPhysicalUnionAll::PdshashedPassThru ( IMemoryPool *pmp, CDistributionSpecHashed *pdshashedRequired, ULONG ulChildIndex ) const { DrgPexpr *pdrgpexprRequired = pdshashedRequired->Pdrgpexpr(); DrgPcr *pdrgpcrChild = (*m_pdrgpdrgpcrInput)[ulChildIndex]; const ULONG ulExprs = pdrgpexprRequired->UlLength(); const ULONG ulOutputCols = m_pdrgpcrOutput->UlLength(); DrgPexpr *pdrgpexprChildRequired = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ulExpr = 0; ulExpr < ulExprs; ulExpr++) { CExpression *pexpr = (*pdrgpexprRequired)[ulExpr]; if (COperator::EopScalarIdent != pexpr->Pop()->Eopid()) { // skip expressions that are not in form of scalar identifiers continue; } const CColRef *pcrHashed = CScalarIdent::PopConvert(pexpr->Pop())->Pcr(); const IMDType *pmdtype = pcrHashed->Pmdtype(); if (!pmdtype->FHashable()) { // skip non-hashable columns continue; } for (ULONG ulCol = 0; ulCol < ulOutputCols; ulCol++) { const CColRef *pcrOutput = (*m_pdrgpcrOutput)[ulCol]; if (pcrOutput == pcrHashed) { const CColRef *pcrInput = (*pdrgpcrChild)[ulCol]; pdrgpexprChildRequired->Append(CUtils::PexprScalarIdent(pmp, pcrInput)); } } } if (0 < pdrgpexprChildRequired->UlLength()) { return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexprChildRequired, true /* fNullsCollocated */); } // failed to create a matching hashed distribution pdrgpexprChildRequired->Release(); if (NULL != pdshashedRequired->PdshashedEquiv()) { // try again with equivalent distribution return PdshashedPassThru(pmp, pdshashedRequired->PdshashedEquiv(), ulChildIndex); } // failed to create hashed distribution return NULL; }
//--------------------------------------------------------------------------- // @function: // CStatsPredUtils::PdrgpstatsjoinExtract // // @doc: // Helper function to extract array of statistics join filter // from an array of join predicates // //--------------------------------------------------------------------------- DrgPstatsjoin * CStatsPredUtils::PdrgpstatsjoinExtract ( IMemoryPool *pmp, CExpression *pexprScalar, DrgPcrs *pdrgpcrsOutput, // array of output columns of join's relational inputs CColRefSet *pcrsOuterRefs, CStatsPred **ppstatspredUnsupported ) { GPOS_ASSERT(NULL != pexprScalar); GPOS_ASSERT(NULL != pdrgpcrsOutput); DrgPstatsjoin *pdrgpstatsjoin = GPOS_NEW(pmp) DrgPstatsjoin(pmp); DrgPexpr *pdrgpexprUnsupported = GPOS_NEW(pmp) DrgPexpr(pmp); // extract all the conjuncts DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprScalar); const ULONG ulSize = pdrgpexprConjuncts->UlLength(); for (ULONG ul = 0; ul < ulSize; ul++) { CExpression *pexprPred = (*pdrgpexprConjuncts) [ul]; CStatisticsJoin *pstatsjoin = PstatsjoinExtract ( pmp, pexprPred, pdrgpcrsOutput, pcrsOuterRefs, pdrgpexprUnsupported ); if (NULL != pstatsjoin) { pdrgpstatsjoin->Append(pstatsjoin); } } const ULONG ulUnsupported = pdrgpexprUnsupported->UlLength(); if (1 == ulUnsupported) { *ppstatspredUnsupported = CStatsPredUtils::PstatspredExtract(pmp, (*pdrgpexprUnsupported)[0], pcrsOuterRefs); } else if (1 < ulUnsupported) { pdrgpexprUnsupported->AddRef(); CExpression *pexprConj = CPredicateUtils::PexprConjDisj(pmp, pdrgpexprUnsupported, true /* fConjunction */); *ppstatspredUnsupported = CStatsPredUtils::PstatspredExtract(pmp, pexprConj, pcrsOuterRefs); pexprConj->Release(); } // clean up pdrgpexprUnsupported->Release(); pdrgpexprConjuncts->Release(); return pdrgpstatsjoin; }
//--------------------------------------------------------------------------- // @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: // CPhysicalUnionAll::PdsMatching // // @doc: // Compute output hashed distribution based on the outer child's // hashed distribution //--------------------------------------------------------------------------- CDistributionSpecHashed * CPhysicalUnionAll::PdsMatching ( IMemoryPool *pmp, const DrgPul *pdrgpulOuter ) const { GPOS_ASSERT(NULL != pdrgpulOuter); const ULONG ulCols = pdrgpulOuter->UlLength(); GPOS_ASSERT(ulCols <= m_pdrgpcrOutput->UlLength()); DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ulCol = 0; ulCol < ulCols; ulCol++) { ULONG ulIdx = *(*pdrgpulOuter)[ulCol]; CExpression *pexpr = CUtils::PexprScalarIdent(pmp, (*m_pdrgpcrOutput)[ulIdx]); pdrgpexpr->Append(pexpr); } GPOS_ASSERT(0 < pdrgpexpr->UlLength()); return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, true /*fNullsColocated*/); }
//--------------------------------------------------------------------------- // @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: // COptimizer::PrintQuery // // @doc: // Helper function to print query expression // //--------------------------------------------------------------------------- void COptimizer::PrintQuery ( IMemoryPool *pmp, CExpression *pexprTranslated, CQueryContext *pqc ) { CAutoTrace at(pmp); at.Os() << std::endl << "Algebrized query: " << std::endl << *pexprTranslated; DrgPexpr *pdrgpexpr = COptCtxt::PoctxtFromTLS()->Pcteinfo()->PdrgPexpr(pmp); const ULONG ulCTEs = pdrgpexpr->UlLength(); if (0 < ulCTEs) { at.Os() << std::endl << "Common Table Expressions: "; for (ULONG ul = 0; ul < ulCTEs; ul++) { at.Os() << std::endl << *(*pdrgpexpr)[ul]; } } pdrgpexpr->Release(); CExpression *pexprPreprocessed = pqc->Pexpr(); (void) pexprPreprocessed->PdpDerive(); at.Os() << std::endl << "Algebrized preprocessed query: " << std::endl << *pexprPreprocessed; }
//--------------------------------------------------------------------------- // @function: // CStatsPredUtils::FConjunction // // @doc: // Is the condition a conjunctive predicate //--------------------------------------------------------------------------- BOOL CStatsPredUtils::FConjunction ( IMemoryPool *pmp, CExpression *pexprPred ) { GPOS_ASSERT(NULL != pexprPred); DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprPred); const ULONG ulLen = pdrgpexprConjuncts->UlLength(); pdrgpexprConjuncts->Release(); return (1 < ulLen); }
//--------------------------------------------------------------------------- // @function: // CLogicalInnerJoin::FFewerConj // // @doc: // Compare two innerJoin group expressions, test whether the first one // has less join predicates than the second one. This is used to // prioritize innerJoin with less predicates for stats derivation // //--------------------------------------------------------------------------- BOOL CLogicalInnerJoin::FFewerConj ( IMemoryPool *pmp, CGroupExpression *pgexprFst, CGroupExpression *pgexprSnd ) { if (NULL == pgexprFst || NULL == pgexprSnd) { return false; } if (COperator::EopLogicalInnerJoin != pgexprFst->Pop()->Eopid() || COperator::EopLogicalInnerJoin != pgexprSnd->Pop()->Eopid()) { return false; } // third child must be the group for join conditions CGroup *pgroupScalarFst = (*pgexprFst)[2]; CGroup *pgroupScalarSnd = (*pgexprSnd)[2]; GPOS_ASSERT(pgroupScalarFst->FScalar()); GPOS_ASSERT(pgroupScalarSnd->FScalar()); DrgPexpr *pdrgpexprConjFst = CPredicateUtils::PdrgpexprConjuncts(pmp, pgroupScalarFst->PexprScalar()); DrgPexpr *pdrgpexprConjSnd = CPredicateUtils::PdrgpexprConjuncts(pmp, pgroupScalarSnd->PexprScalar()); ULONG ulConjFst = pdrgpexprConjFst->UlLength(); ULONG ulConjSnd = pdrgpexprConjSnd->UlLength(); pdrgpexprConjFst->Release(); pdrgpexprConjSnd->Release(); return ulConjFst < ulConjSnd; }
//--------------------------------------------------------------------------- // @function: // CStatsPredUtils::PstatspredConj // // @doc: // Create conjunctive statistics filter composed of the extracted // components of the conjunction //--------------------------------------------------------------------------- CStatsPred * CStatsPredUtils::PstatspredConj ( IMemoryPool *pmp, CExpression *pexprScalar, CColRefSet *pcrsOuterRefs ) { GPOS_ASSERT(NULL != pexprScalar); DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprScalar); const ULONG ulLen = pdrgpexprConjuncts->UlLength(); DrgPstatspred *pdrgpstatspred = GPOS_NEW(pmp) DrgPstatspred(pmp); for (ULONG ul = 0; ul < ulLen; ul++) { CExpression *pexprPred = (*pdrgpexprConjuncts)[ul]; CColRefSet *pcrsUsed = CDrvdPropScalar::Pdpscalar(pexprPred->PdpDerive())->PcrsUsed(); if (NULL != pcrsOuterRefs && pcrsOuterRefs->FSubset(pcrsUsed)) { // skip predicate with outer references continue; } if (CPredicateUtils::FOr(pexprPred)) { CStatsPred *pstatspredDisj = PstatspredDisj(pmp, pexprPred, pcrsOuterRefs); if (NULL != pstatspredDisj) { pdrgpstatspred->Append(pstatspredDisj); } } else { AddSupportedStatsFilters(pmp, pdrgpstatspred, pexprPred, pcrsOuterRefs); } } pdrgpexprConjuncts->Release(); if (0 < pdrgpstatspred->UlLength()) { return GPOS_NEW(pmp) CStatsPredConj(pdrgpstatspred); } pdrgpstatspred->Release(); return NULL; }
//--------------------------------------------------------------------------- // @function: // CPhysicalJoin::FHashJoinPossible // // @doc: // Check if predicate is hashjoin-able and extract arrays of hash keys // //--------------------------------------------------------------------------- BOOL CPhysicalJoin::FHashJoinPossible ( IMemoryPool *pmp, CExpression *pexpr, DrgPexpr *pdrgpexprOuter, DrgPexpr *pdrgpexprInner, CExpression **ppexprResult // output : join expression to be transformed to hash join ) { GPOS_ASSERT(COperator::EopLogicalNAryJoin != pexpr->Pop()->Eopid() && CUtils::FLogicalJoin(pexpr->Pop())); // we should not be here if there are outer references GPOS_ASSERT(!CUtils::FHasOuterRefs(pexpr)); GPOS_ASSERT(NULL != ppexprResult); // introduce explicit casting, if needed DrgPexpr *pdrgpexpr = CPredicateUtils::PdrgpexprCastEquality(pmp, (*pexpr)[2]); // identify hashkeys ULONG ulPreds = pdrgpexpr->UlLength(); for (ULONG ul = 0; ul < ulPreds; ul++) { CExpression *pexprPred = (*pdrgpexpr)[ul]; if (FHashJoinCompatible(pexprPred, (*pexpr)[0], (*pexpr)[1])) { AddHashKeys(pexprPred, (*pexpr)[0], (*pexpr)[1], pdrgpexprOuter, pdrgpexprInner); } } // construct output join expression pexpr->Pop()->AddRef(); (*pexpr)[0]->AddRef(); (*pexpr)[1]->AddRef(); *ppexprResult = GPOS_NEW(pmp) CExpression ( pmp, pexpr->Pop(), (*pexpr)[0], (*pexpr)[1], CPredicateUtils::PexprConjunction(pmp, pdrgpexpr) ); return (0 != pdrgpexprInner->UlLength()); }
//--------------------------------------------------------------------------- // @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: // CStatsPredUtils::PstatspredDisj // // @doc: // Create disjunctive statistics filter composed of the extracted // components of the disjunction //--------------------------------------------------------------------------- CStatsPred * CStatsPredUtils::PstatspredDisj ( IMemoryPool *pmp, CExpression *pexprPred, CColRefSet *pcrsOuterRefs ) { GPOS_ASSERT(NULL != pexprPred); GPOS_ASSERT(CPredicateUtils::FOr(pexprPred)); DrgPstatspred *pdrgpstatspredDisjChild = GPOS_NEW(pmp) DrgPstatspred(pmp); // remove duplicate components of the OR tree CExpression *pexprNew = CExpressionUtils::PexprDedupChildren(pmp, pexprPred); // extract the components of the OR tree DrgPexpr *pdrgpexpr = CPredicateUtils::PdrgpexprDisjuncts(pmp, pexprNew); const ULONG ulLen = pdrgpexpr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CExpression *pexpr = (*pdrgpexpr)[ul]; CColRefSet *pcrsUsed = CDrvdPropScalar::Pdpscalar(pexpr->PdpDerive())->PcrsUsed(); if (NULL != pcrsOuterRefs && pcrsOuterRefs->FSubset(pcrsUsed)) { // skip predicate with outer references continue; } AddSupportedStatsFilters(pmp, pdrgpstatspredDisjChild, pexpr, pcrsOuterRefs); } // clean up pexprNew->Release(); pdrgpexpr->Release(); if (0 < pdrgpstatspredDisjChild->UlLength()) { return GPOS_NEW(pmp) CStatsPredDisj(pdrgpstatspredDisjChild); } pdrgpstatspredDisjChild->Release(); return NULL; }
//--------------------------------------------------------------------------- // @function: // CPhysicalHashJoin::CreateHashRedistributeRequests // // @doc: // Create the set of redistribute requests to send to first // hash join child // //--------------------------------------------------------------------------- void CPhysicalHashJoin::CreateHashRedistributeRequests ( IMemoryPool *pmp ) { GPOS_ASSERT(NULL == m_pdrgpdsRedistributeRequests); GPOS_ASSERT(NULL != m_pdrgpexprOuterKeys); GPOS_ASSERT(NULL != m_pdrgpexprInnerKeys); DrgPexpr *pdrgpexpr = NULL; if (EceoRightToLeft == Eceo()) { pdrgpexpr = m_pdrgpexprInnerKeys; } else { pdrgpexpr = m_pdrgpexprOuterKeys; } m_pdrgpdsRedistributeRequests = GPOS_NEW(pmp) DrgPds(pmp); const ULONG ulExprs = std::min((ULONG) GPOPT_MAX_HASH_DIST_REQUESTS, pdrgpexpr->UlLength()); if (1 < ulExprs) { for (ULONG ul = 0; ul < ulExprs; ul++) { DrgPexpr *pdrgpexprCurrent = GPOS_NEW(pmp) DrgPexpr(pmp); CExpression *pexpr = (*pdrgpexpr)[ul]; pexpr->AddRef(); pdrgpexprCurrent->Append(pexpr); // add a separate request for each hash join key // TODO: - Dec 30, 2011; change fNullsColocated to false when our // distribution matching can handle differences in NULL colocation CDistributionSpecHashed *pdshashedCurrent = GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexprCurrent, true /* fNullsCollocated */); m_pdrgpdsRedistributeRequests->Append(pdshashedCurrent); } } // add a request that contains all hash join keys pdrgpexpr->AddRef(); CDistributionSpecHashed *pdshashed = GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, true /* fNullsCollocated */); m_pdrgpdsRedistributeRequests->Append(pdshashed); }
//--------------------------------------------------------------------------- // @function: // CCNFConverter::Expand // // @doc: // Recursively compute cross product over input array of arrays; // convert each cross product result to a conjunct and store it in // output array // //--------------------------------------------------------------------------- void CCNFConverter::Expand ( IMemoryPool *pmp, DrgPdrgPexpr *pdrgpdrgpexprInput, // input array of arrays DrgPexpr *pdrgpexprOutput, // output array DrgPexpr *pdrgpexprToExpand, // a cross product result to be expanded ULONG ulCurrent // index of current array to be used for expanding a cross product result ) { GPOS_CHECK_STACK_SIZE; GPOS_ASSERT(ulCurrent <= pdrgpdrgpexprInput->UlLength()); if (ulCurrent == pdrgpdrgpexprInput->UlLength()) { // exhausted input, add a new conjunct to output array pdrgpexprOutput->Append(CPredicateUtils::PexprDisjunction(pmp, pdrgpexprToExpand)); return; } DrgPexpr *pdrgpexprCurrent = (*pdrgpdrgpexprInput)[ulCurrent]; const ULONG ulArity = pdrgpexprCurrent->UlLength(); for (ULONG ul = 0; ul < ulArity; ul++) { // append accumulated expressions to a new array DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); CUtils::AddRefAppend<CExpression, CleanupRelease>(pdrgpexpr, pdrgpexprToExpand); // add an expression from current input array only if it's not equal to an existing one if (!CUtils::FEqualAny((*pdrgpexprCurrent)[ul], pdrgpexpr)) { CExpression *pexpr = (*pdrgpexprCurrent)[ul]; pexpr->AddRef(); pdrgpexpr->Append(pexpr); } // recursively expand the resulting array Expand(pmp, pdrgpdrgpexprInput, pdrgpexprOutput, pdrgpexpr, ulCurrent + 1); } pdrgpexprToExpand->Release(); }
//--------------------------------------------------------------------------- // @function: // CDistributionSpecHashed::PdshashedExcludeColumns // // @doc: // Return a copy of the distribution spec after excluding the given // columns, return NULL if all distribution expressions are excluded // //--------------------------------------------------------------------------- CDistributionSpecHashed * CDistributionSpecHashed::PdshashedExcludeColumns ( IMemoryPool *pmp, CColRefSet *pcrs ) { GPOS_ASSERT(NULL != pcrs); DrgPexpr *pdrgpexprNew = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulExprs = m_pdrgpexpr->UlLength(); for (ULONG ul = 0; ul < ulExprs; ul++) { CExpression *pexpr = (*m_pdrgpexpr)[ul]; COperator *pop = pexpr->Pop(); if (COperator::EopScalarIdent == pop->Eopid()) { // we only care here about column identifiers, // any more complicated expressions are copied to output const CColRef *pcr = CScalarIdent::PopConvert(pop)->Pcr(); if (pcrs->FMember(pcr)) { continue; } } pexpr->AddRef(); pdrgpexprNew->Append(pexpr); } if (0 == pdrgpexprNew->UlLength()) { pdrgpexprNew->Release(); return NULL; } return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexprNew, m_fNullsColocated); }
//--------------------------------------------------------------------------- // @function: // CXformSelect2PartialDynamicIndexGet::CreatePartialIndexGetPlan // // @doc: // Create a plan as a union of the given partial index get candidates and // possibly a dynamic table scan // //--------------------------------------------------------------------------- void CXformSelect2PartialDynamicIndexGet::CreatePartialIndexGetPlan ( IMemoryPool *pmp, CExpression *pexpr, DrgPpartdig *pdrgppartdig, const IMDRelation *pmdrel, CXformResult *pxfres ) const { CExpression *pexprRelational = (*pexpr)[0]; CExpression *pexprScalar = (*pexpr)[1]; CLogicalDynamicGet *popGet = CLogicalDynamicGet::PopConvert(pexprRelational->Pop()); DrgPcr *pdrgpcrGet = popGet->PdrgpcrOutput(); const ULONG ulPartialIndexes = pdrgppartdig->UlLength(); DrgDrgPcr *pdrgpdrgpcrInput = GPOS_NEW(pmp) DrgDrgPcr(pmp); DrgPexpr *pdrgpexprInput = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < ulPartialIndexes; ul++) { SPartDynamicIndexGetInfo *ppartdig = (*pdrgppartdig)[ul]; const IMDIndex *pmdindex = ppartdig->m_pmdindex; CPartConstraint *ppartcnstr = ppartdig->m_ppartcnstr; DrgPexpr *pdrgpexprIndex = ppartdig->m_pdrgpexprIndex; DrgPexpr *pdrgpexprResidual = ppartdig->m_pdrgpexprResidual; DrgPcr *pdrgpcrNew = pdrgpcrGet; if (0 < ul) { pdrgpcrNew = CUtils::PdrgpcrCopy(pmp, pdrgpcrGet); } else { pdrgpcrNew->AddRef(); } CExpression *pexprDynamicScan = NULL; if (NULL != pmdindex) { pexprDynamicScan = CXformUtils::PexprPartialDynamicIndexGet ( pmp, popGet, pexpr->Pop()->UlOpId(), pdrgpexprIndex, pdrgpexprResidual, pdrgpcrNew, pmdindex, pmdrel, ppartcnstr, NULL, // pcrsAcceptedOuterRefs NULL, // pdrgpcrOuter NULL // pdrgpcrNewOuter ); } else { pexprDynamicScan = PexprSelectOverDynamicGet ( pmp, popGet, pexprScalar, pdrgpcrNew, ppartcnstr ); } GPOS_ASSERT(NULL != pexprDynamicScan); pdrgpdrgpcrInput->Append(pdrgpcrNew); pdrgpexprInput->Append(pexprDynamicScan); } ULONG ulInput = pdrgpexprInput->UlLength(); if (0 < ulInput) { CExpression *pexprResult = NULL; if (1 < ulInput) { pdrgpcrGet->AddRef(); DrgPcr *pdrgpcrOuter = pdrgpcrGet; // construct a new union all operator pexprResult = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CLogicalUnionAll(pmp, pdrgpcrOuter, pdrgpdrgpcrInput, popGet->UlScanId()), pdrgpexprInput ); } else { pexprResult = (*pdrgpexprInput)[0]; pexprResult->AddRef(); // clean up pdrgpexprInput->Release(); pdrgpdrgpcrInput->Release(); } // if scalar expression involves the partitioning key, keep a SELECT node // on top for the purposes of partition selection DrgDrgPcr *pdrgpdrgpcrPartKeys = popGet->PdrgpdrgpcrPart(); CExpression *pexprPredOnPartKey = CPredicateUtils::PexprExtractPredicatesOnPartKeys ( pmp, pexprScalar, pdrgpdrgpcrPartKeys, NULL, /*pcrsAllowedRefs*/ true /*fUseConstraints*/ ); if (NULL != pexprPredOnPartKey) { pexprResult = GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CLogicalSelect(pmp), pexprResult, pexprPredOnPartKey); } pxfres->Add(pexprResult); return; } // clean up pdrgpdrgpcrInput->Release(); pdrgpexprInput->Release(); }
//--------------------------------------------------------------------------- // @function: // CPartitionPropagationSpec::SplitPartPredicates // // @doc: // Split the partition elimination predicates over the various levels // as well as the residual predicate and add them to the appropriate // hashmaps. These are to be used when creating the partition selector // //--------------------------------------------------------------------------- void CPartitionPropagationSpec::SplitPartPredicates ( IMemoryPool *pmp, CExpression *pexprScalar, DrgDrgPcr *pdrgpdrgpcrKeys, HMUlExpr *phmulexprEqFilter, // output HMUlExpr *phmulexprFilter, // output CExpression **ppexprResidual // output ) { GPOS_ASSERT(NULL != pexprScalar); GPOS_ASSERT(NULL != pdrgpdrgpcrKeys); GPOS_ASSERT(NULL != phmulexprEqFilter); GPOS_ASSERT(NULL != phmulexprFilter); GPOS_ASSERT(NULL != ppexprResidual); GPOS_ASSERT(NULL == *ppexprResidual); DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprScalar); CBitSet *pbsUsed = GPOS_NEW(pmp) CBitSet(pmp); CColRefSet *pcrsKeys = PcrsKeys(pmp, pdrgpdrgpcrKeys); const ULONG ulLevels = pdrgpdrgpcrKeys->UlLength(); for (ULONG ul = 0; ul < ulLevels; ul++) { CColRef *pcr = CUtils::PcrExtractPartKey(pdrgpdrgpcrKeys, ul); // find conjuncts for this key and mark their positions DrgPexpr *pdrgpexprKey = PdrgpexprPredicatesOnKey(pmp, pdrgpexprConjuncts, pcr, pcrsKeys, &pbsUsed); const ULONG ulLen = pdrgpexprKey->UlLength(); if (0 == ulLen) { // no predicates on this key pdrgpexprKey->Release(); continue; } if (1 < ulLen || (!CPredicateUtils::FEquality((*pdrgpexprKey)[0]))) { // more than one predicate on this key or one non-equality predicate #ifdef GPOS_DEBUG BOOL fResult = #endif // GPOS_DEBUG phmulexprFilter->FInsert(GPOS_NEW(pmp) ULONG(ul), CPredicateUtils::PexprConjunction(pmp, pdrgpexprKey)); GPOS_ASSERT(fResult); continue; } // one equality predicate (key = expr); take out the expression // and add it to the equality filters map CExpression *pexprPartKey = NULL; CExpression *pexprOther = NULL; IMDType::ECmpType ecmpt = IMDType::EcmptOther; CPredicateUtils::ExtractComponents((*pdrgpexprKey)[0], pcr, &pexprPartKey, &pexprOther, &ecmpt); GPOS_ASSERT(NULL != pexprOther); pexprOther->AddRef(); #ifdef GPOS_DEBUG BOOL fResult = #endif // GPOS_DEBUG phmulexprEqFilter->FInsert(GPOS_NEW(pmp) ULONG(ul), pexprOther); GPOS_ASSERT(fResult); pdrgpexprKey->Release(); } (*ppexprResidual) = PexprResidualFilter(pmp, pdrgpexprConjuncts, pbsUsed); pcrsKeys->Release(); pdrgpexprConjuncts->Release(); pbsUsed->Release(); }
//--------------------------------------------------------------------------- // @function: // CDecorrelator::FProcessPredicate // // @doc: // Decorrelate predicate // //--------------------------------------------------------------------------- BOOL CDecorrelator::FProcessPredicate ( IMemoryPool *pmp, CExpression *pexprLogical, // logical parent of predicate tree CExpression *pexprScalar, BOOL fEqualityOnly, CColRefSet *pcrsOutput, CExpression **ppexprDecorrelated, DrgPexpr *pdrgpexprCorrelations ) { GPOS_ASSERT(pexprLogical->Pop()->FLogical()); GPOS_ASSERT(pexprScalar->Pop()->FScalar()); *ppexprDecorrelated = NULL; DrgPexpr *pdrgpexprConj = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprScalar); DrgPexpr *pdrgpexprResiduals = GPOS_NEW(pmp) DrgPexpr(pmp); BOOL fSuccess = true; // divvy up the predicates in residuals (w/ no outer ref) and correlations (w/ outer refs) ULONG ulLength = pdrgpexprConj->UlLength(); for(ULONG ul = 0; ul < ulLength && fSuccess; ul++) { CExpression *pexprConj = (*pdrgpexprConj)[ul]; CColRefSet *pcrsUsed = CDrvdPropScalar::Pdpscalar(pexprConj->PdpDerive())->PcrsUsed(); if (pcrsOutput->FSubset(pcrsUsed)) { // no outer ref pexprConj->AddRef(); pdrgpexprResiduals->Append(pexprConj); continue; } fSuccess = FDelayable(pexprLogical, pexprConj, fEqualityOnly); if (fSuccess) { pexprConj->AddRef(); pdrgpexprCorrelations->Append(pexprConj); } } pdrgpexprConj->Release(); if (!fSuccess || 0 == pdrgpexprResiduals->UlLength()) { // clean up pdrgpexprResiduals->Release(); } else { // residuals become new predicate *ppexprDecorrelated = CPredicateUtils::PexprConjunction(pmp, pdrgpexprResiduals); } return fSuccess; }
//--------------------------------------------------------------------------- // @function: // CJoinOrderTest::EresUnittest_Expand // // @doc: // Simple expansion test // //--------------------------------------------------------------------------- GPOS_RESULT CJoinOrderTest::EresUnittest_Expand() { CAutoMemoryPool amp; IMemoryPool *pmp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(pmp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); // install opt context in TLS CAutoOptCtxt aoc ( pmp, &mda, NULL, /* pceeval */ CTestUtils::Pcm(pmp) ); // build test case CExpression *pexpr = CTestUtils::PexprLogicalNAryJoin(pmp); DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); ULONG ulArity = pexpr->UlArity(); for (ULONG ul = 0; ul < ulArity - 1; ul++) { CExpression *pexprChild = (*pexpr)[ul]; pexprChild->AddRef(); pdrgpexpr->Append(pexprChild); } DrgPexpr *pdrgpexprConj = CPredicateUtils::PdrgpexprConjuncts(pmp, (*pexpr)[ulArity - 1]); // add predicates selectively to trigger special case of cross join DrgPexpr *pdrgpexprTest = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < pdrgpexprConj->UlLength() - 1; ul++) { CExpression *pexprConjunct = (*pdrgpexprConj)[ul]; pexprConjunct->AddRef(); pdrgpexprTest->Append(pexprConjunct); } pdrgpexprConj->Release(); // single-table predicate CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel((*pdrgpexpr)[ulArity - 2]->PdpDerive())->PcrsOutput(); CExpression *pexprSingleton = CUtils::PexprScalarEqCmp(pmp, pcrsOutput->PcrAny(), pcrsOutput->PcrAny()); pdrgpexprTest->Append(pexprSingleton); CJoinOrder jo(pmp, pdrgpexpr, pdrgpexprTest); CExpression *pexprResult = jo.PexprExpand(); { CAutoTrace at(pmp); at.Os() << std::endl << "INPUT:" << std::endl << *pexpr << std::endl; at.Os() << std::endl << "OUTPUT:" << std::endl << *pexprResult << std::endl; } CRefCount::SafeRelease(pexprResult); pexpr->Release(); return GPOS_OK; }
//--------------------------------------------------------------------------- // @function: // CPredicateUtilsTest::EresUnittest_Conjunctions // // @doc: // Test extraction and construction of conjuncts // //--------------------------------------------------------------------------- GPOS_RESULT CPredicateUtilsTest::EresUnittest_Conjunctions() { CAutoMemoryPool amp; IMemoryPool *pmp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(pmp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); // install opt context in TLS CAutoOptCtxt aoc ( pmp, &mda, NULL, /* pceeval */ CTestUtils::Pcm(pmp) ); // build conjunction DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulConjs = 3; for (ULONG ul = 0; ul < ulConjs; ul++) { pdrgpexpr->Append(CUtils::PexprScalarConstBool(pmp, true /*fValue*/)); } CExpression *pexprConjunction = CUtils::PexprScalarBoolOp(pmp, CScalarBoolOp::EboolopAnd, pdrgpexpr); // break into conjuncts DrgPexpr *pdrgpexprExtract = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprConjunction); GPOS_ASSERT(pdrgpexprExtract->UlLength() == ulConjs); // collapse into single conjunct CExpression *pexpr = CPredicateUtils::PexprConjunction(pmp, pdrgpexprExtract); GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(CUtils::FScalarConstTrue(pexpr)); pexpr->Release(); // collapse empty input array to conjunct CExpression *pexprSingleton = CPredicateUtils::PexprConjunction(pmp, NULL /*pdrgpexpr*/); GPOS_ASSERT(NULL != pexprSingleton); pexprSingleton->Release(); pexprConjunction->Release(); // conjunction on scalar comparisons CExpression *pexprGet = CTestUtils::PexprLogicalGet(pmp); CColRefSet *pcrs = CDrvdPropRelational::Pdprel(pexprGet->PdpDerive())->PcrsOutput(); CColRef *pcr1 = pcrs->PcrAny(); CColRef *pcr2 = pcrs->PcrFirst(); CExpression *pexprCmp1 = CUtils::PexprScalarCmp(pmp, pcr1, pcr2, IMDType::EcmptEq); CExpression *pexprCmp2 = CUtils::PexprScalarCmp(pmp, pcr1, CUtils::PexprScalarConstInt4(pmp, 1 /*iVal*/), IMDType::EcmptEq); CExpression *pexprConj = CPredicateUtils::PexprConjunction(pmp, pexprCmp1, pexprCmp2); pdrgpexprExtract = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprConj); GPOS_ASSERT(2 == pdrgpexprExtract->UlLength()); pdrgpexprExtract->Release(); pexprCmp1->Release(); pexprCmp2->Release(); pexprConj->Release(); pexprGet->Release(); return GPOS_OK; }
//--------------------------------------------------------------------------- // @function: // CPredicateUtilsTest::EresUnittest_PlainEqualities // // @doc: // Test the extraction of equality predicates between scalar identifiers // //--------------------------------------------------------------------------- GPOS_RESULT CPredicateUtilsTest::EresUnittest_PlainEqualities() { CAutoMemoryPool amp; IMemoryPool *pmp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(pmp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); // install opt context in TLS CAutoOptCtxt aoc ( pmp, &mda, NULL, /* pceeval */ CTestUtils::Pcm(pmp) ); CExpression *pexprLeft = CTestUtils::PexprLogicalGet(pmp); CExpression *pexprRight = CTestUtils::PexprLogicalGet(pmp); DrgPexpr *pdrgpexprOriginal = GPOS_NEW(pmp) DrgPexpr(pmp); CColRefSet *pcrsLeft = CDrvdPropRelational::Pdprel(pexprLeft->PdpDerive())->PcrsOutput(); CColRefSet *pcrsRight = CDrvdPropRelational::Pdprel(pexprRight->PdpDerive())->PcrsOutput(); CColRef *pcrLeft = pcrsLeft->PcrAny(); CColRef *pcrRight = pcrsRight->PcrAny(); // generate an equality predicate between two column reference CExpression *pexprScIdentEquality = CUtils::PexprScalarEqCmp(pmp, pcrLeft, pcrRight); pexprScIdentEquality->AddRef(); pdrgpexprOriginal->Append(pexprScIdentEquality); // generate a non-equality predicate between two column reference CExpression *pexprScIdentInequality = CUtils::PexprScalarCmp(pmp, pcrLeft, pcrRight, CWStringConst(GPOS_WSZ_LIT("<")), GPOS_NEW(pmp) CMDIdGPDB(GPDB_INT4_LT_OP)); pexprScIdentInequality->AddRef(); pdrgpexprOriginal->Append(pexprScIdentInequality); // generate an equality predicate between a column reference and a constant value CExpression *pexprScalarConstInt4 = CUtils::PexprScalarConstInt4(pmp, 10 /*fValue*/); CExpression *pexprScIdentConstEquality = CUtils::PexprScalarEqCmp(pmp, pexprScalarConstInt4, pcrRight); pdrgpexprOriginal->Append(pexprScIdentConstEquality); GPOS_ASSERT(3 == pdrgpexprOriginal->UlLength()); DrgPexpr *pdrgpexprResult = CPredicateUtils::PdrgpexprPlainEqualities(pmp, pdrgpexprOriginal); GPOS_ASSERT(1 == pdrgpexprResult->UlLength()); // clean up pdrgpexprOriginal->Release(); pdrgpexprResult->Release(); pexprLeft->Release(); pexprRight->Release(); pexprScIdentEquality->Release(); pexprScIdentInequality->Release(); return GPOS_OK; }
void CXformJoinAssociativity::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(); // create new predicates DrgPexpr *pdrgpexprLower = GPOS_NEW(pmp) DrgPexpr(pmp); DrgPexpr *pdrgpexprUpper = GPOS_NEW(pmp) DrgPexpr(pmp); CreatePredicates(pmp, pexpr, pdrgpexprLower, pdrgpexprUpper); GPOS_ASSERT(pdrgpexprLower->UlLength() > 0); // cross join contains CScalarConst(1) as the join condition. if the // input expression is as below with cross join at top level between // CLogicalInnerJoin and CLogicalGet "t3" // +--CLogicalInnerJoin // |--CLogicalInnerJoin // | |--CLogicalGet "t1" // | |--CLogicalGet "t2" // | +--CScalarCmp (=) // | |--CScalarIdent "a" (0) // | +--CScalarIdent "b" (9) // |--CLogicalGet "t3" // +--CScalarConst (1) // for the above expression (lower) predicate generated for the cross join // between t1 and t3 will be: CScalarConst (1) In *only* such cases, donot // generate such alternative with the lower join as cross join example: // +--CLogicalInnerJoin // |--CLogicalInnerJoin // | |--CLogicalGet "t1" // | |--CLogicalGet "t3" // | +--CScalarConst (1) // |--CLogicalGet "t2" // +--CScalarCmp (=) // |--CScalarIdent "a" (0) // +--CScalarIdent "b" (9) // NOTE that we want to be careful to check that input lower join wasn't a // cross join to begin with, because we want to build a join in this case even // though a new cross join will be created. // check if the input lower join expression is a cross join BOOL fInputLeftIsCrossJoin = CUtils::FCrossJoin((*pexpr)[0]); // check if the output lower join would result in a cross join BOOL fOutputLeftIsCrossJoin = (1 == pdrgpexprLower->UlLength() && CUtils::FScalarConstTrue((*pdrgpexprLower)[0])); // build a join only if it does not result in a cross join // unless the input itself was a cross join (see earlier comments) if (!fOutputLeftIsCrossJoin || fInputLeftIsCrossJoin) { // bind operators CExpression *pexprLeft = (*pexpr)[0]; CExpression *pexprLeftLeft = (*pexprLeft)[0]; CExpression *pexprLeftRight = (*pexprLeft)[1]; CExpression *pexprRight = (*pexpr)[1]; // add-ref all components for re-use pexprLeftLeft->AddRef(); pexprRight->AddRef(); pexprLeftRight->AddRef(); // build new joins CExpression *pexprBottomJoin = CUtils::PexprLogicalJoin<CLogicalInnerJoin> ( pmp, pexprLeftLeft, pexprRight, CPredicateUtils::PexprConjunction(pmp, pdrgpexprLower) ); CExpression *pexprResult = CUtils::PexprLogicalJoin<CLogicalInnerJoin> ( pmp, pexprBottomJoin, pexprLeftRight, CPredicateUtils::PexprConjunction(pmp, pdrgpexprUpper) ); // add alternative to transformation result pxfres->Add(pexprResult); } else { pdrgpexprLower->Release(); pdrgpexprUpper->Release(); } }
//--------------------------------------------------------------------------- // @function: // CNormalizer::PexprPullUpProjectElements // // @doc: // Pull up project elements from the given projection expression that do not // exist in the given used columns set. The pulled up project elements must only // use columns that are in the output columns of the parent operator. Returns // a new expression that does not have the pulled up project elements. These // project elements are appended to the given array. // //--------------------------------------------------------------------------- CExpression * CNormalizer::PexprPullUpProjectElements ( IMemoryPool *pmp, CExpression *pexpr, CColRefSet *pcrsUsed, CColRefSet *pcrsOutput, DrgPexpr **ppdrgpexprPrElPullUp // output: the pulled-up project elements ) { GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(COperator::EopLogicalProject == pexpr->Pop()->Eopid()); GPOS_ASSERT(NULL != pcrsUsed); GPOS_ASSERT(NULL != ppdrgpexprPrElPullUp); GPOS_ASSERT(NULL != *ppdrgpexprPrElPullUp); if (2 != pexpr->UlArity()) { // the project's children were not extracted as part of the pattern in this xform GPOS_ASSERT(0 == pexpr->UlArity()); pexpr->AddRef(); return pexpr; } DrgPexpr *pdrgpexprPrElNoPullUp = GPOS_NEW(pmp) DrgPexpr(pmp); CExpression *pexprPrL = (*pexpr)[1]; const ULONG ulProjElements = pexprPrL->UlArity(); for (ULONG ul = 0; ul < ulProjElements; ul++) { CExpression *pexprPrEl = (*pexprPrL)[ul]; CScalarProjectElement *popPrEl = CScalarProjectElement::PopConvert(pexprPrEl->Pop()); CColRef *pcrDefined = popPrEl->Pcr(); CColRefSet *pcrsUsedByProjElem = CDrvdPropScalar::Pdpscalar(pexprPrEl->PdpDerive())->PcrsUsed(); // a proj elem can be pulled up only if the defined column is not in // pcrsUsed and its used columns are in pcrOutput pexprPrEl->AddRef(); if (!pcrsUsed->FMember(pcrDefined) && pcrsOutput->FSubset(pcrsUsedByProjElem)) { (*ppdrgpexprPrElPullUp)->Append(pexprPrEl); } else { pdrgpexprPrElNoPullUp->Append(pexprPrEl); } } CExpression *pexprNew = (*pexpr)[0]; pexprNew->AddRef(); if (0 == pdrgpexprPrElNoPullUp->UlLength()) { pdrgpexprPrElNoPullUp->Release(); } else { // some project elements could not be pulled up - need a project here CExpression *pexprPrjList = GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CScalarProjectList(pmp), pdrgpexprPrElNoPullUp); pexprNew = GPOS_NEW(pmp) CExpression(pmp, GPOS_NEW(pmp) CLogicalProject(pmp), pexprNew, pexprPrjList); } return pexprNew; }
//--------------------------------------------------------------------------- // @function: // CXformTest::EresUnittest_ApplyXforms_CTE // // @doc: // Test application of CTE-related xforms // //--------------------------------------------------------------------------- GPOS_RESULT CXformTest::EresUnittest_ApplyXforms_CTE() { CAutoMemoryPool amp; IMemoryPool *pmp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(pmp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); // install opt context in TLS CAutoOptCtxt aoc ( pmp, &mda, NULL, /* pceeval */ CTestUtils::Pcm(pmp) ); DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); // create producer ULONG ulCTEId = 0; CExpression *pexprProducer = CTestUtils::PexprLogicalCTEProducerOverSelect(pmp, ulCTEId); COptCtxt::PoctxtFromTLS()->Pcteinfo()->AddCTEProducer(pexprProducer); pdrgpexpr->Append(pexprProducer); DrgPcr *pdrgpcrProducer = CLogicalCTEProducer::PopConvert(pexprProducer->Pop())->Pdrgpcr(); DrgPcr *pdrgpcrConsumer = CUtils::PdrgpcrCopy(pmp, pdrgpcrProducer); CExpression *pexprConsumer = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CLogicalCTEConsumer(pmp, ulCTEId, pdrgpcrConsumer) ); pdrgpexpr->Append(pexprConsumer); COptCtxt::PoctxtFromTLS()->Pcteinfo()->IncrementConsumers(ulCTEId); pexprConsumer->AddRef(); CExpression *pexprSelect = CTestUtils::PexprLogicalSelect(pmp, pexprConsumer); pdrgpexpr->Append(pexprSelect); pexprSelect->AddRef(); CExpression *pexprAnchor = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CLogicalCTEAnchor(pmp, ulCTEId), pexprSelect ); pdrgpexpr->Append(pexprAnchor); const ULONG ulLen = pdrgpexpr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CWStringDynamic str(pmp); COstreamString oss(&str); ApplyExprXforms(pmp, oss, (*pdrgpexpr)[ul]); GPOS_TRACE(str.Wsz()); } pdrgpexpr->Release(); return GPOS_OK; }
//--------------------------------------------------------------------------- // @function: // CPredicateUtilsTest::EresUnittest_Disjunctions // // @doc: // Test extraction and construction of disjuncts // //--------------------------------------------------------------------------- GPOS_RESULT CPredicateUtilsTest::EresUnittest_Disjunctions() { CAutoMemoryPool amp; IMemoryPool *pmp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(pmp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); // install opt context in TLS CAutoOptCtxt aoc ( pmp, &mda, NULL, /* pceeval */ CTestUtils::Pcm(pmp) ); // build disjunction DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulDisjs = 3; for (ULONG ul = 0; ul < ulDisjs; ul++) { pdrgpexpr->Append(CUtils::PexprScalarConstBool(pmp, false /*fValue*/)); } CExpression *pexprDisjunction = CUtils::PexprScalarBoolOp(pmp, CScalarBoolOp::EboolopOr, pdrgpexpr); // break into disjuncts DrgPexpr *pdrgpexprExtract = CPredicateUtils::PdrgpexprDisjuncts(pmp, pexprDisjunction); GPOS_ASSERT(pdrgpexprExtract->UlLength() == ulDisjs); // collapse into single disjunct CExpression *pexpr = CPredicateUtils::PexprDisjunction(pmp, pdrgpexprExtract); GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(CUtils::FScalarConstFalse(pexpr)); pexpr->Release(); // collapse empty input array to disjunct CExpression *pexprSingleton = CPredicateUtils::PexprDisjunction(pmp, NULL /*pdrgpexpr*/); GPOS_ASSERT(NULL != pexprSingleton); pexprSingleton->Release(); pexprDisjunction->Release(); // disjunction on scalar comparisons CExpression *pexprGet = CTestUtils::PexprLogicalGet(pmp); CColRefSet *pcrs = CDrvdPropRelational::Pdprel(pexprGet->PdpDerive())->PcrsOutput(); CColRefSetIter crsi(*pcrs); #ifdef GPOS_DEBUG BOOL fAdvance = #endif crsi.FAdvance(); GPOS_ASSERT(fAdvance); CColRef *pcr1 = crsi.Pcr(); #ifdef GPOS_DEBUG fAdvance = #endif crsi.FAdvance(); GPOS_ASSERT(fAdvance); CColRef *pcr2 = crsi.Pcr(); #ifdef GPOS_DEBUG fAdvance = #endif crsi.FAdvance(); GPOS_ASSERT(fAdvance); CColRef *pcr3 = crsi.Pcr(); CExpression *pexprCmp1 = CUtils::PexprScalarCmp(pmp, pcr1, pcr2, IMDType::EcmptEq); CExpression *pexprCmp2 = CUtils::PexprScalarCmp(pmp, pcr1, CUtils::PexprScalarConstInt4(pmp, 1 /*iVal*/), IMDType::EcmptEq); { CExpression *pexprDisj = CPredicateUtils::PexprDisjunction(pmp, pexprCmp1, pexprCmp2); pdrgpexprExtract = CPredicateUtils::PdrgpexprDisjuncts(pmp, pexprDisj); GPOS_ASSERT(2 == pdrgpexprExtract->UlLength()); pdrgpexprExtract->Release(); pexprDisj->Release(); } { DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); CExpression *pexprCmp3 = CUtils::PexprScalarCmp(pmp, pcr2, pcr1, IMDType::EcmptG); CExpression *pexprCmp4 = CUtils::PexprScalarCmp(pmp, CUtils::PexprScalarConstInt4(pmp, 200 /*iVal*/), pcr3, IMDType::EcmptL); pexprCmp1->AddRef(); pexprCmp2->AddRef(); pdrgpexpr->Append(pexprCmp3); pdrgpexpr->Append(pexprCmp4); pdrgpexpr->Append(pexprCmp1); pdrgpexpr->Append(pexprCmp2); CExpression *pexprDisj = CPredicateUtils::PexprDisjunction(pmp, pdrgpexpr); pdrgpexprExtract = CPredicateUtils::PdrgpexprDisjuncts(pmp, pexprDisj); GPOS_ASSERT(4 == pdrgpexprExtract->UlLength()); pdrgpexprExtract->Release(); pexprDisj->Release(); } pexprCmp1->Release(); pexprCmp2->Release(); pexprGet->Release(); return GPOS_OK; }
//--------------------------------------------------------------------------- // @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: // CXformSelect2PartialDynamicIndexGet::Transform // // @doc: // Actual transformation // //--------------------------------------------------------------------------- void CXformSelect2PartialDynamicIndexGet::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 *pexprRelational = (*pexpr)[0]; CExpression *pexprScalar = (*pexpr)[1]; // get the indexes on this relation CLogicalDynamicGet *popGet = CLogicalDynamicGet::PopConvert(pexprRelational->Pop()); if (popGet->FPartial()) { // already a partial dynamic get; do not try to split further return; } CTableDescriptor *ptabdesc = popGet->Ptabdesc(); CMDAccessor *pmda = COptCtxt::PoctxtFromTLS()->Pmda(); const IMDRelation *pmdrel = pmda->Pmdrel(ptabdesc->Pmdid()); const ULONG ulIndices = pmdrel->UlIndices(); if (0 == ulIndices) { // no indexes on the table return; } // array of expressions in the scalar expression DrgPexpr *pdrgpexpr = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprScalar); GPOS_ASSERT(0 < pdrgpexpr->UlLength()); // derive the scalar and relational properties to build set of required columns CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel(pexpr->PdpDerive())->PcrsOutput(); CColRefSet *pcrsScalarExpr = CDrvdPropScalar::Pdpscalar(pexprScalar->PdpDerive())->PcrsUsed(); CColRefSet *pcrsReqd = GPOS_NEW(pmp) CColRefSet(pmp); pcrsReqd->Include(pcrsOutput); pcrsReqd->Include(pcrsScalarExpr); CPartConstraint *ppartcnstr = popGet->Ppartcnstr(); ppartcnstr->AddRef(); // find a candidate set of partial index combinations DrgPdrgPpartdig *pdrgpdrgppartdig = CXformUtils::PdrgpdrgppartdigCandidates ( pmp, pmda, pdrgpexpr, popGet->PdrgpdrgpcrPart(), pmdrel, ppartcnstr, popGet->PdrgpcrOutput(), pcrsReqd, pcrsScalarExpr, NULL // pcrsAcceptedOuterRefs ); // construct alternative partial index scan plans const ULONG ulCandidates = pdrgpdrgppartdig->UlLength(); for (ULONG ul = 0; ul < ulCandidates; ul++) { DrgPpartdig *pdrgppartdig = (*pdrgpdrgppartdig)[ul]; CreatePartialIndexGetPlan(pmp, pexpr, pdrgppartdig, pmdrel, pxfres); } ppartcnstr->Release(); pcrsReqd->Release(); pdrgpexpr->Release(); pdrgpdrgppartdig->Release(); }
//--------------------------------------------------------------------------- // @function: // CXformJoinAssociativity::CreatePredicates // // @doc: // Extract all conjuncts and divvy them up between upper and lower join // //--------------------------------------------------------------------------- void CXformJoinAssociativity::CreatePredicates ( IMemoryPool *pmp, CExpression *pexpr, DrgPexpr *pdrgpexprLower, DrgPexpr *pdrgpexprUpper ) const { GPOS_CHECK_ABORT; // bind operators CExpression *pexprLeft = (*pexpr)[0]; CExpression *pexprLeftLeft = (*pexprLeft)[0]; CExpression *pexprRight = (*pexpr)[1]; DrgPexpr *pdrgpexprJoins = GPOS_NEW(pmp) DrgPexpr(pmp); pexprLeft->AddRef(); pdrgpexprJoins->Append(pexprLeft); pexpr->AddRef(); pdrgpexprJoins->Append(pexpr); // columns for new lower join CColRefSet *pcrsLower = GPOS_NEW(pmp) CColRefSet(pmp); pcrsLower->Union(CDrvdPropRelational::Pdprel(pexprLeftLeft->PdpDerive())->PcrsOutput()); pcrsLower->Union(CDrvdPropRelational::Pdprel(pexprRight->PdpDerive())->PcrsOutput()); // convert current predicates into arrays of conjuncts DrgPexpr *pdrgpexprOrig = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < 2; ul++) { DrgPexpr *pdrgpexprPreds = CPredicateUtils::PdrgpexprConjuncts(pmp, (*(*pdrgpexprJoins)[ul])[2]); ULONG ulLen = pdrgpexprPreds->UlLength(); for (ULONG ulConj = 0; ulConj < ulLen; ulConj++) { CExpression *pexprConj = (*pdrgpexprPreds)[ulConj]; pexprConj->AddRef(); pdrgpexprOrig->Append(pexprConj); } pdrgpexprPreds->Release(); } // divvy up conjuncts for upper and lower join ULONG ulConj = pdrgpexprOrig->UlLength(); for (ULONG ul = 0; ul < ulConj; ul++) { CExpression *pexprPred = (*pdrgpexprOrig)[ul]; CColRefSet *pcrs = CDrvdPropScalar::Pdpscalar(pexprPred->PdpDerive())->PcrsUsed(); pexprPred->AddRef(); if (pcrsLower->FSubset(pcrs)) { pdrgpexprLower->Append(pexprPred); } else { pdrgpexprUpper->Append(pexprPred); } } // No predicates indicate a cross join. And for that, ORCA expects // predicate to be a scalar const "true". if (pdrgpexprLower->UlLength() == 0) { CExpression *pexprCrossLowerJoinPred = CUtils::PexprScalarConstBool(pmp, true, false); pdrgpexprLower->Append(pexprCrossLowerJoinPred); } // Same for upper predicates if (pdrgpexprUpper->UlLength() == 0) { CExpression *pexprCrossUpperJoinPred = CUtils::PexprScalarConstBool(pmp, true, false); pdrgpexprUpper->Append(pexprCrossUpperJoinPred); } // clean up pcrsLower->Release(); pdrgpexprOrig->Release(); pdrgpexprJoins->Release(); }
//--------------------------------------------------------------------------- // @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: // CPredicateUtilsTest::EresUnittest_Implication // // @doc: // Test removal of implied predicates // //--------------------------------------------------------------------------- GPOS_RESULT CPredicateUtilsTest::EresUnittest_Implication() { CAutoMemoryPool amp; IMemoryPool *pmp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(pmp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); // install opt context in TLS CAutoOptCtxt aoc ( pmp, &mda, NULL, /* pceeval */ CTestUtils::Pcm(pmp) ); // generate a two cascaded joins CWStringConst strName1(GPOS_WSZ_LIT("Rel1")); CMDIdGPDB *pmdid1 = GPOS_NEW(pmp) CMDIdGPDB(GPOPT_TEST_REL_OID1, 1, 1); CTableDescriptor *ptabdesc1 = CTestUtils::PtabdescCreate(pmp, 3, pmdid1, CName(&strName1)); CWStringConst strAlias1(GPOS_WSZ_LIT("Rel1")); CExpression *pexprRel1 = CTestUtils::PexprLogicalGet(pmp, ptabdesc1, &strAlias1); CWStringConst strName2(GPOS_WSZ_LIT("Rel2")); CMDIdGPDB *pmdid2 = GPOS_NEW(pmp) CMDIdGPDB(GPOPT_TEST_REL_OID2, 1, 1); CTableDescriptor *ptabdesc2 = CTestUtils::PtabdescCreate(pmp, 3, pmdid2, CName(&strName2)); CWStringConst strAlias2(GPOS_WSZ_LIT("Rel2")); CExpression *pexprRel2 = CTestUtils::PexprLogicalGet(pmp, ptabdesc2, &strAlias2); CWStringConst strName3(GPOS_WSZ_LIT("Rel3")); CMDIdGPDB *pmdid3 = GPOS_NEW(pmp) CMDIdGPDB(GPOPT_TEST_REL_OID3, 1, 1); CTableDescriptor *ptabdesc3 = CTestUtils::PtabdescCreate(pmp, 3, pmdid3, CName(&strName3)); CWStringConst strAlias3(GPOS_WSZ_LIT("Rel3")); CExpression *pexprRel3 = CTestUtils::PexprLogicalGet(pmp, ptabdesc3, &strAlias3); CExpression *pexprJoin1 = CTestUtils::PexprLogicalJoin<CLogicalInnerJoin>(pmp, pexprRel1, pexprRel2); CExpression *pexprJoin2 = CTestUtils::PexprLogicalJoin<CLogicalInnerJoin>(pmp, pexprJoin1, pexprRel3); { CAutoTrace at(pmp); at.Os() << "Original expression:" << std::endl << *pexprJoin2 <<std::endl; } // imply new predicates by deriving constraints CExpression *pexprConstraints = CExpressionPreprocessor::PexprAddPredicatesFromConstraints(pmp, pexprJoin2); { CAutoTrace at(pmp); at.Os() << "Expression with implied predicates:" << std::endl << *pexprConstraints <<std::endl;; } // minimize join predicates by removing implied conjuncts CExpressionHandle exprhdl(pmp); exprhdl.Attach(pexprConstraints); CExpression *pexprMinimizedPred = CPredicateUtils::PexprRemoveImpliedConjuncts(pmp, (*pexprConstraints)[2], exprhdl); { CAutoTrace at(pmp); at.Os() << "Minimized join predicate:" << std::endl << *pexprMinimizedPred <<std::endl; } DrgPexpr *pdrgpexprOriginalConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, (*pexprConstraints)[2]); DrgPexpr *pdrgpexprNewConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprMinimizedPred); GPOS_ASSERT(pdrgpexprNewConjuncts->UlLength() < pdrgpexprOriginalConjuncts->UlLength()); // clean up pdrgpexprOriginalConjuncts->Release(); pdrgpexprNewConjuncts->Release(); pexprJoin2->Release(); pexprConstraints->Release(); pexprMinimizedPred->Release(); return GPOS_OK; }