Skip to content

Commit 36f5594

Browse files
committed
Fix computation of varnullingrels when const-folding field selection.
We can simplify FieldSelect on a whole-row Var into a plain Var for the selected field. However, we should copy the whole-row Var's varnullingrels when we do so, because the new Var is clearly nullable by exactly the same rels as the original. Failure to do this led to errors like "wrong varnullingrels (b) (expected (b 3)) for Var 2/2". Richard Guo, per bug #18184 from Marian Krucina. Back-patch to v16 where varnullingrels was introduced. Discussion: https://postgr.es/m/18184-5868dd258782058e@postgresql.org
1 parent b630d9d commit 36f5594

File tree

3 files changed

+51
-6
lines changed

3 files changed

+51
-6
lines changed

src/backend/optimizer/util/clauses.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3296,12 +3296,19 @@ eval_const_expressions_mutator(Node *node,
32963296
fselect->resulttype,
32973297
fselect->resulttypmod,
32983298
fselect->resultcollid))
3299-
return (Node *) makeVar(((Var *) arg)->varno,
3300-
fselect->fieldnum,
3301-
fselect->resulttype,
3302-
fselect->resulttypmod,
3303-
fselect->resultcollid,
3304-
((Var *) arg)->varlevelsup);
3299+
{
3300+
Var *newvar;
3301+
3302+
newvar = makeVar(((Var *) arg)->varno,
3303+
fselect->fieldnum,
3304+
fselect->resulttype,
3305+
fselect->resulttypmod,
3306+
fselect->resultcollid,
3307+
((Var *) arg)->varlevelsup);
3308+
/* New Var is nullable by same rels as the old one */
3309+
newvar->varnullingrels = ((Var *) arg)->varnullingrels;
3310+
return (Node *) newvar;
3311+
}
33053312
}
33063313
if (arg && IsA(arg, RowExpr))
33073314
{

src/test/regress/expected/join.out

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4133,6 +4133,32 @@ select * from mki4(42);
41334133

41344134
drop function mki8(bigint, bigint);
41354135
drop function mki4(int);
4136+
-- test const-folding of a whole-row Var into a per-field Var
4137+
-- (need to inline a function to reach this case, else parser does it)
4138+
create function f_field_select(t onek) returns int4 as
4139+
$$ select t.unique2; $$ language sql immutable;
4140+
explain (verbose, costs off)
4141+
select (t2.*).unique1, f_field_select(t2) from tenk1 t1
4142+
left join onek t2 on t1.unique1 = t2.unique1
4143+
left join int8_tbl t3 on true;
4144+
QUERY PLAN
4145+
--------------------------------------------------------------------
4146+
Nested Loop Left Join
4147+
Output: t2.unique1, t2.unique2
4148+
-> Hash Left Join
4149+
Output: t2.unique1, t2.unique2
4150+
Hash Cond: (t1.unique1 = t2.unique1)
4151+
-> Index Only Scan using tenk1_unique1 on public.tenk1 t1
4152+
Output: t1.unique1
4153+
-> Hash
4154+
Output: t2.unique1, t2.unique2
4155+
-> Seq Scan on public.onek t2
4156+
Output: t2.unique1, t2.unique2
4157+
-> Materialize
4158+
-> Seq Scan on public.int8_tbl t3
4159+
(13 rows)
4160+
4161+
drop function f_field_select(t onek);
41364162
--
41374163
-- test extraction of restriction OR clauses from join OR clause
41384164
-- (we used to only do this for indexable clauses)

src/test/regress/sql/join.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,18 @@ select * from mki4(42);
13811381
drop function mki8(bigint, bigint);
13821382
drop function mki4(int);
13831383

1384+
-- test const-folding of a whole-row Var into a per-field Var
1385+
-- (need to inline a function to reach this case, else parser does it)
1386+
create function f_field_select(t onek) returns int4 as
1387+
$$ select t.unique2; $$ language sql immutable;
1388+
1389+
explain (verbose, costs off)
1390+
select (t2.*).unique1, f_field_select(t2) from tenk1 t1
1391+
left join onek t2 on t1.unique1 = t2.unique1
1392+
left join int8_tbl t3 on true;
1393+
1394+
drop function f_field_select(t onek);
1395+
13841396
--
13851397
-- test extraction of restriction OR clauses from join OR clause
13861398
-- (we used to only do this for indexable clauses)

0 commit comments

Comments
 (0)