diff options
Diffstat (limited to 'src/backend/executor/nodeValuesscan.c')
-rw-r--r-- | src/backend/executor/nodeValuesscan.c | 83 |
1 files changed, 50 insertions, 33 deletions
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index 734795dcbf1..be126755618 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -25,6 +25,7 @@ #include "executor/executor.h" #include "executor/nodeValuesscan.h" +#include "optimizer/clauses.h" #include "utils/expandeddatum.h" @@ -49,7 +50,7 @@ ValuesNext(ValuesScanState *node) EState *estate; ExprContext *econtext; ScanDirection direction; - List *exprlist; + int curr_idx; /* * get information from the estate and scan state @@ -66,19 +67,11 @@ ValuesNext(ValuesScanState *node) { 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; } /* @@ -89,11 +82,12 @@ ValuesNext(ValuesScanState *node) */ ExecClearTuple(slot); - if (exprlist) + curr_idx = node->curr_idx; + if (curr_idx >= 0 && curr_idx < node->array_len) { + List *exprlist = node->exprlists[curr_idx]; + List *exprstatelist = node->exprstatelists[curr_idx]; MemoryContext oldContext; - List *oldsubplans; - List *exprstatelist; Datum *values; bool *isnull; Form_pg_attribute *att; @@ -108,30 +102,28 @@ ValuesNext(ValuesScanState *node) 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. + * Do per-VALUES-row work in the per-tuple context. */ oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); /* - * 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.) + * Unless we already made the expression eval state for this row, + * build it 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. For rows in which that won't work, we already built + * the eval state at plan startup. */ - oldsubplans = node->ss.ps.subPlan; - node->ss.ps.subPlan = NIL; - - exprstatelist = ExecInitExprList(exprlist, &node->ss.ps); - - node->ss.ps.subPlan = oldsubplans; + if (exprstatelist == NIL) + { + /* + * Pass parent as NULL, not my plan node, because we don't want + * anything in this transient state linking into permanent state. + * The only expression type that might wish to do so is a SubPlan, + * and we already checked that there aren't any. + */ + exprstatelist = ExecInitExprList(exprlist, NULL); + } /* parser should have checked all sublists are the same length */ Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts); @@ -272,13 +264,38 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) scanstate->curr_idx = -1; scanstate->array_len = list_length(node->values_lists); - /* convert list of sublists into array of sublists for easy addressing */ + /* + * Convert the list of expression sublists into an array for easier + * addressing at runtime. Also, detect whether any sublists contain + * SubPlans; for just those sublists, go ahead and do expression + * initialization. (This avoids problems with SubPlans wanting to connect + * themselves up to the outer plan tree. Notably, EXPLAIN won't see the + * subplans otherwise; also we will have troubles with dangling pointers + * and/or leaked resources if we try to handle SubPlans the same as + * simpler expressions.) + */ scanstate->exprlists = (List **) palloc(scanstate->array_len * sizeof(List *)); + scanstate->exprstatelists = (List **) + palloc0(scanstate->array_len * sizeof(List *)); i = 0; foreach(vtl, node->values_lists) { - scanstate->exprlists[i++] = (List *) lfirst(vtl); + List *exprs = castNode(List, lfirst(vtl)); + + scanstate->exprlists[i] = exprs; + + /* + * We can avoid the cost of a contain_subplans() scan in the simple + * case where there are no SubPlans anywhere. + */ + if (estate->es_subplanstates && + contain_subplans((Node *) exprs)) + { + scanstate->exprstatelists[i] = ExecInitExprList(exprs, + &scanstate->ss.ps); + } + i++; } /* |