From 6f0617555cbf08bd39566af3a291482065def2d3 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Wed, 22 Jul 2026 23:44:22 +0200 Subject: [PATCH v8 12/13] Add assert to prevent "partial" filters When adding a path (add_path or add_partial_path), make sure none of the expected filters overlaps with the relids of the relation. Such filters are invalid, we can't apply them incrementally. We must get all build relids at once. Fix a bug in compute_join_expected_filters(), violating this. It failed to reject filters matching only some of the build relids. --- src/backend/optimizer/path/joinpath.c | 9 ++++++ src/backend/optimizer/util/pathnode.c | 42 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index b661a5b800f..40f762ccc19 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -1088,6 +1088,15 @@ compute_join_expected_filters(PlannerInfo *root, goto contradiction; } } + else if (bms_overlap(f->build_relids, join_relids)) + { + /* + * We have some relids needed to build the filter, but not all + * of them. We can't apply filters incrementally, either we + * have all the relids in other_relids, or none of them. + */ + goto contradiction; + } else { /* diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 26fecc89cd9..2e7c9c8bb18 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -613,6 +613,27 @@ add_path(RelOptInfo *parent_rel, Path *new_path) */ CHECK_FOR_INTERRUPTS(); + /* + * If the new path expects filters, none of the filters can intersect + * with the rel. Relids of the relation must have no overlap with the + * build relids of the filter. + * + * XXX Do it here, because all paths have to go either through add_path + * or add_partial_path. But maybe there's a better place. + */ +#if USE_ASSERT_CHECKING + { + ListCell *lc; + + foreach (lc, new_path->expected_filters) + { + ExpectedFilter *f = (ExpectedFilter *) lfirst(lc); + + Assert(!bms_overlap(f->build_relids, parent_rel->relids)); + } + } +#endif + /* Pretend parameterized paths have no pathkeys, per comment above */ new_path_pathkeys = new_path->param_info ? NIL : new_path->pathkeys; @@ -974,6 +995,27 @@ add_partial_path(RelOptInfo *parent_rel, Path *new_path) /* Relation should be OK for parallelism, too. */ Assert(parent_rel->consider_parallel); + /* + * If the new path expects filters, none of the filters can intersect + * with the rel. Relids of the relation must have no overlap with the + * build relids of the filter. + * + * XXX Do it here, because all paths have to go either through add_path + * or add_partial_path. But maybe there's a better place. + */ +#if USE_ASSERT_CHECKING + { + ListCell *lc; + + foreach (lc, new_path->expected_filters) + { + ExpectedFilter *f = (ExpectedFilter *) lfirst(lc); + + Assert(!bms_overlap(f->build_relids, parent_rel->relids)); + } + } +#endif + /* * As in add_path, throw out any paths which are dominated by the new * path, but throw out the new path if some existing path dominates it. -- 2.50.1 (Apple Git-155)