Skip to content

Commit b33d5e0

Browse files
committed
Propagate lateral-reference information to indirect descendant relations.
create_lateral_join_info() computes a bunch of information about lateral references between base relations, and then attempts to propagate those markings to appendrel children of the original base relations. But the original coding neglected the possibility of indirect descendants (grandchildren etc). During v11 development we noticed that this was wrong for partitioned-table cases, but failed to realize that it was just as wrong for any appendrel. While the case can't arise for appendrels derived from traditional table inheritance (because we make a flat appendrel for that), nested appendrels can arise from nested UNION ALL subqueries. Failure to mark the lower-level relations as having lateral references leads to confusion in add_paths_to_append_rel about whether unparameterized paths can be built. It's not very clear whether that leads to any user-visible misbehavior; the lack of field reports suggests that it may cause nothing worse than minor cost misestimation. Still, it's a bug, and it leads to failures of Asserts that I intend to add later. To fix, we need to propagate information from all appendrel parents, not just those that are RELOPT_BASERELs. We can still do it in one pass, if we rely on the append_rel_list to be ordered with ancestor relationships before descendant ones; add assertions checking that. While fixing this, we can make a small performance improvement by traversing the append_rel_list just once instead of separately for each appendrel parent relation. Noted while investigating bug #15613, though this patch does not fix that (which is why I'm not committing the related Asserts yet). Discussion: https://postgr.es/m/3951.1549403812@sss.pgh.pa.us
1 parent 13e9566 commit b33d5e0

File tree

1 file changed

+31
-20
lines changed

1 file changed

+31
-20
lines changed

src/backend/optimizer/plan/initsplan.c

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex)
390390
void
391391
create_lateral_join_info(PlannerInfo *root)
392392
{
393+
Relids prev_parents PG_USED_FOR_ASSERTS_ONLY = NULL;
393394
Index rti;
394395
ListCell *lc;
395396

@@ -609,31 +610,41 @@ create_lateral_join_info(PlannerInfo *root)
609610
* every child anyway, and there's no value in forcing extra
610611
* reparameterize_path() calls. Similarly, a lateral reference to the
611612
* parent prevents use of otherwise-movable join rels for each child.
613+
*
614+
* It's possible for child rels to have their own children, in which case
615+
* the topmost parent's lateral info must be propagated all the way down.
616+
* This code handles that case correctly so long as append_rel_list has
617+
* entries for child relationships before grandchild relationships, which
618+
* is an okay assumption right now, but we'll need to be careful to
619+
* preserve it. The assertions below check for incorrect ordering.
612620
*/
613-
for (rti = 1; rti < root->simple_rel_array_size; rti++)
621+
foreach(lc, root->append_rel_list)
614622
{
615-
RelOptInfo *brel = root->simple_rel_array[rti];
623+
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
624+
RelOptInfo *parentrel = root->simple_rel_array[appinfo->parent_relid];
625+
RelOptInfo *childrel = root->simple_rel_array[appinfo->child_relid];
616626

617-
if (brel == NULL || brel->reloptkind != RELOPT_BASEREL)
627+
/*
628+
* If we're processing a subquery of a query with inherited target rel
629+
* (cf. inheritance_planner), append_rel_list may contain entries for
630+
* tables that are not part of the current subquery and hence have no
631+
* RelOptInfo. Ignore them. We can ignore dead rels, too.
632+
*/
633+
if (parentrel == NULL || parentrel->reloptkind == RELOPT_DEADREL)
618634
continue;
619635

620-
if (root->simple_rte_array[rti]->inh)
621-
{
622-
foreach(lc, root->append_rel_list)
623-
{
624-
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
625-
RelOptInfo *childrel;
626-
627-
if (appinfo->parent_relid != rti)
628-
continue;
629-
childrel = root->simple_rel_array[appinfo->child_relid];
630-
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
631-
Assert(childrel->lateral_relids == NULL);
632-
childrel->lateral_relids = brel->lateral_relids;
633-
Assert(childrel->lateral_referencers == NULL);
634-
childrel->lateral_referencers = brel->lateral_referencers;
635-
}
636-
}
636+
/* Verify that children are processed before grandchildren */
637+
#ifdef USE_ASSERT_CHECKING
638+
prev_parents = bms_add_member(prev_parents, appinfo->parent_relid);
639+
Assert(!bms_is_member(appinfo->child_relid, prev_parents));
640+
#endif
641+
642+
/* OK, propagate info down */
643+
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
644+
Assert(childrel->lateral_relids == NULL);
645+
childrel->lateral_relids = parentrel->lateral_relids;
646+
Assert(childrel->lateral_referencers == NULL);
647+
childrel->lateral_referencers = parentrel->lateral_referencers;
637648
}
638649
}
639650

0 commit comments

Comments
 (0)