//--------------------------------------------------------------------------- // @function: // CConstraint::PdrgpcnstrOnColumn // // @doc: // Return a subset of the given constraints which reference the // given column // //--------------------------------------------------------------------------- DrgPcnstr * CConstraint::PdrgpcnstrOnColumn ( IMemoryPool *pmp, DrgPcnstr *pdrgpcnstr, CColRef *pcr, BOOL fExclusive // returned constraints must reference ONLY the given col ) { DrgPcnstr *pdrgpcnstrSubset = GPOS_NEW(pmp) DrgPcnstr(pmp); const ULONG ulLen = pdrgpcnstr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CConstraint *pcnstr = (*pdrgpcnstr)[ul]; CColRefSet *pcrs = pcnstr->PcrsUsed(); // if the fExclusive flag is true, then pcr must be the only column if (pcrs->FMember(pcr) && (!fExclusive || 1 == pcrs->CElements())) { pcnstr->AddRef(); pdrgpcnstrSubset->Append(pcnstr); } } return pdrgpcnstrSubset; }
// mapping between columns and single column constraints in array of constraints static HMColConstr * PhmcolconstrSingleColConstr ( IMemoryPool *pmp, DrgPcnstr *drgPcnstr ) { CAutoRef<DrgPcnstr> arpdrgpcnstr(drgPcnstr); HMColConstr *phmcolconstr = GPOS_NEW(pmp) HMColConstr(pmp); const ULONG ulLen = arpdrgpcnstr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CConstraint *pcnstrChild = (*arpdrgpcnstr)[ul]; CColRefSet *pcrs = pcnstrChild->PcrsUsed(); if (1 == pcrs->CElements()) { CColRef *pcr = pcrs->PcrFirst(); DrgPcnstr *pcnstrMapped = phmcolconstr->PtLookup(pcr); if (NULL == pcnstrMapped) { pcnstrMapped = GPOS_NEW(pmp) DrgPcnstr(pmp); phmcolconstr->FInsert(pcr, pcnstrMapped); } pcnstrChild->AddRef(); pcnstrMapped->Append(pcnstrChild); } } return phmcolconstr; }
//--------------------------------------------------------------------------- // @function: // CLogicalSetOp::PdrgpcrsInputMapped // // @doc: // Get equivalence classes from one input child, mapped to output columns // //--------------------------------------------------------------------------- DrgPcrs * CLogicalSetOp::PdrgpcrsInputMapped ( IMemoryPool *pmp, CExpressionHandle &exprhdl, ULONG ulChild ) const { DrgPcrs *pdrgpcrsInput = exprhdl.Pdprel(ulChild)->Ppc()->PdrgpcrsEquivClasses(); const ULONG ulLen = pdrgpcrsInput->UlLength(); CColRefSet* pcrsChildInput = (*m_pdrgpcrsInput)[ulChild]; DrgPcrs *pdrgpcrs = GPOS_NEW(pmp) DrgPcrs(pmp); for (ULONG ul = 0; ul < ulLen; ul++) { CColRefSet *pcrs = GPOS_NEW(pmp) CColRefSet(pmp); pcrs->Include((*pdrgpcrsInput)[ul]); pcrs->Intersection(pcrsChildInput); if (0 == pcrs->CElements()) { pcrs->Release(); continue; } // replace each input column with its corresponding output column pcrs->Replace((*m_pdrgpdrgpcrInput)[ulChild], m_pdrgpcrOutput); pdrgpcrs->Append(pcrs); } return pdrgpcrs; }
//--------------------------------------------------------------------------- // @function: // CPhysicalJoin::FHashJoinCompatible // // @doc: // Are the given predicate parts hash join compatible? // predicate parts are obtained by splitting equality into outer // and inner expressions // //--------------------------------------------------------------------------- BOOL CPhysicalJoin::FHashJoinCompatible ( CExpression *pexprOuter, // outer child of the join CExpression* pexprInner, // inner child of the join CExpression *pexprPredOuter,// outer part of join predicate CExpression *pexprPredInner // inner part of join predicate ) { GPOS_ASSERT(NULL != pexprOuter); GPOS_ASSERT(NULL != pexprInner); GPOS_ASSERT(NULL != pexprPredOuter); GPOS_ASSERT(NULL != pexprPredInner); IMDId *pmdidTypeOuter = CScalar::PopConvert(pexprPredOuter->Pop())->PmdidType(); IMDId *pmdidTypeInner = CScalar::PopConvert(pexprPredInner->Pop())->PmdidType(); CColRefSet *pcrsUsedPredOuter = CDrvdPropScalar::Pdpscalar(pexprPredOuter->PdpDerive())->PcrsUsed(); CColRefSet *pcrsUsedPredInner = CDrvdPropScalar::Pdpscalar(pexprPredInner->PdpDerive())->PcrsUsed(); CColRefSet *pcrsOuter = CDrvdPropRelational::Pdprel(pexprOuter->Pdp(CDrvdProp::EptRelational))->PcrsOutput(); CColRefSet *pcrsInner = CDrvdPropRelational::Pdprel(pexprInner->Pdp(CDrvdProp::EptRelational))->PcrsOutput(); // make sure that each predicate child uses columns from a different join child // in order to reject predicates of the form 'X Join Y on f(X.a, Y.b) = 5' BOOL fPredOuterUsesJoinOuterChild = (0 < pcrsUsedPredOuter->CElements()) && pcrsOuter->FSubset(pcrsUsedPredOuter); BOOL fPredOuterUsesJoinInnerChild = (0 < pcrsUsedPredOuter->CElements()) && pcrsInner->FSubset(pcrsUsedPredOuter); BOOL fPredInnerUsesJoinOuterChild = (0 < pcrsUsedPredInner->CElements()) && pcrsOuter->FSubset(pcrsUsedPredInner); BOOL fPredInnerUsesJoinInnerChild = (0 < pcrsUsedPredInner->CElements()) && pcrsInner->FSubset(pcrsUsedPredInner); BOOL fHashJoinCompatiblePred = (fPredOuterUsesJoinOuterChild && fPredInnerUsesJoinInnerChild) || (fPredOuterUsesJoinInnerChild && fPredInnerUsesJoinOuterChild); CMDAccessor *pmda = COptCtxt::PoctxtFromTLS()->Pmda(); return fHashJoinCompatiblePred && pmda->Pmdtype(pmdidTypeOuter)->FHashable() && pmda->Pmdtype(pmdidTypeInner)->FHashable(); }
//--------------------------------------------------------------------------- // @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: // CExpressionHandle::PdrgpstatOuterRefs // // @doc: // Given an array of stats objects and a child index, return an array // of stats objects starting from the first stats object referenced by // child // //--------------------------------------------------------------------------- DrgPstat * CExpressionHandle::PdrgpstatOuterRefs ( DrgPstat *pdrgpstat, ULONG ulChildIndex ) const { GPOS_ASSERT(NULL != pdrgpstat); GPOS_ASSERT(ulChildIndex < UlArity()); if (FScalarChild(ulChildIndex) || !FHasOuterRefs(ulChildIndex)) { // if child is scalar or has no outer references, return empty array return GPOS_NEW(m_pmp) DrgPstat(m_pmp); } DrgPstat *pdrgpstatResult = GPOS_NEW(m_pmp) DrgPstat(m_pmp); CColRefSet *pcrsOuter = Pdprel(ulChildIndex)->PcrsOuter(); GPOS_ASSERT(0 < pcrsOuter->CElements()); const ULONG ulSize = pdrgpstat->UlLength(); ULONG ulStartIndex = ULONG_MAX; for (ULONG ul = 0; ul < ulSize; ul++) { IStatistics *pstats = (*pdrgpstat)[ul]; CColRefSet *pcrsStats = pstats->Pcrs(m_pmp); BOOL fStatsColsUsed = !pcrsOuter->FDisjoint(pcrsStats); pcrsStats->Release(); if (fStatsColsUsed) { ulStartIndex = ul; break; } } if (ULONG_MAX != ulStartIndex) { // copy stats starting from index of outer-most stats object referenced by child CUtils::AddRefAppend<IStatistics, CleanupStats>(pdrgpstatResult, pdrgpstat, ulStartIndex); } return pdrgpstatResult; }
//--------------------------------------------------------------------------- // @function: // CColumnFactory::AddComputedToUsedColsMap // // @doc: // Add the map between computed column and its used columns // //--------------------------------------------------------------------------- void CColumnFactory::AddComputedToUsedColsMap ( CExpression *pexpr ) { GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(NULL != m_phmcrcrs); const CScalarProjectElement *popScPrEl = CScalarProjectElement::PopConvert(pexpr->Pop()); CColRef *pcrComputedCol = popScPrEl->Pcr(); CDrvdPropScalar *pdpscalar = CDrvdPropScalar::Pdpscalar(pexpr->PdpDerive()); CColRefSet *pcrsUsed = pdpscalar->PcrsUsed(); if (NULL != pcrsUsed && 0 < pcrsUsed->CElements()) { #ifdef GPOS_DEBUG BOOL fres = #endif // GPOS_DEBUG m_phmcrcrs->FInsert(pcrComputedCol, GPOS_NEW(m_pmp) CColRefSet(m_pmp, *pcrsUsed)); GPOS_ASSERT(fres); } }
//--------------------------------------------------------------------------- // @function: // CConstraint::PdrgpcnstrDeduplicate // // @doc: // Simplify an array of constraints to be used as children for a conjunction // or disjunction. If there are two or more elements that reference only one // particular column, these constraints are combined into one // //--------------------------------------------------------------------------- DrgPcnstr * CConstraint::PdrgpcnstrDeduplicate ( IMemoryPool *pmp, DrgPcnstr *pdrgpcnstr, EConstraintType ect ) const { DrgPcnstr *pdrgpcnstrNew = GPOS_NEW(pmp) DrgPcnstr(pmp); CColRefSet *pcrsDeduped = GPOS_NEW(pmp) CColRefSet(pmp); const ULONG ulLen = pdrgpcnstr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CConstraint *pcnstrChild = (*pdrgpcnstr)[ul]; CColRefSet *pcrs = pcnstrChild->PcrsUsed(); // we only simplify constraints that reference a single column, otherwise // we add constraint as is if (1 < pcrs->CElements()) { pcnstrChild->AddRef(); pdrgpcnstrNew->Append(pcnstrChild); continue; } CColRef *pcr = pcrs->PcrFirst(); if (pcrsDeduped->FMember(pcr)) { // current constraint has already been combined with a previous one continue; } // get all constraints from the input array that reference this column DrgPcnstr *pdrgpcnstrCol = PdrgpcnstrOnColumn(pmp, pdrgpcnstr, pcr, true /*fExclusive*/); if (1 == pdrgpcnstrCol->UlLength()) { // if there is only one such constraint, then no simplification // for this column pdrgpcnstrCol->Release(); pcnstrChild->AddRef(); pdrgpcnstrNew->Append(pcnstrChild); continue; } CExpression *pexpr = NULL; if (EctConjunction == ect) { pexpr = PexprScalarConjDisj(pmp, pdrgpcnstrCol, true /*fConj*/); } else { GPOS_ASSERT(EctDisjunction == ect); pexpr = PexprScalarConjDisj(pmp, pdrgpcnstrCol, false /*fConj*/); } pdrgpcnstrCol->Release(); GPOS_ASSERT(NULL != pexpr); CConstraint *pcnstrNew = CConstraintInterval::PciIntervalFromScalarExpr(pmp, pexpr, pcr); GPOS_ASSERT(NULL != pcnstrNew); pexpr->Release(); pdrgpcnstrNew->Append(pcnstrNew); pcrsDeduped->Include(pcr); } pcrsDeduped->Release(); pdrgpcnstr->Release(); return pdrgpcnstrNew; }
//--------------------------------------------------------------------------- // @function: // CConstraint::PcnstrFromScalarExpr // // @doc: // Create constraint from scalar expression and pass back any discovered // equivalence classes // //--------------------------------------------------------------------------- CConstraint * CConstraint::PcnstrFromScalarExpr ( IMemoryPool *pmp, CExpression *pexpr, DrgPcrs **ppdrgpcrs // output equivalence classes ) { GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(pexpr->Pop()->FScalar()); GPOS_ASSERT(NULL != ppdrgpcrs); GPOS_ASSERT(NULL == *ppdrgpcrs); (void) pexpr->PdpDerive(); CDrvdPropScalar *pdpScalar = CDrvdPropScalar::Pdpscalar(pexpr->Pdp(CDrvdProp::EptScalar)); CColRefSet *pcrs = pdpScalar->PcrsUsed(); ULONG ulCols = pcrs->CElements(); if (0 == ulCols) { // TODO: - May 29, 2012: in case of an expr with no columns (e.g. 1 < 2), // possibly evaluate the expression, and return a "TRUE" or "FALSE" constraint return NULL; } if (1 == ulCols) { CColRef *pcr = pcrs->PcrFirst(); if (!CUtils::FConstrainableType(pcr->Pmdtype()->Pmdid())) { return NULL; } CConstraint *pcnstr = NULL; *ppdrgpcrs = GPOS_NEW(pmp) DrgPcrs(pmp); // first, try creating a single interval constraint from the expression pcnstr = CConstraintInterval::PciIntervalFromScalarExpr(pmp, pexpr, pcr); if (NULL == pcnstr && CUtils::FScalarArrayCmp(pexpr)) { // if the interval creation failed, try creating a disjunction or conjunction // of several interval constraints in the array case pcnstr = PcnstrFromScalarArrayCmp(pmp, pexpr, pcr); } if (NULL != pcnstr) { AddColumnToEquivClasses(pmp, pcr, ppdrgpcrs); } return pcnstr; } switch (pexpr->Pop()->Eopid()) { case COperator::EopScalarBoolOp: return PcnstrFromScalarBoolOp(pmp, pexpr, ppdrgpcrs); case COperator::EopScalarCmp: return PcnstrFromScalarCmp(pmp, pexpr, ppdrgpcrs); default: return NULL; } }
//--------------------------------------------------------------------------- // @function: // CLogical::PpcDeriveConstraintRestrict // // @doc: // Derive constraint property only on the given columns // //--------------------------------------------------------------------------- CPropConstraint * CLogical::PpcDeriveConstraintRestrict ( IMemoryPool *pmp, CExpressionHandle &exprhdl, CColRefSet *pcrsOutput ) { // constraint property from relational child CPropConstraint *ppc = exprhdl.Pdprel(0)->Ppc(); DrgPcrs *pdrgpcrs = ppc->PdrgpcrsEquivClasses(); // construct new array of equivalence classes DrgPcrs *pdrgpcrsNew = GPOS_NEW(pmp) DrgPcrs(pmp); const ULONG ulLen = pdrgpcrs->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CColRefSet *pcrsEquiv = GPOS_NEW(pmp) CColRefSet(pmp); pcrsEquiv->Include((*pdrgpcrs)[ul]); pcrsEquiv->Intersection(pcrsOutput); if (0 < pcrsEquiv->CElements()) { pdrgpcrsNew->Append(pcrsEquiv); } else { pcrsEquiv->Release(); } } CConstraint *pcnstrChild = ppc->Pcnstr(); if (NULL == pcnstrChild) { return GPOS_NEW(pmp) CPropConstraint(pmp, pdrgpcrsNew, NULL); } DrgPcnstr *pdrgpcnstr = GPOS_NEW(pmp) DrgPcnstr(pmp); // include only constraints on given columns CColRefSetIter crsi(*pcrsOutput); while (crsi.FAdvance()) { CColRef *pcr = crsi.Pcr(); CConstraint *pcnstrCol = pcnstrChild->Pcnstr(pmp, pcr); if (NULL == pcnstrCol) { continue; } if (pcnstrCol->FUnbounded()) { pcnstrCol->Release(); continue; } pdrgpcnstr->Append(pcnstrCol); } CConstraint *pcnstr = CConstraint::PcnstrConjunction(pmp, pdrgpcnstr); return GPOS_NEW(pmp) CPropConstraint(pmp, pdrgpcrsNew, pcnstr); }
//--------------------------------------------------------------------------- // @function: // CColRefSetIterTest::EresUnittest_Basics // // @doc: // Testing ctors/dtor; and pcr decoding; // Other functionality already tested in vanilla CBitSetIter; // //--------------------------------------------------------------------------- GPOS_RESULT CColRefSetIterTest::EresUnittest_Basics() { CAutoMemoryPool amp; IMemoryPool *pmp = amp.Pmp(); // Setup an MD cache with 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) ); // get column factory from optimizer context object CColumnFactory *pcf = COptCtxt::PoctxtFromTLS()->Pcf(); CColRefSet *pcrs = GPOS_NEW(pmp) CColRefSet(pmp); CWStringConst strName(GPOS_WSZ_LIT("Test Column")); CName name(&strName); // create a int4 datum const IMDTypeInt4 *pmdtypeint4 = mda.PtMDType<IMDTypeInt4>(); ULONG ulCols = 10; for(ULONG i = 0; i < ulCols; i++) { CColRef *pcr = pcf->PcrCreate(pmdtypeint4, name); pcrs->Include(pcr); GPOS_ASSERT(pcrs->FMember(pcr)); } GPOS_ASSERT(pcrs->CElements() == ulCols); ULONG ulCount = 0; CColRefSetIter crsi(*pcrs); while(crsi.FAdvance()) { GPOS_ASSERT((BOOL)crsi); CColRef *pcr = crsi.Pcr(); GPOS_ASSERT(pcr->Name().FEquals(name)); // to avoid unused variable warnings (void) pcr->UlId(); ulCount++; } GPOS_ASSERT(ulCols == ulCount); GPOS_ASSERT(!((BOOL)crsi)); pcrs->Release(); return GPOS_OK; }