LCOV - code coverage report
Current view: top level - src/backend/executor - nodeResult.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 47 59 79.7 %
Date: 2024-03-29 11:11:17 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-2024, 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             : 
      52             : 
      53             : /* ----------------------------------------------------------------
      54             :  *      ExecResult(node)
      55             :  *
      56             :  *      returns the tuples from the outer plan which satisfy the
      57             :  *      qualification clause.  Since result nodes with right
      58             :  *      subtrees are never planned, we ignore the right subtree
      59             :  *      entirely (for now).. -cim 10/7/89
      60             :  *
      61             :  *      The qualification containing only constant clauses are
      62             :  *      checked first before any processing is done. It always returns
      63             :  *      'nil' if the constant qualification is not satisfied.
      64             :  * ----------------------------------------------------------------
      65             :  */
      66             : static TupleTableSlot *
      67     1131876 : ExecResult(PlanState *pstate)
      68             : {
      69     1131876 :     ResultState *node = castNode(ResultState, pstate);
      70             :     TupleTableSlot *outerTupleSlot;
      71             :     PlanState  *outerPlan;
      72             :     ExprContext *econtext;
      73             : 
      74     1131876 :     CHECK_FOR_INTERRUPTS();
      75             : 
      76     1131872 :     econtext = node->ps.ps_ExprContext;
      77             : 
      78             :     /*
      79             :      * check constant qualifications like (2 > 1), if not already done
      80             :      */
      81     1131872 :     if (node->rs_checkqual)
      82             :     {
      83       14414 :         bool        qualResult = ExecQual(node->resconstantqual, econtext);
      84             : 
      85       14414 :         node->rs_checkqual = false;
      86       14414 :         if (!qualResult)
      87             :         {
      88        8842 :             node->rs_done = true;
      89        8842 :             return NULL;
      90             :         }
      91             :     }
      92             : 
      93             :     /*
      94             :      * Reset per-tuple memory context to free any expression evaluation
      95             :      * storage allocated in the previous tuple cycle.
      96             :      */
      97     1123030 :     ResetExprContext(econtext);
      98             : 
      99             :     /*
     100             :      * if rs_done is true then it means that we were asked to return a
     101             :      * constant tuple and we already did the last time ExecResult() was
     102             :      * called, OR that we failed the constant qual check. Either way, now we
     103             :      * are through.
     104             :      */
     105     1123030 :     if (!node->rs_done)
     106             :     {
     107      887486 :         outerPlan = outerPlanState(node);
     108             : 
     109      887486 :         if (outerPlan != NULL)
     110             :         {
     111             :             /*
     112             :              * retrieve tuples from the outer plan until there are no more.
     113             :              */
     114      531666 :             outerTupleSlot = ExecProcNode(outerPlan);
     115             : 
     116      531652 :             if (TupIsNull(outerTupleSlot))
     117        6850 :                 return NULL;
     118             : 
     119             :             /*
     120             :              * prepare to compute projection expressions, which will expect to
     121             :              * access the input tuples as varno OUTER.
     122             :              */
     123      524802 :             econtext->ecxt_outertuple = outerTupleSlot;
     124             :         }
     125             :         else
     126             :         {
     127             :             /*
     128             :              * if we don't have an outer plan, then we are just generating the
     129             :              * results from a constant target list.  Do it only once.
     130             :              */
     131      355820 :             node->rs_done = true;
     132             :         }
     133             : 
     134             :         /* form the result tuple using ExecProject(), and return it */
     135      880622 :         return ExecProject(node->ps.ps_ProjInfo);
     136             :     }
     137             : 
     138      235544 :     return NULL;
     139             : }
     140             : 
     141             : /* ----------------------------------------------------------------
     142             :  *      ExecResultMarkPos
     143             :  * ----------------------------------------------------------------
     144             :  */
     145             : void
     146           0 : ExecResultMarkPos(ResultState *node)
     147             : {
     148           0 :     PlanState  *outerPlan = outerPlanState(node);
     149             : 
     150           0 :     if (outerPlan != NULL)
     151           0 :         ExecMarkPos(outerPlan);
     152             :     else
     153           0 :         elog(DEBUG2, "Result nodes do not support mark/restore");
     154           0 : }
     155             : 
     156             : /* ----------------------------------------------------------------
     157             :  *      ExecResultRestrPos
     158             :  * ----------------------------------------------------------------
     159             :  */
     160             : void
     161           0 : ExecResultRestrPos(ResultState *node)
     162             : {
     163           0 :     PlanState  *outerPlan = outerPlanState(node);
     164             : 
     165           0 :     if (outerPlan != NULL)
     166           0 :         ExecRestrPos(outerPlan);
     167             :     else
     168           0 :         elog(ERROR, "Result nodes do not support mark/restore");
     169           0 : }
     170             : 
     171             : /* ----------------------------------------------------------------
     172             :  *      ExecInitResult
     173             :  *
     174             :  *      Creates the run-time state information for the result node
     175             :  *      produced by the planner and initializes outer relations
     176             :  *      (child nodes).
     177             :  * ----------------------------------------------------------------
     178             :  */
     179             : ResultState *
     180      337690 : ExecInitResult(Result *node, EState *estate, int eflags)
     181             : {
     182             :     ResultState *resstate;
     183             : 
     184             :     /* check for unsupported flags */
     185             :     Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)) ||
     186             :            outerPlan(node) != NULL);
     187             : 
     188             :     /*
     189             :      * create state structure
     190             :      */
     191      337690 :     resstate = makeNode(ResultState);
     192      337690 :     resstate->ps.plan = (Plan *) node;
     193      337690 :     resstate->ps.state = estate;
     194      337690 :     resstate->ps.ExecProcNode = ExecResult;
     195             : 
     196      337690 :     resstate->rs_done = false;
     197      337690 :     resstate->rs_checkqual = (node->resconstantqual != NULL);
     198             : 
     199             :     /*
     200             :      * Miscellaneous initialization
     201             :      *
     202             :      * create expression context for node
     203             :      */
     204      337690 :     ExecAssignExprContext(estate, &resstate->ps);
     205             : 
     206             :     /*
     207             :      * initialize child nodes
     208             :      */
     209      337690 :     outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate, eflags);
     210             : 
     211             :     /*
     212             :      * we don't use inner plan
     213             :      */
     214             :     Assert(innerPlan(node) == NULL);
     215             : 
     216             :     /*
     217             :      * Initialize result slot, type and projection.
     218             :      */
     219      337690 :     ExecInitResultTupleSlotTL(&resstate->ps, &TTSOpsVirtual);
     220      337690 :     ExecAssignProjectionInfo(&resstate->ps, NULL);
     221             : 
     222             :     /*
     223             :      * initialize child expressions
     224             :      */
     225      337628 :     resstate->ps.qual =
     226      337628 :         ExecInitQual(node->plan.qual, (PlanState *) resstate);
     227      337628 :     resstate->resconstantqual =
     228      337628 :         ExecInitQual((List *) node->resconstantqual, (PlanState *) resstate);
     229             : 
     230      337628 :     return resstate;
     231             : }
     232             : 
     233             : /* ----------------------------------------------------------------
     234             :  *      ExecEndResult
     235             :  *
     236             :  *      frees up storage allocated through C routines
     237             :  * ----------------------------------------------------------------
     238             :  */
     239             : void
     240      320776 : ExecEndResult(ResultState *node)
     241             : {
     242             :     /*
     243             :      * shut down subplans
     244             :      */
     245      320776 :     ExecEndNode(outerPlanState(node));
     246      320776 : }
     247             : 
     248             : void
     249       41608 : ExecReScanResult(ResultState *node)
     250             : {
     251       41608 :     PlanState  *outerPlan = outerPlanState(node);
     252             : 
     253       41608 :     node->rs_done = false;
     254       41608 :     node->rs_checkqual = (node->resconstantqual != NULL);
     255             : 
     256             :     /*
     257             :      * If chgParam of subnode is not null then plan will be re-scanned by
     258             :      * first ExecProcNode.
     259             :      */
     260       41608 :     if (outerPlan && outerPlan->chgParam == NULL)
     261          78 :         ExecReScan(outerPlan);
     262       41608 : }

Generated by: LCOV version 1.14