aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2016-11-02 14:32:13 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2016-11-02 14:32:13 -0400
commitda8f3ebf30bef9c950595dc0d1f03bce2b1b8563 (patch)
treeb0bddd740f9230e69fbaf62627aca312b287be46 /src/backend
parent00a86856c1195f3f653672d3b06aa9e4a4aeab82 (diff)
downloadpostgresql-da8f3ebf30bef9c950595dc0d1f03bce2b1b8563.tar.gz
postgresql-da8f3ebf30bef9c950595dc0d1f03bce2b1b8563.zip
Don't convert Consts into Vars during setrefs.c processing.
While converting expressions in an upper-level plan node so that they reference Vars and expressions provided by the input plan node(s), don't convert plain Const items, even if there happens to be a matching Const in the input. It's silly to do so because a Var is more expensive to execute than a Const. Moreover, converting can fool ExecCheckPlanOutput's check that an insert or update query inserts nulls into dropped columns, leading to "query provides a value for a dropped column" errors during INSERT or UPDATE on a table with a dropped column. We could solve this by making that check more complicated, but I don't see the point; this fix should save a marginal number of cycles, and it also makes for less messy EXPLAIN output, as shown by the ensuing regression test result changes. Per report from Pavel HanĂ¡k. I have not incorporated a test case based on that example, as there doesn't seem to be a simple way of checking this in isolation without making a bunch of assumptions about other planner and SQL-function behavior. Back-patch to 9.6. This setrefs.c behavior exists much further back, but there is not currently reason to think that it causes problems before 9.6. Discussion: <83shraampf.fsf@is-it.eu>
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/optimizer/plan/setrefs.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index d10a98396c7..d91bc3b30de 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1823,6 +1823,19 @@ set_dummy_tlist_references(Plan *plan, int rtoffset)
Var *oldvar = (Var *) tle->expr;
Var *newvar;
+ /*
+ * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
+ * as Consts, not Vars referencing Consts. Here, there's no speed
+ * advantage to be had, but it makes EXPLAIN output look cleaner, and
+ * again it avoids confusing the executor.
+ */
+ if (IsA(oldvar, Const))
+ {
+ /* just reuse the existing TLE node */
+ output_targetlist = lappend(output_targetlist, tle);
+ continue;
+ }
+
newvar = makeVar(OUTER_VAR,
tle->resno,
exprType((Node *) oldvar),
@@ -2010,6 +2023,16 @@ search_indexed_tlist_for_non_var(Node *node,
{
TargetEntry *tle;
+ /*
+ * If it's a simple Const, replacing it with a Var is silly, even if there
+ * happens to be an identical Const below; a Var is more expensive to
+ * execute than a Const. What's more, replacing it could confuse some
+ * places in the executor that expect to see simple Consts for, eg,
+ * dropped columns.
+ */
+ if (IsA(node, Const))
+ return NULL;
+
tle = tlist_member(node, itlist->tlist);
if (tle)
{