On Fri, Oct 9, 2026 at 11:10 PM Haibo Yan <[email protected]> wrote: > > Hi Hackers, > > I found a wrong-result issue with grouping sets when a grouping > expression is reduced to a constant during planning. > > For example: > > CREATE TABLE t (a int NOT NULL); > INSERT INTO t VALUES (1); > > SELECT CASE WHEN a IS NOT NULL THEN 'yes' ELSE 'no' END, > GROUPING(a IS NOT NULL), count(*) > FROM t > GROUP BY ROLLUP (a IS NOT NULL) > ORDER BY 2; > > PostgreSQL 18 returns: > > yes | 0 | 1 > no | 1 | 1 > > PostgreSQL 19 instead returns: > > yes | 0 | 1 > yes | 1 | 1 > > The grand-total row should contain 'no', since the grouping expression > is NULL in that grouping set. > > This regression was exposed by commit e2debb64380, which allows > "a IS NOT NULL" to be folded to true based on the column's NOT NULL > constraint. The folding itself is valid for the grouping input. > > The underlying issue predates this change. For example: > > SELECT (1 + 1) * 10 > FROM generate_series(1, 10) > GROUP BY ROLLUP (1 + 1); > > PostgreSQL 18 already returns 20 for the grand-total row, where the > result should be NULL. > > The problem is that flatten_group_exprs() substitutes the preprocessed > grouping expression for an RTE_GROUP reference. For variable-free > expressions, mark_nullable_by_grouping() wraps the expression in a > PlaceHolderVar, but creates a new PHV ID for each reference to the > same grouping output. > > Consequently, setrefs may fail to match an upper reference to the > actual grouping column. The expression is then evaluated separately, > bypassing the NULL inserted for the corresponding grouping set. > > The attached patch caches one PHV ID per RTE_GROUP attribute in > PlannerInfo, so references to the same grouping output share an ID. > Different grouping attributes retain distinct IDs, even when their > expressions are folded to the same constant. > > This fixes both the PostgreSQL 19 regression and the pre-existing > variable-free grouping-expression issue, without restricting constant > folding or changing the aggregate executor. > > The patch has been tested on master and REL_19_STABLE with assertions > enabled. Core regression, isolation, and relevant TAP tests pass. > Regression tests cover ROLLUP, CUBE, GROUPING SETS, HAVING, LATERAL, > and distinct grouping expressions folded to identical constants. > > Given the wrong-result regression in PostgreSQL 19, I'd appreciate > review of whether this fix is appropriate for REL_19_STABLE. > > The underlying issue also affects PostgreSQL 18. Backpatching there > would require some branch-specific adaptation and testing. > > Comments and review are welcome. > > Thanks, > Haibo
Hi, Attached is v2, updated to current master. There are no changes to the implementation or regression tests from v1. The patch applies cleanly to both master and REL_19_STABLE. I also added the following contributor credit: Reported-by: Shihao Zhong <[email protected]> The patch has been independently tested on both branches with assertions enabled. Core regression (239/239), isolation (134/134), and the relevant postgres_fdw tests all pass. Thanks, Haibo
0002-Fix-preexisting-grouping-expression-bug.patch
Description: Binary data
