]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/nodeValuesscan.c
Make some small planner API cleanups.
[postgresql] / src / backend / executor / nodeValuesscan.c
index 1d4bb08d4dded3fe28119d37d722c7914323c045..0069a73588ad666de879f7d6f7c1ee528a0606b8 100644 (file)
@@ -2,14 +2,14 @@
  *
  * nodeValuesscan.c
  *       Support routines for scanning Values lists
- *    ("VALUES (...), (...), ..." in rangetable).
+ *       ("VALUES (...), (...), ..." in rangetable).
  *
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.2 2006/08/02 18:58:21 tgl Exp $
+ *       src/backend/executor/nodeValuesscan.c
  *
  *-------------------------------------------------------------------------
  */
  *             ExecValuesNext                  retrieve next tuple in sequential order.
  *             ExecInitValuesScan              creates and initializes a valuesscan node.
  *             ExecEndValuesScan               releases any storage allocated.
- *             ExecValuesReScan                rescans the values list
+ *             ExecReScanValuesScan    rescans the values list
  */
 #include "postgres.h"
 
 #include "executor/executor.h"
 #include "executor/nodeValuesscan.h"
-#include "parser/parsetree.h"
-#include "utils/memutils.h"
+#include "jit/jit.h"
+#include "utils/expandeddatum.h"
 
 
 static TupleTableSlot *ValuesNext(ValuesScanState *node);
@@ -47,10 +47,10 @@ static TupleTableSlot *
 ValuesNext(ValuesScanState *node)
 {
        TupleTableSlot *slot;
-       EState             *estate;
-       ExprContext        *econtext;
-       ScanDirection   direction;
-       List               *exprlist;
+       EState     *estate;
+       ExprContext *econtext;
+       ScanDirection direction;
+       List       *exprlist;
 
        /*
         * get information from the estate and scan state
@@ -83,9 +83,9 @@ ValuesNext(ValuesScanState *node)
        }
 
        /*
-        * Always clear the result slot; this is appropriate if we are at the
-        * end of the data, and if we're not, we still need it as the first step
-        * of the store-virtual-tuple protocol.  It seems wise to clear the slot
+        * Always clear the result slot; this is appropriate if we are at the end
+        * of the data, and if we're not, we still need it as the first step of
+        * the store-virtual-tuple protocol.  It seems wise to clear the slot
         * before we reset the context it might have pointers into.
         */
        ExecClearTuple(slot);
@@ -93,11 +93,13 @@ ValuesNext(ValuesScanState *node)
        if (exprlist)
        {
                MemoryContext oldContext;
+               List       *oldsubplans;
                List       *exprstatelist;
                Datum      *values;
                bool       *isnull;
                ListCell   *lc;
                int                     resind;
+               int                     saved_jit_flags;
 
                /*
                 * Get rid of any prior cycle's leftovers.  We use ReScanExprContext
@@ -107,27 +109,45 @@ ValuesNext(ValuesScanState *node)
                ReScanExprContext(econtext);
 
                /*
-                * Build the expression eval state in the econtext's per-tuple
-                * memory.  This is a tad unusual, but we want to delete the eval
-                * state again when we move to the next row, to avoid growth of
-                * memory requirements over a long values list.
+                * Build the expression eval state in the econtext's per-tuple memory.
+                * This is a tad unusual, but we want to delete the eval state again
+                * when we move to the next row, to avoid growth of memory
+                * requirements over a long values list.
                 */
                oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 
                /*
-                * Pass NULL, not my plan node, because we don't want anything
-                * in this transient state linking into permanent state.  The
-                * only possibility is a SubPlan, and there shouldn't be any
-                * (any subselects in the VALUES list should be InitPlans).
+                * The expressions might contain SubPlans (this is currently only
+                * possible if there's a sub-select containing a LATERAL reference,
+                * otherwise sub-selects in a VALUES list should be InitPlans). Those
+                * subplans will want to hook themselves into our subPlan list, which
+                * would result in a corrupted list after we delete the eval state. We
+                * can work around this by saving and restoring the subPlan list.
+                * (There's no need for the functionality that would be enabled by
+                * having the list entries, since the SubPlans aren't going to be
+                * re-executed anyway.)
                 */
-               exprstatelist = (List *) ExecInitExpr((Expr *) exprlist, NULL);
+               oldsubplans = node->ss.ps.subPlan;
+               node->ss.ps.subPlan = NIL;
+
+               /*
+                * As the expressions are only ever used once, disable JIT for them.
+                * This is worthwhile because it's common to insert significant
+                * amounts of data via VALUES().
+                */
+               saved_jit_flags = econtext->ecxt_estate->es_jit_flags;
+               econtext->ecxt_estate->es_jit_flags = PGJIT_NONE;
+               exprstatelist = ExecInitExprList(exprlist, &node->ss.ps);
+               econtext->ecxt_estate->es_jit_flags = saved_jit_flags;
+
+               node->ss.ps.subPlan = oldsubplans;
 
                /* parser should have checked all sublists are the same length */
                Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts);
 
                /*
-                * Compute the expressions and build a virtual result tuple.
-                * We already did ExecClearTuple(slot).
+                * Compute the expressions and build a virtual result tuple. We
+                * already did ExecClearTuple(slot).
                 */
                values = slot->tts_values;
                isnull = slot->tts_isnull;
@@ -135,12 +155,24 @@ ValuesNext(ValuesScanState *node)
                resind = 0;
                foreach(lc, exprstatelist)
                {
-                       ExprState *estate = (ExprState *) lfirst(lc);
+                       ExprState  *estate = (ExprState *) lfirst(lc);
+                       Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor,
+                                                                                                  resind);
 
                        values[resind] = ExecEvalExpr(estate,
                                                                                  econtext,
-                                                                                 &isnull[resind],
-                                                                                 NULL);
+                                                                                 &isnull[resind]);
+
+                       /*
+                        * We must force any R/W expanded datums to read-only state, in
+                        * case they are multiply referenced in the plan node's output
+                        * expressions, or in case we skip the output projection and the
+                        * output column is multiply referenced in higher plan nodes.
+                        */
+                       values[resind] = MakeExpandedObjectReadOnly(values[resind],
+                                                                                                               isnull[resind],
+                                                                                                               attr->attlen);
+
                        resind++;
                }
 
