diff options
author | Joe Conway <mail@joeconway.com> | 2006-08-02 01:59:48 +0000 |
---|---|---|
committer | Joe Conway <mail@joeconway.com> | 2006-08-02 01:59:48 +0000 |
commit | 9caafda579f699b43fa4c89bf13a2331ef00611e (patch) | |
tree | 330423c4be56ffaacb2d028153706f0c213c0aec /src/backend/executor | |
parent | d307c428cbb7c426e40163d234d993e644bbcc6b (diff) | |
download | postgresql-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/Makefile | 5 | ||||
-rw-r--r-- | src/backend/executor/execAmi.c | 22 | ||||
-rw-r--r-- | src/backend/executor/execProcnode.c | 19 | ||||
-rw-r--r-- | src/backend/executor/nodeValuesscan.c | 332 |
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; +} |