From d6c782dde374cc0ff1b1feae7d751066a1db8417 Mon Sep 17 00:00:00 2001 From: Richard Guo Date: Tue, 7 Nov 2023 10:50:00 +0800 Subject: [PATCH v1] Fix mismatched nullingrels when inlining functions When we optimize field selection from a whole-row Var into a simple Var while simplifying functions, we failed to propagate the nullingrels into the new Var. This patch fixes that. Per report from Marian Krucina in BUG #18184 --- src/backend/optimizer/util/clauses.c | 20 ++++++++++++++------ src/test/regress/expected/join.out | 20 ++++++++++++++++++++ src/test/regress/sql/join.sql | 10 ++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index da258968b8..6b3e712905 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -3296,12 +3296,20 @@ eval_const_expressions_mutator(Node *node, fselect->resulttype, fselect->resulttypmod, fselect->resultcollid)) - return (Node *) makeVar(((Var *) arg)->varno, - fselect->fieldnum, - fselect->resulttype, - fselect->resulttypmod, - fselect->resultcollid, - ((Var *) arg)->varlevelsup); + { + Var *newvar; + + newvar = makeVar(((Var *) arg)->varno, + fselect->fieldnum, + fselect->resulttype, + fselect->resulttypmod, + fselect->resultcollid, + ((Var *) arg)->varlevelsup); + + newvar->varnullingrels = ((Var *) arg)->varnullingrels; + + return (Node *) newvar; + } } if (arg && IsA(arg, RowExpr)) { diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 892ea5f170..52fe18d5fa 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -2687,6 +2687,26 @@ select * from onek t1 Filter: (two = t2.two) (11 rows) +-- +-- check for correct handling of nullingrels when simplifying functions +-- +create function f_immutable_nullingrels(t onek) returns text as +$$ select t.unique1::text; $$ language sql immutable; +explain (costs off) +select f_immutable_nullingrels(t2) from onek t1 + left join onek t2 on t1.unique1 = t2.unique1 + left join onek t3 on true; + QUERY PLAN +----------------------------------------------------------- + Nested Loop Left Join + -> Merge Left Join + Merge Cond: (t1.unique1 = t2.unique1) + -> Index Only Scan using onek_unique1 on onek t1 + -> Index Only Scan using onek_unique1 on onek t2 + -> Materialize + -> Index Only Scan using onek_hundred on onek t3 +(7 rows) + -- -- check a case where we formerly got confused by conflicting sort orders -- in redundant merge join path keys diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 559c36dc07..80169f9efb 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -550,6 +550,16 @@ select * from onek t1 (select * from onek t3 where t3.two = t2.two offset 0) s on t2.unique1 = 1; +-- +-- check for correct handling of nullingrels when simplifying functions +-- +create function f_immutable_nullingrels(t onek) returns text as +$$ select t.unique1::text; $$ language sql immutable; +explain (costs off) +select f_immutable_nullingrels(t2) from onek t1 + left join onek t2 on t1.unique1 = t2.unique1 + left join onek t3 on true; + -- -- check a case where we formerly got confused by conflicting sort orders -- in redundant merge join path keys -- 2.31.0