diff --git a/src/backend/gpopt/translate/CTranslatorUtils.cpp b/src/backend/gpopt/translate/CTranslatorUtils.cpp index 0887c72725c..90e0a70ba23 100644 --- a/src/backend/gpopt/translate/CTranslatorUtils.cpp +++ b/src/backend/gpopt/translate/CTranslatorUtils.cpp @@ -918,7 +918,7 @@ CTranslatorUtils::GetColumnAttnosForGroupBy( case GROUPING_SET_EMPTY: { col_attnos_arr_current = GPOS_NEW(mp) CBitSetArray(mp); - CBitSet *bset = GPOS_NEW(mp) CBitSet(mp); + CBitSet *bset = GPOS_NEW(mp) CBitSet(mp, num_cols); col_attnos_arr_current->Append(bset); break; } @@ -1113,11 +1113,12 @@ CTranslatorUtils::CreateGroupingSetsForRollup(CMemoryPool *mp, GPOS_ASSERT(grouping_set->kind == GROUPING_SET_ROLLUP); CBitSetArray *col_attnos_arr = GPOS_NEW(mp) CBitSetArray(mp); ListCell *lc = nullptr; - CBitSet *current_result = GPOS_NEW(mp) CBitSet(mp); + + CBitSet *current_result = GPOS_NEW(mp) CBitSet(mp, num_cols); // Maintaining the order of grouping sets is essential because the // UnionAll operator matches each child's distribution with the // distribution of the first child - col_attnos_arr->Append(GPOS_NEW(mp) CBitSet(mp)); + col_attnos_arr->Append(GPOS_NEW(mp) CBitSet(mp, num_cols)); ForEach(lc, grouping_set->content) { GroupingSet *gs_current = (GroupingSet *) lfirst(lc); @@ -1152,8 +1153,9 @@ CTranslatorUtils::CreateGroupingSetsForCube(CMemoryPool *mp, GPOS_ASSERT(grouping_set->kind == GROUPING_SET_CUBE); CBitSetArray *col_attnos_arr = GPOS_NEW(mp) CBitSetArray(mp); - // add an empty set - col_attnos_arr->Append(GPOS_NEW(mp) CBitSet(mp)); + // add an empty set — vec_size must match what CreateAttnoSetForGroupingSet + // produces (num_cols), otherwise Union below leaves misaligned links. + col_attnos_arr->Append(GPOS_NEW(mp) CBitSet(mp, num_cols)); ListCell *lc = nullptr; ForEach(lc, grouping_set->content) diff --git a/src/backend/gporca/libgpos/src/common/CBitSet.cpp b/src/backend/gporca/libgpos/src/common/CBitSet.cpp index 1eb9d2c939f..c3d7703f59d 100644 --- a/src/backend/gporca/libgpos/src/common/CBitSet.cpp +++ b/src/backend/gporca/libgpos/src/common/CBitSet.cpp @@ -347,6 +347,8 @@ CBitSet::ExchangeClear(ULONG pos) void CBitSet::Union(const CBitSet *pbsOther) { + GPOS_ASSERT(m_vector_size == pbsOther->m_vector_size); + CBitSetLink *bsl = nullptr; CBitSetLink *bsl_other = nullptr; @@ -425,6 +427,10 @@ CBitSet::Intersection(const CBitSet *pbsOther) return; } + // See CBitSet::Union: link offsets depend on m_vector_size, so mixing + // bitsets with different sizes makes FindLinkByOffset miss links. + GPOS_ASSERT(m_vector_size == pbsOther->m_vector_size); + CBitSetLink *bsl_other = nullptr; CBitSetLink *bsl = m_bsllist.First(); diff --git a/src/test/regress/expected/groupingsets.out b/src/test/regress/expected/groupingsets.out index 5222cc22b70..a1cb32e2478 100644 --- a/src/test/regress/expected/groupingsets.out +++ b/src/test/regress/expected/groupingsets.out @@ -2470,4 +2470,32 @@ group by rollup (a,b) order by a; | | 6 (8 rows) +-- ORCA: rollup over a derived-expression group alias with a target-list SRF. +select generate_series(1, a) g, a+b ab + from (values (1,1),(2,2)) t(a,b) + group by rollup(a, ab) order by 1,2; + g | ab +---+---- + 1 | 2 + 1 | 4 + 1 | + 1 | + 2 | 4 + 2 | +(6 rows) + +-- Same shape with cube(): exercises additional grouping-set combinations. +select generate_series(1, a) g, a+b ab + from (values (1,1),(2,2)) t(a,b) + group by cube(a, ab) order by 1,2; + g | ab +---+---- + 1 | 2 + 1 | 4 + 1 | + 1 | + 2 | 4 + 2 | +(6 rows) + -- end diff --git a/src/test/regress/expected/groupingsets_optimizer.out b/src/test/regress/expected/groupingsets_optimizer.out index a07017eca32..f02364c362b 100644 --- a/src/test/regress/expected/groupingsets_optimizer.out +++ b/src/test/regress/expected/groupingsets_optimizer.out @@ -2645,4 +2645,32 @@ group by rollup (a,b) order by a; | | 6 (8 rows) +-- ORCA: rollup over a derived-expression group alias with a target-list SRF. +select generate_series(1, a) g, a+b ab + from (values (1,1),(2,2)) t(a,b) + group by rollup(a, ab) order by 1,2; + g | ab +---+---- + 1 | 2 + 1 | 4 + 1 | + 1 | + 2 | 4 + 2 | +(6 rows) + +-- Same shape with cube(): exercises additional grouping-set combinations. +select generate_series(1, a) g, a+b ab + from (values (1,1),(2,2)) t(a,b) + group by cube(a, ab) order by 1,2; + g | ab +---+---- + 1 | 2 + 1 | 4 + 1 | + 1 | + 2 | 4 + 2 | +(6 rows) + -- end diff --git a/src/test/regress/sql/groupingsets.sql b/src/test/regress/sql/groupingsets.sql index 851a1eea6bb..f7bcba8a46a 100644 --- a/src/test/regress/sql/groupingsets.sql +++ b/src/test/regress/sql/groupingsets.sql @@ -723,4 +723,14 @@ select a, b, rank(b) within group (order by b nulls last) from (values (1,1),(1,4),(1,5),(3,1),(3,2)) v(a,b) group by rollup (a,b) order by a; +-- ORCA: rollup over a derived-expression group alias with a target-list SRF. +select generate_series(1, a) g, a+b ab + from (values (1,1),(2,2)) t(a,b) + group by rollup(a, ab) order by 1,2; + +-- Same shape with cube(): exercises additional grouping-set combinations. +select generate_series(1, a) g, a+b ab + from (values (1,1),(2,2)) t(a,b) + group by cube(a, ab) order by 1,2; + -- end