//--------------------------------------------------------------------------- // @function: // CNormalizer::PexprNormalize // // @doc: // Main driver // //--------------------------------------------------------------------------- CExpression * CNormalizer::PexprNormalize ( IMemoryPool *pmp, CExpression *pexpr ) { GPOS_CHECK_STACK_SIZE; GPOS_ASSERT(NULL != pexpr); if (0 == pexpr->UlArity()) { // end recursion early for leaf patterns extracted from memo pexpr->AddRef(); return pexpr; } CExpression *pexprResult = NULL; COperator *pop = pexpr->Pop(); if (pop->FLogical() && CLogical::PopConvert(pop)->FSelectionOp()) { if (FPushThruOuterChild(pexpr)) { CExpression *pexprConstTrue = CUtils::PexprScalarConstBool(pmp, true /*fVal*/); PushThru(pmp, pexpr, pexprConstTrue, &pexprResult); pexprConstTrue->Release(); } else { // add-ref all children except scalar predicate const ULONG ulArity = pexpr->UlArity(); DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < ulArity - 1; ul++) { CExpression *pexprChild = (*pexpr)[ul]; pexprChild->AddRef(); pdrgpexpr->Append(pexprChild); } // normalize scalar predicate and construct a new expression CExpression *pexprPred = (*pexpr)[pexpr->UlArity() - 1]; CExpression *pexprPredNormalized = PexprRecursiveNormalize(pmp, pexprPred); pdrgpexpr->Append(pexprPredNormalized); COperator *pop = pexpr->Pop(); pop->AddRef(); CExpression *pexprNew = GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexpr); // push normalized predicate through PushThru(pmp, pexprNew, pexprPredNormalized, &pexprResult); pexprNew->Release(); } } else { pexprResult = PexprRecursiveNormalize(pmp, pexpr); } GPOS_ASSERT(NULL != pexprResult); return pexprResult; }
//--------------------------------------------------------------------------- // @function: // CPhysicalPartitionSelector::PexprCombinedPartPred // // @doc: // Return a single combined partition selection predicate // //--------------------------------------------------------------------------- CExpression * CPhysicalPartitionSelector::PexprCombinedPartPred ( IMemoryPool *pmp ) const { DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulLevels = UlPartLevels(); for (ULONG ul = 0; ul < ulLevels; ul++) { CExpression *pexpr = PexprPartPred(pmp, ul); if (NULL != pexpr) { pdrgpexpr->Append(pexpr); } } if (NULL != m_pexprResidual) { m_pexprResidual->AddRef(); pdrgpexpr->Append(m_pexprResidual); } return CPredicateUtils::PexprConjunction(pmp, pdrgpexpr); }
//--------------------------------------------------------------------------- // @function: // CConstraint::PexprScalarConjDisj // // @doc: // Construct a conjunction or disjunction scalar expression from an // array of constraints // //--------------------------------------------------------------------------- CExpression * CConstraint::PexprScalarConjDisj ( IMemoryPool *pmp, DrgPcnstr *pdrgpcnstr, BOOL fConj ) const { DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulLen = pdrgpcnstr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CExpression *pexpr = (*pdrgpcnstr)[ul]->PexprScalar(pmp); pexpr->AddRef(); pdrgpexpr->Append(pexpr); } if (fConj) { return CPredicateUtils::PexprConjunction(pmp, pdrgpexpr); } return CPredicateUtils::PexprDisjunction(pmp, pdrgpexpr); }
CHashedDistributions::CHashedDistributions ( IMemoryPool *pmp, DrgPcr *pdrgpcrOutput, DrgDrgPcr *pdrgpdrgpcrInput ) : DrgPds(pmp) { const ULONG ulCols = pdrgpcrOutput->UlLength(); const ULONG ulArity = pdrgpdrgpcrInput->UlLength(); for (ULONG ulChild = 0; ulChild < ulArity; ulChild++) { DrgPcr *pdrgpcr = (*pdrgpdrgpcrInput)[ulChild]; DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ulCol = 0; ulCol < ulCols; ulCol++) { CColRef *pcr = (*pdrgpcr)[ulCol]; CExpression *pexpr = CUtils::PexprScalarIdent(pmp, pcr); pdrgpexpr->Append(pexpr); } // create a hashed distribution on input columns of the current child BOOL fNullsColocated = true; CDistributionSpec *pdshashed = GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, fNullsColocated); Append(pdshashed); } }
//--------------------------------------------------------------------------- // @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::PushThruSetOp // // @doc: // Push a conjunct through set operation // //--------------------------------------------------------------------------- void CNormalizer::PushThruSetOp ( IMemoryPool *pmp, CExpression *pexprSetOp, CExpression *pexprConj, CExpression **ppexprResult ) { GPOS_ASSERT(NULL != pexprSetOp); GPOS_ASSERT(CUtils::FLogicalSetOp(pexprSetOp->Pop())); GPOS_ASSERT(NULL != pexprConj); GPOS_ASSERT(NULL != ppexprResult); CLogicalSetOp *popSetOp = CLogicalSetOp::PopConvert(pexprSetOp->Pop()); DrgPcr *pdrgpcrOutput = popSetOp->PdrgpcrOutput(); CColRefSet *pcrsOutput = GPOS_NEW(pmp) CColRefSet(pmp, pdrgpcrOutput); DrgDrgPcr *pdrgpdrgpcrInput = popSetOp->PdrgpdrgpcrInput(); DrgPexpr *pdrgpexprNewChildren = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulArity = pexprSetOp->UlArity(); for (ULONG ul = 0; ul < ulArity; ul++) { CExpression *pexprChild = (*pexprSetOp)[ul]; DrgPcr *pdrgpcrChild = (*pdrgpdrgpcrInput)[ul]; CColRefSet *pcrsChild = GPOS_NEW(pmp) CColRefSet(pmp, pdrgpcrChild); pexprConj->AddRef(); CExpression *pexprRemappedConj = pexprConj; if (!pcrsChild->FEqual(pcrsOutput)) { // child columns are different from SetOp output columns, // we need to fix conjunct by mapping output columns to child columns, // columns that are not in the output of SetOp child need also to be re-mapped // to new columns, // // for example, if the conjunct looks like 'x > (select max(y) from T)' // and the SetOp child produces only column x, we need to create a new // conjunct that looks like 'x1 > (select max(y1) from T)' // where x1 is a copy of x, and y1 is a copy of y // // this is achieved by passing (fMustExist = True) flag below, which enforces // creating column copies for columns not already in the given map HMUlCr *phmulcr = CUtils::PhmulcrMapping(pmp, pdrgpcrOutput, pdrgpcrChild); pexprRemappedConj->Release(); pexprRemappedConj = pexprConj->PexprCopyWithRemappedColumns(pmp, phmulcr, true /*fMustExist*/); phmulcr->Release(); } CExpression *pexprNewChild = NULL; PushThru(pmp, pexprChild, pexprRemappedConj, &pexprNewChild); pdrgpexprNewChildren->Append(pexprNewChild); pexprRemappedConj->Release(); pcrsChild->Release(); } pcrsOutput->Release(); popSetOp->AddRef(); *ppexprResult = GPOS_NEW(pmp) CExpression(pmp, popSetOp, pdrgpexprNewChildren); }
//--------------------------------------------------------------------------- // @function: // CPhysicalUnionAll::BuildHashedDistributions // // @doc: // Build hashed distributions used locally during distribution derivation, // // the function builds an array of hashed distribution on input column // of each child, and an output hashed distribution on UnionAll output // columns // // //--------------------------------------------------------------------------- void CPhysicalUnionAll::BuildHashedDistributions ( IMemoryPool *pmp ) { GPOS_ASSERT(NULL == m_pdrgpds); m_pdrgpds = GPOS_NEW(pmp) DrgPds(pmp); const ULONG ulCols = m_pdrgpcrOutput->UlLength(); const ULONG ulArity = m_pdrgpdrgpcrInput->UlLength(); for (ULONG ulChild = 0; ulChild < ulArity; ulChild++) { DrgPcr *pdrgpcr = (*m_pdrgpdrgpcrInput)[ulChild]; DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ulCol = 0; ulCol < ulCols; ulCol++) { CExpression *pexpr = CUtils::PexprScalarIdent(pmp, (*pdrgpcr)[ulCol]); pdrgpexpr->Append(pexpr); } // create a hashed distribution on input columns of the current child CDistributionSpecHashed *pdshashed = GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, true /*fNullsColocated*/); m_pdrgpds->Append(pdshashed); } }
//--------------------------------------------------------------------------- // @function: // CCNFConverter::Pdrgpdrgpexpr // // @doc: // Create an array of arrays each holding the children of an expression // from the given array // // //--------------------------------------------------------------------------- DrgPdrgPexpr * CCNFConverter::Pdrgpdrgpexpr ( IMemoryPool *pmp, DrgPexpr *pdrgpexpr ) { GPOS_ASSERT(NULL != pmp); GPOS_ASSERT(NULL != pdrgpexpr); DrgPdrgPexpr *pdrgpdrgpexpr = GPOS_NEW(pmp) DrgPdrgPexpr(pmp); const ULONG ulArity = pdrgpexpr->UlLength(); for (ULONG ul = 0; ul < ulArity; ul++) { CExpression *pexpr = (*pdrgpexpr)[ul]; DrgPexpr *pdrgpexprChild = NULL; if (CPredicateUtils::FAnd(pexpr)) { pdrgpexprChild = pexpr->PdrgPexpr(); pdrgpexprChild->AddRef(); } else { pdrgpexprChild = GPOS_NEW(pmp) DrgPexpr(pmp); pexpr->AddRef(); pdrgpexprChild->Append(pexpr); } pdrgpdrgpexpr->Append(pdrgpexprChild); } return pdrgpdrgpexpr; }
//--------------------------------------------------------------------------- // @function: // CXformGbAggWithMDQA2Join::PexprTransform // // @doc: // Main transformation driver // //--------------------------------------------------------------------------- CExpression * CXformGbAggWithMDQA2Join::PexprTransform ( IMemoryPool *pmp, CExpression *pexpr ) { // protect against stack overflow during recursion GPOS_CHECK_STACK_SIZE; GPOS_ASSERT(NULL != pmp); GPOS_ASSERT(NULL != pexpr); COperator *pop = pexpr->Pop(); if (COperator::EopLogicalGbAgg == pop->Eopid()) { CExpression *pexprResult = PexprExpandMDQAs(pmp, pexpr); if (NULL != pexprResult) { return pexprResult; } } // recursively process child expressions const ULONG ulArity = pexpr->UlArity(); DrgPexpr *pdrgpexprChildren = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < ulArity; ul++) { CExpression *pexprChild = PexprTransform(pmp, (*pexpr)[ul]); pdrgpexprChildren->Append(pexprChild); } pop->AddRef(); return GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexprChildren); }
//--------------------------------------------------------------------------- // @function: // CDistributionSpecHashed::PdsCopyWithRemappedColumns // // @doc: // Return a copy of the distribution spec with remapped columns // //--------------------------------------------------------------------------- CDistributionSpec * CDistributionSpecHashed::PdsCopyWithRemappedColumns ( IMemoryPool *pmp, HMUlCr *phmulcr, BOOL fMustExist ) { DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulLen = m_pdrgpexpr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CExpression *pexpr = (*m_pdrgpexpr)[ul]; pdrgpexpr->Append(pexpr->PexprCopyWithRemappedColumns(pmp, phmulcr, fMustExist)); } if (NULL == m_pdshashedEquiv) { return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, m_fNullsColocated); } // copy equivalent distribution CDistributionSpec *pds = m_pdshashedEquiv->PdsCopyWithRemappedColumns(pmp, phmulcr, fMustExist); CDistributionSpecHashed *pdshashed = CDistributionSpecHashed::PdsConvert(pds); return GPOS_NEW(pmp) CDistributionSpecHashed(pdrgpexpr, m_fNullsColocated, pdshashed); }
//--------------------------------------------------------------------------- // @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: // CNormalizer::PushThru // // @doc: // Push an array of conjuncts through a logical expression; // compute an array of unpushable conjuncts // //--------------------------------------------------------------------------- void CNormalizer::PushThru ( IMemoryPool *pmp, CExpression *pexprLogical, DrgPexpr *pdrgpexprConjuncts, CExpression **ppexprResult, DrgPexpr **ppdrgpexprRemaining ) { GPOS_ASSERT(NULL != pexprLogical); GPOS_ASSERT(NULL != pdrgpexprConjuncts); GPOS_ASSERT(NULL != ppexprResult); DrgPexpr *pdrgpexprPushable = GPOS_NEW(pmp) DrgPexpr(pmp); DrgPexpr *pdrgpexprUnpushable = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulSize = pdrgpexprConjuncts->UlLength(); for (ULONG ul = 0; ul < ulSize; ul++) { CExpression *pexprConj = (*pdrgpexprConjuncts)[ul]; pexprConj->AddRef(); if (FPushable(pexprLogical, pexprConj)) { pdrgpexprPushable->Append(pexprConj); } else { pdrgpexprUnpushable->Append(pexprConj); } } // push through a conjunction of all pushable predicates CExpression *pexprPred = CPredicateUtils::PexprConjunction(pmp, pdrgpexprPushable); if (FPushThruOuterChild(pexprLogical)) { PushThruOuterChild(pmp, pexprLogical, pexprPred, ppexprResult); } else { PushThru(pmp, pexprLogical, pexprPred, ppexprResult); } pexprPred->Release(); *ppdrgpexprRemaining = pdrgpexprUnpushable; }
//--------------------------------------------------------------------------- // @function: // CCNFConverter::PexprNot2CNF // // @doc: // Convert a NOT tree into CNF // //--------------------------------------------------------------------------- CExpression * CCNFConverter::PexprNot2CNF ( IMemoryPool *pmp, CExpression *pexpr ) { GPOS_ASSERT(NULL != pmp); GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(1 == pexpr->UlArity()); CExpression *pexprNotChild = (*pexpr)[0]; if (!FScalarBoolOp(pexprNotChild)) { pexpr->AddRef(); return pexpr; } CScalarBoolOp::EBoolOperator eboolopChild = CScalarBoolOp::PopConvert(pexprNotChild->Pop())->Eboolop(); // apply DeMorgan laws // NOT(NOT(A)) ==> A if (CScalarBoolOp::EboolopNot == eboolopChild) { return Pexpr2CNF(pmp, (*pexprNotChild)[0]); } // Not child must be either an AND or an OR // NOT(A AND B) ==> NOT(A) OR NOT(B) // NOT(A OR B) ==> NOT(A) AND NOT(B) DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulArity = pexprNotChild->UlArity(); for (ULONG ul = 0; ul < ulArity; ul++) { (*pexprNotChild)[ul]->AddRef(); pdrgpexpr->Append(CUtils::PexprNegate(pmp, (*pexprNotChild)[ul])); } CScalarBoolOp::EBoolOperator eboolop = CScalarBoolOp::EboolopAnd; if (CScalarBoolOp::EboolopAnd == eboolopChild) { eboolop = CScalarBoolOp::EboolopOr; } CExpression *pexprScalarBoolOp = CUtils::PexprScalarBoolOp(pmp, eboolop, pdrgpexpr); CExpression *pexprResult = Pexpr2CNF(pmp, pexprScalarBoolOp); pexprScalarBoolOp->Release(); return pexprResult; }
//--------------------------------------------------------------------------- // @function: // CJoinOrderDP::PexprBuildPred // // @doc: // Build predicate connecting the two given sets // //--------------------------------------------------------------------------- CExpression * CJoinOrderDP::PexprBuildPred ( CBitSet *pbsFst, CBitSet *pbsSnd ) { // collect edges connecting the given sets CBitSet *pbsEdges = GPOS_NEW(m_pmp) CBitSet(m_pmp); CBitSet *pbs = GPOS_NEW(m_pmp) CBitSet(m_pmp, *pbsFst); pbs->Union(pbsSnd); for (ULONG ul = 0; ul < m_ulEdges; ul++) { SEdge *pedge = m_rgpedge[ul]; if ( pbs->FSubset(pedge->m_pbs) && !pbsFst->FDisjoint(pedge->m_pbs) && !pbsSnd->FDisjoint(pedge->m_pbs) ) { #ifdef GPOS_DEBUG BOOL fSet = #endif // GPOS_DEBUG pbsEdges->FExchangeSet(ul); GPOS_ASSERT(!fSet); } } pbs->Release(); CExpression *pexprPred = NULL; if (0 < pbsEdges->CElements()) { DrgPexpr *pdrgpexpr = GPOS_NEW(m_pmp) DrgPexpr(m_pmp); CBitSetIter bsi(*pbsEdges); while (bsi.FAdvance()) { ULONG ul = bsi.UlBit(); SEdge *pedge = m_rgpedge[ul]; pedge->m_pexpr->AddRef(); pdrgpexpr->Append(pedge->m_pexpr); } pexprPred = CPredicateUtils::PexprConjunction(m_pmp, pdrgpexpr); } pbsEdges->Release(); return pexprPred; }
//--------------------------------------------------------------------------- // @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: // 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: // CXformExpandNAryJoin::Transform // // @doc: // Actual transformation of n-ary join to cluster of inner joins // //--------------------------------------------------------------------------- void CXformExpandNAryJoin::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(); const ULONG ulArity = pexpr->UlArity(); GPOS_ASSERT(ulArity >= 3); DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < ulArity - 1; ul++) { CExpression *pexprChild = (*pexpr)[ul]; pexprChild->AddRef(); pdrgpexpr->Append(pexprChild); } CExpression *pexprScalar = (*pexpr)[ulArity - 1]; DrgPexpr *pdrgpexprPreds = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprScalar); // create a join order based on query-specified order of joins CJoinOrder jo(pmp, pdrgpexpr, pdrgpexprPreds); CExpression *pexprResult = jo.PexprExpand(); // normalize resulting expression CExpression *pexprNormalized = CNormalizer::PexprNormalize(pmp, pexprResult); pexprResult->Release(); pxfres->Add(pexprNormalized); AddSpecifiedJoinOrder(pmp, pexpr, pxfres); }
//--------------------------------------------------------------------------- // @function: // CCNFConverter::PdrgpexprConvertChildren // // @doc: // Call converter recursively on children array // //--------------------------------------------------------------------------- DrgPexpr * CCNFConverter::PdrgpexprConvertChildren ( IMemoryPool *pmp, CExpression *pexpr ) { GPOS_ASSERT(NULL != pmp); GPOS_ASSERT(NULL != pexpr); const ULONG ulArity = pexpr->UlArity(); DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < ulArity; ul++) { CExpression *pexprChild = Pexpr2CNF(pmp, (*pexpr)[ul]); pdrgpexpr->Append(pexprChild); } return pdrgpexpr; }
//--------------------------------------------------------------------------- // @function: // CNormalizer::PexprRecursiveNormalize // // @doc: // Call normalizer recursively on children array // // //--------------------------------------------------------------------------- CExpression * CNormalizer::PexprRecursiveNormalize ( IMemoryPool *pmp, CExpression *pexpr ) { GPOS_ASSERT(NULL != pexpr); const ULONG ulArity = pexpr->UlArity(); DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < ulArity; ul++) { CExpression *pexprChild = PexprNormalize(pmp, (*pexpr)[ul]); pdrgpexpr->Append(pexprChild); } COperator *pop = pexpr->Pop(); pop->AddRef(); return GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexpr); }
//--------------------------------------------------------------------------- // @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: // CPartitionPropagationSpec::PexprResidualFilter // // @doc: // Return a residual filter given an array of predicates and a bitset // indicating which predicates have already been used // //--------------------------------------------------------------------------- CExpression * CPartitionPropagationSpec::PexprResidualFilter ( IMemoryPool *pmp, DrgPexpr *pdrgpexpr, CBitSet *pbsUsed ) { GPOS_ASSERT(NULL != pdrgpexpr); GPOS_ASSERT(NULL != pbsUsed); DrgPexpr *pdrgpexprUnused = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulLen = pdrgpexpr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { if (pbsUsed->FBit(ul)) { // predicate already considered continue; } CExpression *pexpr = (*pdrgpexpr)[ul]; pexpr->AddRef(); pdrgpexprUnused->Append(pexpr); } CExpression *pexprResult = CPredicateUtils::PexprConjunction(pmp, pdrgpexprUnused); if (CUtils::FScalarConstTrue(pexprResult)) { pexprResult->Release(); pexprResult = NULL; } return pexprResult; }
//--------------------------------------------------------------------------- // @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: // 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: // CNormalizer::PushThruJoin // // @doc: // Push a conjunct through a join // // //--------------------------------------------------------------------------- void CNormalizer::PushThruJoin ( IMemoryPool *pmp, CExpression *pexprJoin, CExpression *pexprConj, CExpression **ppexprResult ) { GPOS_ASSERT(NULL != pexprConj); GPOS_ASSERT(NULL != ppexprResult); COperator *pop = pexprJoin->Pop(); const ULONG ulArity = pexprJoin->UlArity(); BOOL fLASApply = CUtils::FLeftAntiSemiApply(pop); COperator::EOperatorId eopid = pop->Eopid(); BOOL fOuterJoin = COperator::EopLogicalLeftOuterJoin == eopid || COperator::EopLogicalLeftOuterApply == eopid || COperator::EopLogicalLeftOuterCorrelatedApply == eopid; if (fOuterJoin && !CUtils::FScalarConstTrue(pexprConj)) { // whenever possible, push incoming predicate through outer join's outer child, // recursion will eventually reach the rest of PushThruJoin() to process join predicates PushThruOuterChild(pmp, pexprJoin, pexprConj, ppexprResult); return; } // combine conjunct with join predicate CExpression *pexprScalar = (*pexprJoin)[ulArity - 1]; CExpression *pexprPred = CPredicateUtils::PexprConjunction(pmp, pexprScalar, pexprConj); // break predicate to conjuncts DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprPred); pexprPred->Release(); // push predicates through children and compute new child expressions DrgPexpr *pdrgpexprChildren = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < ulArity - 1; ul++) { CExpression *pexprChild = (*pexprJoin)[ul]; CExpression *pexprNewChild = NULL; if (fLASApply) { // do not push anti-semi-apply predicates to any of the children pexprNewChild = PexprNormalize(pmp, pexprChild); pdrgpexprChildren->Append(pexprNewChild); continue; } if (0 == ul && fOuterJoin) { // do not push outer join predicates through outer child // otherwise, we will throw away outer child's tuples that should // be part of the join result pexprNewChild = PexprNormalize(pmp, pexprChild); pdrgpexprChildren->Append(pexprNewChild); continue; } DrgPexpr *pdrgpexprRemaining = NULL; PushThru(pmp, pexprChild, pdrgpexprConjuncts, &pexprNewChild, &pdrgpexprRemaining); pdrgpexprChildren->Append(pexprNewChild); pdrgpexprConjuncts->Release(); pdrgpexprConjuncts = pdrgpexprRemaining; } // remaining conjuncts become the new join predicate CExpression *pexprNewScalar = CPredicateUtils::PexprConjunction(pmp, pdrgpexprConjuncts); pdrgpexprChildren->Append(pexprNewScalar); // create a new join expression pop->AddRef(); *ppexprResult = GPOS_NEW(pmp) CExpression(pmp, pop, pdrgpexprChildren); }
//--------------------------------------------------------------------------- // @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; }
//--------------------------------------------------------------------------- // @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: // CJoinOrderTest::EresUnittest_ExpandMinCard // // @doc: // Expansion expansion based on cardinality of intermediate results // //--------------------------------------------------------------------------- GPOS_RESULT CJoinOrderTest::EresUnittest_ExpandMinCard() { CAutoMemoryPool amp; IMemoryPool *pmp = amp.Pmp(); // array of relation names CWStringConst rgscRel[] = { GPOS_WSZ_LIT("Rel10"), GPOS_WSZ_LIT("Rel3"), GPOS_WSZ_LIT("Rel4"), GPOS_WSZ_LIT("Rel6"), GPOS_WSZ_LIT("Rel7"), GPOS_WSZ_LIT("Rel8"), GPOS_WSZ_LIT("Rel12"), GPOS_WSZ_LIT("Rel13"), GPOS_WSZ_LIT("Rel5"), GPOS_WSZ_LIT("Rel14"), GPOS_WSZ_LIT("Rel15"), GPOS_WSZ_LIT("Rel1"), GPOS_WSZ_LIT("Rel11"), GPOS_WSZ_LIT("Rel2"), GPOS_WSZ_LIT("Rel9"), }; // array of relation IDs ULONG rgulRel[] = { GPOPT_TEST_REL_OID10, GPOPT_TEST_REL_OID3, GPOPT_TEST_REL_OID4, GPOPT_TEST_REL_OID6, GPOPT_TEST_REL_OID7, GPOPT_TEST_REL_OID8, GPOPT_TEST_REL_OID12, GPOPT_TEST_REL_OID13, GPOPT_TEST_REL_OID5, GPOPT_TEST_REL_OID14, GPOPT_TEST_REL_OID15, GPOPT_TEST_REL_OID1, GPOPT_TEST_REL_OID11, GPOPT_TEST_REL_OID2, GPOPT_TEST_REL_OID9, }; const ULONG ulRels = GPOS_ARRAY_SIZE(rgscRel); GPOS_ASSERT(GPOS_ARRAY_SIZE(rgulRel) == ulRels); // setup a file-based provider CMDProviderMemory *pmdp = CTestUtils::m_pmdpf; pmdp->AddRef(); CMDAccessor mda(pmp, CMDCache::Pcache()); mda.RegisterProvider(CTestUtils::m_sysidDefault, pmdp); { // install opt context in TLS CAutoOptCtxt aoc ( pmp, &mda, NULL, /* pceeval */ CTestUtils::Pcm(pmp) ); CExpression *pexprNAryJoin = CTestUtils::PexprLogicalNAryJoin(pmp, rgscRel, rgulRel, ulRels, false /*fCrossProduct*/); // derive stats on input expression CExpressionHandle exprhdl(pmp); exprhdl.Attach(pexprNAryJoin); exprhdl.DeriveStats(pmp, pmp, NULL /*prprel*/, NULL /*pdrgpstatCtxt*/); DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); for (ULONG ul = 0; ul < ulRels; ul++) { CExpression *pexprChild = (*pexprNAryJoin)[ul]; pexprChild->AddRef(); pdrgpexpr->Append(pexprChild); } DrgPexpr *pdrgpexprPred = CPredicateUtils::PdrgpexprConjuncts(pmp, (*pexprNAryJoin)[ulRels]); pdrgpexpr->AddRef(); pdrgpexprPred->AddRef(); CJoinOrderMinCard jomc(pmp, pdrgpexpr, pdrgpexprPred); CExpression *pexprResult = jomc.PexprExpand(); { CAutoTrace at(pmp); at.Os() << std::endl << "INPUT:" << std::endl << *pexprNAryJoin << std::endl; at.Os() << std::endl << "OUTPUT:" << std::endl << *pexprResult << std::endl; } pexprResult->Release(); pexprNAryJoin->Release(); pdrgpexpr->Release(); pdrgpexprPred->Release(); } return GPOS_OK; }
//--------------------------------------------------------------------------- // @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(); }