Re: Use exact nullingrels matches for NestLoopParams

From: Richard Guo <guofenglinux(at)gmail(dot)com>
To: Pg Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Use exact nullingrels matches for NestLoopParams
Date: 2025-11-17 07:28:45
Message-ID: CAMbWs49LYoEvxQW1fkU5e5BWVCi06VOdse7=qYe5POEhqdz9DQ@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Tue, Nov 11, 2025 at 3:58 PM Richard Guo <guofenglinux(at)gmail(dot)com> wrote:
> Here is a patch that makes that change. It also removes the
> NRM_SUBSET enum value, along with all remaining checks for it, since
> it is no longer used.

With the changes in 0001, we should now be able to use exact
nullingrels matches in all cases when fixing up expressions of
upper-level plan nodes that are not joins. Therefore, I think we can
remove the nrm_match parameter from fix_upper_expr(), along with the
corresponding field in fix_upper_expr_context. I've done that in 0002
(which will be squashed into 0001 when committed).

> (I'm wondering if we have a way to identify the nullingrels added by
> an outer join when fixing up its targetlist and qpqual. If so, we
> might be able to switch to exact nullingrels matches for them and
> thereby get rid of NRM_SUPERSET too.)

After looking into this, I think it's quite challenging to determine
the effects of an outer join when the join has been commuted with
another one per outer join identity 3. In such cases, the Vars/PHVs
in the join's targetlist and qpqual should have the same nullingrels
they would have if the two joins had been done in syntactic order.
Unfortunately, in setrefs.c we do not have enough information (such as
the relevant SpecialJoinInfos) to determine that.

For example, consider when we transform

(A leftjoin B on (Pab)) leftjoin C on (Pbc)

to

A leftjoin (B leftjoin C on (Pbc)) on (Pab)

For the now-upper A/B join, whose ojrelids is {3, 5}, the Vars from B
in its targetlist and qpqual have nullingrels = {3}, and the Vars from
C have nullingrels = {5}. In its inner plan's targetlist, however,
both B and C Vars have empty nullingrels. The problem is that we have
no reliable way in setrefs.c to determine which of the join's ojrelids
should apply to which Vars.

On the other hand, if we perform the transformation in the reverse
order, then for the B/C join whose ojrelids is {4}, the C Vars in its
targetlist and qpqual have nullingrels = {4, 5}, while in its inner
plan's targetlist the C Vars have empty nullingrels. We have no
reliable way to determine that {5} should also be applied to the C
Vars.

However, we can tighten the check somewhat. Currently, we check
whether the jointype is JOIN_INNER and use NRM_SUPERSET if it is not.
We can improve this by checking whether the Join node has non-empty
ojrelids and using NRM_SUPERSET only in that case. This allows us to
perform exact matches in more situations, such as the pushed-down B/C
join in the first case.

0003 implements this. To support it, we record the outer-join relids
in Join plan nodes (the related changes for adding ojrelids are
adapted from the patch in [1]). This may seem like overengineering to
have a new field just for this check, but the field also improves
EXPLAIN (RANGE_TABLE) output by showing which outer-join relids are
completed by each Join plan node. I expect that we will find other
uses for the ojrelids information in the future.

[1] https://postgr.es/m/3200728.1758662857@sss.pgh.pa.us

- Richard

Attachment Content-Type Size
v2-0001-Use-exact-nullingrels-matches-for-NestLoopParams.patch application/octet-stream 4.6 KB
v2-0002-Remove-nrm_match-parameter-from-fix_upper_expr.patch application/octet-stream 7.6 KB
v2-0003-Tighten-nullingrels-checks-for-outer-joins.patch application/octet-stream 15.2 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Peter Smith 2025-11-17 07:51:57 Re: Skipping schema changes in publication
Previous Message Neil Chen 2025-11-17 07:17:56 Re: Fix GetOperatorFromCompareType