@@ -155,23 +187,33 @@ ValuesNext(ValuesScanState *node)
        return slot;
 }
 
+/*
+ * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
+ */
+static bool
+ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
+{
+       /* nothing to check */
+       return true;
+}
 
 /* ----------------------------------------------------------------
  *             ExecValuesScan(node)
  *
  *             Scans the values lists sequentially and returns the next qualifying
  *             tuple.
- *             It calls the ExecScan() routine and passes it the access method
- *             which retrieves tuples sequentially.
+ *             We call the ExecScan() routine and pass it the appropriate
+ *             access method functions.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
-ExecValuesScan(ValuesScanState *node)
+static TupleTableSlot *
+ExecValuesScan(PlanState *pstate)
 {
-       /*
-        * use ValuesNext as access method
-        */
-       return ExecScan(&node->ss, (ExecScanAccessMtd) ValuesNext);
+       ValuesScanState *node = castNode(ValuesScanState, pstate);
+
+       return ExecScan(&node->ss,
+                                       (ExecScanAccessMtd) ValuesNext,
+                                       (ExecScanRecheckMtd) ValuesRecheck);
 }
 
 /* ----------------------------------------------------------------
@@ -181,12 +223,11 @@ ExecValuesScan(ValuesScanState *node)
 ValuesScanState *
 ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
 {
-       ValuesScanState    *scanstate;
-       RangeTblEntry      *rte;
-       TupleDesc                       tupdesc;
-       ListCell                   *vtl;
-       int                                     i;
-       PlanState                  *planstate;
+       ValuesScanState *scanstate;
+       TupleDesc       tupdesc;
+       ListCell   *vtl;
+       int                     i;
+       PlanState  *planstate;
 
        /*
         * ValuesScan should not have any children.
@@ -200,6 +241,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
        scanstate = makeNode(ValuesScanState);
        scanstate->ss.ps.plan = (Plan *) node;
        scanstate->ss.ps.state = estate;
+       scanstate->ss.ps.ExecProcNode = ExecValuesScan;
 
        /*
         * Miscellaneous initialization
@@ -207,76 +249,50 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
        planstate = &scanstate->ss.ps;
 
        /*
-        * Create expression contexts.  We need two, one for per-sublist
-        * processing and one for execScan.c to use for quals and projections.
-        * We cheat a little by using ExecAssignExprContext() to build both.
+        * Create expression contexts.  We need two, one for per-sublist
+        * processing and one for execScan.c to use for quals and projections. We
+        * cheat a little by using ExecAssignExprContext() to build both.
         */
        ExecAssignExprContext(estate, planstate);
        scanstate->rowcontext = planstate->ps_ExprContext;
        ExecAssignExprContext(estate, planstate);
 
