//--------------------------------------------------------------------------- // @function: // CScalarArrayCmp::PexprExpand // // @doc: // Expand array comparison expression into a conjunctive/disjunctive // expression // //--------------------------------------------------------------------------- CExpression * CScalarArrayCmp::PexprExpand ( IMemoryPool *mp, CExpression *pexprArrayCmp ) { GPOS_ASSERT(NULL != pexprArrayCmp); GPOS_ASSERT(EopScalarArrayCmp == pexprArrayCmp->Pop()->Eopid()); CExpression *pexprIdent = (*pexprArrayCmp)[0]; CExpression *pexprArray = CUtils::PexprScalarArrayChild(pexprArrayCmp); CScalarArrayCmp *popArrayCmp = CScalarArrayCmp::PopConvert(pexprArrayCmp->Pop()); ULONG ulArrayElems = 0; if (CUtils::FScalarArray(pexprArray)) { ulArrayElems = CUtils::UlScalarArrayArity(pexprArray); } // if this condition is true, we know the right child of ArrayCmp is a constant. if (0 == ulArrayElems) { // if right child is not an actual array (e.g., Const of type array), return input // expression without expansion pexprArrayCmp->AddRef(); return pexprArrayCmp; } CExpressionArray *pdrgpexpr = GPOS_NEW(mp) CExpressionArray(mp); for (ULONG ul = 0; ul < ulArrayElems; ul++) { CExpression *pexprArrayElem = CUtils::PScalarArrayExprChildAt(mp, pexprArray, ul); pexprIdent->AddRef(); const CWStringConst *str_opname = popArrayCmp->Pstr(); IMDId *mdid_op = popArrayCmp->MdIdOp(); GPOS_ASSERT(IMDId::IsValid(mdid_op)); mdid_op->AddRef(); CExpression *pexprCmp = CUtils::PexprScalarCmp(mp, pexprIdent, pexprArrayElem, *str_opname, mdid_op); pdrgpexpr->Append(pexprCmp); } GPOS_ASSERT(0 < pdrgpexpr->Size()); // deduplicate resulting array CExpressionArray *pdrgpexprDeduped = CUtils::PdrgpexprDedup(mp, pdrgpexpr); pdrgpexpr->Release(); EArrCmpType earrcmpt = popArrayCmp->Earrcmpt(); if (EarrcmpAny == earrcmpt) { return CPredicateUtils::PexprDisjunction(mp, pdrgpexprDeduped); } GPOS_ASSERT(EarrcmpAll == earrcmpt); return CPredicateUtils::PexprConjunction(mp, pdrgpexprDeduped); }
//--------------------------------------------------------------------------- // @function: // CConstraint::PcnstrFromScalarArrayCmp // // @doc: // Create constraint from scalar array comparison expression // //--------------------------------------------------------------------------- CConstraint * CConstraint::PcnstrFromScalarArrayCmp ( IMemoryPool *pmp, CExpression *pexpr, CColRef *pcr ) { GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(CUtils::FScalarArrayCmp(pexpr)); CScalarArrayCmp *popScArrayCmp = CScalarArrayCmp::PopConvert(pexpr->Pop()); CScalarArrayCmp::EArrCmpType earrccmpt = popScArrayCmp->Earrcmpt(); if ((CScalarArrayCmp::EarrcmpAny == earrccmpt || CScalarArrayCmp::EarrcmpAll == earrccmpt) && CPredicateUtils::FCompareIdentToConstArray(pexpr)) { // column #ifdef GPOS_DEBUG CScalarIdent *popScId = CScalarIdent::PopConvert((*pexpr)[0]->Pop()); GPOS_ASSERT (pcr == (CColRef *) popScId->Pcr()); #endif // GPOS_DEBUG // get comparison type IMDType::ECmpType ecmpt = CUtils::Ecmpt(popScArrayCmp->PmdidOp()); CExpression *pexprArray = (*pexpr)[1]; DrgPcnstr *pdrgpcnstr = GPOS_NEW(pmp) DrgPcnstr(pmp); const ULONG ulArity = pexprArray->UlArity(); for (ULONG ul = 0; ul < ulArity; ul++) { GPOS_ASSERT(CUtils::FScalarConst((*pexprArray)[ul]) && "expecting a constant"); CScalarConst *popScConst = CScalarConst::PopConvert((*pexprArray)[ul]->Pop()); CConstraintInterval *pci = CConstraintInterval::PciIntervalFromColConstCmp(pmp, pcr, ecmpt, popScConst); pdrgpcnstr->Append(pci); } if (earrccmpt == CScalarArrayCmp::EarrcmpAny) { // predicate is of the form 'A IN (1,2,3)' // return a disjunction of ranges {[1,1], [2,2], [3,3]} return GPOS_NEW(pmp) CConstraintDisjunction(pmp, pdrgpcnstr); } // predicate is of the form 'A NOT IN (1,2,3)' // return a conjunctive negation on {[1,1], [2,2], [3,3]} return GPOS_NEW(pmp) CConstraintConjunction(pmp, pdrgpcnstr); } return NULL; }
//--------------------------------------------------------------------------- // @function: // CScalarArrayCmp::Matches // // @doc: // Match function on operator level // //--------------------------------------------------------------------------- BOOL CScalarArrayCmp::Matches ( COperator *pop ) const { if (pop->Eopid() == Eopid()) { CScalarArrayCmp *popCmp = CScalarArrayCmp::PopConvert(pop); // match if operator oid are identical return m_earrccmpt == popCmp->Earrcmpt() && m_mdid_op->Equals(popCmp->MdIdOp()); } return false; }
//--------------------------------------------------------------------------- // @function: // CConstraint::PcnstrFromScalarArrayCmp // // @doc: // Create constraint from scalar array comparison expression // //--------------------------------------------------------------------------- CConstraint * CConstraint::PcnstrFromScalarArrayCmp ( IMemoryPool *pmp, CExpression *pexpr, CColRef *pcr ) { GPOS_ASSERT(NULL != pexpr); GPOS_ASSERT(CUtils::FScalarArrayCmp(pexpr)); CScalarArrayCmp *popScArrayCmp = CScalarArrayCmp::PopConvert(pexpr->Pop()); CScalarArrayCmp::EArrCmpType earrccmpt = popScArrayCmp->Earrcmpt(); if ((CScalarArrayCmp::EarrcmpAny == earrccmpt || CScalarArrayCmp::EarrcmpAll == earrccmpt) && CPredicateUtils::FCompareIdentToConstArray(pexpr)) { // column #ifdef GPOS_DEBUG CScalarIdent *popScId = CScalarIdent::PopConvert((*pexpr)[0]->Pop()); GPOS_ASSERT (pcr == (CColRef *) popScId->Pcr()); #endif // GPOS_DEBUG // get comparison type IMDType::ECmpType ecmpt = CUtils::Ecmpt(popScArrayCmp->PmdidOp()); CExpression *pexprArray = CUtils::PexprScalarArrayChild(pexpr); const ULONG ulArity = CUtils::UlScalarArrayArity(pexprArray); // When array size exceeds the threshold, don't expand it into a DNF COptimizerConfig *poconf = COptCtxt::PoctxtFromTLS()->Poconf(); ULONG ulArrayExpansionThreshold = poconf->Phint()->UlArrayExpansionThreshold(); if (ulArity > ulArrayExpansionThreshold) { return NULL; } DrgPcnstr *pdrgpcnstr = GPOS_NEW(pmp) DrgPcnstr(pmp); for (ULONG ul = 0; ul < ulArity; ul++) { CScalarConst *popScConst = CUtils::PScalarArrayConstChildAt(pexprArray,ul); CConstraintInterval *pci = CConstraintInterval::PciIntervalFromColConstCmp(pmp, pcr, ecmpt, popScConst); pdrgpcnstr->Append(pci); } if (earrccmpt == CScalarArrayCmp::EarrcmpAny) { // predicate is of the form 'A IN (1,2,3)' // return a disjunction of ranges {[1,1], [2,2], [3,3]} return GPOS_NEW(pmp) CConstraintDisjunction(pmp, pdrgpcnstr); } // predicate is of the form 'A NOT IN (1,2,3)' // return a conjunctive negation on {[1,1], [2,2], [3,3]} return GPOS_NEW(pmp) CConstraintConjunction(pmp, pdrgpcnstr); } return NULL; }
//--------------------------------------------------------------------------- // @function: // CStatsPredUtils::ProcessArrayCmp // // @doc: // Extract statistics filtering information from scalar array comparison //--------------------------------------------------------------------------- void CStatsPredUtils::ProcessArrayCmp ( IMemoryPool *pmp, CExpression *pexprPred, DrgPstatspred *pdrgpstatspred ) { GPOS_ASSERT(NULL != pdrgpstatspred); GPOS_ASSERT(NULL != pexprPred); GPOS_ASSERT(2 == pexprPred->UlArity()); CScalarArrayCmp *popScArrayCmp = CScalarArrayCmp::PopConvert(pexprPred->Pop()); CExpression *pexprLeft = (*pexprPred)[0]; CExpression *pexprRight = (*pexprPred)[1]; BOOL fCompareToConst = ((COperator::EopScalarIdent == pexprLeft->Pop()->Eopid()) && (COperator::EopScalarArray == pexprRight->Pop()->Eopid())); if (!fCompareToConst) { // unsupported predicate for stats calculations pdrgpstatspred->Append(GPOS_NEW(pmp) CStatsPredUnsupported(ULONG_MAX, CStatsPred::EstatscmptOther)); return; } BOOL fAny = (CScalarArrayCmp::EarrcmpAny == popScArrayCmp->Earrcmpt()); DrgPstatspred *pdrgpstatspredChild = pdrgpstatspred; if (fAny) { pdrgpstatspredChild = GPOS_NEW(pmp) DrgPstatspred(pmp); } const ULONG ulConstants = pexprRight->UlArity(); // comparison semantics for statistics purposes is looser than regular comparison. CStatsPred::EStatsCmpType escmpt = Estatscmptype(popScArrayCmp->PmdidOp()); CScalarIdent *popScalarIdent = CScalarIdent::PopConvert(pexprLeft->Pop()); const CColRef *pcr = popScalarIdent->Pcr(); if (!CHistogram::FSupportsFilter(escmpt)) { // unsupported predicate for stats calculations pdrgpstatspred->Append(GPOS_NEW(pmp) CStatsPredUnsupported(pcr->UlId(), escmpt)); return; } for (ULONG ul = 0; ul < ulConstants; ul++) { CExpression *pexprConst = (*pexprRight)[ul]; if (COperator::EopScalarConst == pexprConst->Pop()->Eopid()) { CScalarConst *popScalarConst = CScalarConst::PopConvert(pexprConst->Pop()); IDatum *pdatumLiteral = popScalarConst->Pdatum(); CStatsPred *pstatspredChild = NULL; if (!pdatumLiteral->FStatsComparable(pdatumLiteral)) { // stats calculations on such datums unsupported pstatspredChild = GPOS_NEW(pmp) CStatsPredUnsupported(pcr->UlId(), escmpt); } else { pstatspredChild = GPOS_NEW(pmp) CStatsPredPoint(pmp, pcr, escmpt, pdatumLiteral); } pdrgpstatspredChild->Append(pstatspredChild); } } if (fAny) { CStatsPredDisj *pstatspredOr = GPOS_NEW(pmp) CStatsPredDisj(pdrgpstatspredChild); pdrgpstatspred->Append(pstatspredOr); } }