//--------------------------------------------------------------------------- // @function: // CConstraint::PexprScalarConjDisj // // @doc: // Construct a conjunction or disjunction scalar expression from an // array of constraints // //--------------------------------------------------------------------------- CExpression * CConstraint::PexprScalarConjDisj ( IMemoryPool *pmp, DrgPcnstr *pdrgpcnstr, BOOL fConj ) const { DrgPexpr *pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); const ULONG ulLen = pdrgpcnstr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CExpression *pexpr = (*pdrgpcnstr)[ul]->PexprScalar(pmp); pexpr->AddRef(); pdrgpexpr->Append(pexpr); } if (fConj) { return CPredicateUtils::PexprConjunction(pmp, pdrgpexpr); } return CPredicateUtils::PexprDisjunction(pmp, pdrgpexpr); }
//--------------------------------------------------------------------------- // @function: // 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::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: // 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; }
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: // 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: // 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: // CNormalizer::SplitConjunctForSeqPrj // // @doc: // Split the given conjunct into pushable and unpushable predicates // for a sequence project expression // //--------------------------------------------------------------------------- void CNormalizer::SplitConjunctForSeqPrj ( IMemoryPool *pmp, CExpression *pexprSeqPrj, CExpression *pexprConj, DrgPexpr **ppdrgpexprPushable, DrgPexpr **ppdrgpexprUnpushable ) { GPOS_ASSERT(NULL != pexprSeqPrj); GPOS_ASSERT(NULL != pexprConj); GPOS_ASSERT(NULL != ppdrgpexprPushable); GPOS_ASSERT(NULL != ppdrgpexprUnpushable); *ppdrgpexprPushable = GPOS_NEW(pmp) DrgPexpr(pmp); *ppdrgpexprUnpushable = GPOS_NEW(pmp) DrgPexpr(pmp); DrgPexpr *pdrgpexprPreds = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprConj); const ULONG ulPreds = pdrgpexprPreds->UlLength(); for (ULONG ul = 0; ul < ulPreds; ul++) { CExpression *pexprPred = (*pdrgpexprPreds)[ul]; pexprPred->AddRef(); if (FPushableThruSeqPrjChild(pexprSeqPrj, pexprPred)) { (*ppdrgpexprPushable)->Append(pexprPred); } else { (*ppdrgpexprUnpushable)->Append(pexprPred); } } pdrgpexprPreds->Release(); }
//--------------------------------------------------------------------------- // @function: // 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: // CNormalizer::SplitConjunct // // @doc: // Split the given conjunct into pushable and unpushable predicates // // //--------------------------------------------------------------------------- void CNormalizer::SplitConjunct ( IMemoryPool *pmp, CExpression *pexpr, CExpression *pexprConj, DrgPexpr **ppdrgpexprPushable, DrgPexpr **ppdrgpexprUnpushable ) { GPOS_ASSERT(pexpr->Pop()->FLogical()); GPOS_ASSERT(pexprConj->Pop()->FScalar()); GPOS_ASSERT(NULL != ppdrgpexprPushable); GPOS_ASSERT(NULL != ppdrgpexprUnpushable); // collect pushable predicates from given conjunct *ppdrgpexprPushable = GPOS_NEW(pmp) DrgPexpr(pmp); *ppdrgpexprUnpushable = GPOS_NEW(pmp) DrgPexpr(pmp); DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprConj); const ULONG ulSize = pdrgpexprConjuncts->UlLength(); for (ULONG ul = 0; ul < ulSize; ul++) { CExpression *pexprScalar = (*pdrgpexprConjuncts)[ul]; pexprScalar->AddRef(); if (FPushable(pexpr, pexprScalar)) { (*ppdrgpexprPushable)->Append(pexprScalar); } else { (*ppdrgpexprUnpushable)->Append(pexprScalar); } } pdrgpexprConjuncts->Release(); }
//--------------------------------------------------------------------------- // @function: // CNormalizer::PushThruUnaryWithScalarChild // // @doc: // Push a conjunct through a unary operator with scalar child // //--------------------------------------------------------------------------- void CNormalizer::PushThruUnaryWithScalarChild ( IMemoryPool *pmp, CExpression *pexprLogical, CExpression *pexprConj, CExpression **ppexprResult ) { GPOS_ASSERT(NULL != pexprLogical); GPOS_ASSERT(2 == pexprLogical->UlArity()); GPOS_ASSERT(NULL != pexprConj); GPOS_ASSERT(NULL != ppexprResult); // get logical and scalar children CExpression *pexprLogicalChild = (*pexprLogical)[0]; CExpression *pexprScalarChild = (*pexprLogical)[1]; // push conjuncts through the logical child CExpression *pexprNewLogicalChild = NULL; DrgPexpr *pdrgpexprUnpushable = NULL; // break scalar expression to conjuncts DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprConj); PushThru(pmp, pexprLogicalChild, pdrgpexprConjuncts, &pexprNewLogicalChild, &pdrgpexprUnpushable); pdrgpexprConjuncts->Release(); // create a new logical expression based on recursion results COperator *pop = pexprLogical->Pop(); pop->AddRef(); pexprScalarChild->AddRef(); CExpression *pexprNewLogical = GPOS_NEW(pmp) CExpression(pmp, pop, pexprNewLogicalChild, pexprScalarChild); *ppexprResult = PexprSelect(pmp, pexprNewLogical, pdrgpexprUnpushable); }
//--------------------------------------------------------------------------- // @function: // 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; }
void CDistributionSpecHashedNoOp::AppendEnforcers ( IMemoryPool *pmp, CExpressionHandle &exprhdl, CReqdPropPlan *, DrgPexpr *pdrgpexpr, CExpression *pexpr ) { CDrvdProp *pdp = exprhdl.Pdp(); CDistributionSpec *pdsChild = CDrvdPropPlan::Pdpplan(pdp)->Pds(); CDistributionSpecHashed *pdsChildHashed = dynamic_cast<CDistributionSpecHashed *>(pdsChild); if (NULL == pdsChildHashed) { return; } DrgPexpr *pdrgpexprNoOpRedistributionColumns = pdsChildHashed->Pdrgpexpr(); pdrgpexprNoOpRedistributionColumns->AddRef(); CDistributionSpecHashedNoOp* pdsNoOp = GPOS_NEW(pmp) CDistributionSpecHashedNoOp(pdrgpexprNoOpRedistributionColumns); pexpr->AddRef(); CExpression *pexprMotion = GPOS_NEW(pmp) CExpression ( pmp, GPOS_NEW(pmp) CPhysicalMotionHashDistribute(pmp, pdsNoOp), pexpr ); pdrgpexpr->Append(pexprMotion); }
//--------------------------------------------------------------------------- // @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: // 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: // CNormalizer::PushThruSelect // // @doc: // Push a conjunct through a select // //--------------------------------------------------------------------------- void CNormalizer::PushThruSelect ( IMemoryPool *pmp, CExpression *pexprSelect, CExpression *pexprConj, CExpression **ppexprResult ) { GPOS_ASSERT(NULL != pexprConj); GPOS_ASSERT(NULL != ppexprResult); CExpression *pexprLogicalChild = (*pexprSelect)[0]; CExpression *pexprScalarChild = (*pexprSelect)[1]; CExpression *pexprPred = CPredicateUtils::PexprConjunction(pmp, pexprScalarChild, pexprConj); if (CUtils::FScalarConstTrue(pexprPred)) { pexprPred->Release(); *ppexprResult = PexprNormalize(pmp, pexprLogicalChild); return; } COperator::EOperatorId eopid = pexprLogicalChild->Pop()->Eopid(); if (COperator::EopLogicalLeftOuterJoin == eopid) { CExpression *pexprSimplified = NULL; if (FSimplifySelectOnOuterJoin(pmp, pexprLogicalChild, pexprPred, &pexprSimplified)) { // simplification succeeded, normalize resulting expression *ppexprResult = PexprNormalize(pmp, pexprSimplified); pexprPred->Release(); pexprSimplified->Release(); return; } } if (FPushThruOuterChild(pexprLogicalChild)) { PushThruOuterChild(pmp, pexprLogicalChild, pexprPred, ppexprResult); } else { // logical child may not pass all predicates through, we need to collect // unpushable predicates, if any, into a top Select node DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprPred); DrgPexpr *pdrgpexprRemaining = NULL; CExpression *pexpr = NULL; PushThru(pmp, pexprLogicalChild, pdrgpexprConjuncts, &pexpr, &pdrgpexprRemaining); *ppexprResult = PexprSelect(pmp, pexpr, pdrgpexprRemaining); pdrgpexprConjuncts->Release(); } pexprPred->Release(); }
//--------------------------------------------------------------------------- // @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: // CBinding::PexprExtract // // @doc: // Extract a binding according to a given pattern; // Keep root node fixed; // //--------------------------------------------------------------------------- CExpression * CBinding::PexprExtract ( IMemoryPool *pmp, CGroupExpression *pgexpr, CExpression *pexprPattern, CExpression *pexprLast ) { GPOS_CHECK_ABORT; if (!pexprPattern->FMatchPattern(pgexpr)) { // shallow matching fails return NULL; } // the previously extracted pattern must have the same root GPOS_ASSERT_IMP(NULL != pexprLast, pexprLast->Pgexpr() == pgexpr); COperator *popPattern = pexprPattern->Pop(); if (popPattern->FPattern() && CPattern::PopConvert(popPattern)->FLeaf()) { // return immediately; no deep extraction for leaf patterns pgexpr->Pop()->AddRef(); return GPOS_NEW(pmp) CExpression(pmp, pgexpr->Pop(), pgexpr); } DrgPexpr *pdrgpexpr = NULL; ULONG ulArity = pgexpr->UlArity(); if (0 == ulArity && NULL != pexprLast) { // no more bindings return NULL; } else { // attempt binding to children pdrgpexpr = GPOS_NEW(pmp) DrgPexpr(pmp); if (!FExtractChildren(pmp, pgexpr, pexprPattern, pexprLast, pdrgpexpr)) { pdrgpexpr->Release(); return NULL; } } CExpression *pexpr = PexprFinalize(pmp, pgexpr, pdrgpexpr); GPOS_ASSERT(NULL != pexpr); return pexpr; }
//--------------------------------------------------------------------------- // @function: // CStatsPredUtils::FConjunction // // @doc: // Is the condition a conjunctive predicate //--------------------------------------------------------------------------- BOOL CStatsPredUtils::FConjunction ( IMemoryPool *pmp, CExpression *pexprPred ) { GPOS_ASSERT(NULL != pexprPred); DrgPexpr *pdrgpexprConjuncts = CPredicateUtils::PdrgpexprConjuncts(pmp, pexprPred); const ULONG ulLen = pdrgpexprConjuncts->UlLength(); pdrgpexprConjuncts->Release(); return (1 < ulLen); }
//--------------------------------------------------------------------------- // @function: // 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: // 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: // CNormalizer::PushThruSeqPrj // // @doc: // Push a conjunct through a sequence project expression // //--------------------------------------------------------------------------- void CNormalizer::PushThruSeqPrj ( IMemoryPool *pmp, CExpression *pexprSeqPrj, CExpression *pexprConj, CExpression **ppexprResult ) { GPOS_ASSERT(NULL != pexprSeqPrj); GPOS_ASSERT(CLogical::EopLogicalSequenceProject == pexprSeqPrj->Pop()->Eopid()); GPOS_ASSERT(NULL != pexprConj); GPOS_ASSERT(NULL != ppexprResult); // get logical and scalar children CExpression *pexprLogicalChild = (*pexprSeqPrj)[0]; CExpression *pexprScalarChild = (*pexprSeqPrj)[1]; // break scalar expression to pushable and unpushable conjuncts DrgPexpr *pdrgpexprPushable = NULL; DrgPexpr *pdrgpexprUnpushable = NULL; SplitConjunctForSeqPrj(pmp, pexprSeqPrj, pexprConj, &pdrgpexprPushable, &pdrgpexprUnpushable); CExpression *pexprNewLogicalChild = NULL; if (0 < pdrgpexprPushable->UlLength()) { CExpression *pexprPushableConj = CPredicateUtils::PexprConjunction(pmp, pdrgpexprPushable); PushThru(pmp, pexprLogicalChild, pexprPushableConj, &pexprNewLogicalChild); pexprPushableConj->Release(); } else { // no pushable predicates on top of sequence project, // we still need to process child recursively to push-down child's own predicates pdrgpexprPushable->Release(); pexprNewLogicalChild = PexprNormalize(pmp, pexprLogicalChild); } // create a new logical expression based on recursion results COperator *pop = pexprSeqPrj->Pop(); pop->AddRef(); pexprScalarChild->AddRef(); CExpression *pexprNewLogical = GPOS_NEW(pmp) CExpression(pmp, pop, pexprNewLogicalChild, pexprScalarChild); // create a select node for remaining predicates, if any *ppexprResult = PexprSelect(pmp, pexprNewLogical, pdrgpexprUnpushable); }
//--------------------------------------------------------------------------- // @function: // CPhysicalJoin::FHashJoinPossible // // @doc: // Check if predicate is hashjoin-able and extract arrays of hash keys // //--------------------------------------------------------------------------- BOOL CPhysicalJoin::FHashJoinPossible ( IMemoryPool *pmp, CExpression *pexpr, DrgPexpr *pdrgpexprOuter, DrgPexpr *pdrgpexprInner, CExpression **ppexprResult // output : join expression to be transformed to hash join ) { GPOS_ASSERT(COperator::EopLogicalNAryJoin != pexpr->Pop()->Eopid() && CUtils::FLogicalJoin(pexpr->Pop())); // we should not be here if there are outer references GPOS_ASSERT(!CUtils::FHasOuterRefs(pexpr)); GPOS_ASSERT(NULL != ppexprResult); // introduce explicit casting, if needed DrgPexpr *pdrgpexpr = CPredicateUtils::PdrgpexprCastEquality(pmp, (*pexpr)[2]); // identify hashkeys ULONG ulPreds = pdrgpexpr->UlLength(); for (ULONG ul = 0; ul < ulPreds; ul++) { CExpression *pexprPred = (*pdrgpexpr)[ul]; if (FHashJoinCompatible(pexprPred, (*pexpr)[0], (*pexpr)[1])) { AddHashKeys(pexprPred, (*pexpr)[0], (*pexpr)[1], pdrgpexprOuter, pdrgpexprInner); } } // construct output join expression pexpr->Pop()->AddRef(); (*pexpr)[0]->AddRef(); (*pexpr)[1]->AddRef(); *ppexprResult = GPOS_NEW(pmp) CExpression ( pmp, pexpr->Pop(), (*pexpr)[0], (*pexpr)[1], CPredicateUtils::PexprConjunction(pmp, pdrgpexpr) ); return (0 != pdrgpexprInner->UlLength()); }
//--------------------------------------------------------------------------- // @function: // CNormalizer::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: // 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: // 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; }