-#define VALUESSCAN_NSLOTS 2
-
        /*
-        * tuple table initialization
+        * Get info about values list, initialize scan slot with it.
         */
-       ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
-       ExecInitScanTupleSlot(estate, &scanstate->ss);
+       tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
+       ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc, &TTSOpsVirtual);
 
        /*
-        * initialize child expressions
+        * Initialize result type and projection.
         */
-       scanstate->ss.ps.targetlist = (List *)
-               ExecInitExpr((Expr *) node->scan.plan.targetlist,
-                                        (PlanState *) scanstate);
-       scanstate->ss.ps.qual = (List *)
-               ExecInitExpr((Expr *) node->scan.plan.qual,
-                                        (PlanState *) scanstate);
+       ExecInitResultTypeTL(&scanstate->ss.ps);
+       ExecAssignScanProjectionInfo(&scanstate->ss);
 
        /*
-        * get info about values list
+        * initialize child expressions
         */
-       rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
-       Assert(rte->rtekind == RTE_VALUES);
-       tupdesc = ExecTypeFromExprList((List *) linitial(rte->values_lists));
-
-       ExecAssignScanType(&scanstate->ss, tupdesc);
+       scanstate->ss.ps.qual =
+               ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
 
        /*
         * Other node-specific setup
         */
-       scanstate->marked_idx = -1;
        scanstate->curr_idx = -1;
-       scanstate->array_len = list_length(rte->values_lists);
+       scanstate->array_len = list_length(node->values_lists);
 
        /* convert list of sublists into array of sublists for easy addressing */
        scanstate->exprlists = (List **)
                palloc(scanstate->array_len * sizeof(List *));
        i = 0;
-       foreach(vtl, rte->values_lists)
+       foreach(vtl, node->values_lists)
        {
                scanstate->exprlists[i++] = (List *) lfirst(vtl);
        }
 
-       scanstate->ss.ps.ps_TupFromTlist = false;
-
-       /*
-        * Initialize result tuple type and projection info.
-        */
-       ExecAssignResultTypeFromTL(&scanstate->ss.ps);
-       ExecAssignScanProjectionInfo(&scanstate->ss);
-
        return scanstate;
 }
 
-int
-ExecCountSlotsValuesScan(ValuesScan *node)
-{
-       return ExecCountSlotsNode(outerPlan(node)) +
-               ExecCountSlotsNode(innerPlan(node)) +
-               VALUESSCAN_NSLOTS;
-}
-
 /* ----------------------------------------------------------------
  *             ExecEndValuesScan
  *
@@ -296,44 +312,24 @@ ExecEndValuesScan(ValuesScanState *node)
        /*
         * clean out the tuple table
         */
-       ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+       if (node->ss.ps.ps_ResultTupleSlot)
+               ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
        ExecClearTuple(node->ss.ss_ScanTupleSlot);
 }
 
 /* ----------------------------------------------------------------
- *             ExecValuesMarkPos
- *
- *             Marks scan position.
- * ----------------------------------------------------------------
- */
-void
-ExecValuesMarkPos(ValuesScanState *node)
-{
-       node->marked_idx = node->curr_idx;
-}
-
-/* ----------------------------------------------------------------
- *             ExecValuesRestrPos
- *
- *             Restores scan position.
- * ----------------------------------------------------------------
- */
-void
-ExecValuesRestrPos(ValuesScanState *node)
-{
-       node->curr_idx = node->marked_idx;
-}
-
-/* ----------------------------------------------------------------
- *             ExecValuesReScan
+ *             ExecReScanValuesScan
  *
  *             Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt)
+ExecReScanValuesScan(ValuesScanState *node)
 {
-       ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+       if (node->ss.ps.ps_ResultTupleSlot)
+               ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+
+       ExecScanReScan(&node->ss);
 
        node->curr_idx = -1;
 }