LCOV - code coverage report
Current view: top level - src/backend/executor - nodeValuesscan.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 96.3 % 107 103
Test Date: 2026-01-26 10:56:24 Functions: 80.0 % 5 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 75.0 % 40 30

             Branch data     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                 :       36244 : ValuesNext(ValuesScanState *node)
      48                 :             : {
      49                 :       36244 :         TupleTableSlot *slot;
      50                 :       36244 :         EState     *estate;
      51                 :       36244 :         ExprContext *econtext;
      52                 :       36244 :         ScanDirection direction;
      53                 :       36244 :         int                     curr_idx;
      54                 :             : 
      55                 :             :         /*
      56                 :             :          * get information from the estate and scan state
      57                 :             :          */
      58                 :       36244 :         estate = node->ss.ps.state;
      59                 :       36244 :         direction = estate->es_direction;
      60                 :       36244 :         slot = node->ss.ss_ScanTupleSlot;
      61                 :       36244 :         econtext = node->rowcontext;
      62                 :             : 
      63                 :             :         /*
      64                 :             :          * Get the next tuple. Return NULL if no more tuples.
      65                 :             :          */
      66         [ +  - ]:       36244 :         if (ScanDirectionIsForward(direction))
      67                 :             :         {
      68         [ -  + ]:       36244 :                 if (node->curr_idx < node->array_len)
      69                 :       36244 :                         node->curr_idx++;
      70                 :       36244 :         }
      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                 :       36244 :         ExecClearTuple(slot);
      84                 :             : 
      85                 :       36244 :         curr_idx = node->curr_idx;
      86   [ +  -  +  + ]:       36244 :         if (curr_idx >= 0 && curr_idx < node->array_len)
      87                 :             :         {
      88                 :       25068 :                 List       *exprlist = node->exprlists[curr_idx];
      89                 :       25068 :                 List       *exprstatelist = node->exprstatelists[curr_idx];
      90                 :       25068 :                 MemoryContext oldContext;
      91                 :       25068 :                 Datum      *values;
      92                 :       25068 :                 bool       *isnull;
      93                 :       25068 :                 ListCell   *lc;
      94                 :       25068 :                 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                 :       25068 :                 ReScanExprContext(econtext);
     102                 :             : 
     103                 :             :                 /*
     104                 :             :                  * Do per-VALUES-row work in the per-tuple context.
     105                 :             :                  */
     106                 :       25068 :                 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         [ +  + ]:       25068 :                 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                 :       25058 :                         exprstatelist = ExecInitExprList(exprlist, NULL);
     129                 :       25058 :                 }
     130                 :             : 
     131                 :             :                 /* parser should have checked all sublists are the same length */
     132         [ +  - ]:       25068 :                 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                 :       25068 :                 values = slot->tts_values;
     139                 :       25068 :                 isnull = slot->tts_isnull;
     140                 :             : 
     141                 :       25068 :                 resind = 0;
     142   [ +  -  +  +  :       54152 :                 foreach(lc, exprstatelist)
                   +  + ]
     143                 :             :                 {
     144                 :       29084 :                         ExprState  *estate = (ExprState *) lfirst(lc);
     145                 :       58168 :                         CompactAttribute *attr = TupleDescCompactAttr(slot->tts_tupleDescriptor,
     146                 :       29084 :                                                                                                                   resind);
     147                 :             : 
     148                 :       58168 :                         values[resind] = ExecEvalExpr(estate,
     149                 :       29084 :                                                                                   econtext,
     150                 :       29084 :                                                                                   &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   [ +  +  +  + ]:       29084 :                         values[resind] = MakeExpandedObjectReadOnly(values[resind],
     159                 :             :                                                                                                                 isnull[resind],
     160                 :             :                                                                                                                 attr->attlen);
     161                 :             : 
     162                 :       29084 :                         resind++;
     163                 :       29084 :                 }
     164                 :             : 
     165                 :       25068 :                 MemoryContextSwitchTo(oldContext);
     166                 :             : 
     167                 :             :                 /*
     168                 :             :                  * And return the virtual tuple.
     169                 :             :                  */
     170                 :       25068 :                 ExecStoreVirtualTuple(slot);
     171                 :       25068 :         }
     172                 :             : 
     173                 :       72488 :         return slot;
     174                 :       36244 : }
     175                 :             : 
     176                 :             : /*
     177                 :             :  * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
     178                 :             :  */
     179                 :             : static bool
     180                 :           0 : ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
     181                 :             : {
     182                 :             :         /* nothing to check */
     183                 :           0 :         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                 :       36088 : ExecValuesScan(PlanState *pstate)
     197                 :             : {
     198                 :       36088 :         ValuesScanState *node = castNode(ValuesScanState, pstate);
     199                 :             : 
     200                 :       72176 :         return ExecScan(&node->ss,
     201                 :             :                                         (ExecScanAccessMtd) ValuesNext,
     202                 :             :                                         (ExecScanRecheckMtd) ValuesRecheck);
     203                 :       36088 : }
     204                 :             : 
     205                 :             : /* ----------------------------------------------------------------
     206                 :             :  *              ExecInitValuesScan
     207                 :             :  * ----------------------------------------------------------------
     208                 :             :  */
     209                 :             : ValuesScanState *
     210                 :        1250 : ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
     211                 :             : {
     212                 :        1250 :         ValuesScanState *scanstate;
     213                 :        1250 :         TupleDesc       tupdesc;
     214                 :        1250 :         ListCell   *vtl;
     215                 :        1250 :         int                     i;
     216                 :        1250 :         PlanState  *planstate;
     217                 :             : 
     218                 :             :         /*
     219                 :             :          * ValuesScan should not have any children.
     220                 :             :          */
     221         [ +  - ]:        1250 :         Assert(outerPlan(node) == NULL);
     222         [ +  - ]:        1250 :         Assert(innerPlan(node) == NULL);
     223                 :             : 
     224                 :             :         /*
     225                 :             :          * create new ScanState for node
     226                 :             :          */
     227                 :        1250 :         scanstate = makeNode(ValuesScanState);
     228                 :        1250 :         scanstate->ss.ps.plan = (Plan *) node;
     229                 :        1250 :         scanstate->ss.ps.state = estate;
     230                 :        1250 :         scanstate->ss.ps.ExecProcNode = ExecValuesScan;
     231                 :             : 
     232                 :             :         /*
     233                 :             :          * Miscellaneous initialization
     234                 :             :          */
     235                 :        1250 :         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                 :        1250 :         ExecAssignExprContext(estate, planstate);
     243                 :        1250 :         scanstate->rowcontext = planstate->ps_ExprContext;
     244                 :        1250 :         ExecAssignExprContext(estate, planstate);
     245                 :             : 
     246                 :             :         /*
     247                 :             :          * Get info about values list, initialize scan slot with it.
     248                 :             :          */
     249                 :        1250 :         tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
     250                 :        1250 :         ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
     251                 :             : 
     252                 :             :         /*
     253                 :             :          * Initialize result type and projection.
     254                 :             :          */
     255                 :        1250 :         ExecInitResultTypeTL(&scanstate->ss.ps);
     256                 :        1250 :         ExecAssignScanProjectionInfo(&scanstate->ss);
     257                 :             : 
     258                 :             :         /*
     259                 :             :          * initialize child expressions
     260                 :             :          */
     261                 :        1250 :         scanstate->ss.ps.qual =
     262                 :        1250 :                 ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     263                 :             : 
     264                 :             :         /*
     265                 :             :          * Other node-specific setup
     266                 :             :          */
     267                 :        1250 :         scanstate->curr_idx = -1;
     268                 :        1250 :         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                 :        1250 :         scanstate->exprlists = (List **)
     281                 :        1250 :                 palloc(scanstate->array_len * sizeof(List *));
     282                 :        1250 :         scanstate->exprstatelists = (List **)
     283                 :        1250 :                 palloc0(scanstate->array_len * sizeof(List *));
     284                 :        1250 :         i = 0;
     285   [ +  -  +  +  :        6482 :         foreach(vtl, node->values_lists)
                   +  + ]
     286                 :             :         {
     287                 :        5232 :                 List       *exprs = lfirst_node(List, vtl);
     288                 :             : 
     289                 :        5232 :                 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   [ +  +  +  + ]:        5232 :                 if (estate->es_subplanstates &&
     296                 :          88 :                         contain_subplans((Node *) exprs))
     297                 :             :                 {
     298                 :           6 :                         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                 :           6 :                         saved_jit_flags = estate->es_jit_flags;
     308                 :           6 :                         estate->es_jit_flags = PGJIT_NONE;
     309                 :             : 
     310                 :          12 :                         scanstate->exprstatelists[i] = ExecInitExprList(exprs,
     311                 :           6 :                                                                                                                         &scanstate->ss.ps);
     312                 :             : 
     313                 :           6 :                         estate->es_jit_flags = saved_jit_flags;
     314                 :           6 :                 }
     315                 :        5232 :                 i++;
     316                 :        5232 :         }
     317                 :             : 
     318                 :        2500 :         return scanstate;
     319                 :        1250 : }
     320                 :             : 
     321                 :             : /* ----------------------------------------------------------------
     322                 :             :  *              ExecReScanValuesScan
     323                 :             :  *
     324                 :             :  *              Rescans the relation.
     325                 :             :  * ----------------------------------------------------------------
     326                 :             :  */
     327                 :             : void
     328                 :       10061 : ExecReScanValuesScan(ValuesScanState *node)
     329                 :             : {
     330         [ +  + ]:       10061 :         if (node->ss.ps.ps_ResultTupleSlot)
     331                 :           2 :                 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     332                 :             : 
     333                 :       10061 :         ExecScanReScan(&node->ss);
     334                 :             : 
     335                 :       10061 :         node->curr_idx = -1;
     336                 :       10061 : }
        

Generated by: LCOV version 2.3.2-1