Commit df5a9961 authored by Tom Lane's avatar Tom Lane

Simplify ExecutorRun's API and save some trivial number of cycles by having

it just return void instead of sometimes returning a TupleTableSlot.  SQL
functions don't need that anymore, and noplace else does either.  Eliminating
the return value also means one less hassle for the ExecutorRun hook functions
that will be supported beginning in 8.4.
parent e9816533
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.313 2008/08/25 22:42:32 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.314 2008/10/31 21:07:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -76,7 +76,7 @@ typedef struct evalPlanQual ...@@ -76,7 +76,7 @@ typedef struct evalPlanQual
static void InitPlan(QueryDesc *queryDesc, int eflags); static void InitPlan(QueryDesc *queryDesc, int eflags);
static void ExecCheckPlanOutput(Relation resultRel, List *targetList); static void ExecCheckPlanOutput(Relation resultRel, List *targetList);
static void ExecEndPlan(PlanState *planstate, EState *estate); static void ExecEndPlan(PlanState *planstate, EState *estate);
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate, static void ExecutePlan(EState *estate, PlanState *planstate,
CmdType operation, CmdType operation,
long numberTuples, long numberTuples,
ScanDirection direction, ScanDirection direction,
...@@ -220,26 +220,28 @@ ExecutorStart(QueryDesc *queryDesc, int eflags) ...@@ -220,26 +220,28 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
* Note: count = 0 is interpreted as no portal limit, i.e., run to * Note: count = 0 is interpreted as no portal limit, i.e., run to
* completion. * 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 * We provide a function hook variable that lets loadable plugins
* get control when ExecutorRun is called. Such a plugin would * get control when ExecutorRun is called. Such a plugin would
* normally call standard_ExecutorRun(). * normally call standard_ExecutorRun().
* *
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
TupleTableSlot * void
ExecutorRun(QueryDesc *queryDesc, ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count) ScanDirection direction, long count)
{ {
TupleTableSlot *result;
if (ExecutorRun_hook) if (ExecutorRun_hook)
result = (*ExecutorRun_hook) (queryDesc, direction, count); (*ExecutorRun_hook) (queryDesc, direction, count);
else else
result = standard_ExecutorRun(queryDesc, direction, count); standard_ExecutorRun(queryDesc, direction, count);
return result;
} }
TupleTableSlot * void
standard_ExecutorRun(QueryDesc *queryDesc, standard_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count) ScanDirection direction, long count)
{ {
...@@ -247,7 +249,6 @@ standard_ExecutorRun(QueryDesc *queryDesc, ...@@ -247,7 +249,6 @@ standard_ExecutorRun(QueryDesc *queryDesc,
CmdType operation; CmdType operation;
DestReceiver *dest; DestReceiver *dest;
bool sendTuples; bool sendTuples;
TupleTableSlot *result;
MemoryContext oldcontext; MemoryContext oldcontext;
/* sanity checks */ /* sanity checks */
...@@ -283,15 +284,13 @@ standard_ExecutorRun(QueryDesc *queryDesc, ...@@ -283,15 +284,13 @@ standard_ExecutorRun(QueryDesc *queryDesc,
/* /*
* run plan * run plan
*/ */
if (ScanDirectionIsNoMovement(direction)) if (!ScanDirectionIsNoMovement(direction))
result = NULL; ExecutePlan(estate,
else queryDesc->planstate,
result = ExecutePlan(estate, operation,
queryDesc->planstate, count,
operation, direction,
count, dest);
direction,
dest);
/* /*
* shutdown tuple receiver, if we started it * shutdown tuple receiver, if we started it
...@@ -300,8 +299,6 @@ standard_ExecutorRun(QueryDesc *queryDesc, ...@@ -300,8 +299,6 @@ standard_ExecutorRun(QueryDesc *queryDesc,
(*dest->rShutdown) (dest); (*dest->rShutdown) (dest);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
return result;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -1271,19 +1268,16 @@ ExecEndPlan(PlanState *planstate, EState *estate) ...@@ -1271,19 +1268,16 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecutePlan * ExecutePlan
* *
* processes the query plan to retrieve 'numberTuples' tuples in the * Processes the query plan until we have processed 'numberTuples' tuples,
* direction specified. * moving in the specified direction.
*
* Retrieves all tuples if numberTuples is 0
* *
* result is either a slot containing the last tuple in the case * Runs to completion if numberTuples is 0
* of a SELECT or NULL otherwise.
* *
* Note: the ctid attribute is a 'junk' attribute that is removed before the * Note: the ctid attribute is a 'junk' attribute that is removed before the
* user can see it * user can see it
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static TupleTableSlot * static void
ExecutePlan(EState *estate, ExecutePlan(EState *estate,
PlanState *planstate, PlanState *planstate,
CmdType operation, CmdType operation,
...@@ -1297,13 +1291,11 @@ ExecutePlan(EState *estate, ...@@ -1297,13 +1291,11 @@ ExecutePlan(EState *estate,
ItemPointer tupleid = NULL; ItemPointer tupleid = NULL;
ItemPointerData tuple_ctid; ItemPointerData tuple_ctid;
long current_tuple_count; long current_tuple_count;
TupleTableSlot *result;
/* /*
* initialize local variables * initialize local variables
*/ */
current_tuple_count = 0; current_tuple_count = 0;
result = NULL;
/* /*
* Set the direction. * Set the direction.
...@@ -1332,7 +1324,6 @@ ExecutePlan(EState *estate, ...@@ -1332,7 +1324,6 @@ ExecutePlan(EState *estate,
/* /*
* Loop until we've processed the proper number of tuples from the plan. * Loop until we've processed the proper number of tuples from the plan.
*/ */
for (;;) for (;;)
{ {
/* Reset the per-output-tuple exprcontext */ /* Reset the per-output-tuple exprcontext */
...@@ -1353,13 +1344,10 @@ lnext: ; ...@@ -1353,13 +1344,10 @@ lnext: ;
/* /*
* if the tuple is null, then we assume there is nothing more to * if the tuple is null, then we assume there is nothing more to
* process so we just return null... * process so we just end the loop...
*/ */
if (TupIsNull(planSlot)) if (TupIsNull(planSlot))
{
result = NULL;
break; break;
}
slot = planSlot; slot = planSlot;
/* /*
...@@ -1453,7 +1441,6 @@ lnext: ; ...@@ -1453,7 +1441,6 @@ lnext: ;
default: default:
elog(ERROR, "unrecognized heap_lock_tuple status: %u", elog(ERROR, "unrecognized heap_lock_tuple status: %u",
test); test);
return NULL;
} }
} }
} }
...@@ -1488,35 +1475,30 @@ lnext: ; ...@@ -1488,35 +1475,30 @@ lnext: ;
/* /*
* now that we have a tuple, do the appropriate thing with it.. either * now that we have a tuple, do the appropriate thing with it.. either
* return it to the user, add it to a relation someplace, delete it * send it to the output destination, add it to a relation someplace,
* from a relation, or modify some of its attributes. * delete it from a relation, or modify some of its attributes.
*/ */
switch (operation) switch (operation)
{ {
case CMD_SELECT: case CMD_SELECT:
ExecSelect(slot, dest, estate); ExecSelect(slot, dest, estate);
result = slot;
break; break;
case CMD_INSERT: case CMD_INSERT:
ExecInsert(slot, tupleid, planSlot, dest, estate); ExecInsert(slot, tupleid, planSlot, dest, estate);
result = NULL;
break; break;
case CMD_DELETE: case CMD_DELETE:
ExecDelete(tupleid, planSlot, dest, estate); ExecDelete(tupleid, planSlot, dest, estate);
result = NULL;
break; break;
case CMD_UPDATE: case CMD_UPDATE:
ExecUpdate(slot, tupleid, planSlot, dest, estate); ExecUpdate(slot, tupleid, planSlot, dest, estate);
result = NULL;
break; break;
default: default:
elog(ERROR, "unrecognized operation code: %d", elog(ERROR, "unrecognized operation code: %d",
(int) operation); (int) operation);
result = NULL;
break; break;
} }
...@@ -1548,12 +1530,6 @@ lnext: ; ...@@ -1548,12 +1530,6 @@ lnext: ;
/* do nothing */ /* do nothing */
break; break;
} }
/*
* here, result is either a slot containing a tuple in the case of a
* SELECT or NULL otherwise.
*/
return result;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.127 2008/10/31 19:37:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.128 2008/10/31 21:07:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -105,8 +105,7 @@ static execution_state *init_execution_state(List *queryTree_list, ...@@ -105,8 +105,7 @@ static execution_state *init_execution_state(List *queryTree_list,
bool lazyEvalOK); bool lazyEvalOK);
static void init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK); static void init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK);
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache); static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
static TupleTableSlot *postquel_getnext(execution_state *es, static bool postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache);
SQLFunctionCachePtr fcache);
static void postquel_end(execution_state *es); static void postquel_end(execution_state *es);
static void postquel_sub_params(SQLFunctionCachePtr fcache, static void postquel_sub_params(SQLFunctionCachePtr fcache,
FunctionCallInfo fcinfo); FunctionCallInfo fcinfo);
...@@ -441,10 +440,11 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache) ...@@ -441,10 +440,11 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
} }
/* Run one execution_state; either to completion or to first result row */ /* Run one execution_state; either to completion or to first result row */
static TupleTableSlot * /* Returns true if we ran to completion */
static bool
postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache) postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
{ {
TupleTableSlot *result; bool result;
/* Make our snapshot the active one for any called functions */ /* Make our snapshot the active one for any called functions */
PushActiveSnapshot(es->qd->snapshot); PushActiveSnapshot(es->qd->snapshot);
...@@ -460,14 +460,20 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache) ...@@ -460,14 +460,20 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
false, /* not top level */ false, /* not top level */
es->qd->dest, es->qd->dest,
NULL); NULL);
result = NULL; result = true; /* never stops early */
} }
else else
{ {
/* Run regular commands to completion unless lazyEval */ /* Run regular commands to completion unless lazyEval */
long count = (es->lazyEval) ? 1L : 0L; long count = (es->lazyEval) ? 1L : 0L;
result = ExecutorRun(es->qd, ForwardScanDirection, count); ExecutorRun(es->qd, ForwardScanDirection, count);
/*
* If we requested run to completion OR there was no tuple returned,
* command must be complete.
*/
result = (count == 0L || es->qd->estate->es_processed == 0);
} }
PopActiveSnapshot(); PopActiveSnapshot();
...@@ -678,22 +684,22 @@ fmgr_sql(PG_FUNCTION_ARGS) ...@@ -678,22 +684,22 @@ fmgr_sql(PG_FUNCTION_ARGS)
*/ */
while (es) while (es)
{ {
TupleTableSlot *slot; bool completed;
if (es->status == F_EXEC_START) if (es->status == F_EXEC_START)
postquel_start(es, fcache); postquel_start(es, fcache);
slot = postquel_getnext(es, fcache); completed = postquel_getnext(es, fcache);
/* /*
* If we ran the command to completion, we can shut it down now. * If we ran the command to completion, we can shut it down now.
* Any row(s) we need to return are safely stashed in the tuplestore, * Any row(s) we need to return are safely stashed in the tuplestore,
* and we want to be sure that, for example, AFTER triggers get fired * and we want to be sure that, for example, AFTER triggers get fired
* before we return anything. Also, if the function doesn't return * before we return anything. Also, if the function doesn't return
* set, we can shut it down anyway because we don't care about * set, we can shut it down anyway because it must be a SELECT and
* fetching any more result rows. * we don't care about fetching any more result rows.
*/ */
if (TupIsNull(slot) || !fcache->returnsSet) if (completed || !fcache->returnsSet)
postquel_end(es); postquel_end(es);
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.151 2008/10/29 00:00:39 tgl Exp $ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.152 2008/10/31 21:07:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,9 +61,9 @@ ...@@ -61,9 +61,9 @@
/* Hook for plugins to get control in ExecutorRun() */ /* Hook for plugins to get control in ExecutorRun() */
typedef TupleTableSlot *(*ExecutorRun_hook_type) (QueryDesc *queryDesc, typedef void (*ExecutorRun_hook_type) (QueryDesc *queryDesc,
ScanDirection direction, ScanDirection direction,
long count); long count);
extern PGDLLIMPORT ExecutorRun_hook_type ExecutorRun_hook; extern PGDLLIMPORT ExecutorRun_hook_type ExecutorRun_hook;
...@@ -140,10 +140,10 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot); ...@@ -140,10 +140,10 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
* prototypes from functions in execMain.c * prototypes from functions in execMain.c
*/ */
extern void ExecutorStart(QueryDesc *queryDesc, int eflags); extern void ExecutorStart(QueryDesc *queryDesc, int eflags);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, extern void ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count); ScanDirection direction, long count);
extern TupleTableSlot *standard_ExecutorRun(QueryDesc *queryDesc, extern void standard_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count); ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc); extern void ExecutorEnd(QueryDesc *queryDesc);
extern void ExecutorRewind(QueryDesc *queryDesc); extern void ExecutorRewind(QueryDesc *queryDesc);
extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment