//--------------------------------------------------------------------------- // @function: // CLogical::PcrsDeriveOuterIndexGet // // @doc: // Derive outer references for index get and dynamic index get operators // //--------------------------------------------------------------------------- CColRefSet * CLogical::PcrsDeriveOuterIndexGet ( IMemoryPool *pmp, CExpressionHandle &exprhdl ) { ULONG ulArity = exprhdl.UlArity(); CColRefSet *pcrsOuter = GPOS_NEW(pmp) CColRefSet(pmp); CColRefSet *pcrsOutput = PcrsDeriveOutput(pmp, exprhdl); CColRefSet *pcrsUsed = GPOS_NEW(pmp) CColRefSet(pmp); for (ULONG i = 0; i < ulArity; i++) { GPOS_ASSERT(exprhdl.FScalarChild(i)); CDrvdPropScalar *pdpscalar = exprhdl.Pdpscalar(i); pcrsUsed->Union(pdpscalar->PcrsUsed()); } // outer references are columns used by scalar children // but are not included in the output columns of relational children pcrsOuter->Union(pcrsUsed); pcrsOuter->Exclude(pcrsOutput); pcrsOutput->Release(); pcrsUsed->Release(); return pcrsOuter; }
//--------------------------------------------------------------------------- // @function: // CLogical::PcrsDeriveOuter // // @doc: // Derive outer references // //--------------------------------------------------------------------------- CColRefSet * CLogical::PcrsDeriveOuter ( IMemoryPool *pmp, CExpressionHandle &exprhdl, CColRefSet *pcrsUsedAdditional ) { ULONG ulArity = exprhdl.UlArity(); CColRefSet *pcrsOuter = GPOS_NEW(pmp) CColRefSet(pmp); // collect output columns from relational children // and used columns from scalar children CColRefSet *pcrsOutput = GPOS_NEW(pmp) CColRefSet(pmp); CColRefSet *pcrsUsed = GPOS_NEW(pmp) CColRefSet(pmp); for (ULONG i = 0; i < ulArity; i++) { if (exprhdl.FScalarChild(i)) { CDrvdPropScalar *pdpscalar = exprhdl.Pdpscalar(i); pcrsUsed->Union(pdpscalar->PcrsUsed()); } else { CDrvdPropRelational *pdprel = exprhdl.Pdprel(i); pcrsOutput->Union(pdprel->PcrsOutput()); // add outer references from relational children pcrsOuter->Union(pdprel->PcrsOuter()); } } if (NULL != pcrsUsedAdditional) { pcrsUsed->Include(pcrsUsedAdditional); } // outer references are columns used by scalar child // but are not included in the output columns of relational children pcrsOuter->Union(pcrsUsed); pcrsOuter->Exclude(pcrsOutput); pcrsOutput->Release(); pcrsUsed->Release(); return pcrsOuter; }
//--------------------------------------------------------------------------- // @function: // CPhysicalComputeScalar::PrsDerive // // @doc: // Derive rewindability // //--------------------------------------------------------------------------- CRewindabilitySpec * CPhysicalComputeScalar::PrsDerive ( IMemoryPool *pmp, CExpressionHandle &exprhdl ) const { CDrvdPropScalar *pdpscalar = exprhdl.Pdpscalar(1 /*ulChildIndex*/); if (pdpscalar->FHasNonScalarFunction() || IMDFunction::EfsVolatile == pdpscalar->Pfp()->Efs()) { // ComputeScalar is not rewindable if it has non-scalar/volatile functions in project list return GPOS_NEW(pmp) CRewindabilitySpec(CRewindabilitySpec::ErtNone /*ert*/); } return PrsDerivePassThruOuter(exprhdl); }
//--------------------------------------------------------------------------- // @function: // CConstExprEvaluatorDXL::FValidInput // // @doc: // Checks if the given expression is a valid input for constant expression evaluation, // i.e., a scalar expression without variables and without subqueries. // If it returns false, it sets the contents of the error message appropriately. // If szErrorMsg is not null and this function returns false, szErrorMsg will contain // the error message. // //--------------------------------------------------------------------------- BOOL CConstExprEvaluatorDXL::FValidInput ( CExpression *pexpr, const CHAR **szErrorMsg ) { GPOS_ASSERT(NULL != pexpr); // if the expression is not scalar, we should not try to evaluate it if (!pexpr->Pop()->FScalar()) { if (NULL != szErrorMsg) { *szErrorMsg = pexpr->Pop()->SzId(); } return false; } // if the expression has a subquery, we should not try to evaluate it if (CDrvdPropScalar::Pdpscalar(pexpr->PdpDerive())->FHasSubquery()) { if (NULL != szErrorMsg) { *szErrorMsg = "expression containing subqueries"; } return false; } // if the expression uses or defines any variables, we should not try to evaluate it CDrvdPropScalar *pdpScalar = CDrvdPropScalar::Pdpscalar(pexpr->PdpDerive()); if (0 != pdpScalar->PcrsUsed()->CElements() || 0 != pdpScalar->PcrsDefined()->CElements()) { if (NULL != szErrorMsg) { *szErrorMsg = "expression with variables"; } return false; } return true; }
//--------------------------------------------------------------------------- // @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::GetDrvdScalarProps(pexpr->PdpDerive()); CColRefSet *pcrsUsed = pdpscalar->PcrsUsed(); if (NULL != pcrsUsed && 0 < pcrsUsed->Size()) { #ifdef GPOS_DEBUG BOOL fres = #endif // GPOS_DEBUG m_phmcrcrs->Insert(pcrComputedCol, GPOS_NEW(m_mp) CColRefSet(m_mp, *pcrsUsed)); GPOS_ASSERT(fres); } }
//--------------------------------------------------------------------------- // @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: // CPhysicalComputeScalar::PdsRequired // // @doc: // Compute required distribution of the n-th child // //--------------------------------------------------------------------------- CDistributionSpec * CPhysicalComputeScalar::PdsRequired ( IMemoryPool *pmp, CExpressionHandle &exprhdl, CDistributionSpec *pdsRequired, ULONG ulChildIndex, DrgPdp *, // pdrgpdpCtxt ULONG ulOptReq ) const { GPOS_ASSERT(0 == ulChildIndex); GPOS_ASSERT(2 > ulOptReq); // check if master-only/replicated distribution needs to be requested CDistributionSpec *pds = PdsMasterOnlyOrReplicated(pmp, exprhdl, pdsRequired, ulChildIndex, ulOptReq); if (NULL != pds) { return pds; } CDrvdPropScalar *pdpscalar = exprhdl.Pdpscalar(1 /*ulChildIndex*/); // if a Project operator has a call to a set function, passing a Random distribution through this // Project may have the effect of not distributing the results of the set function to all nodes, // but only to the nodes on which first child of the Project is distributed. // to avoid that, we don't push the distribution requirement in this case and thus, for a random // distribution, the result of the set function is spread uniformly over all nodes if (pdpscalar->FHasNonScalarFunction()) { return GPOS_NEW(pmp) CDistributionSpecAny(); } // if required distribution uses any defined column, it has to be enforced on top of ComputeScalar, // in this case, we request Any distribution from the child CDistributionSpec::EDistributionType edtRequired = pdsRequired->Edt(); if (CDistributionSpec::EdtHashed == edtRequired) { CDistributionSpecHashed *pdshashed = CDistributionSpecHashed::PdsConvert(pdsRequired); CColRefSet *pcrs = pdshashed->PcrsUsed(m_pmp); BOOL fUsesDefinedCols = FUnaryUsesDefinedColumns(pcrs, exprhdl); pcrs->Release(); if (fUsesDefinedCols) { return GPOS_NEW(pmp) CDistributionSpecAny(); } } if (CDistributionSpec::EdtRouted == edtRequired) { CDistributionSpecRouted *pdsrouted = CDistributionSpecRouted::PdsConvert(pdsRequired); CColRefSet *pcrs = GPOS_NEW(m_pmp) CColRefSet(m_pmp); pcrs->Include(pdsrouted->Pcr()); BOOL fUsesDefinedCols = FUnaryUsesDefinedColumns(pcrs, exprhdl); pcrs->Release(); if (fUsesDefinedCols) { return GPOS_NEW(pmp) CDistributionSpecAny(); } } if (0 == ulOptReq) { // Req0: required distribution will be enforced on top of ComputeScalar return GPOS_NEW(pmp) CDistributionSpecAny(); } // Req1: required distribution will be enforced on top of ComputeScalar's child return PdsPassThru(pmp, exprhdl, pdsRequired, ulChildIndex); }
//--------------------------------------------------------------------------- // @function: // CLogicalDynamicGetBase::PstatsDeriveFilter // // @doc: // Derive stats from base table using filters on partition and/or index columns // //--------------------------------------------------------------------------- IStatistics * CLogicalDynamicGetBase::PstatsDeriveFilter ( IMemoryPool *pmp, CExpressionHandle &exprhdl, CExpression *pexprFilter ) const { CExpression *pexprFilterNew = NULL; CConstraint *pcnstr = m_ppartcnstr->PcnstrCombined(); if (m_fPartial && NULL != pcnstr && !pcnstr->FUnbounded()) { if (NULL == pexprFilter) { pexprFilterNew = pcnstr->PexprScalar(pmp); pexprFilterNew->AddRef(); } else { pexprFilterNew = CPredicateUtils::PexprConjunction(pmp, pexprFilter, pcnstr->PexprScalar(pmp)); } } else if (NULL != pexprFilter) { pexprFilterNew = pexprFilter; pexprFilterNew->AddRef(); } CColRefSet *pcrsStat = GPOS_NEW(pmp) CColRefSet(pmp); CDrvdPropScalar *pdpscalar = NULL; if (NULL != pexprFilterNew) { pdpscalar = CDrvdPropScalar::Pdpscalar(pexprFilterNew->PdpDerive()); pcrsStat->Include(pdpscalar->PcrsUsed()); } // requesting statistics on distribution columns to estimate data skew if (NULL != m_pcrsDist) { pcrsStat->Include(m_pcrsDist); } IStatistics *pstatsFullTable = PstatsBaseTable(pmp, exprhdl, m_ptabdesc, pcrsStat); pcrsStat->Release(); if (NULL == pexprFilterNew || pdpscalar->FHasSubquery()) { return pstatsFullTable; } CStatsPred *pstatspred = CStatsPredUtils::PstatspredExtract ( pmp, pexprFilterNew, NULL /*pcrsOuterRefs*/ ); pexprFilterNew->Release(); IStatistics *pstatsResult = pstatsFullTable->PstatsFilter ( pmp, pstatspred, true /* fCapNdvs */ ); pstatspred->Release(); pstatsFullTable->Release(); return pstatsResult; }