LCOV - code coverage report
Current view: top level - src/backend/executor - nodeResult.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 49 61 80.3 %
Date: 2023-06-06 09:15:10 Functions: 4 6 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * nodeResult.c
       4             :  *    support for constant nodes needing special code.
       5             :  *
       6             :  * DESCRIPTION
       7             :  *
       8             :  *      Result nodes are used in queries where no relations are scanned.
       9             :  *      Examples of such queries are:
      10             :  *
      11             :  *              select 1 * 2
      12             :  *
      13             :  *              insert into emp values ('mike', 15000)
      14             :  *
      15             :  *      (Remember that in an INSERT or UPDATE, we need a plan tree that
      16             :  *      generates the new rows.)
      17             :  *
      18             :  *      Result nodes are also used to optimise queries with constant
      19             :  *      qualifications (ie, quals that do not depend on the scanned data),
      20             :  *      such as:
      21             :  *
      22             :  *              select * from emp where 2 > 1
      23             :  *
      24             :  *      In this case, the plan generated is
      25             :  *
      26             :  *                      Result  (with 2 > 1 qual)
      27             :  *                      /
      28             :  *                 SeqScan (emp.*)
      29             :  *
      30             :  *      At runtime, the Result node evaluates the constant qual once,
      31             :  *      which is shown by EXPLAIN as a One-Time Filter.  If it's
      32             :  *      false, we can return an empty result set without running the
      33             :  *      controlled plan at all.  If it's true, we run the controlled
      34             :  *      plan normally and pass back the results.
      35             :  *
      36             :  *
      37             :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
      38             :  * Portions Copyright (c) 1994, Regents of the University of California
      39             :  *
      40             :  * IDENTIFICATION
      41             :  *    src/backend/executor/nodeResult.c
      42             :  *
      43             :  *-------------------------------------------------------------------------
      44             :  */
      45             : 
      46             : #include "postgres.h"
      47             : 
      48             : #include "executor/executor.h"
      49             : #include "executor/nodeResult.h"
      50             : #include "miscadmin.h"
      51             : #include "utils/memutils.h"
      52             : 
      53             : 
      54             : /* ----------------------------------------------------------------
      55             :  *      ExecResult(node)
      56             :  *
      57             :  *      returns the tuples from the outer plan which satisfy the
      58             :  *      qualification clause.  Since result nodes with right
      59             :  *      subtrees are never planned, we ignore the right subtree
      60             :  *      entirely (for now).. -cim 10/7/89
      61             :  *
      62             :  *      The qualification containing only constant clauses are
      63             :  *      checked first before any processing is done. It always returns
      64             :  *      'nil' if the constant qualification is not satisfied.
      65             :  * ----------------------------------------------------------------
      66             :  */
      67             : static TupleTableSlot *
      68     1351234 : ExecResult(PlanState *pstate)
      69             : {
      70     1351234 :     ResultState *node = castNode(ResultState, pstate);
      71             :     TupleTableSlot *outerTupleSlot;
      72             :     PlanState  *outerPlan;
      73             :     ExprContext *econtext;
      74             : 
      75     1351234 :     CHECK_FOR_INTERRUPTS();
      76             : 
      77     1351230 :     econtext = node->ps.ps_ExprContext;
      78             : 
      79             :     /*
      80             :      * check constant qualifications like (2 > 1), if not already done
      81             :      */
      82     1351230 :     if (node->rs_checkqual)
      83             :     {
      84       12156 :         bool        qualResult = ExecQual(node->resconstantqual, econtext);
      85             : 
      86       12156 :         node->rs_checkqual = false;
      87       12156 :         if (!qualResult)
      88             :         {
      89        7660 :             node->rs_done = true;
      90        7660 :             return NULL;
      91             :         }
      92             :     }
      93             : 
      94             :     /*
      95             :      * Reset per-tuple memory context to free any expression evaluation
      96             :      * storage allocated in the previous tuple cycle.
      97             :      */
      98     1343570 :     ResetExprContext(econtext);
      99             : 
     100             :     /*
     101             :      * if rs_done is true then it means that we were asked to return a
     102             :      * constant tuple and we already did the last time ExecResult() was
     103             :      * called, OR that we failed the constant qual check. Either way, now we
     104             :      * are through.
     105             :      */
     106     1343570 :     if (!node->rs_done)
     107             :     {
     108      972118 :         outerPlan = outerPlanState(node);
     109             : 
     110      972118 :         if (outerPlan != NULL)
     111             :         {
     112             :             /*
     113             :              * retrieve tuples from the outer plan until there are no more.
     114             :              */
     115      530096 :             outerTupleSlot = ExecProcNode(outerPlan);
     116             : 
     117      530082 :             if (TupIsNull(outerTupleSlot))
     118        5754 :                 return NULL;
     119             : 
     120             :             /*
     121             :              * prepare to compute projection expressions, which will expect to
     122             :              * access the input tuples as varno OUTER.
     123             :              */
     124      524328 :             econtext->ecxt_outertuple = outerTupleSlot;
     125             :         }
     126             :         else
     127             :         {
     128             :             /*
     129             :              * if we don't have an outer plan, then we are just generating the
     130             :              * results from a constant target list.  Do it only once.
     131             :              */
     132      442022 :             node->rs_done = true;
     133             :         }
     134             : 
     135             :         /* form the result tuple using ExecProject(), and return it */
     136      966350 :         return ExecProject(node->ps.ps_ProjInfo);
     137             :     }
     138             : 
     139      371452 :     return NULL;
     140             : }
     141             : 
     142             : /* ----------------------------------------------------------------
     143             :  *      ExecResultMarkPos
     144             :  * ----------------------------------------------------------------
     145             :  */
     146             : void
     147           0 : ExecResultMarkPos(ResultState *node)
     148             : {
     149           0 :     PlanState  *outerPlan = outerPlanState(node);
     150             : 
     151           0 :     if (outerPlan != NULL)
     152           0 :         ExecMarkPos(outerPlan);
     153             :     else
     154           0 :         elog(DEBUG2, "Result nodes do not support mark/restore");
     155           0 : }
     156             : 
     157             : /* ----------------------------------------------------------------
     158             :  *      ExecResultRestrPos
     159             :  * ----------------------------------------------------------------
     160             :  */
     161             : void
     162           0 : ExecResultRestrPos(ResultState *node)
     163             : {
     164           0 :     PlanState  *outerPlan = outerPlanState(node);
     165             : 
     166           0 :     if (outerPlan != NULL)
     167           0 :         ExecRestrPos(outerPlan);
     168             :     else
     169           0 :         elog(ERROR, "Result nodes do not support mark/restore");
     170           0 : }
     171             : 
     172             : /* ----------------------------------------------------------------
     173             :  *      ExecInitResult
     174             :  *
     175             :  *      Creates the run-time state information for the result node
     176             :  *      produced by the planner and initializes outer relations
     177             :  *      (child nodes).
     178             :  * ----------------------------------------------------------------
     179             :  */
     180             : ResultState *
     181      297912 : ExecInitResult(Result *node, EState *estate, int eflags)
     182             : {
     183             :     ResultState *resstate;
     184             : 
     185             :     /* check for unsupported flags */
     186             :     Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)) ||
     187             :            outerPlan(node) != NULL);
     188             : 
     189             :     /*
     190             :      * create state structure
     191             :      */
     192      297912 :     resstate = makeNode(ResultState);
     193      297912 :     resstate->ps.plan = (Plan *) node;
     194      297912 :     resstate->ps.state = estate;
     195      297912 :     resstate->ps.ExecProcNode = ExecResult;
     196             : 
     197      297912 :     resstate->rs_done = false;
     198      297912 :     resstate->rs_checkqual = (node->resconstantqual != NULL);
     199             : 
     200             :     /*
     201             :      * Miscellaneous initialization
     202             :      *
     203             :      * create expression context for node
     204             :      */
     205      297912 :     ExecAssignExprContext(estate, &resstate->ps);
     206             : 
     207             :     /*
     208             :      * initialize child nodes
     209             :      */
     210      297912 :     outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags);
     211             : 
     212             :     /*
     213             :      * we don't use inner plan
     214             :      */
     215             :     Assert(innerPlan(node) == NULL);
     216             : 
     217             :     /*
     218             :      * Initialize result slot, type and projection.
     219             :      */
     220      297912 :     ExecInitResultTupleSlotTL(&resstate->ps, &TTSOpsVirtual);
     221      297912 :     ExecAssignProjectionInfo(&resstate->ps, NULL);
     222             : 
     223             :     /*
     224             :      * initialize child expressions
     225             :      */
     226      297842 :     resstate->ps.qual =
     227      297842 :         ExecInitQual(node->plan.qual, (PlanState *) resstate);
     228      297842 :     resstate->resconstantqual =
     229      297842 :         ExecInitQual((List *) node->resconstantqual, (PlanState *) resstate);
     230             : 
     231      297842 :     return resstate;
     232             : }
     233             : 
     234             : /* ----------------------------------------------------------------
     235             :  *      ExecEndResult
     236             :  *
     237             :  *      frees up storage allocated through C routines
     238             :  * ----------------------------------------------------------------
     239             :  */
     240             : void
     241      282444 : ExecEndResult(ResultState *node)
     242             : {
     243             :     /*
     244             :      * Free the exprcontext
     245             :      */
     246      282444 :     ExecFreeExprContext(&node->ps);
     247             : 
     248             :     /*
     249             :      * clean out the tuple table
     250             :      */
     251      282444 :     ExecClearTuple(node->ps.ps_ResultTupleSlot);
     252             : 
     253             :     /*
     254             :      * shut down subplans
     255             :      */
     256      282444 :     ExecEndNode(outerPlanState(node));
     257      282444 : }
     258             : 
     259             : void
     260      164834 : ExecReScanResult(ResultState *node)
     261             : {
     262      164834 :     PlanState  *outerPlan = outerPlanState(node);
     263             : 
     264      164834 :     node->rs_done = false;
     265      164834 :     node->rs_checkqual = (node->resconstantqual != NULL);
     266             : 
     267             :     /*
     268             :      * If chgParam of subnode is not null then plan will be re-scanned by
     269             :      * first ExecProcNode.
     270             :      */
     271      164834 :     if (outerPlan && outerPlan->chgParam == NULL)
     272          78 :         ExecReScan(outerPlan);
     273      164834 : }

Generated by: LCOV version 1.14