On Fri, Nov 29, 2024 at 10:44 AM Tom Lane <t...@sss.pgh.pa.us> wrote:
> Richard Guo <guofengli...@gmail.com> writes:
> > On Fri, Nov 29, 2024 at 7:33 AM Tom Lane <t...@sss.pgh.pa.us> wrote:
> >> It seems to be sufficient to just not mark lateral
> >> references at all in this case.  (I have a nagging feeling that more
> >> complexity may be needed in cases where there are several levels of
> >> outer join, but some attempts to break it with that didn't succeed.)

> > You're right about your feeling.  Here is a query that breaks it.

> Ah, thanks for the test case.  I'll look into it tomorrow.

I spent some time looking into this issue.  For the Vars/PHVs of the
subquery, we should mark them as being nulled by all the outer joins
in var->varnullingrels, for sure.  For the Vars/PHVs of lateral
references, it seems that how we mark them depends on whether they are
under the same lowest nulling outer join as the subquery.

First of all, the lateral references cannot be outside of the lowest
outer join above the subquery; otherwise, is_simple_subquery() would
consider the subquery not eligible for pull-up.  So, IIUC, the lateral
references should be marked either with the full var->varnullingrels,
or with that set excluding lowest_outer_join->rtindex, depending on
whether they are under the same lowest nulling outer join as the
subquery or not.

For example:

explain (costs off)
select x from
  t t1 left join
  (t t2 left join
   lateral (select t2.a+t3.a as x, * from t t3) t3 on t2.a <> t3.a)
  on t1.b = t2.b;

In this query, the lowest_outer_join is t2/t3 join {4}, and the
varnullingrels of 'x' is {4, 5}.  For the lateral reference variable
't2.a', it is NOT under the same lowest nulling outer join, so we
should mark it with {5}.

explain (costs off)
select x from
  t t1 left join
  (t t2 inner join
   lateral (select t2.a+t3.a as x, * from t t3) t3 on t2.a <> t3.a)
  on t1.b = t2.b;

In this query, the lateral reference variable 't2.a' is under the same
lowest nulling outer join as the subquery, so we should just mark it
with var->varnullingrels.

I've drafted a patch based on this idea.  I borrowed the concept of
lowest_nullable_relids from another patch of mine [1], which uses
lowest_nullable_relids to avoid wrapping lateral references that are
under the same lowest nulling outer join.

Please ignore all the comments and formatting stuff in the patch.  I
haven't worked on those, and I haven't included a test case yet.

[1] 
https://postgr.es/m/CAMbWs4_eDRaJ9vv5zmNV=tbgkwtkxvmcvn7xpxcjksukc7n...@mail.gmail.com

Thanks
Richard

Attachment: v1-0001-Fix-wrong-varnullingrels.patch
Description: Binary data

Reply via email to