* Support routines for scanning Values lists
* ("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.4 2006/12/26 19:26:46 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);
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
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);
foreach(lc, exprstatelist)
{
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++;
}
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);
}
/* ----------------------------------------------------------------
ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
{
ValuesScanState *scanstate;
- RangeTblEntry *rte;
TupleDesc tupdesc;
ListCell *vtl;
int i;
scanstate = makeNode(ValuesScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecValuesScan;
/*
* Miscellaneous initialization
planstate = &scanstate->ss.ps;
/*
- * Create expression contexts. We need two, one for per-sublist
+ * 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.
*/
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
*
/*
* 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);
- node->ss.ps.ps_TupFromTlist = false;
+ if (node->ss.ps.ps_ResultTupleSlot)
+ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+
+ ExecScanReScan(&node->ss);
node->curr_idx = -1;
}