aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorJoe Conway <mail@joeconway.com>2006-08-02 01:59:48 +0000
committerJoe Conway <mail@joeconway.com>2006-08-02 01:59:48 +0000
commit9caafda579f699b43fa4c89bf13a2331ef00611e (patch)
tree330423c4be56ffaacb2d028153706f0c213c0aec /src/backend/executor
parentd307c428cbb7c426e40163d234d993e644bbcc6b (diff)
downloadpostgresql-9caafda579f699b43fa4c89bf13a2331ef00611e.tar.gz
postgresql-9caafda579f699b43fa4c89bf13a2331ef00611e.zip
Add support for multi-row VALUES clauses as part of INSERT statements
(e.g. "INSERT ... VALUES (...), (...), ...") and elsewhere as allowed by the spec. (e.g. similar to a FROM clause subselect). initdb required. Joe Conway and Tom Lane.
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/Makefile5
-rw-r--r--src/backend/executor/execAmi.c22
-rw-r--r--src/backend/executor/execProcnode.c19
-rw-r--r--src/backend/executor/nodeValuesscan.c332
4 files changed, 372 insertions, 6 deletions
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index e9caf7d8373..7bc8eac7f51 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -4,7 +4,7 @@
# Makefile for executor
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/executor/Makefile,v 1.23 2005/04/19 22:35:11 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/executor/Makefile,v 1.24 2006/08/02 01:59:45 joe Exp $
#
#-------------------------------------------------------------------------
@@ -19,7 +19,8 @@ OBJS = execAmi.o execGrouping.o execJunk.o execMain.o \
nodeBitmapHeapscan.o nodeBitmapIndexscan.o nodeHash.o \
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
nodeNestloop.o nodeFunctionscan.o nodeResult.o nodeSeqscan.o \
- nodeSetOp.o nodeSort.o nodeUnique.o nodeLimit.o nodeGroup.o \
+ nodeSetOp.o nodeSort.o nodeUnique.o \
+ nodeValuesscan.o nodeLimit.o nodeGroup.o \
nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o tstoreReceiver.o spi.o
all: SUBSYS.o
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index df692d9bdfd..1d5246f9ecd 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.88 2006/07/14 14:52:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.89 2006/08/02 01:59:45 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,6 +38,7 @@
#include "executor/nodeSubqueryscan.h"
#include "executor/nodeTidscan.h"
#include "executor/nodeUnique.h"
+#include "executor/nodeValuesscan.h"
/*
@@ -144,6 +145,10 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
ExecFunctionReScan((FunctionScanState *) node, exprCtxt);
break;
+ case T_ValuesScanState:
+ ExecValuesReScan((ValuesScanState *) node, exprCtxt);
+ break;
+
case T_NestLoopState:
ExecReScanNestLoop((NestLoopState *) node, exprCtxt);
break;
@@ -226,6 +231,10 @@ ExecMarkPos(PlanState *node)
ExecFunctionMarkPos((FunctionScanState *) node);
break;
+ case T_ValuesScanState:
+ ExecValuesMarkPos((ValuesScanState *) node);
+ break;
+
case T_MaterialState:
ExecMaterialMarkPos((MaterialState *) node);
break;
@@ -275,6 +284,10 @@ ExecRestrPos(PlanState *node)
ExecFunctionRestrPos((FunctionScanState *) node);
break;
+ case T_ValuesScanState:
+ ExecValuesRestrPos((ValuesScanState *) node);
+ break;
+
case T_MaterialState:
ExecMaterialRestrPos((MaterialState *) node);
break;
@@ -298,8 +311,8 @@ ExecRestrPos(PlanState *node)
*
* (However, since the only present use of mark/restore is in mergejoin,
* there is no need to support mark/restore in any plan type that is not
- * capable of generating ordered output. So the seqscan, tidscan, and
- * functionscan support is actually useless code at present.)
+ * capable of generating ordered output. So the seqscan, tidscan,
+ * functionscan, and valuesscan support is actually useless code at present.)
*/
bool
ExecSupportsMarkRestore(NodeTag plantype)
@@ -310,6 +323,7 @@ ExecSupportsMarkRestore(NodeTag plantype)
case T_IndexScan:
case T_TidScan:
case T_FunctionScan:
+ case T_ValuesScan:
case T_Material:
case T_Sort:
return true;
@@ -359,6 +373,7 @@ ExecSupportsBackwardScan(Plan *node)
case T_IndexScan:
case T_TidScan:
case T_FunctionScan:
+ case T_ValuesScan:
return true;
case T_SubqueryScan:
@@ -413,6 +428,7 @@ ExecMayReturnRawTuples(PlanState *node)
case T_TidScanState:
case T_SubqueryScanState:
case T_FunctionScanState:
+ case T_ValuesScanState:
if (node->ps_ProjInfo == NULL)
return true;
break;
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 77f9f2e42ed..9f1fd54a8e5 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.57 2006/07/14 14:52:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.58 2006/08/02 01:59:45 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -102,6 +102,7 @@
#include "executor/nodeSubqueryscan.h"
#include "executor/nodeTidscan.h"
#include "executor/nodeUnique.h"
+#include "executor/nodeValuesscan.h"
#include "miscadmin.h"
/* ------------------------------------------------------------------------
@@ -194,6 +195,11 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
estate, eflags);
break;
+ case T_ValuesScan:
+ result = (PlanState *) ExecInitValuesScan((ValuesScan *) node,
+ estate, eflags);
+ break;
+
/*
* join nodes
*/
@@ -365,6 +371,10 @@ ExecProcNode(PlanState *node)
result = ExecFunctionScan((FunctionScanState *) node);
break;
+ case T_ValuesScanState:
+ result = ExecValuesScan((ValuesScanState *) node);
+ break;
+
/*
* join nodes
*/
@@ -536,6 +546,9 @@ ExecCountSlotsNode(Plan *node)
case T_FunctionScan:
return ExecCountSlotsFunctionScan((FunctionScan *) node);
+ case T_ValuesScan:
+ return ExecCountSlotsValuesScan((ValuesScan *) node);
+
/*
* join nodes
*/
@@ -669,6 +682,10 @@ ExecEndNode(PlanState *node)
ExecEndFunctionScan((FunctionScanState *) node);
break;
+ case T_ValuesScanState:
+ ExecEndValuesScan((ValuesScanState *) node);
+ break;
+
/*
* join nodes
*/
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
new file mode 100644
index 00000000000..eb053d8cc76
--- /dev/null
+++ b/src/backend/executor/nodeValuesscan.c
@@ -0,0 +1,332 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeValuesscan.c
+ * Support routines for scanning Values lists
+ * ("VALUES (...), (...), ..." in rangetable).
+ *
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.1 2006/08/02 01:59:45 joe Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * INTERFACE ROUTINES
+ * ExecValuesScan scans a values list.
+ * ExecValuesNext retrieve next tuple in sequential order.
+ * ExecInitValuesScan creates and initializes a valuesscan node.
+ * ExecEndValuesScan releases any storage allocated.
+ * ExecValuesReScan rescans the values list
+ */
+#include "postgres.h"
+
+#include "executor/executor.h"
+#include "executor/nodeValuesscan.h"
+#include "parser/parsetree.h"
+#include "utils/memutils.h"
+
+
+static TupleTableSlot *ValuesNext(ValuesScanState *node);
+static void ExecMakeValuesResult(List *targetlist,
+ ExprContext *econtext,
+ TupleTableSlot *slot);
+
+
+/* ----------------------------------------------------------------
+ * Scan Support
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------
+ * ValuesNext
+ *
+ * This is a workhorse for ExecValuesScan
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ValuesNext(ValuesScanState *node)
+{
+ TupleTableSlot *slot;
+ EState *estate;
+ ExprContext *econtext;
+ ScanDirection direction;
+ List *exprlist;
+
+ /*
+ * get information from the estate and scan state
+ */
+ estate = node->ss.ps.state;
+ direction = estate->es_direction;
+ slot = node->ss.ss_ScanTupleSlot;
+ econtext = node->ss.ps.ps_ExprContext;
+
+ /*
+ * Get the next tuple. Return NULL if no more tuples.
+ */
+ if (ScanDirectionIsForward(direction))
+ {
+ if (node->curr_idx < node->array_len)
+ node->curr_idx++;
+ if (node->curr_idx < node->array_len)
+ exprlist = node->exprlists[node->curr_idx];
+ else
+ exprlist = NIL;
+ }
+ else
+ {
+ if (node->curr_idx >= 0)
+ node->curr_idx--;
+ if (node->curr_idx >= 0)
+ exprlist = node->exprlists[node->curr_idx];
+ else
+ exprlist = NIL;
+ }
+
+ if (exprlist)
+ {
+ List *init_exprlist;
+
+ init_exprlist = (List *) ExecInitExpr((Expr *) exprlist,
+ (PlanState *) node);
+ ExecMakeValuesResult(init_exprlist,
+ econtext,
+ slot);
+ list_free_deep(init_exprlist);
+ }
+ else
+ ExecClearTuple(slot);
+
+ return slot;
+}
+
+/*
+ * ExecMakeValuesResult
+ *
+ * Evaluate a values list, store into a virtual slot.
+ */
+static void
+ExecMakeValuesResult(List *targetlist,
+ ExprContext *econtext,
+ TupleTableSlot *slot)
+{
+ MemoryContext oldContext;
+ Datum *values;
+ bool *isnull;
+ ListCell *lc;
+ int resind = 0;
+
+ /* caller should have checked all targetlists are the same length */
+ Assert(list_length(targetlist) == slot->tts_tupleDescriptor->natts);
+
+ /*
+ * Prepare to build a virtual result tuple.
+ */
+ ExecClearTuple(slot);
+ values = slot->tts_values;
+ isnull = slot->tts_isnull;
+
+ /*
+ * Switch to short-lived context for evaluating the row.
+ * Reset per-tuple memory context before each row.
+ */
+ ResetExprContext(econtext);
+ oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+
+ foreach(lc, targetlist)
+ {
+ ExprState *estate = (ExprState *) lfirst(lc);
+
+ values[resind] = ExecEvalExpr(estate,
+ econtext,
+ &isnull[resind],
+ NULL);
+ resind++;
+ }
+
+ MemoryContextSwitchTo(oldContext);
+
+ /*
+ * And return the virtual tuple.
+ */
+ ExecStoreVirtualTuple(slot);
+}
+
+
+/* ----------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------
+ */
+TupleTableSlot *
+ExecValuesScan(ValuesScanState *node)
+{
+ /*
+ * use ValuesNext as access method
+ */
+ return ExecScan(&node->ss, (ExecScanAccessMtd) ValuesNext);
+}
+
+/* ----------------------------------------------------------------
+ * ExecInitValuesScan
+ * ----------------------------------------------------------------
+ */
+ValuesScanState *
+ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
+{
+ ValuesScanState *scanstate;
+ RangeTblEntry *rte;
+ TupleDesc tupdesc;
+ ListCell *vtl;
+ int i;
+ PlanState *planstate;
+ ExprContext *econtext;
+
+ /*
+ * ValuesScan should not have any children.
+ */
+ Assert(outerPlan(node) == NULL);
+ Assert(innerPlan(node) == NULL);
+
+ /*
+ * create new ScanState for node
+ */
+ scanstate = makeNode(ValuesScanState);
+ scanstate->ss.ps.plan = (Plan *) node;
+ scanstate->ss.ps.state = estate;
+
+ /*
+ * Miscellaneous initialization
+ *
+ * create expression context for node
+ */
+ planstate = &scanstate->ss.ps;
+ ExecAssignExprContext(estate, planstate);
+ econtext = planstate->ps_ExprContext;
+
+#define VALUESSCAN_NSLOTS 2
+
+ /*
+ * tuple table initialization
+ */
+ ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
+ ExecInitScanTupleSlot(estate, &scanstate->ss);
+
+ /*
+ * initialize child expressions
+ */
+ 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);
+
+ /*
+ * get info about values list
+ */
+ 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);
+
+ /*
+ * Other node-specific setup
+ */
+ scanstate->marked_idx = -1;
+ scanstate->curr_idx = -1;
+ scanstate->array_len = list_length(rte->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)
+ {
+ 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
+ *
+ * frees any storage allocated through C routines.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndValuesScan(ValuesScanState *node)
+{
+ /*
+ * Free the exprcontext
+ */
+ ExecFreeExprContext(&node->ss.ps);
+
+ /*
+ * clean out the tuple table
+ */
+ 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
+ *
+ * Rescans the relation.
+ * ----------------------------------------------------------------
+ */
+void
+ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt)
+{
+ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+
+ node->curr_idx = -1;
+}