Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0dfb595

Browse files
committed
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.
1 parent 9649b18 commit 0dfb595

File tree

2 files changed

+87
-73
lines changed

2 files changed

+87
-73
lines changed

src/backend/executor/nodeValuesscan.c

Lines changed: 77 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.1 2006/08/02 01:59:45 joe Exp $
12+
* $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.2 2006/08/02 18:58:21 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -30,9 +30,6 @@
3030

3131

3232
static TupleTableSlot *ValuesNext(ValuesScanState *node);
33-
static void ExecMakeValuesResult(List *targetlist,
34-
ExprContext *econtext,
35-
TupleTableSlot *slot);
3633

3734

3835
/* ----------------------------------------------------------------
@@ -61,7 +58,7 @@ ValuesNext(ValuesScanState *node)
6158
estate = node->ss.ps.state;
6259
direction = estate->es_direction;
6360
slot = node->ss.ss_ScanTupleSlot;
64-
econtext = node->ss.ps.ps_ExprContext;
61+
econtext = node->rowcontext;
6562

6663
/*
6764
* Get the next tuple. Return NULL if no more tuples.
@@ -85,73 +82,77 @@ ValuesNext(ValuesScanState *node)
8582
exprlist = NIL;
8683
}
8784

88-
if (exprlist)
89-
{
90-
List *init_exprlist;
91-
92-
init_exprlist = (List *) ExecInitExpr((Expr *) exprlist,
93-
(PlanState *) node);
94-
ExecMakeValuesResult(init_exprlist,
95-
econtext,
96-
slot);
97-
list_free_deep(init_exprlist);
98-
}
99-
else
100-
ExecClearTuple(slot);
101-
102-
return slot;
103-
}
104-
105-
/*
106-
* ExecMakeValuesResult
107-
*
108-
* Evaluate a values list, store into a virtual slot.
109-
*/
110-
static void
111-
ExecMakeValuesResult(List *targetlist,
112-
ExprContext *econtext,
113-
TupleTableSlot *slot)
114-
{
115-
MemoryContext oldContext;
116-
Datum *values;
117-
bool *isnull;
118-
ListCell *lc;
119-
int resind = 0;
120-
121-
/* caller should have checked all targetlists are the same length */
122-
Assert(list_length(targetlist) == slot->tts_tupleDescriptor->natts);
123-
12485
/*
125-
* Prepare to build a virtual result tuple.
86+
* Always clear the result slot; this is appropriate if we are at the
87+
* end of the data, and if we're not, we still need it as the first step
88+
* of the store-virtual-tuple protocol. It seems wise to clear the slot
89+
* before we reset the context it might have pointers into.
12690
*/
12791
ExecClearTuple(slot);
128-
values = slot->tts_values;
129-
isnull = slot->tts_isnull;
13092

131-
/*
132-
* Switch to short-lived context for evaluating the row.
133-
* Reset per-tuple memory context before each row.
134-
*/
135-
ResetExprContext(econtext);
136-
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
137-
138-
foreach(lc, targetlist)
93+
if (exprlist)
13994
{
140-
ExprState *estate = (ExprState *) lfirst(lc);
141-
142-
values[resind] = ExecEvalExpr(estate,
143-
econtext,
144-
&isnull[resind],
145-
NULL);
146-
resind++;
95+
MemoryContext oldContext;
96+
List *exprstatelist;
97+
Datum *values;
98+
bool *isnull;
99+
ListCell *lc;
100+
int resind;
101+
102+
/*
103+
* Get rid of any prior cycle's leftovers. We use ReScanExprContext
104+
* not just ResetExprContext because we want any registered shutdown
105+
* callbacks to be called.
106+
*/
107+
ReScanExprContext(econtext);
108+
109+
/*
110+
* Build the expression eval state in the econtext's per-tuple
111+
* memory. This is a tad unusual, but we want to delete the eval
112+
* state again when we move to the next row, to avoid growth of
113+
* memory requirements over a long values list.
114+
*/
115+
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
116+
117+
/*
118+
* Pass NULL, not my plan node, because we don't want anything
119+
* in this transient state linking into permanent state. The
120+
* only possibility is a SubPlan, and there shouldn't be any
121+
* (any subselects in the VALUES list should be InitPlans).
122+
*/
123+
exprstatelist = (List *) ExecInitExpr((Expr *) exprlist, NULL);
124+
125+
/* parser should have checked all sublists are the same length */
126+
Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts);
127+
128+
/*
129+
* Compute the expressions and build a virtual result tuple.
130+
* We already did ExecClearTuple(slot).
131+
*/
132+
values = slot->tts_values;
133+
isnull = slot->tts_isnull;
134+
135+
resind = 0;
136+
foreach(lc, exprstatelist)
137+
{
138+
ExprState *estate = (ExprState *) lfirst(lc);
139+
140+
values[resind] = ExecEvalExpr(estate,
141+
econtext,
142+
&isnull[resind],
143+
NULL);
144+
resind++;
145+
}
146+
147+
MemoryContextSwitchTo(oldContext);
148+
149+
/*
150+
* And return the virtual tuple.
151+
*/
152+
ExecStoreVirtualTuple(slot);
147153
}
148154

