LCOV - code coverage report
Current view: top level - src/backend/executor - nodeValuesscan.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 97.3 % 75 73
Test Date: 2026-02-28 23:15:01 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * nodeValuesscan.c
       4              :  *    Support routines for scanning Values lists
       5              :  *    ("VALUES (...), (...), ..." in rangetable).
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  *
      11              :  * IDENTIFICATION
      12              :  *    src/backend/executor/nodeValuesscan.c
      13              :  *
      14              :  *-------------------------------------------------------------------------
      15              :  */
      16              : /*
      17              :  * INTERFACE ROUTINES
      18              :  *      ExecValuesScan          scans a values list.
      19              :  *      ExecValuesNext          retrieve next tuple in sequential order.
      20              :  *      ExecInitValuesScan      creates and initializes a valuesscan node.
      21              :  *      ExecReScanValuesScan    rescans the values list
      22              :  */
      23              : #include "postgres.h"
      24              : 
      25              : #include "executor/executor.h"
      26              : #include "executor/nodeValuesscan.h"
      27              : #include "jit/jit.h"
      28              : #include "optimizer/clauses.h"
      29              : #include "utils/expandeddatum.h"
      30              : 
      31              : 
      32              : static TupleTableSlot *ValuesNext(ValuesScanState *node);
      33              : 
      34              : 
      35              : /* ----------------------------------------------------------------
      36              :  *                      Scan Support
      37              :  * ----------------------------------------------------------------
      38              :  */
      39              : 
      40              : /* ----------------------------------------------------------------
      41              :  *      ValuesNext
      42              :  *
      43              :  *      This is a workhorse for ExecValuesScan
      44              :  * ----------------------------------------------------------------
      45              :  */
      46              : static TupleTableSlot *
      47       113025 : ValuesNext(ValuesScanState *node)
      48              : {
      49              :     TupleTableSlot *slot;
      50              :     EState     *estate;
      51              :     ExprContext *econtext;
      52              :     ScanDirection direction;
      53              :     int         curr_idx;
      54              : 
      55              :     /*
      56              :      * get information from the estate and scan state
      57              :      */
      58       113025 :     estate = node->ss.ps.state;
      59       113025 :     direction = estate->es_direction;
      60       113025 :     slot = node->ss.ss_ScanTupleSlot;
      61       113025 :     econtext = node->rowcontext;
      62              : 
      63              :     /*
      64              :      * Get the next tuple. Return NULL if no more tuples.
      65              :      */
      66       113025 :     if (ScanDirectionIsForward(direction))
      67              :     {
      68       113025 :         if (node->curr_idx < node->array_len)
      69       113025 :             node->curr_idx++;
      70              :     }
      71              :     else
      72              :     {
      73            0 :         if (node->curr_idx >= 0)
      74            0 :             node->curr_idx--;
      75              :     }
      76              : 
      77              :     /*
      78              :      * Always clear the result slot; this is appropriate if we are at the end
      79              :      * of the data, and if we're not, we still need it as the first step of
      80              :      * the store-virtual-tuple protocol.  It seems wise to clear the slot
      81              :      * before we reset the context it might have pointers into.
      82              :      */
      83       113025 :     ExecClearTuple(slot);
      84              : 
      85       113025 :     curr_idx = node->curr_idx;
      86       113025 :     if (curr_idx >= 0 && curr_idx < node->array_len)
      87              :     {
      88        78528 :         List       *exprlist = node->exprlists[curr_idx];
      89        78528 :         List       *exprstatelist = node->exprstatelists[curr_idx];
      90              :         MemoryContext oldContext;
      91              :         Datum      *values;
      92              :         bool       *isnull;
      93              :         ListCell   *lc;
      94              :         int         resind;
      95              : 
      96              :         /*
      97              :          * Get rid of any prior cycle's leftovers.  We use ReScanExprContext
      98              :          * not just ResetExprContext because we want any registered shutdown
      99              :          * callbacks to be called.
     100              :          */
     101        78528 :         ReScanExprContext(econtext);
     102              : 
     103              :         /*
     104              :          * Do per-VALUES-row work in the per-tuple context.
     105              :          */
     106        78528 :         oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
     107              : 
     108              :         /*
     109              :          * Unless we already made the expression eval state for this row,
     110              :          * build it in the econtext's per-tuple memory.  This is a tad
     111              :          * unusual, but we want to delete the eval state again when we move to
     112              :          * the next row, to avoid growth of memory requirements over a long
     113              :          * values list.  For rows in which that won't work, we already built
     114              :          * the eval state at plan startup.
     115              :          */
     116        78528 :         if (exprstatelist == NIL)
     117              :         {
     118              :             /*
     119              :              * Pass parent as NULL, not my plan node, because we don't want
     120              :              * anything in this transient state linking into permanent state.
     121              :              * The only expression type that might wish to do so is a SubPlan,
     122              :              * and we already checked that there aren't any.
     123              :              *
     124              :              * Note that passing parent = NULL also disables JIT compilation
     125              :              * of the expressions, which is a win, because they're only going
     126              :              * to be used once under normal circumstances.
     127              :              */
     128        78498 :             exprstatelist = ExecInitExprList(exprlist, NULL);
     129              :         }
     130              : 
     131              :         /* parser should have checked all sublists are the same length */
     132              :         Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts);
     133              : 
     134              :         /*
     135              :          * Compute the expressions and build a virtual result tuple. We
     136              :          * already did ExecClearTuple(slot).
     137              :          */
     138        78528 :         values = slot->tts_values;
     139        78528 :         isnull = slot->tts_isnull;
     140              : 
     141        78528 :         resind = 0;
     142       171651 :         foreach(lc, exprstatelist)
     143              :         {
     144        93123 :             ExprState  *estate = (ExprState *) lfirst(lc);
     145        93123 :             CompactAttribute *attr = TupleDescCompactAttr(slot->tts_tupleDescriptor,
     146              :                                                           resind);
     147              : 
     148        93123 :             values[resind] = ExecEvalExpr(estate,
     149              :                                           econtext,
     150              :                                           &isnull[resind]);
     151              : 
     152              :             /*
     153              :              * We must force any R/W expanded datums to read-only state, in
     154              :              * case they are multiply referenced in the plan node's output
     155              :              * expressions, or in case we skip the output projection and the
     156              :              * output column is multiply referenced in higher plan nodes.
     157              :              */
     158        93123 :             values[resind] = MakeExpandedObjectReadOnly(values[resind],
     159              :                                                         isnull[resind],
     160              :                                                         attr->attlen);
     161              : 
     162        93123 :             resind++;
     163              :         }
     164              : 
     165        78528 :         MemoryContextSwitchTo(oldContext);
     166              : 
     167              :         /*
     168              :          * And return the virtual tuple.
     169              :          */
     170        78528 :         ExecStoreVirtualTuple(slot);
     171              :     }
     172              : 
     173       113025 :     return slot;
     174              : }
     175              : 
     176              : /*
     177              :  * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
     178              :  */
     179              : static bool
     180            4 : ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
     181              : {
     182              :     /* nothing to check */
     183            4 :     return true;
     184              : }
     185              : 
     186              : /* ----------------------------------------------------------------
     187              :  *      ExecValuesScan(node)
     188              :  *
     189              :  *      Scans the values lists sequentially and returns the next qualifying
     190              :  *      tuple.
     191              :  *      We call the ExecScan() routine and pass it the appropriate
     192              :  *      access method functions.
     193              :  * ----------------------------------------------------------------
     194              :  */
     195              : static TupleTableSlot *
     196       112529 : ExecValuesScan(PlanState *pstate)
     197              : {
     198       112529 :     ValuesScanState *node = castNode(ValuesScanState, pstate);
     199              : 
     200       112529 :     return ExecScan(&node->ss,
     201              :                     (ExecScanAccessMtd) ValuesNext,
     202              :                     (ExecScanRecheckMtd) ValuesRecheck);
     203              : }
     204              : 
     205              : /* ----------------------------------------------------------------
     206              :  *      ExecInitValuesScan
     207              :  * ----------------------------------------------------------------
     208              :  */
     209              : ValuesScanState *
     210         4739 : ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
     211              : {
     212              :     ValuesScanState *scanstate;
     213              :     TupleDesc   tupdesc;
     214              :     ListCell   *vtl;
     215              :     int         i;
     216              :     PlanState  *planstate;
     217              : 
     218              :     /*
     219              :      * ValuesScan should not have any children.
     220              :      */
     221              :     Assert(outerPlan(node) == NULL);
     222              :     Assert(innerPlan(node) == NULL);
     223              : 
     224              :     /*
     225              :      * create new ScanState for node
     226              :      */
     227         4739 :     scanstate = makeNode(ValuesScanState);
     228         4739 :     scanstate->ss.ps.plan = (Plan *) node;
     229         4739 :     scanstate->ss.ps.state = estate;
     230         4739 :     scanstate->ss.ps.ExecProcNode = ExecValuesScan;
     231              : 
     232              :     /*
     233              :      * Miscellaneous initialization
     234              :      */
     235         4739 :     planstate = &scanstate->ss.ps;
     236              : 
     237              :     /*
     238              :      * Create expression contexts.  We need two, one for per-sublist
     239              :      * processing and one for execScan.c to use for quals and projections. We
     240              :      * cheat a little by using ExecAssignExprContext() to build both.
     241              :      */
     242         4739 :     ExecAssignExprContext(estate, planstate);
     243         4739 :     scanstate->rowcontext = planstate->ps_ExprContext;
     244         4739 :     ExecAssignExprContext(estate, planstate);
     245              : 
     246              :     /*
     247              :      * Get info about values list, initialize scan slot with it.
     248              :      */
     249         4739 :     tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
     250         4739 :     ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
     251              : 
     252              :     /*
     253              :      * Initialize result type and projection.
     254              :      */
     255         4739 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     256         4739 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     257              : 
     258              :     /*
     259              :      * initialize child expressions
     260              :      */
     261         4739 :     scanstate->ss.ps.qual =
     262         4739 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     263              : 
     264              :     /*
     265              :      * Other node-specific setup
     266              :      */
     267         4739 :     scanstate->curr_idx = -1;
     268         4739 :     scanstate->array_len = list_length(node->values_lists);
     269              : 
     270              :     /*
     271              :      * Convert the list of expression sublists into an array for easier
     272              :      * addressing at runtime.  Also, detect whether any sublists contain
     273              :      * SubPlans; for just those sublists, go ahead and do expression
     274              :      * initialization.  (This avoids problems with SubPlans wanting to connect
     275              :      * themselves up to the outer plan tree.  Notably, EXPLAIN won't see the
     276              :      * subplans otherwise; also we will have troubles with dangling pointers
     277              :      * and/or leaked resources if we try to handle SubPlans the same as
     278              :      * simpler expressions.)
     279              :      */
     280         4739 :     scanstate->exprlists = (List **)
     281         4739 :         palloc(scanstate->array_len * sizeof(List *));
     282         4739 :     scanstate->exprstatelists = (List **)
     283         4739 :         palloc0(scanstate->array_len * sizeof(List *));
     284         4739 :     i = 0;
     285        23709 :     foreach(vtl, node->values_lists)
     286              :     {
     287        18970 :         List       *exprs = lfirst_node(List, vtl);
     288              : 
     289        18970 :         scanstate->exprlists[i] = exprs;
     290              : 
     291              :         /*
     292              :          * We can avoid the cost of a contain_subplans() scan in the simple
     293              :          * case where there are no SubPlans anywhere.
     294              :          */
     295        19234 :         if (estate->es_subplanstates &&
     296          264 :             contain_subplans((Node *) exprs))
     297              :         {
     298              :             int         saved_jit_flags;
     299              : 
     300              :             /*
     301              :              * As these expressions are only used once, disable JIT for them.
     302              :              * This is worthwhile because it's common to insert significant
     303              :              * amounts of data via VALUES().  Note that this doesn't prevent
     304              :              * use of JIT *within* a subplan, since that's initialized
     305              :              * separately; this just affects the upper-level subexpressions.
     306              :              */
     307           18 :             saved_jit_flags = estate->es_jit_flags;
     308           18 :             estate->es_jit_flags = PGJIT_NONE;
     309              : 
     310           18 :             scanstate->exprstatelists[i] = ExecInitExprList(exprs,
     311              :                                                             &scanstate->ss.ps);
     312              : 
     313           18 :             estate->es_jit_flags = saved_jit_flags;
     314              :         }
     315        18970 :         i++;
     316              :     }
     317              : 
     318         4739 :     return scanstate;
     319              : }
     320              : 
     321              : /* ----------------------------------------------------------------
     322              :  *      ExecReScanValuesScan
     323              :  *
     324              :  *      Rescans the relation.
     325              :  * ----------------------------------------------------------------
     326              :  */
     327              : void
     328        30190 : ExecReScanValuesScan(ValuesScanState *node)
     329              : {
     330        30190 :     if (node->ss.ps.ps_ResultTupleSlot)
     331            7 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     332              : 
     333        30190 :     ExecScanReScan(&node->ss);
     334              : 
     335        30190 :     node->curr_idx = -1;
     336        30190 : }
        

Generated by: LCOV version 2.0-1