*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
* 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)
{
CmdType operation;
DestReceiver *dest;
bool sendTuples;
- TupleTableSlot *result;
MemoryContext oldcontext;
/* sanity checks */
/*
* 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
(*dest->rShutdown) (dest);
MemoryContextSwitchTo(oldcontext);
-
- return result;
}
/* ----------------------------------------------------------------
/* ----------------------------------------------------------------
* 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,
ItemPointer tupleid = NULL;
ItemPointerData tuple_ctid;
long current_tuple_count;
- TupleTableSlot *result;
/*
* initialize local variables
*/
current_tuple_count = 0;
- result = NULL;
/*
* Set the direction.
/*
* Loop until we've processed the proper number of tuples from the plan.
*/
-
for (;;)
{
/* Reset the per-output-tuple exprcontext */
/*
* 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;
/*
default:
elog(ERROR, "unrecognized heap_lock_tuple status: %u",
test);
- return NULL;
}
}
}
/*
* 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;
}
/* do nothing */
break;
}
-
- /*
- * here, result is either a slot containing a tuple in the case of a
- * SELECT or NULL otherwise.
- */
- return result;
}
/* ----------------------------------------------------------------
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
}
/* 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);
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();
*/
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);
/*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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;
* 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,