Skip to content

Commit f4d865f

Browse files
committed
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>
1 parent 2a8783e commit f4d865f

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

src/backend/optimizer/plan/setrefs.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,19 @@ set_dummy_tlist_references(Plan *plan, int rtoffset)
18231823
Var *oldvar = (Var *) tle->expr;
18241824
Var *newvar;
18251825

1826+
/*
1827+
* As in search_indexed_tlist_for_non_var(), we prefer to keep Consts
1828+
* as Consts, not Vars referencing Consts. Here, there's no speed
1829+
* advantage to be had, but it makes EXPLAIN output look cleaner, and
1830+
* again it avoids confusing the executor.
1831+
*/
1832+
if (IsA(oldvar, Const))
1833+
{
1834+
/* just reuse the existing TLE node */
1835+
output_targetlist = lappend(output_targetlist, tle);
1836+
continue;
1837+
}
1838+
18261839
newvar = makeVar(OUTER_VAR,
18271840
tle->resno,
18281841
exprType((Node *) oldvar),
@@ -2010,6 +2023,16 @@ search_indexed_tlist_for_non_var(Node *node,
20102023
{
20112024
TargetEntry *tle;
20122025

2026+
/*
2027+
* If it's a simple Const, replacing it with a Var is silly, even if there
2028+
* happens to be an identical Const below; a Var is more expensive to
2029+
* execute than a Const. What's more, replacing it could confuse some
2030+
* places in the executor that expect to see simple Consts for, eg,
2031+
* dropped columns.
2032+
*/
2033+
if (IsA(node, Const))
2034+
return NULL;
2035+
20132036
tle = tlist_member(node, itlist->tlist);
20142037
if (tle)
20152038
{

src/test/regress/expected/inherit.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,7 @@ ORDER BY thousand, tenthous;
14261426
Sort Key: tenk1.thousand, tenk1.tenthous
14271427
-> Index Only Scan using tenk1_thous_tenthous on tenk1
14281428
-> Sort
1429-
Sort Key: (42), (42)
1429+
Sort Key: 42, 42
14301430
-> Index Only Scan using tenk1_hundred on tenk1 tenk1_1
14311431
(6 rows)
14321432

0 commit comments

Comments
 (0)