//--------------------------------------------------------------------------- // @function: // CPartConstraint::FOverlapLevel // // @doc: // Does the current constraint overlap with given one at the given level // //--------------------------------------------------------------------------- BOOL CPartConstraint::FOverlapLevel ( IMemoryPool *mp, const CPartConstraint *ppartcnstr, ULONG ulLevel ) const { GPOS_ASSERT(NULL != ppartcnstr); GPOS_ASSERT(!IsConstraintUnbounded()); GPOS_ASSERT(!ppartcnstr->IsConstraintUnbounded()); CConstraintArray *pdrgpcnstr = GPOS_NEW(mp) CConstraintArray(mp); CConstraint *pcnstrCurrent = Pcnstr(ulLevel); CConstraint *pcnstrOther = ppartcnstr->Pcnstr(ulLevel); GPOS_ASSERT(NULL != pcnstrCurrent); GPOS_ASSERT(NULL != pcnstrOther); pcnstrCurrent->AddRef(); pcnstrOther->AddRef(); pdrgpcnstr->Append(pcnstrCurrent); pdrgpcnstr->Append(pcnstrOther); CConstraint *pcnstrIntersect = CConstraint::PcnstrConjunction(mp, pdrgpcnstr); BOOL fOverlap = !pcnstrIntersect->FContradiction(); pcnstrIntersect->Release(); return fOverlap || (IsDefaultPartition(ulLevel) && ppartcnstr->IsDefaultPartition(ulLevel)); }
//--------------------------------------------------------------------------- // @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: // CPartConstraint::PpartcnstrRemaining // // @doc: // Return what remains of the current part constraint after taking out // the given part constraint. Returns NULL is the difference cannot be // performed // //--------------------------------------------------------------------------- CPartConstraint * CPartConstraint::PpartcnstrRemaining ( IMemoryPool *mp, CPartConstraint *ppartcnstr ) { GPOS_ASSERT(!m_fUninterpreted && "Calling PpartcnstrRemaining on uninterpreted partition constraint"); GPOS_ASSERT(NULL != ppartcnstr); if (m_num_of_part_levels != ppartcnstr->m_num_of_part_levels || !ppartcnstr->FCanNegate()) { return NULL; } UlongToConstraintMap *phmulcnstr = GPOS_NEW(mp) UlongToConstraintMap(mp); CBitSet *pbsDefaultParts = GPOS_NEW(mp) CBitSet(mp); // constraint on first level CConstraint *pcnstrCurrent = Pcnstr(0 /*ulLevel*/); CConstraint *pcnstrOther = ppartcnstr->Pcnstr(0 /*ulLevel*/); CConstraint *pcnstrRemaining = PcnstrRemaining(mp, pcnstrCurrent, pcnstrOther); #ifdef GPOS_DEBUG BOOL result = #endif // GPOS_DEBUG phmulcnstr->Insert(GPOS_NEW(mp) ULONG(0), pcnstrRemaining); GPOS_ASSERT(result); if (IsDefaultPartition(0 /*ulLevel*/) && !ppartcnstr->IsDefaultPartition(0 /*ulLevel*/)) { pbsDefaultParts->ExchangeSet(0 /*ulBit*/); } // copy the remaining constraints and default partition flags for (ULONG ul = 1; ul < m_num_of_part_levels; ul++) { CConstraint *pcnstrLevel = Pcnstr(ul); if (NULL != pcnstrLevel) { pcnstrLevel->AddRef(); #ifdef GPOS_DEBUG BOOL result = #endif // GPOS_DEBUG phmulcnstr->Insert(GPOS_NEW(mp) ULONG(ul), pcnstrLevel); GPOS_ASSERT(result); } if (IsDefaultPartition(ul)) { pbsDefaultParts->ExchangeSet(ul); } } m_pdrgpdrgpcr->AddRef(); return GPOS_NEW(mp) CPartConstraint(mp, phmulcnstr, pbsDefaultParts, false /*is_unbounded*/, m_pdrgpdrgpcr); }
//--------------------------------------------------------------------------- // @function: // CLogical::PpcDeriveConstraintFromTableWithPredicates // // @doc: // Derive constraint property from a table/index get with predicates // //--------------------------------------------------------------------------- CPropConstraint * CLogical::PpcDeriveConstraintFromTableWithPredicates ( IMemoryPool *pmp, CExpressionHandle &exprhdl, const CTableDescriptor *ptabdesc, const DrgPcr *pdrgpcrOutput ) { DrgPcnstr *pdrgpcnstr = GPOS_NEW(pmp) DrgPcnstr(pmp); CPropConstraint *ppcTable = PpcDeriveConstraintFromTable(pmp, ptabdesc, pdrgpcrOutput); CConstraint *pcnstrTable = ppcTable->Pcnstr(); if (NULL != pcnstrTable) { pcnstrTable->AddRef(); pdrgpcnstr->Append(pcnstrTable); } DrgPcrs *pdrgpcrsEquivClassesTable = ppcTable->PdrgpcrsEquivClasses(); CPropConstraint *ppcnstrCond = PpcDeriveConstraintFromPredicates(pmp, exprhdl); CConstraint *pcnstrCond = ppcnstrCond->Pcnstr(); if (NULL != pcnstrCond) { pcnstrCond->AddRef(); pdrgpcnstr->Append(pcnstrCond); } else if (NULL == pcnstrTable) { ppcTable->Release(); pdrgpcnstr->Release(); return ppcnstrCond; } DrgPcrs *pdrgpcrsCond = ppcnstrCond->PdrgpcrsEquivClasses(); DrgPcrs *pdrgpcrs = CUtils::PdrgpcrsMergeEquivClasses(pmp, pdrgpcrsEquivClassesTable, pdrgpcrsCond); CPropConstraint *ppc = GPOS_NEW(pmp) CPropConstraint(pmp, pdrgpcrs, CConstraint::PcnstrConjunction(pmp, pdrgpcnstr)); ppcnstrCond->Release(); ppcTable->Release(); return ppc; }
//--------------------------------------------------------------------------- // @function: // CConstraint::PcnstrConjDisj // // @doc: // Create conjunction/disjunction from array of constraints // //--------------------------------------------------------------------------- CConstraint * CConstraint::PcnstrConjDisj ( IMemoryPool *pmp, DrgPcnstr *pdrgpcnstr, BOOL fConj ) { GPOS_ASSERT(NULL != pdrgpcnstr); CConstraint *pcnstr = NULL; const ULONG ulLen = pdrgpcnstr->UlLength(); switch (ulLen) { case 0: { pdrgpcnstr->Release(); break; } case 1: { pcnstr = (*pdrgpcnstr)[0]; pcnstr->AddRef(); pdrgpcnstr->Release(); break; } default: { if (fConj) { pcnstr = GPOS_NEW(pmp) CConstraintConjunction(pmp, pdrgpcnstr); } else { pcnstr = GPOS_NEW(pmp) CConstraintDisjunction(pmp, pdrgpcnstr); } } } return pcnstr; }
//--------------------------------------------------------------------------- // @function: // CPartConstraint::PcnstrBuildCombined // // @doc: // Construct the combined constraint // //--------------------------------------------------------------------------- CConstraint * CPartConstraint::PcnstrBuildCombined ( IMemoryPool *mp ) { CConstraintArray *pdrgpcnstr = GPOS_NEW(mp) CConstraintArray(mp); for (ULONG ul = 0; ul < m_num_of_part_levels; ul++) { CConstraint *pcnstr = m_phmulcnstr->Find(&ul); if (NULL != pcnstr) { pcnstr->AddRef(); pdrgpcnstr->Append(pcnstr); } } return CConstraint::PcnstrConjunction(mp, pdrgpcnstr); }
//--------------------------------------------------------------------------- // @function: // CConstraint::PdrgpcnstrFlatten // // @doc: // Flatten an array of constraints to be used as children for a conjunction // or disjunction. If any of these children is of the same type then use // its children directly instead of having multiple levels of the same type // //--------------------------------------------------------------------------- DrgPcnstr * CConstraint::PdrgpcnstrFlatten ( IMemoryPool *pmp, DrgPcnstr *pdrgpcnstr, EConstraintType ect ) const { DrgPcnstr *pdrgpcnstrNew = GPOS_NEW(pmp) DrgPcnstr(pmp); const ULONG ulLen = pdrgpcnstr->UlLength(); for (ULONG ul = 0; ul < ulLen; ul++) { CConstraint *pcnstrChild = (*pdrgpcnstr)[ul]; EConstraintType ectChild = pcnstrChild->Ect(); if (EctConjunction == ectChild && EctConjunction == ect) { CConstraintConjunction *pcconj = (CConstraintConjunction *)pcnstrChild; CUtils::AddRefAppend<CConstraint, CleanupRelease>(pdrgpcnstrNew, pcconj->Pdrgpcnstr()); } else if (EctDisjunction == ectChild && EctDisjunction == ect) { CConstraintDisjunction *pcdisj = (CConstraintDisjunction *)pcnstrChild; CUtils::AddRefAppend<CConstraint, CleanupRelease>(pdrgpcnstrNew, pcdisj->Pdrgpcnstr()); } else { pcnstrChild->AddRef(); pdrgpcnstrNew->Append(pcnstrChild); } } pdrgpcnstr->Release(); return PdrgpcnstrDeduplicate(pmp, pdrgpcnstrNew, ect); }
//--------------------------------------------------------------------------- // @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::PcnstrFromScalarBoolOp // // @doc: // Create constraint from scalar boolean expression // //--------------------------------------------------------------------------- CConstraint * CConstraint::PcnstrFromScalarBoolOp ( IMemoryPool *pmp, CExpression *pexpr, DrgPcrs **ppdrgpcrs // output equivalence classes ) { GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(CUtils::FScalarBoolOp(pexpr)); GPOS_ASSERT(NULL != ppdrgpcrs); GPOS_ASSERT(NULL == *ppdrgpcrs); *ppdrgpcrs = GPOS_NEW(pmp) DrgPcrs(pmp); DrgPcnstr *pdrgpcnstr = GPOS_NEW(pmp) DrgPcnstr(pmp); const ULONG ulArity= pexpr->UlArity(); for (ULONG ul = 0; ul < ulArity; ul++) { DrgPcrs *pdrgpcrsChild = NULL; CConstraint *pcnstrChild = PcnstrFromScalarExpr(pmp, (*pexpr)[ul], &pdrgpcrsChild); if (NULL == pcnstrChild || pcnstrChild->FUnbounded()) { CRefCount::SafeRelease(pcnstrChild); CRefCount::SafeRelease(pdrgpcrsChild); if (CPredicateUtils::FOr(pexpr)) { pdrgpcnstr->Release(); return NULL; } continue; } GPOS_ASSERT(NULL != pdrgpcrsChild); pdrgpcnstr->Append(pcnstrChild); DrgPcrs *pdrgpcrsMerged = PdrgpcrsMergeFromBoolOp(pmp, pexpr, *ppdrgpcrs, pdrgpcrsChild); (*ppdrgpcrs)->Release(); *ppdrgpcrs = pdrgpcrsMerged; pdrgpcrsChild->Release(); } const ULONG ulLen = pdrgpcnstr->UlLength(); if (0 == ulLen) { pdrgpcnstr->Release(); return NULL; } if (1 == ulLen) { CConstraint *pcnstrChild = (*pdrgpcnstr)[0]; pcnstrChild->AddRef(); pdrgpcnstr->Release(); if (CPredicateUtils::FNot(pexpr)) { return GPOS_NEW(pmp) CConstraintNegation(pmp, pcnstrChild); } return pcnstrChild; } // we know we have more than one child if (CPredicateUtils::FAnd(pexpr)) { return GPOS_NEW(pmp) CConstraintConjunction(pmp, pdrgpcnstr); } if (CPredicateUtils::FOr(pexpr)) { return GPOS_NEW(pmp) CConstraintDisjunction(pmp, pdrgpcnstr); } return NULL; }
//--------------------------------------------------------------------------- // @function: // CLogical::PpcDeriveConstraintFromPredicates // // @doc: // Derive constraint property when expression has relational children and // scalar children (predicates) // //--------------------------------------------------------------------------- CPropConstraint * CLogical::PpcDeriveConstraintFromPredicates ( IMemoryPool *pmp, CExpressionHandle &exprhdl ) { DrgPcrs *pdrgpcrs = GPOS_NEW(pmp) DrgPcrs(pmp); DrgPcnstr *pdrgpcnstr = GPOS_NEW(pmp) DrgPcnstr(pmp); // collect constraint properties from relational children // and predicates from scalar children const ULONG ulArity = exprhdl.UlArity(); for (ULONG ul = 0; ul < ulArity; ul++) { if (exprhdl.FScalarChild(ul)) { CExpression *pexprScalar = exprhdl.PexprScalarChild(ul); // make sure it is a predicate... boolop, cmp, nulltest if (NULL == pexprScalar || !CUtils::FPredicate(pexprScalar)) { continue; } DrgPcrs *pdrgpcrsChild = NULL; CConstraint *pcnstr = CConstraint::PcnstrFromScalarExpr(pmp, pexprScalar, &pdrgpcrsChild); if (NULL != pcnstr) { pdrgpcnstr->Append(pcnstr); // merge with the equivalence classes we have so far DrgPcrs *pdrgpcrsMerged = CUtils::PdrgpcrsMergeEquivClasses(pmp, pdrgpcrs, pdrgpcrsChild); pdrgpcrs->Release(); pdrgpcrs = pdrgpcrsMerged; } CRefCount::SafeRelease(pdrgpcrsChild); } else { CDrvdPropRelational *pdprel = exprhdl.Pdprel(ul); CPropConstraint *ppc = pdprel->Ppc(); // equivalence classes coming from child DrgPcrs *pdrgpcrsChild = ppc->PdrgpcrsEquivClasses(); // merge with the equivalence classes we have so far DrgPcrs *pdrgpcrsMerged = CUtils::PdrgpcrsMergeEquivClasses(pmp, pdrgpcrs, pdrgpcrsChild); pdrgpcrs->Release(); pdrgpcrs = pdrgpcrsMerged; // constraint coming from child CConstraint *pcnstr = ppc->Pcnstr(); if (NULL != pcnstr) { pcnstr->AddRef(); pdrgpcnstr->Append(pcnstr); } } } CConstraint *pcnstrNew = CConstraint::PcnstrConjunction(pmp, pdrgpcnstr); return GPOS_NEW(pmp) CPropConstraint(pmp, pdrgpcrs, pcnstrNew); }
//--------------------------------------------------------------------------- // @function: // CPartConstraint::PpartcnstrDisjunction // // @doc: // Construct a disjunction of the two part constraints. We can only // construct this disjunction if they differ only on the last level // //--------------------------------------------------------------------------- CPartConstraint * CPartConstraint::PpartcnstrDisjunction ( IMemoryPool *mp, CPartConstraint *ppartcnstrFst, CPartConstraint *ppartcnstrSnd ) { GPOS_ASSERT(NULL != ppartcnstrFst); GPOS_ASSERT(NULL != ppartcnstrSnd); if (ppartcnstrFst->IsConstraintUnbounded()) { ppartcnstrFst->AddRef(); return ppartcnstrFst; } if (ppartcnstrSnd->IsConstraintUnbounded()) { ppartcnstrSnd->AddRef(); return ppartcnstrSnd; } if (!FDisjunctionPossible(ppartcnstrFst, ppartcnstrSnd)) { return NULL; } UlongToConstraintMap *phmulcnstr = GPOS_NEW(mp) UlongToConstraintMap(mp); CBitSet *pbsCombined = GPOS_NEW(mp) CBitSet(mp); const ULONG ulLevels = ppartcnstrFst->m_num_of_part_levels; for (ULONG ul = 0; ul < ulLevels-1; ul++) { CConstraint *pcnstrFst = ppartcnstrFst->Pcnstr(ul); pcnstrFst->AddRef(); #ifdef GPOS_DEBUG BOOL result = #endif // GPOS_DEBUG phmulcnstr->Insert(GPOS_NEW(mp) ULONG(ul), pcnstrFst); GPOS_ASSERT(result); if (ppartcnstrFst->IsDefaultPartition(ul)) { pbsCombined->ExchangeSet(ul); } } // create the disjunction between the constraints of the last level CConstraint *pcnstrFst = ppartcnstrFst->Pcnstr(ulLevels - 1); CConstraint *pcnstrSnd = ppartcnstrSnd->Pcnstr(ulLevels - 1); pcnstrFst->AddRef(); pcnstrSnd->AddRef(); CConstraintArray *pdrgpcnstrCombined = GPOS_NEW(mp) CConstraintArray(mp); pdrgpcnstrCombined->Append(pcnstrFst); pdrgpcnstrCombined->Append(pcnstrSnd); CConstraint *pcnstrDisj = CConstraint::PcnstrDisjunction(mp, pdrgpcnstrCombined); GPOS_ASSERT(NULL != pcnstrDisj); #ifdef GPOS_DEBUG BOOL result = #endif // GPOS_DEBUG phmulcnstr->Insert(GPOS_NEW(mp) ULONG(ulLevels - 1), pcnstrDisj); GPOS_ASSERT(result); if (ppartcnstrFst->IsDefaultPartition(ulLevels - 1) || ppartcnstrSnd->IsDefaultPartition(ulLevels - 1)) { pbsCombined->ExchangeSet(ulLevels - 1); } CColRef2dArray *pdrgpdrgpcr = ppartcnstrFst->Pdrgpdrgpcr(); pdrgpdrgpcr->AddRef(); return GPOS_NEW(mp) CPartConstraint(mp, phmulcnstr, pbsCombined, false /*is_unbounded*/, pdrgpdrgpcr); }