mirror of
https://github.com/postgres/postgres.git
synced 2025-04-29 13:56:47 +03:00
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
This commit is contained in:
parent
b630d9d6c8
commit
36f5594c0f
@ -3296,12 +3296,19 @@ 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);
|
||||
/* New Var is nullable by same rels as the old one */
|
||||
newvar->varnullingrels = ((Var *) arg)->varnullingrels;
|
||||
return (Node *) newvar;
|
||||
}
|
||||
}
|
||||
if (arg && IsA(arg, RowExpr))
|
||||
{
|
||||
|
@ -4133,6 +4133,32 @@ select * from mki4(42);
|
||||
|
||||
drop function mki8(bigint, bigint);
|
||||
drop function mki4(int);
|
||||
-- test const-folding of a whole-row Var into a per-field Var
|
||||
-- (need to inline a function to reach this case, else parser does it)
|
||||
create function f_field_select(t onek) returns int4 as
|
||||
$$ select t.unique2; $$ language sql immutable;
|
||||
explain (verbose, costs off)
|
||||
select (t2.*).unique1, f_field_select(t2) from tenk1 t1
|
||||
left join onek t2 on t1.unique1 = t2.unique1
|
||||
left join int8_tbl t3 on true;
|
||||
QUERY PLAN
|
||||
--------------------------------------------------------------------
|
||||
Nested Loop Left Join
|
||||
Output: t2.unique1, t2.unique2
|
||||
-> Hash Left Join
|
||||
Output: t2.unique1, t2.unique2
|
||||
Hash Cond: (t1.unique1 = t2.unique1)
|
||||
-> Index Only Scan using tenk1_unique1 on public.tenk1 t1
|
||||
Output: t1.unique1
|
||||
-> Hash
|
||||
Output: t2.unique1, t2.unique2
|
||||
-> Seq Scan on public.onek t2
|
||||
Output: t2.unique1, t2.unique2
|
||||
-> Materialize
|
||||
-> Seq Scan on public.int8_tbl t3
|
||||
(13 rows)
|
||||
|
||||
drop function f_field_select(t onek);
|
||||
--
|
||||
-- test extraction of restriction OR clauses from join OR clause
|
||||
-- (we used to only do this for indexable clauses)
|
||||
|
@ -1381,6 +1381,18 @@ select * from mki4(42);
|
||||
drop function mki8(bigint, bigint);
|
||||
drop function mki4(int);
|
||||
|
||||
-- test const-folding of a whole-row Var into a per-field Var
|
||||
-- (need to inline a function to reach this case, else parser does it)
|
||||
create function f_field_select(t onek) returns int4 as
|
||||
$$ select t.unique2; $$ language sql immutable;
|
||||
|
||||
explain (verbose, costs off)
|
||||
select (t2.*).unique1, f_field_select(t2) from tenk1 t1
|
||||
left join onek t2 on t1.unique1 = t2.unique1
|
||||
left join int8_tbl t3 on true;
|
||||
|
||||
drop function f_field_select(t onek);
|
||||
|
||||
--
|
||||
-- test extraction of restriction OR clauses from join OR clause
|
||||
-- (we used to only do this for indexable clauses)
|
||||
|
Loading…
x
Reference in New Issue
Block a user