diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2006-08-02 18:58:21 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2006-08-02 18:58:21 +0000 |
commit | 0dfb595d7a5eb85617fb98f0eede0776e45bf3b4 (patch) | |
tree | 84e344f5aef749744dde70103591f979b572a622 /src/backend/executor/nodeValuesscan.c | |
parent | 9649b182a1548ea6fbbdb0ebab4e9e5e2bfe815b (diff) | |
download | postgresql-0dfb595d7a5eb85617fb98f0eede0776e45bf3b4.tar.gz postgresql-0dfb595d7a5eb85617fb98f0eede0776e45bf3b4.zip |
Arrange for ValuesScan to keep per-sublist expression eval state in a
temporary context that can be reset when advancing to the next sublist.
This is faster and more thorough at recovering space than the previous
method; moreover it will do the right thing if something in the sublist
tries to register an expression context callback.
Diffstat (limited to 'src/backend/executor/nodeValuesscan.c')
-rw-r--r-- | src/backend/executor/nodeValuesscan.c | 147 |
1 files changed, 77 insertions, 70 deletions
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index eb053d8cc76..1d4bb08d4dd 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.1 2006/08/02 01:59:45 joe Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.2 2006/08/02 18:58:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -30,9 +30,6 @@ static TupleTableSlot *ValuesNext(ValuesScanState *node); -static void ExecMakeValuesResult(List *targetlist, - ExprContext *econtext, - TupleTableSlot *slot); /* ---------------------------------------------------------------- @@ -61,7 +58,7 @@ ValuesNext(ValuesScanState *node) estate = node->ss.ps.state; direction = estate->es_direction; slot = node->ss.ss_ScanTupleSlot; - econtext = node->ss.ps.ps_ExprContext; + econtext = node->rowcontext; /* * Get the next tuple. Return NULL if no more tuples. @@ -85,73 +82,77 @@ ValuesNext(ValuesScanState *node) 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. + * 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); - 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) + if (exprlist) { - ExprState *estate = (ExprState *) lfirst(lc); - - values[resind] = ExecEvalExpr(estate, - econtext, - &isnull[resind], - NULL); - resind++; + MemoryContext oldContext; + List *exprstatelist; + Datum *values; + bool *isnull; + ListCell *lc; + int resind; + + /* + * Get rid of any prior cycle's leftovers. We use ReScanExprContext + * not just ResetExprContext because we want any registered shutdown + * callbacks to be called. + */ + 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. + */ + 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). + */ + exprstatelist = (List *) ExecInitExpr((Expr *) exprlist, NULL); + + /* 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). + */ + values = slot->tts_values; + isnull = slot->tts_isnull; + + resind = 0; + foreach(lc, exprstatelist) + { + ExprState *estate = (ExprState *) lfirst(lc); + + values[resind] = ExecEvalExpr(estate, + econtext, + &isnull[resind], + NULL); + resind++; + } + + MemoryContextSwitchTo(oldContext); + + /* + * And return the virtual tuple. + */ + ExecStoreVirtualTuple(slot); } - MemoryContextSwitchTo(oldContext); - - /* - * And return the virtual tuple. - */ - ExecStoreVirtualTuple(slot); + return slot; } @@ -186,7 +187,6 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) ListCell *vtl; int i; PlanState *planstate; - ExprContext *econtext; /* * ValuesScan should not have any children. @@ -203,12 +203,17 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) /* * Miscellaneous initialization - * - * create expression context for node */ 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. + */ + ExecAssignExprContext(estate, planstate); + scanstate->rowcontext = planstate->ps_ExprContext; ExecAssignExprContext(estate, planstate); - econtext = planstate->ps_ExprContext; #define VALUESSCAN_NSLOTS 2 @@ -282,9 +287,11 @@ void ExecEndValuesScan(ValuesScanState *node) { /* - * Free the exprcontext + * Free both exprcontexts */ ExecFreeExprContext(&node->ss.ps); + node->ss.ps.ps_ExprContext = node->rowcontext; + ExecFreeExprContext(&node->ss.ps); /* * clean out the tuple table |