OSDN Git Service

Simplify ExecutorRun's API and save some trivial number of cycles by having
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 31 Oct 2008 21:07:55 +0000 (21:07 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 31 Oct 2008 21:07:55 +0000 (21:07 +0000)
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.

src/backend/executor/execMain.c
src/backend/executor/functions.c
src/include/executor/executor.h

index 49fa415..47840d4 100644 (file)
@@ -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;
 }
 
 /* ----------------------------------------------------------------
index a587031..b34b904 100644 (file)
@@ -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);
 
                /*
index ac1b81c..2fdaddd 100644 (file)
@@ -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,