您的位置:首页 > 数据库

PostgreSQL在何处处理 sql查询之三十六

2013-05-30 15:23 477 查看
接前面:

/* ----------------------------------------------------------------
*        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)) 跳出去。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: