Header And Logo

PostgreSQL
| The world's most advanced open source database.

nodeResult.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * nodeResult.c
00004  *    support for constant nodes needing special code.
00005  *
00006  * DESCRIPTION
00007  *
00008  *      Result nodes are used in queries where no relations are scanned.
00009  *      Examples of such queries are:
00010  *
00011  *              select 1 * 2
00012  *
00013  *              insert into emp values ('mike', 15000)
00014  *
00015  *      (Remember that in an INSERT or UPDATE, we need a plan tree that
00016  *      generates the new rows.)
00017  *
00018  *      Result nodes are also used to optimise queries with constant
00019  *      qualifications (ie, quals that do not depend on the scanned data),
00020  *      such as:
00021  *
00022  *              select * from emp where 2 > 1
00023  *
00024  *      In this case, the plan generated is
00025  *
00026  *                      Result  (with 2 > 1 qual)
00027  *                      /
00028  *                 SeqScan (emp.*)
00029  *
00030  *      At runtime, the Result node evaluates the constant qual once,
00031  *      which is shown by EXPLAIN as a One-Time Filter.  If it's
00032  *      false, we can return an empty result set without running the
00033  *      controlled plan at all.  If it's true, we run the controlled
00034  *      plan normally and pass back the results.
00035  *
00036  *
00037  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00038  * Portions Copyright (c) 1994, Regents of the University of California
00039  *
00040  * IDENTIFICATION
00041  *    src/backend/executor/nodeResult.c
00042  *
00043  *-------------------------------------------------------------------------
00044  */
00045 
00046 #include "postgres.h"
00047 
00048 #include "executor/executor.h"
00049 #include "executor/nodeResult.h"
00050 #include "utils/memutils.h"
00051 
00052 
00053 /* ----------------------------------------------------------------
00054  *      ExecResult(node)
00055  *
00056  *      returns the tuples from the outer plan which satisfy the
00057  *      qualification clause.  Since result nodes with right
00058  *      subtrees are never planned, we ignore the right subtree
00059  *      entirely (for now).. -cim 10/7/89
00060  *
00061  *      The qualification containing only constant clauses are
00062  *      checked first before any processing is done. It always returns
00063  *      'nil' if the constant qualification is not satisfied.
00064  * ----------------------------------------------------------------
00065  */
00066 TupleTableSlot *
00067 ExecResult(ResultState *node)
00068 {
00069     TupleTableSlot *outerTupleSlot;
00070     TupleTableSlot *resultSlot;
00071     PlanState  *outerPlan;
00072     ExprContext *econtext;
00073     ExprDoneCond isDone;
00074 
00075     econtext = node->ps.ps_ExprContext;
00076 
00077     /*
00078      * check constant qualifications like (2 > 1), if not already done
00079      */
00080     if (node->rs_checkqual)
00081     {
00082         bool        qualResult = ExecQual((List *) node->resconstantqual,
00083                                           econtext,
00084                                           false);
00085 
00086         node->rs_checkqual = false;
00087         if (!qualResult)
00088         {
00089             node->rs_done = true;
00090             return NULL;
00091         }
00092     }
00093 
00094     /*
00095      * Check to see if we're still projecting out tuples from a previous scan
00096      * tuple (because there is a function-returning-set in the projection
00097      * expressions).  If so, try to project another one.
00098      */
00099     if (node->ps.ps_TupFromTlist)
00100     {
00101         resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
00102         if (isDone == ExprMultipleResult)
00103             return resultSlot;
00104         /* Done with that source tuple... */
00105         node->ps.ps_TupFromTlist = false;
00106     }
00107 
00108     /*
00109      * Reset per-tuple memory context to free any expression evaluation
00110      * storage allocated in the previous tuple cycle.  Note this can't happen
00111      * until we're done projecting out tuples from a scan tuple.
00112      */
00113     ResetExprContext(econtext);
00114 
00115     /*
00116      * if rs_done is true then it means that we were asked to return a
00117      * constant tuple and we already did the last time ExecResult() was
00118      * called, OR that we failed the constant qual check. Either way, now we
00119      * are through.
00120      */
00121     while (!node->rs_done)
00122     {
00123         outerPlan = outerPlanState(node);
00124 
00125         if (outerPlan != NULL)
00126         {
00127             /*
00128              * retrieve tuples from the outer plan until there are no more.
00129              */
00130             outerTupleSlot = ExecProcNode(outerPlan);
00131 
00132             if (TupIsNull(outerTupleSlot))
00133                 return NULL;
00134 
00135             /*
00136              * prepare to compute projection expressions, which will expect to
00137              * access the input tuples as varno OUTER.
00138              */
00139             econtext->ecxt_outertuple = outerTupleSlot;
00140         }
00141         else
00142         {
00143             /*
00144              * if we don't have an outer plan, then we are just generating the
00145              * results from a constant target list.  Do it only once.
00146              */
00147             node->rs_done = true;
00148         }
00149 
00150         /*
00151          * form the result tuple using ExecProject(), and return it --- unless
00152          * the projection produces an empty set, in which case we must loop
00153          * back to see if there are more outerPlan tuples.
00154          */
00155         resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
00156 
00157         if (isDone != ExprEndResult)
00158         {
00159             node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
00160             return resultSlot;
00161         }
00162     }
00163 
00164     return NULL;
00165 }
00166 
00167 /* ----------------------------------------------------------------
00168  *      ExecResultMarkPos
00169  * ----------------------------------------------------------------
00170  */
00171 void
00172 ExecResultMarkPos(ResultState *node)
00173 {
00174     PlanState  *outerPlan = outerPlanState(node);
00175 
00176     if (outerPlan != NULL)
00177         ExecMarkPos(outerPlan);
00178     else
00179         elog(DEBUG2, "Result nodes do not support mark/restore");
00180 }
00181 
00182 /* ----------------------------------------------------------------
00183  *      ExecResultRestrPos
00184  * ----------------------------------------------------------------
00185  */
00186 void
00187 ExecResultRestrPos(ResultState *node)
00188 {
00189     PlanState  *outerPlan = outerPlanState(node);
00190 
00191     if (outerPlan != NULL)
00192         ExecRestrPos(outerPlan);
00193     else
00194         elog(ERROR, "Result nodes do not support mark/restore");
00195 }
00196 
00197 /* ----------------------------------------------------------------
00198  *      ExecInitResult
00199  *
00200  *      Creates the run-time state information for the result node
00201  *      produced by the planner and initializes outer relations
00202  *      (child nodes).
00203  * ----------------------------------------------------------------
00204  */
00205 ResultState *
00206 ExecInitResult(Result *node, EState *estate, int eflags)
00207 {
00208     ResultState *resstate;
00209 
00210     /* check for unsupported flags */
00211     Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)) ||
00212            outerPlan(node) != NULL);
00213 
00214     /*
00215      * create state structure
00216      */
00217     resstate = makeNode(ResultState);
00218     resstate->ps.plan = (Plan *) node;
00219     resstate->ps.state = estate;
00220 
00221     resstate->rs_done = false;
00222     resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
00223 
00224     /*
00225      * Miscellaneous initialization
00226      *
00227      * create expression context for node
00228      */
00229     ExecAssignExprContext(estate, &resstate->ps);
00230 
00231     resstate->ps.ps_TupFromTlist = false;
00232 
00233     /*
00234      * tuple table initialization
00235      */
00236     ExecInitResultTupleSlot(estate, &resstate->ps);
00237 
00238     /*
00239      * initialize child expressions
00240      */
00241     resstate->ps.targetlist = (List *)
00242         ExecInitExpr((Expr *) node->plan.targetlist,
00243                      (PlanState *) resstate);
00244     resstate->ps.qual = (List *)
00245         ExecInitExpr((Expr *) node->plan.qual,
00246                      (PlanState *) resstate);
00247     resstate->resconstantqual = ExecInitExpr((Expr *) node->resconstantqual,
00248                                              (PlanState *) resstate);
00249 
00250     /*
00251      * initialize child nodes
00252      */
00253     outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags);
00254 
00255     /*
00256      * we don't use inner plan
00257      */
00258     Assert(innerPlan(node) == NULL);
00259 
00260     /*
00261      * initialize tuple type and projection info
00262      */
00263     ExecAssignResultTypeFromTL(&resstate->ps);
00264     ExecAssignProjectionInfo(&resstate->ps, NULL);
00265 
00266     return resstate;
00267 }
00268 
00269 /* ----------------------------------------------------------------
00270  *      ExecEndResult
00271  *
00272  *      frees up storage allocated through C routines
00273  * ----------------------------------------------------------------
00274  */
00275 void
00276 ExecEndResult(ResultState *node)
00277 {
00278     /*
00279      * Free the exprcontext
00280      */
00281     ExecFreeExprContext(&node->ps);
00282 
00283     /*
00284      * clean out the tuple table
00285      */
00286     ExecClearTuple(node->ps.ps_ResultTupleSlot);
00287 
00288     /*
00289      * shut down subplans
00290      */
00291     ExecEndNode(outerPlanState(node));
00292 }
00293 
00294 void
00295 ExecReScanResult(ResultState *node)
00296 {
00297     node->rs_done = false;
00298     node->ps.ps_TupFromTlist = false;
00299     node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
00300 
00301     /*
00302      * If chgParam of subnode is not null then plan will be re-scanned by
00303      * first ExecProcNode.
00304      */
00305     if (node->ps.lefttree &&
00306         node->ps.lefttree->chgParam == NULL)
00307         ExecReScan(node->ps.lefttree);
00308 }