]> granicus.if.org Git - postgresql/commitdiff
Don't convert Consts into Vars during setrefs.c processing.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 2 Nov 2016 18:32:13 +0000 (14:32 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 2 Nov 2016 18:32:13 +0000 (14:32 -0400)
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>

src/backend/optimizer/plan/setrefs.c
src/test/regress/expected/inherit.out

index d10a98396c7f75566ed0064ba9fa392b2bc54d7a..d91bc3b30de5c80f9112f52003cb794de72688fe 100644 (file)
@@ -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)
        {
index df7cba6614dc31ea48c8110f03016c67b9111bb3..79e9969d574f5ce03a9d3207722b53109c6b9afe 100644 (file)
@@ -1426,7 +1426,7 @@ ORDER BY thousand, tenthous;
    Sort Key: tenk1.thousand, tenk1.tenthous
    ->  Index Only Scan using tenk1_thous_tenthous on tenk1
    ->  Sort
-         Sort Key: (42), (42)
+         Sort Key: 42, 42
          ->  Index Only Scan using tenk1_hundred on tenk1 tenk1_1
 (6 rows)