149-
MemoryContextSwitchTo(oldContext);
150-
151-
/*
152-
* And return the virtual tuple.
153-
*/
154-
ExecStoreVirtualTuple(slot);
155+
return slot;
155156
}
156157

157158

@@ -186,7 +187,6 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
186187
ListCell *vtl;
187188
int i;
188189
PlanState *planstate;
189-
ExprContext *econtext;
190190

191191
/*
192192
* ValuesScan should not have any children.
@@ -203,12 +203,17 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
203203

204204
/*
205205
* Miscellaneous initialization
206-
*
207-
* create expression context for node
208206
*/
209207
planstate = &scanstate->ss.ps;
208+
209+
/*
210+
* Create expression contexts. We need two, one for per-sublist
211+
* processing and one for execScan.c to use for quals and projections.
212+
* We cheat a little by using ExecAssignExprContext() to build both.
213+
*/
214+
ExecAssignExprContext(estate, planstate);
215+
scanstate->rowcontext = planstate->ps_ExprContext;
210216
ExecAssignExprContext(estate, planstate);
211-
econtext = planstate->ps_ExprContext;
212217

213218
#define VALUESSCAN_NSLOTS 2
214219

@@ -282,9 +287,11 @@ void
282287
ExecEndValuesScan(ValuesScanState *node)
283288
{
284289
/*
285-
* Free the exprcontext
290+
* Free both exprcontexts
286291
*/
287292
ExecFreeExprContext(&node->ss.ps);
293+
node->ss.ps.ps_ExprContext = node->rowcontext;
294+
ExecFreeExprContext(&node->ss.ps);
288295

289296
/*
290297
* clean out the tuple table

src/include/nodes/execnodes.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.156 2006/08/02 01:59:47 joe Exp $
10+
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.157 2006/08/02 18:58:21 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -1044,18 +1044,25 @@ typedef struct FunctionScanState
10441044
/* ----------------
10451045
* ValuesScanState information
10461046
*
1047-
* Values nodes are used to scan the results of a
1048-
* values list appearing in FROM or INSERT
1047+
* ValuesScan nodes are used to scan the results of a VALUES list
10491048
*
1049+
* rowcontext per-expression-list context
10501050
* exprlists array of expression lists being evaluated
10511051
* array_len size of array
10521052
* curr_idx current array index (0-based)
10531053
* marked_idx marked position (for mark/restore)
1054+
*
1055+
* Note: ss.ps.ps_ExprContext is used to evaluate any qual or projection
1056+
* expressions attached to the node. We create a second ExprContext,
1057+
* rowcontext, in which to build the executor expression state for each
1058+
* Values sublist. Resetting this context lets us get rid of expression
1059+
* state for each row, avoiding major memory leakage over a long values list.
10541060
* ----------------
10551061
*/
10561062
typedef struct ValuesScanState
10571063
{
10581064
ScanState ss; /* its first field is NodeTag */
1065+
ExprContext *rowcontext;
10591066
List **exprlists;
10601067
int array_len;
10611068
int curr_idx;

0 commit comments

Comments
 (0)