//--------------------------------------------------------------------------- // @function: // CJobGroupExploration::FScheduleGroupExpressions // // @doc: // Schedule exploration jobs for all unexplored group expressions; // the function returns true if it could schedule any new jobs // //--------------------------------------------------------------------------- BOOL CJobGroupExploration::FScheduleGroupExpressions ( CSchedulerContext *psc ) { CGroupExpression *pgexprLast = m_pgexprLastScheduled; // iterate on expressions and schedule them as needed CGroupExpression *pgexpr = PgexprFirstUnsched(); while (NULL != pgexpr) { if (!pgexpr->FTransitioned(CGroupExpression::estExplored)) { CJobGroupExpressionExploration::ScheduleJob(psc, pgexpr, this); pgexprLast = pgexpr; } // move to next expression { CGroupProxy gp(m_pgroup); pgexpr = gp.PgexprNext(pgexpr); } } BOOL fNewJobs = (m_pgexprLastScheduled != pgexprLast); // set last scheduled expression m_pgexprLastScheduled = pgexprLast; return fNewJobs; }
//--------------------------------------------------------------------------- // @function: // CGroupProxy::PgexprSkip // // @doc: // Skip group expressions starting from the given expression; // the type of group expressions to skip is determined by the passed // flag // //--------------------------------------------------------------------------- CGroupExpression * CGroupProxy::PgexprSkip ( CGroupExpression *pgexprStart, BOOL fSkipLogical ) { CGroupExpression *pgexpr = pgexprStart; while (NULL != pgexpr && fSkipLogical == pgexpr->Pop()->FLogical()) { pgexpr = PgexprNext(pgexpr); } return pgexpr; }
//--------------------------------------------------------------------------- // @function: // CGroupExpression::UlHash // // @doc: // static hash function for group expressions // //--------------------------------------------------------------------------- ULONG CGroupExpression::UlHash ( const CGroupExpression &gexpr ) { return gexpr.UlHash(); }
//--------------------------------------------------------------------------- // @function: // CJobGroupOptimization::FScheduleGroupExpressions // // @doc: // Schedule optimization jobs for all unoptimized group expressions with // the current optimization priority; // the function returns true if it could schedule any new jobs // //--------------------------------------------------------------------------- BOOL CJobGroupOptimization::FScheduleGroupExpressions ( CSchedulerContext *psc ) { CGroupExpression *pgexprLast = m_pgexprLastScheduled; // iterate on expressions and schedule them as needed CGroupExpression *pgexpr = PgexprFirstUnsched(); while (NULL != pgexpr) { // we consider only group expressions matching current optimization level, // other group expressions will be optimized when damping current // optimization level if (psc->Peng()->FOptimizeChild(m_pgexprOrigin, pgexpr, m_poc, EolCurrent())) { const ULONG ulOptRequests = CPhysical::PopConvert(pgexpr->Pop())->UlOptRequests(); for (ULONG ul = 0; ul < ulOptRequests; ul++) { // schedule an optimization job for each request CJobGroupExpressionOptimization::ScheduleJob(psc, pgexpr, m_poc, ul, this); } } pgexprLast = pgexpr; // move to next expression { CGroupProxy gp(m_pgroup); pgexpr = gp.PgexprSkipLogical(pgexpr); } } BOOL fNewJobs = (m_pgexprLastScheduled != pgexprLast); // set last scheduled expression m_pgexprLastScheduled = pgexprLast; return fNewJobs; }
//--------------------------------------------------------------------------- // @function: // CCostContext::CCostContext // // @doc: // Ctor // //--------------------------------------------------------------------------- CCostContext::CCostContext ( IMemoryPool *pmp, COptimizationContext *poc, ULONG ulOptReq, CGroupExpression *pgexpr ) : m_pmp(pmp), m_cost(GPOPT_INVALID_COST), m_estate(estUncosted), m_pgexpr(pgexpr), m_pgexprForStats(NULL), m_pdrgpoc(NULL), m_pdpplan(NULL), m_ulOptReq(ulOptReq), m_fPruned(false), m_pstats(NULL), m_poc(poc) { GPOS_ASSERT(NULL != poc); GPOS_ASSERT(NULL != pgexpr); GPOS_ASSERT_IMP ( pgexpr->Pop()->FPhysical(), ulOptReq < CPhysical::PopConvert(pgexpr->Pop())->UlOptRequests() ); if (!m_pgexpr->Pop()->FScalar() && !CPhysical::PopConvert(m_pgexpr->Pop())->FPassThruStats()) { CGroupExpression *pgexprForStats = m_pgexpr->Pgroup()->PgexprBestPromise(m_pmp, m_pgexpr); if (NULL != pgexprForStats) { pgexprForStats->AddRef(); m_pgexprForStats = pgexprForStats; } } }
//--------------------------------------------------------------------------- // @function: // CJobTransformation::EevtTransform // // @doc: // Apply transformation action // //--------------------------------------------------------------------------- CJobTransformation::EEvent CJobTransformation::EevtTransform ( CSchedulerContext *psc, CJob *pjOwner ) { // get a job pointer CJobTransformation *pjt = PjConvert(pjOwner); IMemoryPool *pmpGlobal = psc->PmpGlobal(); IMemoryPool *pmpLocal = psc->PmpLocal(); CGroupExpression *pgexpr = pjt->m_pgexpr; CXform *pxform = pjt->m_pxform; // insert transformation results to memo CXformResult *pxfres = GPOS_NEW(pmpGlobal) CXformResult(pmpGlobal); ULONG ulElapsedTime = 0; pgexpr->Transform(pmpGlobal, pmpLocal, pxform, pxfres, &ulElapsedTime); psc->Peng()->InsertXformResult(pgexpr->Pgroup(), pxfres, pxform->Exfid(), pgexpr, ulElapsedTime); pxfres->Release(); return eevCompleted; }
//--------------------------------------------------------------------------- // @function: // CExpressionHandle::DeriveProducerStats // // @doc: // If the child (ulChildIndex) is a CTE consumer, then derive is corresponding // producer statistics. // //--------------------------------------------------------------------------- void CExpressionHandle::DeriveProducerStats ( ULONG ulChildIndex, CColRefSet *pcrsStats ) { // check to see if there are any CTE consumers in the group whose properties have // to be pushed to its corresponding CTE producer CGroupExpression *pgexpr = Pgexpr(); if (NULL != pgexpr) { CGroup *pgroupChild = (*pgexpr)[ulChildIndex]; if (pgroupChild->FHasAnyCTEConsumer()) { CGroupExpression *pgexprCTEConsumer = pgroupChild->PgexprAnyCTEConsumer(); CLogicalCTEConsumer *popConsumer = CLogicalCTEConsumer::PopConvert(pgexprCTEConsumer->Pop()); COptCtxt::PoctxtFromTLS()->Pcteinfo()->DeriveProducerStats(popConsumer, pcrsStats); } return; } // statistics are also derived on expressions representing the producer that may have // multiple CTE consumers. We should ensure that their properties are to pushed to their // corresponding CTE producer CExpression *pexpr = Pexpr(); if (NULL != pexpr) { CExpression *pexprChild = (*pexpr)[ulChildIndex]; if (COperator::EopLogicalCTEConsumer == pexprChild->Pop()->Eopid()) { CLogicalCTEConsumer *popConsumer = CLogicalCTEConsumer::PopConvert(pexprChild->Pop()); COptCtxt::PoctxtFromTLS()->Pcteinfo()->DeriveProducerStats(popConsumer, pcrsStats); } } }
//--------------------------------------------------------------------------- // @function: // CExpressionHandle::PexprScalarChild // // @doc: // Get the scalar child at given index // //--------------------------------------------------------------------------- CExpression * CExpressionHandle::PexprScalarChild ( ULONG ulChildIndex ) const { GPOS_ASSERT(ulChildIndex < UlArity()); if (NULL != m_pgexpr) { // access scalar expression cached on the child scalar group GPOS_ASSERT((*m_pgexpr)[ulChildIndex]->FScalar()); CExpression *pexprScalar = (*m_pgexpr)[ulChildIndex]->PexprScalar(); GPOS_ASSERT_IMP(NULL == pexprScalar, CDrvdPropScalar::Pdpscalar((*m_pgexpr)[ulChildIndex]->Pdp())->FHasSubquery()); return pexprScalar; } if (NULL != m_pexpr && NULL != (*m_pexpr)[ulChildIndex]->Pgexpr()) { // if the expression does not come from a group, but its child does then // get the scalar child from that group CGroupExpression *pgexpr = (*m_pexpr)[ulChildIndex]->Pgexpr(); CExpression *pexprScalar = pgexpr->Pgroup()->PexprScalar(); GPOS_ASSERT_IMP(NULL == pexprScalar, CDrvdPropScalar::Pdpscalar((*m_pexpr)[ulChildIndex]->PdpDerive())->FHasSubquery()); return pexprScalar; } // access scalar expression from the child expression node GPOS_ASSERT((*m_pexpr)[ulChildIndex]->Pop()->FScalar()); return (*m_pexpr)[ulChildIndex]; }
//--------------------------------------------------------------------------- // @function: // COptimizationContext::PrppCTEProducer // // @doc: // Compute required properties to CTE producer based on plan properties // of CTE consumer // //--------------------------------------------------------------------------- CReqdPropPlan * COptimizationContext::PrppCTEProducer ( IMemoryPool *mp, COptimizationContext *poc, ULONG ulSearchStages ) { GPOS_ASSERT(NULL != poc); GPOS_ASSERT(NULL != poc->PccBest()); CCostContext *pccBest = poc->PccBest(); CGroupExpression *pgexpr = pccBest->Pgexpr(); BOOL fOptimizeCTESequence = ( COperator::EopPhysicalSequence == pgexpr->Pop()->Eopid() && (*pgexpr)[0]->FHasCTEProducer() ); if (!fOptimizeCTESequence) { // best group expression is not a CTE sequence return NULL; } COptimizationContext *pocProducer = (*pgexpr)[0]->PocLookupBest(mp, ulSearchStages, (*pccBest->Pdrgpoc())[0]->Prpp()); if (NULL == pocProducer) { return NULL; } CCostContext *pccProducer = pocProducer->PccBest(); if (NULL == pccProducer) { return NULL; } COptimizationContext *pocConsumer = (*pgexpr)[1]->PocLookupBest(mp, ulSearchStages, (*pccBest->Pdrgpoc())[1]->Prpp()); if (NULL == pocConsumer) { return NULL; } CCostContext *pccConsumer = pocConsumer->PccBest(); if (NULL == pccConsumer) { return NULL; } CColRefSet *pcrsInnerOutput = CDrvdPropRelational::GetRelationalProperties((*pgexpr)[1]->Pdp())->PcrsOutput(); CPhysicalCTEProducer *popProducer = CPhysicalCTEProducer::PopConvert(pccProducer->Pgexpr()->Pop()); UlongToColRefMap *colref_mapping = COptCtxt::PoctxtFromTLS()->Pcteinfo()->PhmulcrConsumerToProducer(mp, popProducer->UlCTEId(), pcrsInnerOutput, popProducer->Pdrgpcr()); CReqdPropPlan *prppProducer = CReqdPropPlan::PrppRemap(mp, pocProducer->Prpp(), pccConsumer->Pdpplan(), colref_mapping); colref_mapping->Release(); if (prppProducer->Equals(pocProducer->Prpp())) { prppProducer->Release(); return NULL; } return prppProducer; }