zoukankan      html  css  js  c++  java
  • PostgreSQL在何处处理 sql查询之三十六

    接前面:

    /* ----------------------------------------------------------------
     *        ExecutorRun
     *
     *        This is the main routine of the executor module. It accepts
     *        the query descriptor from the traffic cop and executes the
     *        query plan.
     *
     *        ExecutorStart must have been called already.
     *
     *        If direction is NoMovementScanDirection then nothing is done
     *        except to start up/shut down the destination.  Otherwise,
     *        we retrieve up to 'count' tuples in the specified direction.
     *
     *        Note: count = 0 is interpreted as no portal limit, i.e., run to
     *        completion.
     *
     *        There is no return value, but output tuples (if any) are sent to
     *        the destination receiver specified in the QueryDesc; and the number
     *        of tuples processed at the top level can be found in
     *        estate->es_processed.
     *
     *        We provide a function hook variable that lets loadable plugins
     *        get control when ExecutorRun is called.  Such a plugin would
     *        normally call standard_ExecutorRun().
     *
     * ----------------------------------------------------------------
     */
    void
    ExecutorRun(QueryDesc *queryDesc,
                ScanDirection direction, long count)
    {
        if (ExecutorRun_hook)
            (*ExecutorRun_hook) (queryDesc, direction, count);
        else
            standard_ExecutorRun(queryDesc, direction, count);
    }
    
    void
    standard_ExecutorRun(QueryDesc *queryDesc,
                         ScanDirection direction, long count)
    {
        EState       *estate;
        CmdType        operation;
        DestReceiver *dest;
        bool        sendTuples;
        MemoryContext oldcontext;
    
        /* sanity checks */
        Assert(queryDesc != NULL);
    
        estate = queryDesc->estate;
    
        Assert(estate != NULL);
        Assert(!(estate->es_top_eflags & EXEC_FLAG_EXPLAIN_ONLY));
    
        /*
         * Switch into per-query memory context
         */
        oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
    
        /* Allow instrumentation of Executor overall runtime */
        if (queryDesc->totaltime)
            InstrStartNode(queryDesc->totaltime);
    
        /*
         * extract information from the query descriptor and the query feature.
         */
        operation = queryDesc->operation;
        dest = queryDesc->dest;
    
        /*
         * startup tuple receiver, if we will be emitting tuples
         */
        estate->es_processed = 0;
        estate->es_lastoid = InvalidOid;
    
        sendTuples = (operation == CMD_SELECT ||
                      queryDesc->plannedstmt->hasReturning);
    
        if (sendTuples)
            (*dest->rStartup) (dest, operation, queryDesc->tupDesc);
    
        /*
         * run plan
         */
        if (!ScanDirectionIsNoMovement(direction))
            ExecutePlan(estate,
                        queryDesc->planstate,
                        operation,
                        sendTuples,
                        count,
                        direction,
                        dest);
    
        /*
         * shutdown tuple receiver, if we started it
         */
        if (sendTuples)
            (*dest->rShutdown) (dest);
    
        if (queryDesc->totaltime)
            InstrStopNode(queryDesc->totaltime, estate->es_processed);
    
        MemoryContextSwitchTo(oldcontext);
    }

    其中,最为核心的,也就是这一段了:

            ExecutePlan(estate,
                        queryDesc->planstate,
                        operation,
                        sendTuples,
                        count,
                        direction,
                        dest);

    展开 ExecutePlan的源代码:

    static void
    ExecutePlan(EState *estate,
                PlanState *planstate,
                CmdType operation,
                bool sendTuples,
                long numberTuples,
                ScanDirection direction,
                DestReceiver *dest)
    {
    
    
        TupleTableSlot *slot;
        long        current_tuple_count;
    
        /*
         * initialize local variables
         */
        current_tuple_count = 0;
    
        /*
         * Set the direction.
         */
        estate->es_direction = direction;
    
        /*
         * Loop until we've processed the proper number of tuples from the plan.
         */
        for (;;)
        {
    
    
            fprintf(stderr,"In ExecutePlan ...for loop...\n");
    
            /* Reset the per-output-tuple exprcontext */
            ResetPerTupleExprContext(estate);
    
            /*
             * Execute the plan and obtain a tuple
             */
            slot = ExecProcNode(planstate);
    
            /*
             * if the tuple is null, then we assume there is nothing more to
             * process so we just end the loop...
             */
            if (TupIsNull(slot))
                break;
    
            /*
             * If we have a junk filter, then project a new tuple with the junk
             * removed.
             *
             * Store this new "clean" tuple in the junkfilter's resultSlot.
             * (Formerly, we stored it back over the "dirty" tuple, which is WRONG
             * because that tuple slot has the wrong descriptor.)
             */
            if (estate->es_junkFilter != NULL)
                slot = ExecFilterJunk(estate->es_junkFilter, slot);
    
            /*
             * If we are supposed to send the tuple somewhere, do so. (In
             * practice, this is probably always the case at this point.)
             */
            if (sendTuples)
                (*dest->receiveSlot) (slot, dest);
    
            /*
             * Count tuples processed, if this is a SELECT.  (For other operation
             * types, the ModifyTable plan node must count the appropriate
             * events.)
             */
            if (operation == CMD_SELECT)
                (estate->es_processed)++;
    
            /*
             * check our tuple count.. if we've processed the proper number then
             * quit, else loop again and process more tuples.  Zero numberTuples
             * means no limit.
             */
            current_tuple_count++;
            if (numberTuples && numberTuples == current_tuple_count)
                break;
        }
    }

    把它缩略一下,得到的是:

    static void
    ExecutePlan(EState *estate,
                PlanState *planstate,
                CmdType operation,
                bool sendTuples,
                long numberTuples,
                ScanDirection direction,
                DestReceiver *dest)
    {
        ...
        /*
         * Loop until we've processed the proper number of tuples from the plan.
         */
        for (;;)
        {
            ...
    
            /*
             * check our tuple count.. if we've processed the proper number then
             * quit, else loop again and process more tuples.  Zero numberTuples
             * means no limit.
             */
            current_tuple_count++;
            if (numberTuples && numberTuples == current_tuple_count)
                break;
        }
    }

    可以发现:对于有很多条记录第表tst01而言,select * from tst01 where id<10 ,执行循环10次。

    下面,仔细探究其for 循环的内容,从其循环退出条件的角度来看看:

    static void
    ExecutePlan(EState *estate,
                PlanState *planstate,
                CmdType operation,
                bool sendTuples,
                long numberTuples,
                ScanDirection direction,
                DestReceiver *dest)
    {
    
    
        TupleTableSlot *slot;
        long        current_tuple_count;
    
        /*
         * initialize local variables
         */
        current_tuple_count = 0;
    
        ...
        for (;;)
        {
    ...
            /*
             * if the tuple is null, then we assume there is nothing more to
             * process so we just end the loop...
             */
            if (TupIsNull(slot))
                break;

    ...
    /* * check our tuple count.. if we've processed the proper number then * quit, else loop again and process more tuples. Zero numberTuples * means no limit. */ current_tuple_count++; if (numberTuples && numberTuples == current_tuple_count) break; } }

    可以说,应当查询多少条记录,如果表中有10条记录符合条件,那么执行10循环后,从  if (TupIsNull(slot)) 跳出去。

  • 相关阅读:
    自闭的D7
    D2
    Codeforces Round #531 (Div. 3)
    hello 2019 D
    牛客练习赛36B
    cf954H
    gym102007 E
    Gym 101972
    Gym 101810
    试题 历届试题 青蛙跳杯子(bfs)
  • 原文地址:https://www.cnblogs.com/gaojian/p/3108292.html
Copyright © 2011-2022 走看看