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 @@
*
*
* 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
static void InitPlan(QueryDesc *queryDesc, int eflags);
static void ExecCheckPlanOutput(Relation resultRel, List *targetList);
static void ExecEndPlan(PlanState *planstate, EState *estate);
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
static void ExecutePlan(EState *estate, PlanState *planstate,
CmdType operation,
long numberTuples,
ScanDirection direction,
......@@ -220,26 +220,28 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
* 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().
*
* ----------------------------------------------------------------
*/
TupleTableSlot *
void
ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count)
{
TupleTableSlot *result;
if (ExecutorRun_hook)
result = (*ExecutorRun_hook) (queryDesc, direction, count);
(*ExecutorRun_hook) (queryDesc, direction, count);
else
result = standard_ExecutorRun(queryDesc, direction, count);
return result;
standard_ExecutorRun(queryDesc, direction, count);
}
TupleTableSlot *
void
standard_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count)
{
......@@ -247,7 +249,6 @@ standard_ExecutorRun(QueryDesc *queryDesc,
CmdType operation;
DestReceiver *dest;
bool sendTuples;
TupleTableSlot *result;
MemoryContext oldcontext;
/* sanity checks */
......@@ -283,15 +284,13 @@ standard_ExecutorRun(QueryDesc *queryDesc,
/*
* run plan
*/
if (ScanDirectionIsNoMovement(direction))
result = NULL;
else
result = ExecutePlan(estate,
queryDesc->planstate,
operation,
count,
direction,
dest);
if (!ScanDirectionIsNoMovement(direction))
ExecutePlan(estate,
queryDesc->planstate,
operation,
count,
direction,
dest);
/*
* shutdown tuple receiver, if we started it
......@@ -300,8 +299,6 @@ standard_ExecutorRun(QueryDesc *queryDesc,
(*dest->rShutdown) (dest);
MemoryContextSwitchTo(oldcontext);
return result;
}
/* ----------------------------------------------------------------
......@@ -1271,19 +1268,16 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* ----------------------------------------------------------------
* ExecutePlan
*
* processes the query plan to retrieve 'numberTuples' tuples in the
* direction specified.
*
* Retrieves all tuples if numberTuples is 0
* Processes the query plan until we have processed 'numberTuples' tuples,
* moving in the specified direction.
*
* result is either a slot containing the last tuple in the case
* of a SELECT or NULL otherwise.
* Runs to completion if numberTuples is 0
*
* Note: the ctid attribute is a 'junk' attribute that is removed before the
* user can see it
* ----------------------------------------------------------------
*/
static TupleTableSlot *
static void
ExecutePlan(EState *estate,
PlanState *planstate,
CmdType operation,
......@@ -1297,13 +1291,11 @@ ExecutePlan(EState *estate,
ItemPointer tupleid = NULL;
ItemPointerData tuple_ctid;
long current_tuple_count;
TupleTableSlot *result;
/*
* initialize local variables
*/
current_tuple_count = 0;
result = NULL;
/*
* Set the direction.
......@@ -1332,7 +1324,6 @@ ExecutePlan(EState *estate,
/*
* Loop until we've processed the proper number of tuples from the plan.
*/
for (;;)
{
/* Reset the per-output-tuple exprcontext */
......@@ -1353,13 +1344,10 @@ lnext: ;
/*
* 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))
{
result = NULL;
break;
}
slot = planSlot;
/*
......@@ -1453,7 +1441,6 @@ lnext: ;
default:
elog(ERROR, "unrecognized heap_lock_tuple status: %u",
test);
return NULL;
}
}
}
......@@ -1488,35 +1475,30 @@ lnext: ;
/*
* 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
* from a relation, or modify some of its attributes.
* send it to the output destination, add it to a relation someplace,
* delete it from a relation, or modify some of its attributes.
*/
switch (operation)
{
case CMD_SELECT:
ExecSelect(slot, dest, estate);
result = slot;
break;
case CMD_INSERT:
ExecInsert(slot, tupleid, planSlot, dest, estate);
result = NULL;
break;
case CMD_DELETE:
ExecDelete(tupleid, planSlot, dest, estate);
result = NULL;
break;
case CMD_UPDATE:
ExecUpdate(slot, tupleid, planSlot, dest, estate);
result = NULL;
break;
default:
elog(ERROR, "unrecognized operation code: %d",
(int) operation);
result = NULL;
break;
}
......@@ -1548,12 +1530,6 @@ lnext: ;
/* do nothing */
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 @@
*
*
* 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,
bool lazyEvalOK);
static void init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK);
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
static TupleTableSlot *postquel_getnext(execution_state *es,
SQLFunctionCachePtr fcache);
static bool postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache);
static void postquel_end(execution_state *es);
static void postquel_sub_params(SQLFunctionCachePtr fcache,
FunctionCallInfo fcinfo);
......@@ -441,10 +440,11 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
}
/* 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)
{
TupleTableSlot *result;
bool result;
/* Make our snapshot the active one for any called functions */
PushActiveSnapshot(es->qd->snapshot);
......@@ -460,14 +460,20 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
false, /* not top level */
es->qd->dest,
NULL);
result = NULL;
result = true; /* never stops early */
}
else
{
/* Run regular commands to completion unless lazyEval */
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();
......@@ -678,22 +684,22 @@ fmgr_sql(PG_FUNCTION_ARGS)
*/
while (es)
{
TupleTableSlot *slot;
bool completed;
if (es->status == F_EXEC_START)
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.
* 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
* before we return anything. Also, if the function doesn't return
* set, we can shut it down anyway because we don't care about
* fetching any more result rows.
* set, we can shut it down anyway because it must be a SELECT and
* we don't care about fetching any more result rows.
*/
if (TupIsNull(slot) || !fcache->returnsSet)
if (completed || !fcache->returnsSet)
postquel_end(es);
/*
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 @@
/* Hook for plugins to get control in ExecutorRun() */
typedef TupleTableSlot *(*ExecutorRun_hook_type) (QueryDesc *queryDesc,
ScanDirection direction,
long count);
typedef void (*ExecutorRun_hook_type) (QueryDesc *queryDesc,
ScanDirection direction,
long count);
extern PGDLLIMPORT ExecutorRun_hook_type ExecutorRun_hook;
......@@ -140,10 +140,10 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
* prototypes from functions in execMain.c
*/
extern void ExecutorStart(QueryDesc *queryDesc, int eflags);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count);
extern TupleTableSlot *standard_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count);
extern void ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count);
extern void standard_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc);
extern void ExecutorRewind(QueryDesc *queryDesc);
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