On Sun, Aug 30, 2026 at 5:10 AM Tom Lane <[email protected]> wrote:
> So after contemplating my navel for awhile, the least grotty
> solution I can see is to update the subquery's copy of the PHV
> with the preprocessed expression, as attached.  I don't really
> love doing that, but the alternatives I can think of are worse.
> Anyone have another idea?

I looked at the patch.  I noticed a couple of problems with putting
the preprocessed expression back into the subquery.

One is that preprocess_expression is not something we can run twice on
the same expression.  If join removal restarts query_planner,
extract_lateral_references runs again and preprocesses the PHV copy
that we wrote back in the previous round.  If that expression contains
a SubPlan by then, we can hit "Assert(!IsA(node, SubPlan))" in several
places.  For instance:

explain (verbose, costs off)
select c1, c2
from (select case when false then remov.id else (select i41.f1) end as c1
      from int4_tbl i41 left join a remov on i41.f1 = remov.id) ss1
     right join int4_tbl i42 on false,
     lateral (select ss1.c1 as c2 from int4_tbl i43 offset 0) ss2;

TRAP: failed Assert("!IsA(node, SubPlan)")

The other one is that find_lateral_references ignores appendrel
otherrels.  The appendrel children created by pull_up_simple_union_all
are copies of the arm RTEs, so the PHV copies in those child
subqueries are never fixed, and we still hit the original Assert:

explain (verbose, costs off)
select c1, c2
from (select case when false then remov.id end as c1
      from int4_tbl i41 left join a remov on i41.f1 = remov.id) ss1
     right join int4_tbl i42 on false,
     lateral ((select ss1.c1 as c2 from int4_tbl i43 offset 0)
              union all
              (select ss1.c1 from int4_tbl i44 offset 0)) ss2;

TRAP: failed Assert("context->new_index != INVALID_VAR")

I tried a few different things, and I found another way to fix it,
which is to preprocess these PHV copies once in subquery_planner, in
the loop where we already flatten join aliases in LATERAL subqueries,
and not preprocess them again in extract_lateral_references.  That
covers the appendrel children too, since they are marked LATERAL as
well.

One consequence is that a not-yet-planned subquery can now contain
SubPlans, within a PHV of an upper query level.  (This applies to your
patch as well.)  This seems to be new.  AFAICT, an unplanned subquery
never held SubPlans before.  Fortunately, most of the tree walkers
that run on the subquery before SS_replace_correlation_vars replaces
the outer PHV with a Param cope with that.  The exception is
flatten_join_alias_vars, which descends into every PHV and asserts on
SubPlans.  I changed it to leave PHVs of upper levels alone; such a
PHV cannot contain join aliases of the level being flattened anyway.

Also, the edge case in identify_current_nestloop_params that
substitutes the ph_var copy for a nestloop-param PHV was there because
the copy from the subquery could still contain SubLinks.  That is no
longer possible, but I kept the substitution, since it still avoids
evaluating duplicate SubPlans when the PHV contains a sublink.  I
updated the comment accordingly and added an Assert.

- Richard

Attachment: v2-0001-Fix-stale-copies-of-PHVs-in-LATERAL-subqueries.patch
Description: Binary data

Reply via email to