LCOV - code coverage report
Current view: top level - src/backend/executor - nodeValuesscan.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 73 75 97.3 %
Date: 2024-05-09 15:13:04 Functions: 5 5 100.0 %
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-2024, 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      221924 : 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      221924 :     estate = node->ss.ps.state;
      59      221924 :     direction = estate->es_direction;
      60      221924 :     slot = node->ss.ss_ScanTupleSlot;
      61      221924 :     econtext = node->rowcontext;
      62             : 
      63             :     /*
      64             :      * Get the next tuple. Return NULL if no more tuples.
      65             :      */
      66      221924 :     if (ScanDirectionIsForward(direction))
      67             :     {
      68      221924 :         if (node->curr_idx < node->array_len)
      69      221924 :             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      221924 :     ExecClearTuple(slot);
      84             : 
      85      221924 :     curr_idx = node->curr_idx;
      86      221924 :     if (curr_idx >= 0 && curr_idx < node->array_len)
      87             :     {
      88      153684 :         List       *exprlist = node->exprlists[curr_idx];
      89      153684 :         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      153684 :         ReScanExprContext(econtext);
     102             : 
     103             :         /*
     104             :          * Do per-VALUES-row work in the per-tuple context.
     105             :          */
     106      153684 :         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      153684 :         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      153624 :             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      153684 :         values = slot->tts_values;
     139      153684 :         isnull = slot->tts_isnull;
     140             : 
     141      153684 :         resind = 0;
     142      330618 :         foreach(lc, exprstatelist)
     143             :         {
     144      176934 :             ExprState  *estate = (ExprState *) lfirst(lc);
     145      176934 :             Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor,
     146             :                                                    resind);
     147             : 
     148      176934 :             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      176934 :             values[resind] = MakeExpandedObjectReadOnly(values[resind],
     159             :                                                         isnull[resind],
     160             :                                                         attr->attlen);
     161             : 
     162      176934 :             resind++;
     163             :         }
     164             : 
     165      153684 :         MemoryContextSwitchTo(oldContext);
     166             : 
     167             :         /*
     168             :          * And return the virtual tuple.
     169             :          */
     170      153684 :         ExecStoreVirtualTuple(slot);
     171             :     }
     172             : 
     173      221924 :     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      220964 : ExecValuesScan(PlanState *pstate)
     197             : {
     198      220964 :     ValuesScanState *node = castNode(ValuesScanState, pstate);
     199             : 
     200      220964 :     return ExecScan(&node->ss,
     201             :                     (ExecScanAccessMtd) ValuesNext,
     202             :                     (ExecScanRecheckMtd) ValuesRecheck);
     203             : }
     204             : 
     205             : /* ----------------------------------------------------------------
     206             :  *      ExecInitValuesScan
     207             :  * ----------------------------------------------------------------
     208             :  */
     209             : ValuesScanState *
     210        8548 : 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        8548 :     scanstate = makeNode(ValuesScanState);
     228        8548 :     scanstate->ss.ps.plan = (Plan *) node;
     229        8548 :     scanstate->ss.ps.state = estate;
     230        8548 :     scanstate->ss.ps.ExecProcNode = ExecValuesScan;
     231             : 
     232             :     /*
     233             :      * Miscellaneous initialization
     234             :      */
     235        8548 :     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        8548 :     ExecAssignExprContext(estate, planstate);
     243        8548 :     scanstate->rowcontext = planstate->ps_ExprContext;
     244        8548 :     ExecAssignExprContext(estate, planstate);
     245             : 
     246             :     /*
     247             :      * Get info about values list, initialize scan slot with it.
     248             :      */
     249        8548 :     tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
     250        8548 :     ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
     251             : 
     252             :     /*
     253             :      * Initialize result type and projection.
     254             :      */
     255        8548 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     256        8548 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     257             : 
     258             :     /*
     259             :      * initialize child expressions
     260             :      */
     261        8548 :     scanstate->ss.ps.qual =
     262        8548 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     263             : 
     264             :     /*
     265             :      * Other node-specific setup
     266             :      */
     267        8548 :     scanstate->curr_idx = -1;
     268        8548 :     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        8548 :     scanstate->exprlists = (List **)
     281        8548 :         palloc(scanstate->array_len * sizeof(List *));
     282        8548 :     scanstate->exprstatelists = (List **)
     283        8548 :         palloc0(scanstate->array_len * sizeof(List *));
     284        8548 :     i = 0;
     285       42796 :     foreach(vtl, node->values_lists)
     286             :     {
     287       34248 :         List       *exprs = lfirst_node(List, vtl);
     288             : 
     289       34248 :         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       34666 :         if (estate->es_subplanstates &&
     296         418 :             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       34248 :         i++;
     316             :     }
     317             : 
     318        8548 :     return scanstate;
     319             : }
     320             : 
     321             : /* ----------------------------------------------------------------
     322             :  *      ExecReScanValuesScan
     323             :  *
     324             :  *      Rescans the relation.
     325             :  * ----------------------------------------------------------------
     326             :  */
     327             : void
     328       60398 : ExecReScanValuesScan(ValuesScanState *node)
     329             : {
     330       60398 :     if (node->ss.ps.ps_ResultTupleSlot)
     331          12 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     332             : 
     333       60398 :     ExecScanReScan(&node->ss);
     334             : 
     335       60398 :     node->curr_idx = -1;
     336       60398 : }

Generated by: LCOV version 1.14