//--------------------------------------------------------------------------- // @function: // CXformTest::PexprStarJoinTree // // @doc: // Generate a randomized star join tree // //--------------------------------------------------------------------------- CExpression * CXformTest::PexprStarJoinTree ( IMemoryPool *pmp, ULONG ulTabs ) { CExpression *pexprLeft = CTestUtils::PexprLogicalGet(pmp); for (ULONG ul = 1; ul < ulTabs; ul++) { CDrvdPropRelational *pdprelLeft = CDrvdPropRelational::Pdprel(pexprLeft->PdpDerive()); CColRef *pcrLeft = pdprelLeft->PcrsOutput()->PcrAny(); CExpression *pexprRight = CTestUtils::PexprLogicalGet(pmp); CDrvdPropRelational *pdprelRight = CDrvdPropRelational::Pdprel(pexprRight->PdpDerive()); CColRef *pcrRight = pdprelRight->PcrsOutput()->PcrAny(); CExpression *pexprPred = CUtils::PexprScalarEqCmp(pmp, pcrLeft, pcrRight); pexprLeft = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(pmp, pexprLeft, pexprRight, pexprPred); } return pexprLeft; }
//--------------------------------------------------------------------------- // @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: // 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: // 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: // 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: // CXformSimplifyGbAgg::FDropGbAgg // // @doc: // Return true if GbAgg operator can be dropped because grouping // columns include a key // //--------------------------------------------------------------------------- BOOL CXformSimplifyGbAgg::FDropGbAgg ( IMemoryPool *pmp, CExpression *pexpr, CXformResult *pxfres ) { CLogicalGbAgg *popAgg = CLogicalGbAgg::PopConvert(pexpr->Pop()); CExpression *pexprRelational = (*pexpr)[0]; CExpression *pexprProjectList = (*pexpr)[1]; if (0 < pexprProjectList->UlArity()) { // GbAgg cannot be dropped if Agg functions are computed return false; } CKeyCollection *pkc = CDrvdPropRelational::Pdprel(pexprRelational->PdpDerive())->Pkc(); if (NULL == pkc) { // relational child does not have key return false; } const ULONG ulKeys = pkc->UlKeys(); BOOL fDrop = false; for (ULONG ul = 0; !fDrop && ul < ulKeys; ul++) { DrgPcr *pdrgpcrKey = pkc->PdrgpcrKey(pmp, ul); CColRefSet *pcrs = GPOS_NEW(pmp) CColRefSet(pmp, pdrgpcrKey); pdrgpcrKey->Release(); CColRefSet *pcrsGrpCols = GPOS_NEW(pmp) CColRefSet(pmp); pcrsGrpCols->Include(popAgg->Pdrgpcr()); BOOL fGrpColsHasKey = pcrsGrpCols->FSubset(pcrs); pcrs->Release(); pcrsGrpCols->Release(); if (fGrpColsHasKey) { // Gb operator can be dropped pexprRelational->AddRef(); CExpression *pexprResult = CUtils::PexprLogicalSelect(pmp, pexprRelational, CPredicateUtils::PexprConjunction(pmp, NULL)); pxfres->Add(pexprResult); fDrop = true; } } return fDrop; }
//--------------------------------------------------------------------------- // @function: // 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: // CXformGbAggWithMDQA2Join::PexprMDQAs2Join // // @doc: // Converts GbAgg with multiple distinct aggregates into a join of single // distinct aggregates, // // distinct aggregates that share the same argument are grouped together // in one leaf of the generated join expression, // // non-distinct aggregates are also grouped together in one leaf of the // generated join expression // //--------------------------------------------------------------------------- CExpression * CXformGbAggWithMDQA2Join::PexprMDQAs2Join ( IMemoryPool *pmp, CExpression *pexpr ) { GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(COperator::EopLogicalGbAgg == pexpr->Pop()->Eopid()); GPOS_ASSERT(CDrvdPropScalar::Pdpscalar((*pexpr)[1]->PdpDerive())->FHasMultipleDistinctAggs()); // extract components CExpression *pexprChild = (*pexpr)[0]; CColRefSet *pcrsChildOutput = CDrvdPropRelational::Pdprel(pexprChild->PdpDerive())->PcrsOutput(); DrgPcr *pdrgpcrChildOutput = pcrsChildOutput->Pdrgpcr(pmp); // create a CTE producer based on child expression CCTEInfo *pcteinfo = COptCtxt::PoctxtFromTLS()->Pcteinfo(); const ULONG ulCTEId = pcteinfo->UlNextId(); (void) CXformUtils::PexprAddCTEProducer(pmp, ulCTEId, pdrgpcrChildOutput, pexprChild); // create a CTE consumer with child output columns CExpression *pexprConsumer = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CLogicalCTEConsumer(pmp, ulCTEId, pdrgpcrChildOutput) ); pcteinfo->IncrementConsumers(ulCTEId); // finalize GbAgg expression by replacing its child with CTE consumer pexpr->Pop()->AddRef(); (*pexpr)[1]->AddRef(); CExpression *pexprGbAggWithConsumer = GPOS_NEW(pmp) CExpression(pmp, pexpr->Pop(), pexprConsumer, (*pexpr)[1]); CExpression *pexprJoinDQAs = CXformUtils::PexprGbAggOnCTEConsumer2Join(pmp, pexprGbAggWithConsumer); GPOS_ASSERT(NULL != pexprJoinDQAs); pexprGbAggWithConsumer->Release(); return GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CLogicalCTEAnchor(pmp, ulCTEId), pexprJoinDQAs ); }
//--------------------------------------------------------------------------- // @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: // CLogicalCTEAnchor::PpartinfoDerive // // @doc: // Derive part consumer // //--------------------------------------------------------------------------- CPartInfo * CLogicalCTEAnchor::PpartinfoDerive ( IMemoryPool *pmp, CExpressionHandle &exprhdl ) const { CPartInfo *ppartinfoChild = exprhdl.Pdprel(0 /*ulChildIndex*/)->Ppartinfo(); GPOS_ASSERT(NULL != ppartinfoChild); CExpression *pexprProducer = COptCtxt::PoctxtFromTLS()->Pcteinfo()->PexprCTEProducer(m_ulId); GPOS_ASSERT(NULL != pexprProducer); CPartInfo *ppartinfoCTEProducer = CDrvdPropRelational::Pdprel(pexprProducer->PdpDerive())->Ppartinfo(); return CPartInfo::PpartinfoCombine(pmp, ppartinfoChild, ppartinfoCTEProducer); }
//--------------------------------------------------------------------------- // @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: // CExpressionHandle::DeriveProps // // @doc: // Recursive property derivation // //--------------------------------------------------------------------------- void CExpressionHandle::DeriveProps ( CDrvdPropCtxt *pdpctxt ) { GPOS_ASSERT(NULL == m_pdrgpdp); GPOS_ASSERT(NULL == m_pdp); GPOS_CHECK_ABORT; if (NULL != m_pgexpr) { CopyGroupProps(); return; } GPOS_ASSERT(NULL != m_pexpr); // check if expression already has derived props if (NULL != m_pexpr->Pdp(m_pexpr->Ept())) { CopyExprProps(); return; } // copy stats of attached expression CopyStats(); // extract children's properties m_pdrgpdp = GPOS_NEW(m_pmp) DrgPdp(m_pmp); const ULONG ulArity = m_pexpr->UlArity(); for (ULONG ul = 0; ul < ulArity; ul++) { CExpression *pexprChild = (*m_pexpr)[ul]; CDrvdProp *pdp = pexprChild->PdpDerive(pdpctxt); pdp->AddRef(); m_pdrgpdp->Append(pdp); // add child props to derivation context CDrvdPropCtxt::AddDerivedProps(pdp, pdpctxt); } // create/derive local properties m_pdp = Pop()->PdpCreate(m_pmp); m_pdp->Derive(m_pmp, *this, pdpctxt); }
//--------------------------------------------------------------------------- // @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: // CPartitionPropagationSpec::PdrgpexprPredicatesOnKey // // @doc: // Returns an array of predicates on the given partitioning key given // an array of predicates on all keys // //--------------------------------------------------------------------------- DrgPexpr * CPartitionPropagationSpec::PdrgpexprPredicatesOnKey ( IMemoryPool *pmp, DrgPexpr *pdrgpexpr, CColRef *pcr, CColRefSet *pcrsKeys, CBitSet **ppbs ) { GPOS_ASSERT(NULL != pdrgpexpr); GPOS_ASSERT(NULL != pcr); GPOS_ASSERT(NULL != ppbs); GPOS_ASSERT(NULL != *ppbs); DrgPexpr *pdrgpexprResult = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulLen = pdrgpexpr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { if ((*ppbs)->FBit(ul)) { // this expression has already been added for another column continue; } CExpression *pexpr = (*pdrgpexpr)[ul]; GPOS_ASSERT(pexpr->Pop()->FScalar()); CColRefSet *pcrsUsed = CDrvdPropScalar::Pdpscalar(pexpr->PdpDerive())->PcrsUsed(); CColRefSet *pcrsUsedKeys = GPOS_NEW(pmp) CColRefSet(pmp, *pcrsUsed); pcrsUsedKeys->Intersection(pcrsKeys); if (1 == pcrsUsedKeys->CElements() && pcrsUsedKeys->FMember(pcr)) { pexpr->AddRef(); pdrgpexprResult->Append(pexpr); (*ppbs)->FExchangeSet(ul); } pcrsUsedKeys->Release(); } return pdrgpexprResult; }
//--------------------------------------------------------------------------- // @function: // CPartitionPropagationSpec::PdrgpexprPredicatesOnKey // // @doc: // Returns an array of predicates on the given partitioning key given // an array of predicates on all keys // //--------------------------------------------------------------------------- CExpressionArray * CPartitionPropagationSpec::PdrgpexprPredicatesOnKey ( IMemoryPool *mp, CExpressionArray *pdrgpexpr, CColRef *colref, CColRefSet *pcrsKeys, CBitSet **ppbs ) { GPOS_ASSERT(NULL != pdrgpexpr); GPOS_ASSERT(NULL != colref); GPOS_ASSERT(NULL != ppbs); GPOS_ASSERT(NULL != *ppbs); CExpressionArray *pdrgpexprResult = GPOS_NEW(mp) CExpressionArray(mp); const ULONG length = pdrgpexpr->Size(); for (ULONG ul = 0; ul < length; ul++) { if ((*ppbs)->Get(ul)) { // this expression has already been added for another column continue; } CExpression *pexpr = (*pdrgpexpr)[ul]; GPOS_ASSERT(pexpr->Pop()->FScalar()); CColRefSet *pcrsUsed = CDrvdPropScalar::GetDrvdScalarProps(pexpr->PdpDerive())->PcrsUsed(); CColRefSet *pcrsUsedKeys = GPOS_NEW(mp) CColRefSet(mp, *pcrsUsed); pcrsUsedKeys->Intersection(pcrsKeys); if (1 == pcrsUsedKeys->Size() && pcrsUsedKeys->FMember(colref)) { pexpr->AddRef(); pdrgpexprResult->Append(pexpr); (*ppbs)->ExchangeSet(ul); } pcrsUsedKeys->Release(); } return pdrgpexprResult; }
//--------------------------------------------------------------------------- // @function: // CDecorrelator::FProcessAssert // // @doc: // Decorrelate assert operator // //--------------------------------------------------------------------------- BOOL CDecorrelator::FProcessAssert ( IMemoryPool *pmp, CExpression *pexpr, BOOL fEqualityOnly, CExpression **ppexprDecorrelated, DrgPexpr *pdrgpexprCorrelations ) { GPOS_ASSERT(NULL != pexpr); COperator *pop = pexpr->Pop(); GPOS_ASSERT(COperator::EopLogicalAssert == pop->Eopid()); CExpression *pexprScalar = (*pexpr)[1]; // fail if assert expression has outer references CColRefSet *pcrsOutput = CDrvdPropRelational::Pdprel((*pexpr)[0]->PdpDerive())->PcrsOutput(); CColRefSet *pcrsUsed = CDrvdPropScalar::Pdpscalar(pexprScalar->PdpDerive())->PcrsUsed(); if (!pcrsOutput->FSubset(pcrsUsed)) { return false; } // decorrelate relational child CExpression *pexprRelational = NULL; if (!FProcess(pmp, (*pexpr)[0], fEqualityOnly, &pexprRelational, pdrgpexprCorrelations)) { GPOS_ASSERT(NULL == pexprRelational); return false; } // assemble new project pop->AddRef(); pexprScalar->AddRef(); *ppexprDecorrelated = GPOS_NEW(pmp) CExpression(pmp, pop, pexprRelational, pexprScalar); return true; }
//--------------------------------------------------------------------------- // @function: // CPredicateUtilsTest::EresUnittest_Disjunctions // // @doc: // Test extraction and construction of disjuncts // //--------------------------------------------------------------------------- GPOS_RESULT CPredicateUtilsTest::EresUnittest_Disjunctions() { CAutoMemoryPool amp; IMemoryPool *mp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(mp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); // install opt context in TLS CAutoOptCtxt aoc ( mp, &mda, NULL, /* pceeval */ CTestUtils::GetCostModel(mp) ); // build disjunction CExpressionArray *pdrgpexpr = GPOS_NEW(mp) CExpressionArray(mp); const ULONG ulDisjs = 3; for (ULONG ul = 0; ul < ulDisjs; ul++) { pdrgpexpr->Append(CUtils::PexprScalarConstBool(mp, false /*fValue*/)); } CExpression *pexprDisjunction = CUtils::PexprScalarBoolOp(mp, CScalarBoolOp::EboolopOr, pdrgpexpr); // break into disjuncts CExpressionArray *pdrgpexprExtract = CPredicateUtils::PdrgpexprDisjuncts(mp, pexprDisjunction); GPOS_ASSERT(pdrgpexprExtract->Size() == ulDisjs); // collapse into single disjunct CExpression *pexpr = CPredicateUtils::PexprDisjunction(mp, pdrgpexprExtract); GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(CUtils::FScalarConstFalse(pexpr)); pexpr->Release(); // collapse empty input array to disjunct CExpression *pexprSingleton = CPredicateUtils::PexprDisjunction(mp, NULL /*pdrgpexpr*/); GPOS_ASSERT(NULL != pexprSingleton); pexprSingleton->Release(); pexprDisjunction->Release(); // disjunction on scalar comparisons CExpression *pexprGet = CTestUtils::PexprLogicalGet(mp); CColRefSet *pcrs = CDrvdPropRelational::GetRelationalProperties(pexprGet->PdpDerive())->PcrsOutput(); CColRefSetIter crsi(*pcrs); #ifdef GPOS_DEBUG BOOL fAdvance = #endif crsi.Advance(); GPOS_ASSERT(fAdvance); CColRef *pcr1 = crsi.Pcr(); #ifdef GPOS_DEBUG fAdvance = #endif crsi.Advance(); GPOS_ASSERT(fAdvance); CColRef *pcr2 = crsi.Pcr(); #ifdef GPOS_DEBUG fAdvance = #endif crsi.Advance(); GPOS_ASSERT(fAdvance); CColRef *pcr3 = crsi.Pcr(); CExpression *pexprCmp1 = CUtils::PexprScalarCmp(mp, pcr1, pcr2, IMDType::EcmptEq); CExpression *pexprCmp2 = CUtils::PexprScalarCmp(mp, pcr1, CUtils::PexprScalarConstInt4(mp, 1 /*val*/), IMDType::EcmptEq); { CExpression *pexprDisj = CPredicateUtils::PexprDisjunction(mp, pexprCmp1, pexprCmp2); pdrgpexprExtract = CPredicateUtils::PdrgpexprDisjuncts(mp, pexprDisj); GPOS_ASSERT(2 == pdrgpexprExtract->Size()); pdrgpexprExtract->Release(); pexprDisj->Release(); } { CExpressionArray *pdrgpexpr = GPOS_NEW(mp) CExpressionArray(mp); CExpression *pexprCmp3 = CUtils::PexprScalarCmp(mp, pcr2, pcr1, IMDType::EcmptG); CExpression *pexprCmp4 = CUtils::PexprScalarCmp(mp, CUtils::PexprScalarConstInt4(mp, 200 /*val*/), pcr3, IMDType::EcmptL); pexprCmp1->AddRef(); pexprCmp2->AddRef(); pdrgpexpr->Append(pexprCmp3); pdrgpexpr->Append(pexprCmp4); pdrgpexpr->Append(pexprCmp1); pdrgpexpr->Append(pexprCmp2); CExpression *pexprDisj = CPredicateUtils::PexprDisjunction(mp, pdrgpexpr); pdrgpexprExtract = CPredicateUtils::PdrgpexprDisjuncts(mp, pexprDisj); GPOS_ASSERT(4 == pdrgpexprExtract->Size()); pdrgpexprExtract->Release(); pexprDisj->Release(); } pexprCmp1->Release(); pexprCmp2->Release(); pexprGet->Release(); return GPOS_OK; }
//--------------------------------------------------------------------------- // @function: // CPartitionPropagationSpec::AppendEnforcers // // @doc: // Add required enforcers to dynamic array // //--------------------------------------------------------------------------- void CPartitionPropagationSpec::AppendEnforcers ( IMemoryPool *mp, CExpressionHandle &exprhdl, CReqdPropPlan * #ifdef GPOS_DEBUG prpp #endif // GPOS_DEBUG , CExpressionArray *pdrgpexpr, CExpression *pexpr ) { GPOS_ASSERT(NULL != prpp); GPOS_ASSERT(NULL != mp); GPOS_ASSERT(NULL != pdrgpexpr); GPOS_ASSERT(NULL != pexpr); ULongPtrArray *pdrgpul = m_ppim->PdrgpulScanIds(mp); const ULONG size = pdrgpul->Size(); for (ULONG ul = 0; ul < size; ul++) { ULONG scan_id = *((*pdrgpul)[ul]); GPOS_ASSERT(m_ppim->Contains(scan_id)); if (CPartIndexMap::EpimConsumer != m_ppim->Epim(scan_id) || 0 < m_ppim->UlExpectedPropagators(scan_id)) { continue; } if (!FRequiresPartitionPropagation(mp, pexpr, exprhdl, scan_id)) { continue; } CExpression *pexprResolver = NULL; IMDId *mdid = m_ppim->GetRelMdId(scan_id); CColRef2dArray *pdrgpdrgpcrKeys = NULL; CPartKeysArray *pdrgppartkeys = m_ppim->Pdrgppartkeys(scan_id); CPartConstraint *ppartcnstr = m_ppim->PpartcnstrRel(scan_id); UlongToPartConstraintMap *ppartcnstrmap = m_ppim->Ppartcnstrmap(scan_id); mdid->AddRef(); ppartcnstr->AddRef(); ppartcnstrmap->AddRef(); pexpr->AddRef(); // check if there is a predicate on this part index id UlongToExprMap *phmulexprEqFilter = GPOS_NEW(mp) UlongToExprMap(mp); UlongToExprMap *phmulexprFilter = GPOS_NEW(mp) UlongToExprMap(mp); CExpression *pexprResidual = NULL; if (m_ppfm->FContainsScanId(scan_id)) { CExpression *pexprScalar = PexprFilter(mp, scan_id); // find out which keys are used in the predicate, in case there are multiple // keys at this point (e.g. from a union of multiple CTE consumers) CColRefSet *pcrsUsed = CDrvdPropScalar::GetDrvdScalarProps(pexprScalar->PdpDerive())->PcrsUsed(); const ULONG ulKeysets = pdrgppartkeys->Size(); for (ULONG ulKey = 0; NULL == pdrgpdrgpcrKeys && ulKey < ulKeysets; ulKey++) { // get partition key CPartKeys *ppartkeys = (*pdrgppartkeys)[ulKey]; if (ppartkeys->FOverlap(pcrsUsed)) { pdrgpdrgpcrKeys = ppartkeys->Pdrgpdrgpcr(); } } // if we cannot find partition keys mapping the partition predicates, fall back to planner if (NULL == pdrgpdrgpcrKeys) { GPOS_RAISE(gpopt::ExmaGPOPT, gpopt::ExmiUnsatisfiedRequiredProperties); } pdrgpdrgpcrKeys->AddRef(); // split predicates and put them in the appropriate hashmaps SplitPartPredicates(mp, pexprScalar, pdrgpdrgpcrKeys, phmulexprEqFilter, phmulexprFilter, &pexprResidual); pexprScalar->Release(); } else { // doesn't matter which keys we use here since there is no filter GPOS_ASSERT(1 <= pdrgppartkeys->Size()); pdrgpdrgpcrKeys = (*pdrgppartkeys)[0]->Pdrgpdrgpcr(); pdrgpdrgpcrKeys->AddRef(); } pexprResolver = GPOS_NEW(mp) CExpression ( mp, GPOS_NEW(mp) CPhysicalPartitionSelector ( mp, scan_id, mdid, pdrgpdrgpcrKeys, ppartcnstrmap, ppartcnstr, phmulexprEqFilter, phmulexprFilter, pexprResidual ), pexpr ); pdrgpexpr->Append(pexprResolver); } pdrgpul->Release(); }
//--------------------------------------------------------------------------- // @function: // CContradictionTest::EresUnittest_Constraint // // @doc: // Tests for constraint property derivation and constraint push down // //--------------------------------------------------------------------------- GPOS_RESULT CContradictionTest::EresUnittest_Constraint() { 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); typedef CExpression *(*Pfpexpr)(IMemoryPool*); Pfpexpr rgpf[] = { CTestUtils::PexprLogicalApplyWithOuterRef<CLogicalInnerApply>, CTestUtils::PexprLogicalApply<CLogicalLeftSemiApply>, CTestUtils::PexprLogicalApply<CLogicalLeftAntiSemiApply>, CTestUtils::PexprLogicalApplyWithOuterRef<CLogicalLeftOuterApply>, CTestUtils::PexprLogicalGet, CTestUtils::PexprLogicalGetPartitioned, CTestUtils::PexprLogicalSelect, CTestUtils::PexprLogicalSelectCmpToConst, CTestUtils::PexprLogicalSelectPartitioned, CTestUtils::PexprLogicalSelectWithContradiction, CTestUtils::PexprLogicalJoin<CLogicalInnerJoin>, CTestUtils::PexprLogicalJoin<CLogicalLeftOuterJoin>, CTestUtils::PexprLogicalJoin<CLogicalLeftSemiJoin>, CTestUtils::PexprLogicalJoin<CLogicalLeftAntiSemiJoin>, CTestUtils::PexprLogicalGbAgg, CTestUtils::PexprLogicalGbAggOverJoin, CTestUtils::PexprLogicalGbAggWithSum, CTestUtils::PexprLogicalLimit, CTestUtils::PexprLogicalNAryJoin, CTestUtils::PexprLogicalProject, CTestUtils::PexprConstTableGet5, CTestUtils::PexprLogicalDynamicGet, CTestUtils::PexprLogicalSequence, CTestUtils::PexprLogicalTVFTwoArgs, }; for (ULONG i = 0; i < GPOS_ARRAY_SIZE(rgpf); i++) { // install opt context in TLS CAutoOptCtxt aoc ( pmp, &mda, NULL, /* pceeval */ CTestUtils::Pcm(pmp) ); // generate simple expression CExpression *pexpr = rgpf[i](pmp); // self-match GPOS_ASSERT(pexpr->FMatchDebug(pexpr)); // debug print CWStringDynamic str(pmp, GPOS_WSZ_LIT("\n")); COstreamString oss(&str); oss << "EXPR:" << std::endl << *pexpr << std::endl; GPOS_TRACE(str.Wsz()); str.Reset(); #ifdef GPOS_DEBUG // derive properties on expression (void) pexpr->PdpDerive(); oss << std::endl << "DERIVED PROPS:" << std::endl; GPOS_TRACE(str.Wsz()); str.Reset(); pexpr->DbgPrint(); #endif // GPOS_DEBUG CExpression *pexprPreprocessed = CExpressionPreprocessor::PexprPreprocess(pmp, pexpr); oss << std::endl << "PREPROCESSED EXPR:" << std::endl << *pexprPreprocessed << std::endl; GPOS_TRACE(str.Wsz()); str.Reset(); // cleanup pexprPreprocessed->Release(); pexpr->Release(); } return GPOS_OK; }
//--------------------------------------------------------------------------- // @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: // CLogicalDynamicGetBase::PstatsDeriveFilter // // @doc: // Derive stats from base table using filters on partition and/or index columns // //--------------------------------------------------------------------------- IStatistics * CLogicalDynamicGetBase::PstatsDeriveFilter ( IMemoryPool *pmp, CExpressionHandle &exprhdl, CExpression *pexprFilter ) const { CExpression *pexprFilterNew = NULL; CConstraint *pcnstr = m_ppartcnstr->PcnstrCombined(); if (m_fPartial && NULL != pcnstr && !pcnstr->FUnbounded()) { if (NULL == pexprFilter) { pexprFilterNew = pcnstr->PexprScalar(pmp); pexprFilterNew->AddRef(); } else { pexprFilterNew = CPredicateUtils::PexprConjunction(pmp, pexprFilter, pcnstr->PexprScalar(pmp)); } } else if (NULL != pexprFilter) { pexprFilterNew = pexprFilter; pexprFilterNew->AddRef(); } CColRefSet *pcrsStat = GPOS_NEW(pmp) CColRefSet(pmp); CDrvdPropScalar *pdpscalar = NULL; if (NULL != pexprFilterNew) { pdpscalar = CDrvdPropScalar::Pdpscalar(pexprFilterNew->PdpDerive()); pcrsStat->Include(pdpscalar->PcrsUsed()); } // requesting statistics on distribution columns to estimate data skew if (NULL != m_pcrsDist) { pcrsStat->Include(m_pcrsDist); } IStatistics *pstatsFullTable = PstatsBaseTable(pmp, exprhdl, m_ptabdesc, pcrsStat); pcrsStat->Release(); if (NULL == pexprFilterNew || pdpscalar->FHasSubquery()) { return pstatsFullTable; } CStatsPred *pstatspred = CStatsPredUtils::PstatspredExtract ( pmp, pexprFilterNew, NULL /*pcrsOuterRefs*/ ); pexprFilterNew->Release(); IStatistics *pstatsResult = pstatsFullTable->PstatsFilter ( pmp, pstatspred, true /* fCapNdvs */ ); pstatspred->Release(); pstatsFullTable->Release(); return pstatsResult; }
//--------------------------------------------------------------------------- // @function: // CXformSubqJoin2Apply::PexprSubqueryPushdown // // @doc: // Push down subquery below join // //--------------------------------------------------------------------------- CExpression * CXformSubqJoin2Apply::PexprSubqueryPushDown ( IMemoryPool *mp, CExpression *pexpr, BOOL fEnforceCorrelatedApply ) { GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(COperator::EopLogicalSelect == pexpr->Pop()->Eopid()); CExpression *pexprJoin = (*pexpr)[0]; const ULONG arity = pexprJoin->Arity(); CExpression *pexprScalar = (*pexpr)[1]; CExpression *join_pred_expr = (*pexprJoin)[arity - 1]; // collect output columns of all logical children CColRefSetArray *pdrgpcrs = GPOS_NEW(mp) CColRefSetArray(mp); CExpressionArrays *pdrgpdrgpexprSubqs = GPOS_NEW(mp) CExpressionArrays(mp); for (ULONG ul = 0; ul < arity - 1; ul++) { CExpression *pexprChild = (*pexprJoin)[ul]; CColRefSet *pcrsOutput = CDrvdPropRelational::GetRelationalProperties(pexprChild->PdpDerive())->PcrsOutput(); pcrsOutput->AddRef(); pdrgpcrs->Append(pcrsOutput); pdrgpdrgpexprSubqs->Append(GPOS_NEW(mp) CExpressionArray(mp)); } // collect subqueries that exclusively use columns from each join child CollectSubqueries(mp, pexprScalar, pdrgpcrs, pdrgpdrgpexprSubqs); // create new join children by pushing subqueries to Project nodes on top // of corresponding join children CExpressionArray *pdrgpexprNewChildren = GPOS_NEW(mp) CExpressionArray(mp); ExprToColRefMap *phmexprcr = GPOS_NEW(mp) ExprToColRefMap(mp); for (ULONG ulChild = 0; ulChild < arity - 1; ulChild++) { CExpression *pexprChild = (*pexprJoin)[ulChild]; pexprChild->AddRef(); CExpression *pexprNewChild = pexprChild; CExpressionArray *pdrgpexprSubqs = (*pdrgpdrgpexprSubqs)[ulChild]; const ULONG ulSubqs = pdrgpexprSubqs->Size(); if (0 < ulSubqs) { // join child has pushable subqueries pexprNewChild = CUtils::PexprAddProjection(mp, pexprChild, pdrgpexprSubqs); CExpression *pexprPrjList = (*pexprNewChild)[1]; // add pushed subqueries to map for (ULONG ulSubq = 0; ulSubq < ulSubqs; ulSubq++) { CExpression *pexprSubq = (*pdrgpexprSubqs)[ulSubq]; pexprSubq->AddRef(); CColRef *colref = CScalarProjectElement::PopConvert((*pexprPrjList)[ulSubq]->Pop())->Pcr(); #ifdef GPOS_DEBUG BOOL fInserted = #endif // GPOS_DEBUG phmexprcr->Insert(pexprSubq, colref); GPOS_ASSERT(fInserted); } // unnest subqueries in newly created child CExpression *pexprUnnested = PexprSubqueryUnnest(mp, pexprNewChild, fEnforceCorrelatedApply); if (NULL != pexprUnnested) { pexprNewChild->Release(); pexprNewChild = pexprUnnested; } } pdrgpexprNewChildren->Append(pexprNewChild); } join_pred_expr->AddRef(); pdrgpexprNewChildren->Append(join_pred_expr); // replace subqueries in the original scalar expression with // scalar identifiers based on constructed map CExpression *pexprNewScalar = PexprReplaceSubqueries(mp, pexprScalar, phmexprcr); phmexprcr->Release(); pdrgpcrs->Release(); pdrgpdrgpexprSubqs->Release(); // build the new join expression COperator *pop = pexprJoin->Pop(); pop->AddRef(); CExpression *pexprNewJoin = GPOS_NEW(mp) CExpression(mp, pop, pdrgpexprNewChildren); // return a new Select expression pop = pexpr->Pop(); pop->AddRef(); return GPOS_NEW(mp) CExpression(mp, pop, pexprNewJoin, pexprNewScalar); }
//--------------------------------------------------------------------------- // @function: // CXformSubqJoin2Apply::Transform // // @doc: // Helper of transformation function // //--------------------------------------------------------------------------- void CXformSubqJoin2Apply::Transform ( CXformContext *pxfctxt, CXformResult *pxfres, CExpression *pexpr, BOOL fEnforceCorrelatedApply ) const { GPOS_ASSERT(NULL != pxfctxt); GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); GPOS_ASSERT(FCheckPattern(pexpr)); IMemoryPool *mp = pxfctxt->Pmp(); CExpression *pexprSelect = CXformUtils::PexprSeparateSubqueryPreds(mp, pexpr); // attempt pushing subqueries to join children, // this optimization may not always succeed since unnested subqueries below joins // could hide columns needed to evaluate join condition CExpression *pexprSubqsPushedDown = PexprSubqueryPushDown(mp, pexprSelect, fEnforceCorrelatedApply); // check if join columns in join condition are still accessible after subquery pushdown CExpression *pexprJoin = (*pexprSubqsPushedDown)[0]; CExpression *pexprJoinCondition = (*pexprJoin)[pexprJoin->Arity() - 1]; CColRefSet *pcrsUsed = CDrvdPropScalar::GetDrvdScalarProps(pexprJoinCondition->PdpDerive())->PcrsUsed(); CColRefSet *pcrsJoinOutput = CDrvdPropRelational::GetRelationalProperties(pexprJoin->PdpDerive())->PcrsOutput(); if (!pcrsJoinOutput->ContainsAll(pcrsUsed)) { // discard expression after subquery push down pexprSubqsPushedDown->Release(); pexprSelect->AddRef(); pexprSubqsPushedDown = pexprSelect; } pexprSelect->Release(); CExpression *pexprResult = NULL; BOOL fHasSubquery = CDrvdPropScalar::GetDrvdScalarProps((*pexprSubqsPushedDown)[1]->PdpDerive())->FHasSubquery(); if (fHasSubquery) { // unnest subqueries remaining in the top Select expression pexprResult = PexprSubqueryUnnest(mp, pexprSubqsPushedDown, fEnforceCorrelatedApply); pexprSubqsPushedDown->Release(); } else { pexprResult = pexprSubqsPushedDown; } if (NULL == pexprResult) { // unnesting failed, return here return; } // normalize resulting expression and add it to xform results container CExpression *pexprNormalized = CNormalizer::PexprNormalize(mp, pexprResult); pexprResult->Release(); pxfres->Add(pexprNormalized); }
//--------------------------------------------------------------------------- // @function: // CPhysicalJoin::AddHashKeys // // @doc: // Helper for adding a pair of hash join keys to given arrays // //--------------------------------------------------------------------------- void CPhysicalJoin::AddHashKeys ( CExpression *pexprPred, // equality predicate in the form (ColRef1 = ColRef2) or // in the form (ColRef1 is not distinct from ColRef2) CExpression *pexprOuter, CExpression * #ifdef GPOS_DEBUG pexprInner #endif // GPOS_DEBUG , DrgPexpr *pdrgpexprOuter, // array of outer hash keys DrgPexpr *pdrgpexprInner // array of inner hash keys ) { GPOS_ASSERT(FHashJoinCompatible(pexprPred, pexprOuter, pexprInner)); // output of outer side CColRefSet *pcrsOuter = CDrvdPropRelational::Pdprel(pexprOuter->PdpDerive())->PcrsOutput(); #ifdef GPOS_DEBUG // output of inner side CColRefSet *pcrsInner = CDrvdPropRelational::Pdprel(pexprInner->PdpDerive())->PcrsOutput(); #endif // GPOS_DEBUG // extract outer and inner columns from predicate CExpression *pexprPredOuter = NULL; CExpression *pexprPredInner = NULL; ExtractHashJoinExpressions(pexprPred, &pexprPredOuter, &pexprPredInner); GPOS_ASSERT(NULL != pexprPredOuter); GPOS_ASSERT(NULL != pexprPredInner); CColRefSet *pcrsPredOuter = CDrvdPropScalar::Pdpscalar(pexprPredOuter->PdpDerive())->PcrsUsed(); #ifdef GPOS_DEBUG CColRefSet *pcrsPredInner = CDrvdPropScalar::Pdpscalar(pexprPredInner->PdpDerive())->PcrsUsed(); #endif // GPOS_DEBUG // determine outer and inner hash keys CExpression *pexprKeyOuter = NULL; CExpression *pexprKeyInner = NULL; if (pcrsOuter->FSubset(pcrsPredOuter)) { pexprKeyOuter = pexprPredOuter; GPOS_ASSERT(pcrsInner->FSubset(pcrsPredInner)); pexprKeyInner = pexprPredInner; } else { GPOS_ASSERT(pcrsOuter->FSubset(pcrsPredInner)); pexprKeyOuter = pexprPredInner; GPOS_ASSERT(pcrsInner->FSubset(pcrsPredOuter)); pexprKeyInner = pexprPredOuter; } pexprKeyOuter->AddRef(); pexprKeyInner->AddRef(); pdrgpexprOuter->Append(pexprKeyOuter); pdrgpexprInner->Append(pexprKeyInner); GPOS_ASSERT(pdrgpexprInner->UlLength() == pdrgpexprOuter->UlLength()); }
//--------------------------------------------------------------------------- // @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: // CCostTest::EresUnittest_SetParams // // @doc: // Test of setting cost model params // //--------------------------------------------------------------------------- GPOS_RESULT CCostTest::EresUnittest_SetParams() { CAutoMemoryPool amp; IMemoryPool *mp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(mp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); ICostModel *pcm = GPOS_NEW(mp) CCostModelGPDB(mp, GPOPT_TEST_SEGMENTS); // install opt context in TLS CAutoOptCtxt aoc(mp, &mda, NULL, /* pceeval */ pcm); // generate in-equality join expression CExpression *pexprOuter = CTestUtils::PexprLogicalGet(mp); const CColRef *pcrOuter = CDrvdPropRelational::GetRelationalProperties(pexprOuter->PdpDerive())->PcrsOutput()->PcrAny(); CExpression *pexprInner = CTestUtils::PexprLogicalGet(mp); const CColRef *pcrInner = CDrvdPropRelational::GetRelationalProperties(pexprInner->PdpDerive())->PcrsOutput()->PcrAny(); CExpression *pexprPred = CUtils::PexprScalarCmp(mp, pcrOuter, pcrInner, IMDType::EcmptNEq); CExpression *pexpr = CUtils::PexprLogicalJoin<CLogicalInnerJoin>(mp, pexprOuter, pexprInner, pexprPred); // optimize in-equality join based on default cost model params CExpression *pexprPlan1 = NULL; { CEngine eng(mp); // generate query context CQueryContext *pqc = CTestUtils::PqcGenerate(mp, pexpr); // Initialize engine eng.Init(pqc, NULL /*search_stage_array*/); // optimize query eng.Optimize(); // extract plan pexprPlan1 = eng.PexprExtractPlan(); GPOS_ASSERT(NULL != pexprPlan1); GPOS_DELETE(pqc); } // change NLJ cost factor ICostModelParams::SCostParam *pcp = pcm->GetCostModelParams()->PcpLookup(CCostModelParamsGPDB::EcpNLJFactor); CDouble dNLJFactor = CDouble(2.0); CDouble dVal = pcp->Get() * dNLJFactor; pcm->GetCostModelParams()->SetParam(pcp->Id(), dVal, dVal - 0.5, dVal + 0.5); // optimize again after updating NLJ cost factor CExpression *pexprPlan2 = NULL; { CEngine eng(mp); // generate query context CQueryContext *pqc = CTestUtils::PqcGenerate(mp, pexpr); // Initialize engine eng.Init(pqc, NULL /*search_stage_array*/); // optimize query eng.Optimize(); // extract plan pexprPlan2 = eng.PexprExtractPlan(); GPOS_ASSERT(NULL != pexprPlan2); GPOS_DELETE(pqc); } { CAutoTrace at(mp); at.Os() << "\nPLAN1: \n" << *pexprPlan1; at.Os() << "\nNLJ Cost1: " << (*pexprPlan1)[0]->Cost(); at.Os() << "\n\nPLAN2: \n" << *pexprPlan2; at.Os() << "\nNLJ Cost2: " << (*pexprPlan2)[0]->Cost(); } GPOS_ASSERT((*pexprPlan2)[0]->Cost() >= (*pexprPlan1)[0]->Cost() * dNLJFactor && "expected NLJ cost in PLAN2 to be larger than NLJ cost in PLAN1"); // clean up pexpr->Release(); pexprPlan1->Release(); pexprPlan2->Release(); return GPOS_OK; }
//--------------------------------------------------------------------------- // @function: // CPredicateUtilsTest::EresUnittest_Conjunctions // // @doc: // Test extraction and construction of conjuncts // //--------------------------------------------------------------------------- GPOS_RESULT CPredicateUtilsTest::EresUnittest_Conjunctions() { CAutoMemoryPool amp; IMemoryPool *mp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(mp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); // install opt context in TLS CAutoOptCtxt aoc ( mp, &mda, NULL, /* pceeval */ CTestUtils::GetCostModel(mp) ); // build conjunction CExpressionArray *pdrgpexpr = GPOS_NEW(mp) CExpressionArray(mp); const ULONG ulConjs = 3; for (ULONG ul = 0; ul < ulConjs; ul++) { pdrgpexpr->Append(CUtils::PexprScalarConstBool(mp, true /*fValue*/)); } CExpression *pexprConjunction = CUtils::PexprScalarBoolOp(mp, CScalarBoolOp::EboolopAnd, pdrgpexpr); // break into conjuncts CExpressionArray *pdrgpexprExtract = CPredicateUtils::PdrgpexprConjuncts(mp, pexprConjunction); GPOS_ASSERT(pdrgpexprExtract->Size() == ulConjs); // collapse into single conjunct CExpression *pexpr = CPredicateUtils::PexprConjunction(mp, pdrgpexprExtract); GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(CUtils::FScalarConstTrue(pexpr)); pexpr->Release(); // collapse empty input array to conjunct CExpression *pexprSingleton = CPredicateUtils::PexprConjunction(mp, NULL /*pdrgpexpr*/); GPOS_ASSERT(NULL != pexprSingleton); pexprSingleton->Release(); pexprConjunction->Release(); // conjunction on scalar comparisons CExpression *pexprGet = CTestUtils::PexprLogicalGet(mp); CColRefSet *pcrs = CDrvdPropRelational::GetRelationalProperties(pexprGet->PdpDerive())->PcrsOutput(); CColRef *pcr1 = pcrs->PcrAny(); CColRef *pcr2 = pcrs->PcrFirst(); CExpression *pexprCmp1 = CUtils::PexprScalarCmp(mp, pcr1, pcr2, IMDType::EcmptEq); CExpression *pexprCmp2 = CUtils::PexprScalarCmp(mp, pcr1, CUtils::PexprScalarConstInt4(mp, 1 /*val*/), IMDType::EcmptEq); CExpression *pexprConj = CPredicateUtils::PexprConjunction(mp, pexprCmp1, pexprCmp2); pdrgpexprExtract = CPredicateUtils::PdrgpexprConjuncts(mp, pexprConj); GPOS_ASSERT(2 == pdrgpexprExtract->Size()); 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 *mp = amp.Pmp(); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(mp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp); // install opt context in TLS CAutoOptCtxt aoc ( mp, &mda, NULL, /* pceeval */ CTestUtils::GetCostModel(mp) ); CExpression *pexprLeft = CTestUtils::PexprLogicalGet(mp); CExpression *pexprRight = CTestUtils::PexprLogicalGet(mp); CExpressionArray *pdrgpexprOriginal = GPOS_NEW(mp) CExpressionArray(mp); CColRefSet *pcrsLeft = CDrvdPropRelational::GetRelationalProperties(pexprLeft->PdpDerive())->PcrsOutput(); CColRefSet *pcrsRight = CDrvdPropRelational::GetRelationalProperties(pexprRight->PdpDerive())->PcrsOutput(); CColRef *pcrLeft = pcrsLeft->PcrAny(); CColRef *pcrRight = pcrsRight->PcrAny(); // generate an equality predicate between two column reference CExpression *pexprScIdentEquality = CUtils::PexprScalarEqCmp(mp, pcrLeft, pcrRight); pexprScIdentEquality->AddRef(); pdrgpexprOriginal->Append(pexprScIdentEquality); // generate a non-equality predicate between two column reference CExpression *pexprScIdentInequality = CUtils::PexprScalarCmp(mp, pcrLeft, pcrRight, CWStringConst(GPOS_WSZ_LIT("<")), GPOS_NEW(mp) 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(mp, 10 /*fValue*/); CExpression *pexprScIdentConstEquality = CUtils::PexprScalarEqCmp(mp, pexprScalarConstInt4, pcrRight); pdrgpexprOriginal->Append(pexprScIdentConstEquality); GPOS_ASSERT(3 == pdrgpexprOriginal->Size()); CExpressionArray *pdrgpexprResult = CPredicateUtils::PdrgpexprPlainEqualities(mp, pdrgpexprOriginal); GPOS_ASSERT(1 == pdrgpexprResult->Size()); // clean up pdrgpexprOriginal->Release(); pdrgpexprResult->Release(); pexprLeft->Release(); pexprRight->Release(); pexprScIdentEquality->Release(); pexprScIdentInequality->Release(); return GPOS_OK; }
//--------------------------------------------------------------------------- // @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: // CDecorrelator::FProcessJoin // // @doc: // Decorrelate a join expression; // //--------------------------------------------------------------------------- BOOL CDecorrelator::FProcessJoin ( IMemoryPool *pmp, CExpression *pexpr, BOOL fEqualityOnly, CExpression **ppexprDecorrelated, DrgPexpr *pdrgpexprCorrelations ) { GPOS_ASSERT(CUtils::FLogicalJoin(pexpr->Pop()) || CUtils::FApply(pexpr->Pop())); ULONG ulArity = pexpr->UlArity(); DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp, ulArity); CColRefSet *pcrsOutput = GPOS_NEW(pmp) CColRefSet(pmp); // decorrelate all relational children for (ULONG ul = 0; ul < ulArity - 1; ul++) { CExpression *pexprInput = NULL; if (FProcess(pmp, (*pexpr)[ul], fEqualityOnly, &pexprInput, pdrgpexprCorrelations)) { pdrgpexpr->Append(pexprInput); pcrsOutput->Union(CDrvdPropRelational::Pdprel(pexprInput->PdpDerive())->PcrsOutput()); } else { pdrgpexpr->Release(); pcrsOutput->Release(); return false; } } // check for valid semi join correlations if (!FPullableCorrelations(pmp, pexpr, pdrgpexpr, pdrgpexprCorrelations)) { pdrgpexpr->Release(); pcrsOutput->Release(); return false; } // decorrelate predicate and build new join operator CExpression *pexprPredicate = NULL; BOOL fSuccess = FProcessPredicate(pmp, pexpr, (*pexpr)[ulArity - 1], fEqualityOnly, pcrsOutput, &pexprPredicate, pdrgpexprCorrelations); pcrsOutput->Release(); if (fSuccess) { // in case entire predicate is being deferred, plug in a 'true' if (NULL == pexprPredicate) { pexprPredicate = CUtils::PexprScalarConstBool(pmp, true /*fVal*/); } pdrgpexpr->Append(pexprPredicate); COperator *pop = pexpr->Pop(); pop->AddRef(); *ppexprDecorrelated = GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexpr); } else { pdrgpexpr->Release(); CRefCount::SafeRelease(pexprPredicate); } return fSuccess; }