Re: Problems with "pg.dropped" column after upgrade 9.5 to 9.6 - Mailing list pgsql-bugs

From Tom Lane
Subject Re: Problems with "pg.dropped" column after upgrade 9.5 to 9.6
Date
Msg-id 27650.1478106537@sss.pgh.pa.us
Whole thread Raw
In response to Re: Problems with "pg.dropped" column after upgrade 9.5 to 9.6  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Problems with "pg.dropped" column after upgrade 9.5 to 9.6
List pgsql-bugs
I wrote:
> So I'm pretty tempted to fix it as per attached, that is, teach setrefs.c
> that it's silly to try to convert a Const into a Var.  It is sane to
> replace more-complicated expressions with Vars, because that means we save
> re-evaluating those expressions.  But a quick look at ExecEvalConst and
> ExecEvalVar shows that a Const is strictly cheaper to execute than a Var,
> so doing such a conversion is actually a pessimization.

After further poking around, I concluded that it'd be a good idea to make
a similar change in set_dummy_tlist_references(), to prevent a failure
if the top plan node below ModifyTable chances to be a Sort or other
non-projecting plan node.  I'm not sure such a case can arise today, but
I'm not sure it can't either.

With that, there are a couple more changes in regression test EXPLAIN
output.  A full patch that passes "make check-world" is attached.

I'm not sure if it's worth memorializing the specific test case discussed
in this thread as a regression test.  It depends enough on the behavior
of SQL function planning that I wouldn't have much confidence in it
continuing to test what we meant it to test going forward.

            regards, tom lane

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 2745ad5..7339b58 100644
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
*************** select count(c2) w, c2 x, 5 y, 7.0 z fro
*** 2447,2456 ****
                                                  QUERY PLAN
  ----------------------------------------------------------------------------------------------------------
   Sort
!    Output: (count(c2)), c2, (5), (7.0), (9)
     Sort Key: ft1.c2
     ->  Foreign Scan
!          Output: (count(c2)), c2, (5), (7.0), (9)
           Relations: Aggregate on (public.ft1)
           Remote SQL: SELECT count(c2), c2, 5, 7.0, 9 FROM "S 1"."T 1" GROUP BY c2, 5::integer, 9::integer
  (7 rows)
--- 2447,2456 ----
                                                  QUERY PLAN
  ----------------------------------------------------------------------------------------------------------
   Sort
!    Output: (count(c2)), c2, 5, 7.0, 9
     Sort Key: ft1.c2
     ->  Foreign Scan
!          Output: (count(c2)), c2, 5, 7.0, 9
           Relations: Aggregate on (public.ft1)
           Remote SQL: SELECT count(c2), c2, 5, 7.0, 9 FROM "S 1"."T 1" GROUP BY c2, 5::integer, 9::integer
  (7 rows)
*************** select count(*) from (select c5, count(c
*** 2499,2505 ****
   Aggregate
     Output: count(*)
     ->  Foreign Scan
!          Output: ft1.c5, (NULL::bigint), (sqrt((ft1.c2)::double precision))
           Filter: (((((avg(ft1.c1)) / (avg(ft1.c1))))::double precision * random()) <= '1'::double precision)
           Relations: Aggregate on (public.ft1)
           Remote SQL: SELECT c5, NULL::bigint, sqrt(c2), avg("C 1") FROM "S 1"."T 1" GROUP BY c5, (sqrt(c2)) HAVING
((avg("C1") < 500::numeric)) 
--- 2499,2505 ----
   Aggregate
     Output: count(*)
     ->  Foreign Scan
!          Output: ft1.c5, NULL::bigint, (sqrt((ft1.c2)::double precision))
           Filter: (((((avg(ft1.c1)) / (avg(ft1.c1))))::double precision * random()) <= '1'::double precision)
           Relations: Aggregate on (public.ft1)
           Remote SQL: SELECT c5, NULL::bigint, sqrt(c2), avg("C 1") FROM "S 1"."T 1" GROUP BY c5, (sqrt(c2)) HAVING
((avg("C1") < 500::numeric)) 
*************** select sum(q.a), count(q.b) from ft4 lef
*** 3139,3145 ****
                 ->  Subquery Scan on q
                       Output: q.a, q.b
                       ->  Foreign Scan
!                            Output: (13), (avg(ft1.c1)), (NULL::bigint)
                             Relations: Aggregate on ((public.ft2) LEFT JOIN (public.ft1))
                             Remote SQL: SELECT 13, avg(r1."C 1"), NULL::bigint FROM ("S 1"."T 1" r2 LEFT JOIN "S 1"."T
1"r1 ON (((r1."C 1" = r2."C 1")))) 
  (16 rows)
--- 3139,3145 ----
                 ->  Subquery Scan on q
                       Output: q.a, q.b
                       ->  Foreign Scan
!                            Output: 13, (avg(ft1.c1)), NULL::bigint
                             Relations: Aggregate on ((public.ft2) LEFT JOIN (public.ft1))
                             Remote SQL: SELECT 13, avg(r1."C 1"), NULL::bigint FROM ("S 1"."T 1" r2 LEFT JOIN "S 1"."T
1"r1 ON (((r1."C 1" = r2."C 1")))) 
  (16 rows)
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index d10a983..d91bc3b 100644
*** a/src/backend/optimizer/plan/setrefs.c
--- b/src/backend/optimizer/plan/setrefs.c
*************** set_dummy_tlist_references(Plan *plan, i
*** 1823,1828 ****
--- 1823,1841 ----
          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),
*************** search_indexed_tlist_for_non_var(Node *n
*** 2010,2015 ****
--- 2023,2038 ----
  {
      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)
      {
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index df7cba6..79e9969 100644
*** a/src/test/regress/expected/inherit.out
--- b/src/test/regress/expected/inherit.out
*************** ORDER BY thousand, tenthous;
*** 1426,1432 ****
     Sort Key: tenk1.thousand, tenk1.tenthous
     ->  Index Only Scan using tenk1_thous_tenthous on tenk1
     ->  Sort
!          Sort Key: (42), (42)
           ->  Index Only Scan using tenk1_hundred on tenk1 tenk1_1
  (6 rows)

--- 1426,1432 ----
     Sort Key: tenk1.thousand, tenk1.tenthous
     ->  Index Only Scan using tenk1_thous_tenthous on tenk1
     ->  Sort
!          Sort Key: 42, 42
           ->  Index Only Scan using tenk1_hundred on tenk1 tenk1_1
  (6 rows)


pgsql-bugs by date:

Previous
From: Tom Lane
Date:
Subject: Re: Problems with "pg.dropped" column after upgrade 9.5 to 9.6
Next
From: Clinton Adams
Date:
Subject: Re: BUG #14404: High row estimates when query uses master inherited tables