This is an automated email from the ASF dual-hosted git repository.
yjhjstz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git
The following commit(s) were added to refs/heads/main by this push:
new 977f63daf77 [ORCA] Narrow CTE Producer columns in
CXformGbAggWithMDQA2Join
977f63daf77 is described below
commit 977f63daf7727351eee5945576cde8414ba793c1
Author: Jianghua Yang <[email protected]>
AuthorDate: Fri Aug 21 00:36:30 2026 +0800
[ORCA] Narrow CTE Producer columns in CXformGbAggWithMDQA2Join
When rewriting a GbAgg with multiple distinct-qualified aggregates
(MDQAs) into a join of single-DQA aggregates, the transform declared
every column the child expression could produce on the CTE Producer.
On the partitioned-table path the over-declared columns included
unreferenced and system columns whose usage state is EUnknown/EUnused,
which fails the assertion "col_ref->GetUsage() != CColRef::EUnknown"
in CPhysicalCTEProducer::PcrsRequired on assert builds and crashes
with SIGSEGV in MakeDXLTableDescr on release builds:
CREATE TABLE mdqa_part(a int, b int, c int, d int)
DISTRIBUTED BY (a)
PARTITION BY RANGE(a) (START (0) END (100) EVERY (50),
DEFAULT PARTITION other);
SET optimizer_enable_multiple_distinct_aggs = on;
SELECT a, count(DISTINCT b), count(DISTINCT c)
FROM mdqa_part WHERE b BETWEEN 0 AND 2 GROUP BY a;
Fix by restricting the CTE Producer/Consumer columns to the columns
the GbAgg actually needs: group-by keys plus aggregate-argument
references, clipped to what the child can produce. Besides fixing the
crash, this also simplifies MDQA plans on non-partitioned tables: the
narrowed producer no longer carries unused and system columns, and
ORCA can now place a single Redistribute Motion below the producer
instead of one per consumer.
Ported from warehouse-pg/warehouse-pg#149, minidump changes omitted.
---
.../src/test/regress/expected/gp_dqa_optimizer.out | 37 ++--
.../src/xforms/CXformGbAggWithMDQA2Join.cpp | 13 +-
src/test/regress/expected/gp_dqa.out | 113 ++++++++++++
src/test/regress/expected/gp_dqa_optimizer.out | 191 ++++++++++++++++-----
src/test/regress/sql/gp_dqa.sql | 28 +++
5 files changed, 312 insertions(+), 70 deletions(-)
diff --git a/contrib/pax_storage/src/test/regress/expected/gp_dqa_optimizer.out
b/contrib/pax_storage/src/test/regress/expected/gp_dqa_optimizer.out
index ad85ad9f14a..2d2e3a87da2 100644
--- a/contrib/pax_storage/src/test/regress/expected/gp_dqa_optimizer.out
+++ b/contrib/pax_storage/src/test/regress/expected/gp_dqa_optimizer.out
@@ -3251,16 +3251,19 @@ DETAIL: Falling back to Postgres-based planner because
GPORCA does not support
set optimizer_enable_multiple_distinct_aggs=on;
explain (verbose on, costs off) select count(distinct a), count(distinct b)
from dqa_f4 group by c;
-
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
Output: (count(DISTINCT share0_ref3.a)), (count(DISTINCT share0_ref2.b))
-> Sequence
Output: (count(DISTINCT share0_ref3.a)), (count(DISTINCT
share0_ref2.b))
-> Shared Scan (share slice:id 1:0)
- Output: share0_ref1.a, share0_ref1.b, share0_ref1.c,
share0_ref1.ctid, share0_ref1.tableoid, share0_ref1.gp_segment_id,
share0_ref1.gp_foreign_server
- -> Seq Scan on public.dqa_f4
- Output: dqa_f4.a, dqa_f4.b, dqa_f4.c, dqa_f4.ctid,
dqa_f4.tableoid, dqa_f4.gp_segment_id, dqa_f4.gp_foreign_server
+ Output: share0_ref1.a, share0_ref1.b, share0_ref1.c
+ -> Redistribute Motion 3:3 (slice2; segments: 3)
+ Output: dqa_f4.a, dqa_f4.b, dqa_f4.c
+ Hash Key: dqa_f4.c
+ -> Seq Scan on public.dqa_f4
+ Output: dqa_f4.a, dqa_f4.b, dqa_f4.c
-> Hash Join
Output: (count(DISTINCT share0_ref3.a)), (count(DISTINCT
share0_ref2.b))
Hash Cond: (NOT (share0_ref3.c IS DISTINCT FROM share0_ref2.c))
@@ -3268,33 +3271,23 @@ explain (verbose on, costs off) select count(distinct
a), count(distinct b) from
Output: count(DISTINCT share0_ref3.a), share0_ref3.c
Group Key: share0_ref3.c
-> Sort
- Output: share0_ref3.a, share0_ref3.c
+ Output: share0_ref3.a, share0_ref3.b, share0_ref3.c
Sort Key: share0_ref3.c
- -> Redistribute Motion 3:3 (slice2; segments: 3)
- Output: share0_ref3.a, share0_ref3.c
- Hash Key: share0_ref3.c
- -> Result
- Output: share0_ref3.a, share0_ref3.c
- -> Shared Scan (share slice:id 2:0)
- Output: share0_ref3.a,
share0_ref3.b, share0_ref3.c
+ -> Shared Scan (share slice:id 1:0)
+ Output: share0_ref3.a, share0_ref3.b,
share0_ref3.c
-> Hash
Output: (count(DISTINCT share0_ref2.b)), share0_ref2.c
-> GroupAggregate
Output: count(DISTINCT share0_ref2.b), share0_ref2.c
Group Key: share0_ref2.c
-> Sort
- Output: share0_ref2.b, share0_ref2.c
+ Output: share0_ref2.a, share0_ref2.b,
share0_ref2.c
Sort Key: share0_ref2.c
- -> Redistribute Motion 3:3 (slice3;
segments: 3)
- Output: share0_ref2.b, share0_ref2.c
- Hash Key: share0_ref2.c
- -> Result
- Output: share0_ref2.b,
share0_ref2.c
- -> Shared Scan (share slice:id
3:0)
- Output: share0_ref2.a,
share0_ref2.b, share0_ref2.c
+ -> Shared Scan (share slice:id 1:0)
+ Output: share0_ref2.a, share0_ref2.b,
share0_ref2.c
Settings: optimizer = 'on', gp_motion_cost_per_row = '2', enable_hashagg =
'on', enable_groupagg = 'off'
Optimizer: GPORCA
-(41 rows)
+(34 rows)
select count(distinct a), count(distinct b) from dqa_f4 group by c;
count | count
diff --git
a/src/backend/gporca/libgpopt/src/xforms/CXformGbAggWithMDQA2Join.cpp
b/src/backend/gporca/libgpopt/src/xforms/CXformGbAggWithMDQA2Join.cpp
index 0ca823a499c..e0a112f29b3 100644
--- a/src/backend/gporca/libgpopt/src/xforms/CXformGbAggWithMDQA2Join.cpp
+++ b/src/backend/gporca/libgpopt/src/xforms/CXformGbAggWithMDQA2Join.cpp
@@ -98,10 +98,21 @@ CXformGbAggWithMDQA2Join::PexprMDQAs2Join(CMemoryPool *mp,
CExpression *pexpr)
GPOS_ASSERT((*pexpr)[1]->DeriveHasMultipleDistinctAggs());
// extract components
+ CLogicalGbAgg *popGbAgg = CLogicalGbAgg::PopConvert(pexpr->Pop());
CExpression *pexprChild = (*pexpr)[0];
+ CExpression *pexprAggList = (*pexpr)[1]; // GbAgg's scalar child
+ // Compute the columns actually needed by the GbAgg:
+ // group-by keys + aggregate-argument references
+ // Clip to what the child can provide.
CColRefSet *pcrsChildOutput = pexprChild->DeriveOutputColumns();
- CColRefArray *pdrgpcrChildOutput = pcrsChildOutput->Pdrgpcr(mp);
+ CColRefSet *pcrsAggListRefs = pexprAggList->DeriveUsedColumns();
// cols read by aggregate args
+ CColRefSet *pcrsUsed = GPOS_NEW(mp) CColRefSet(mp);
+ pcrsUsed->Include(popGbAgg->Pdrgpcr()); // group-by keys
+ pcrsUsed->Union(pcrsAggListRefs); // agg-list refs
+ pcrsUsed->Intersection(pcrsChildOutput); // clip to producible
+ CColRefArray *pdrgpcrChildOutput = pcrsUsed->Pdrgpcr(mp);
+ pcrsUsed->Release();
// create a CTE producer based on child expression
CCTEInfo *pcteinfo = COptCtxt::PoctxtFromTLS()->Pcteinfo();
diff --git a/src/test/regress/expected/gp_dqa.out
b/src/test/regress/expected/gp_dqa.out
index c2422e09450..2488462f3e3 100644
--- a/src/test/regress/expected/gp_dqa.out
+++ b/src/test/regress/expected/gp_dqa.out
@@ -3115,3 +3115,116 @@ select count(distinct a), count(distinct b) from dqa_f5
group by c;
reset optimizer_enable_multiple_distinct_aggs;
drop table dqa_f4;
drop table dqa_f5;
+-- Test MDQA on a partitioned table.
+-- Pre-fix, CXformGbAggWithMDQA2Join declared every column the child could
+-- produce on the CTE Producer, so unused and system columns with EUnknown
+-- usage leaked into the producer's column list and crashed ORCA on the
+-- partitioned-table path (failed assertion "col_ref->GetUsage() !=
+-- CColRef::EUnknown" in assert builds, SIGSEGV in release builds).
+set optimizer_enable_multiple_distinct_aggs=on;
+create table mdqa_part(a int, b int, c int, d int)
+distributed by (a)
+partition by range(a) (
+ start (0) end (100) every (50),
+ default partition other
+);
+insert into mdqa_part select i, i%5, i%3, i%7 from generate_series(1, 100) i;
+create index mdqa_part_b_idx on mdqa_part(b);
+analyze mdqa_part;
+explain (costs off)
+select a, count(distinct b) as cnt_b, count(distinct c) as cnt_c
+from mdqa_part where b between 0 and 2 group by a;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------
+ Finalize HashAggregate
+ Group Key: mdqa_part.a
+ -> Gather Motion 3:1 (slice1; segments: 3)
+ -> Partial HashAggregate
+ Group Key: mdqa_part.a
+ -> HashAggregate
+ Group Key: (AggExprId), mdqa_part.b, mdqa_part.c,
mdqa_part.a
+ -> Redistribute Motion 3:3 (slice2; segments: 3)
+ Hash Key: mdqa_part.a, mdqa_part.b, mdqa_part.c,
(AggExprId)
+ -> Streaming HashAggregate
+ Group Key: AggExprId, mdqa_part.b,
mdqa_part.c, mdqa_part.a
+ -> TupleSplit
+ Split by Col: (mdqa_part.b),
(mdqa_part.c)
+ Group Key: mdqa_part.a
+ -> Append
+ -> Seq Scan on mdqa_part_1_prt_2
mdqa_part_1
+ Filter: ((b >= 0) AND (b <=
2))
+ -> Seq Scan on mdqa_part_1_prt_3
mdqa_part_2
+ Filter: ((b >= 0) AND (b <=
2))
+ -> Seq Scan on
mdqa_part_1_prt_other mdqa_part_3
+ Filter: ((b >= 0) AND (b <=
2))
+ Optimizer: Postgres query optimizer
+(22 rows)
+
+select a, count(distinct b) as cnt_b, count(distinct c) as cnt_c
+from mdqa_part where b between 0 and 2 group by a;
+ a | cnt_b | cnt_c
+-----+-------+-------
+ 87 | 1 | 1
+ 71 | 1 | 1
+ 51 | 1 | 1
+ 96 | 1 | 1
+ 52 | 1 | 1
+ 80 | 1 | 1
+ 70 | 1 | 1
+ 67 | 1 | 1
+ 90 | 1 | 1
+ 10 | 1 | 1
+ 35 | 1 | 1
+ 45 | 1 | 1
+ 6 | 1 | 1
+ 86 | 1 | 1
+ 92 | 1 | 1
+ 36 | 1 | 1
+ 31 | 1 | 1
+ 50 | 1 | 1
+ 60 | 1 | 1
+ 97 | 1 | 1
+ 66 | 1 | 1
+ 22 | 1 | 1
+ 65 | 1 | 1
+ 2 | 1 | 1
+ 16 | 1 | 1
+ 62 | 1 | 1
+ 75 | 1 | 1
+ 11 | 1 | 1
+ 42 | 1 | 1
+ 82 | 1 | 1
+ 41 | 1 | 1
+ 46 | 1 | 1
+ 40 | 1 | 1
+ 32 | 1 | 1
+ 7 | 1 | 1
+ 100 | 1 | 1
+ 15 | 1 | 1
+ 26 | 1 | 1
+ 12 | 1 | 1
+ 85 | 1 | 1
+ 72 | 1 | 1
+ 95 | 1 | 1
+ 57 | 1 | 1
+ 81 | 1 | 1
+ 61 | 1 | 1
+ 77 | 1 | 1
+ 25 | 1 | 1
+ 30 | 1 | 1
+ 21 | 1 | 1
+ 47 | 1 | 1
+ 17 | 1 | 1
+ 37 | 1 | 1
+ 20 | 1 | 1
+ 1 | 1 | 1
+ 76 | 1 | 1
+ 5 | 1 | 1
+ 55 | 1 | 1
+ 27 | 1 | 1
+ 56 | 1 | 1
+ 91 | 1 | 1
+(60 rows)
+
+reset optimizer_enable_multiple_distinct_aggs;
+drop table mdqa_part;
diff --git a/src/test/regress/expected/gp_dqa_optimizer.out
b/src/test/regress/expected/gp_dqa_optimizer.out
index 5307bd0f909..d49080ac3d5 100644
--- a/src/test/regress/expected/gp_dqa_optimizer.out
+++ b/src/test/regress/expected/gp_dqa_optimizer.out
@@ -3251,16 +3251,19 @@ DETAIL: Falling back to Postgres-based planner because
GPORCA does not support
set optimizer_enable_multiple_distinct_aggs=on;
explain (verbose on, costs off) select count(distinct a), count(distinct b)
from dqa_f4 group by c;
-
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
Output: (count(DISTINCT share0_ref3.a)), (count(DISTINCT share0_ref2.b))
-> Sequence
Output: (count(DISTINCT share0_ref3.a)), (count(DISTINCT
share0_ref2.b))
-> Shared Scan (share slice:id 1:0)
- Output: share0_ref1.a, share0_ref1.b, share0_ref1.c,
share0_ref1.ctid, share0_ref1.xmin, share0_ref1.cmin, share0_ref1.xmax,
share0_ref1.cmax, share0_ref1.tableoid, share0_ref1.gp_segment_id,
share0_ref1.gp_foreign_server
- -> Seq Scan on public.dqa_f4
- Output: dqa_f4.a, dqa_f4.b, dqa_f4.c, dqa_f4.ctid,
dqa_f4.xmin, dqa_f4.cmin, dqa_f4.xmax, dqa_f4.cmax, dqa_f4.tableoid,
dqa_f4.gp_segment_id, dqa_f4.gp_foreign_server
+ Output: share0_ref1.a, share0_ref1.b, share0_ref1.c
+ -> Redistribute Motion 3:3 (slice2; segments: 3)
+ Output: dqa_f4.a, dqa_f4.b, dqa_f4.c
+ Hash Key: dqa_f4.c
+ -> Seq Scan on public.dqa_f4
+ Output: dqa_f4.a, dqa_f4.b, dqa_f4.c
-> Hash Join
Output: (count(DISTINCT share0_ref3.a)), (count(DISTINCT
share0_ref2.b))
Hash Cond: (NOT (share0_ref3.c IS DISTINCT FROM share0_ref2.c))
@@ -3268,33 +3271,23 @@ explain (verbose on, costs off) select count(distinct
a), count(distinct b) from
Output: count(DISTINCT share0_ref3.a), share0_ref3.c
Group Key: share0_ref3.c
-> Sort
- Output: share0_ref3.a, share0_ref3.c
+ Output: share0_ref3.a, share0_ref3.b, share0_ref3.c
Sort Key: share0_ref3.c
- -> Redistribute Motion 3:3 (slice2; segments: 3)
- Output: share0_ref3.a, share0_ref3.c
- Hash Key: share0_ref3.c
- -> Result
- Output: share0_ref3.a, share0_ref3.c
- -> Shared Scan (share slice:id 2:0)
- Output: share0_ref3.a,
share0_ref3.b, share0_ref3.c
+ -> Shared Scan (share slice:id 1:0)
+ Output: share0_ref3.a, share0_ref3.b,
share0_ref3.c
-> Hash
Output: (count(DISTINCT share0_ref2.b)), share0_ref2.c
-> GroupAggregate
Output: count(DISTINCT share0_ref2.b), share0_ref2.c
Group Key: share0_ref2.c
-> Sort
- Output: share0_ref2.b, share0_ref2.c
+ Output: share0_ref2.a, share0_ref2.b,
share0_ref2.c
Sort Key: share0_ref2.c
- -> Redistribute Motion 3:3 (slice3;
segments: 3)
- Output: share0_ref2.b, share0_ref2.c
- Hash Key: share0_ref2.c
- -> Result
- Output: share0_ref2.b,
share0_ref2.c
- -> Shared Scan (share slice:id
3:0)
- Output: share0_ref2.a,
share0_ref2.b, share0_ref2.c
- Settings: enable_groupagg = 'off', enable_hashagg = 'on', enable_parallel =
'off', gp_motion_cost_per_row = '2', optimizer = 'on'
+ -> Shared Scan (share slice:id 1:0)
+ Output: share0_ref2.a, share0_ref2.b,
share0_ref2.c
+ Settings: gp_motion_cost_per_row = '2', enable_hashagg = 'on',
enable_groupagg = 'off'
Optimizer: GPORCA
-(41 rows)
+(34 rows)
select count(distinct a), count(distinct b) from dqa_f4 group by c;
count | count
@@ -3312,16 +3305,19 @@ insert into dqa_f5 values(null, null, null);
insert into dqa_f5 values(1, 1, 1);
insert into dqa_f5 values(2, 2, 2);
explain (verbose on, costs off) select count(distinct a), count(distinct b)
from dqa_f5 group by c;
-
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3)
Output: (count(DISTINCT share0_ref3.a)), (count(DISTINCT share0_ref2.b))
-> Sequence
Output: (count(DISTINCT share0_ref3.a)), (count(DISTINCT
share0_ref2.b))
-> Shared Scan (share slice:id 1:0)
- Output: share0_ref1.a, share0_ref1.b, share0_ref1.c,
share0_ref1.ctid, share0_ref1.tableoid, share0_ref1.gp_segment_id,
share0_ref1.gp_foreign_server
- -> Seq Scan on public.dqa_f5
- Output: dqa_f5.a, dqa_f5.b, dqa_f5.c, dqa_f5.ctid,
dqa_f5.tableoid, dqa_f5.gp_segment_id, dqa_f5.gp_foreign_server
+ Output: share0_ref1.a, share0_ref1.b, share0_ref1.c
+ -> Redistribute Motion 3:3 (slice2; segments: 3)
+ Output: dqa_f5.a, dqa_f5.b, dqa_f5.c
+ Hash Key: dqa_f5.c
+ -> Seq Scan on public.dqa_f5
+ Output: dqa_f5.a, dqa_f5.b, dqa_f5.c
-> Hash Join
Output: (count(DISTINCT share0_ref3.a)), (count(DISTINCT
share0_ref2.b))
Hash Cond: (NOT (share0_ref3.c IS DISTINCT FROM share0_ref2.c))
@@ -3329,42 +3325,143 @@ explain (verbose on, costs off) select count(distinct
a), count(distinct b) from
Output: count(DISTINCT share0_ref3.a), share0_ref3.c
Group Key: share0_ref3.c
-> Sort
- Output: share0_ref3.a, share0_ref3.c
+ Output: share0_ref3.a, share0_ref3.b, share0_ref3.c
Sort Key: share0_ref3.c
- -> Redistribute Motion 3:3 (slice2; segments: 3)
- Output: share0_ref3.a, share0_ref3.c
- Hash Key: share0_ref3.c
- -> Result
- Output: share0_ref3.a, share0_ref3.c
- -> Shared Scan (share slice:id 2:0)
- Output: share0_ref3.a,
share0_ref3.b, share0_ref3.c
+ -> Shared Scan (share slice:id 1:0)
+ Output: share0_ref3.a, share0_ref3.b,
share0_ref3.c
-> Hash
Output: (count(DISTINCT share0_ref2.b)), share0_ref2.c
-> GroupAggregate
Output: count(DISTINCT share0_ref2.b), share0_ref2.c
Group Key: share0_ref2.c
-> Sort
- Output: share0_ref2.b, share0_ref2.c
+ Output: share0_ref2.a, share0_ref2.b,
share0_ref2.c
Sort Key: share0_ref2.c
- -> Redistribute Motion 3:3 (slice3;
segments: 3)
- Output: share0_ref2.b, share0_ref2.c
- Hash Key: share0_ref2.c
- -> Result
- Output: share0_ref2.b,
share0_ref2.c
- -> Shared Scan (share slice:id
3:0)
- Output: share0_ref2.a,
share0_ref2.b, share0_ref2.c
- Settings: enable_groupagg = 'off', enable_hashagg = 'on',
gp_motion_cost_per_row = '2'
+ -> Shared Scan (share slice:id 1:0)
+ Output: share0_ref2.a, share0_ref2.b,
share0_ref2.c
+ Settings: gp_motion_cost_per_row = '2', enable_hashagg = 'on',
enable_groupagg = 'off'
Optimizer: GPORCA
-(41 rows)
+(34 rows)
select count(distinct a), count(distinct b) from dqa_f5 group by c;
count | count
-------+-------
1 | 1
- 0 | 0
1 | 1
+ 0 | 0
(3 rows)
reset optimizer_enable_multiple_distinct_aggs;
drop table dqa_f4;
drop table dqa_f5;
+-- Test MDQA on a partitioned table.
+-- Pre-fix, CXformGbAggWithMDQA2Join declared every column the child could
+-- produce on the CTE Producer, so unused and system columns with EUnknown
+-- usage leaked into the producer's column list and crashed ORCA on the
+-- partitioned-table path (failed assertion "col_ref->GetUsage() !=
+-- CColRef::EUnknown" in assert builds, SIGSEGV in release builds).
+set optimizer_enable_multiple_distinct_aggs=on;
+create table mdqa_part(a int, b int, c int, d int)
+distributed by (a)
+partition by range(a) (
+ start (0) end (100) every (50),
+ default partition other
+);
+insert into mdqa_part select i, i%5, i%3, i%7 from generate_series(1, 100) i;
+create index mdqa_part_b_idx on mdqa_part(b);
+analyze mdqa_part;
+explain (costs off)
+select a, count(distinct b) as cnt_b, count(distinct c) as cnt_c
+from mdqa_part where b between 0 and 2 group by a;
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Gather Motion 3:1 (slice1; segments: 3)
+ -> Sequence
+ -> Shared Scan (share slice:id 1:0)
+ -> Dynamic Index Scan on mdqa_part_b_idx on mdqa_part
+ Index Cond: ((b >= 0) AND (b <= 2))
+ Number of partitions to scan: 3 (out of 3)
+ -> Hash Join
+ Hash Cond: (NOT (share0_ref3.a IS DISTINCT FROM share0_ref2.a))
+ -> GroupAggregate
+ Group Key: share0_ref3.a
+ -> Sort
+ Sort Key: share0_ref3.a
+ -> Shared Scan (share slice:id 1:0)
+ -> Hash
+ -> GroupAggregate
+ Group Key: share0_ref2.a
+ -> Sort
+ Sort Key: share0_ref2.a
+ -> Shared Scan (share slice:id 1:0)
+ Optimizer: GPORCA
+(20 rows)
+
+select a, count(distinct b) as cnt_b, count(distinct c) as cnt_c
+from mdqa_part where b between 0 and 2 group by a;
+ a | cnt_b | cnt_c
+-----+-------+-------
+ 2 | 1 | 1
+ 7 | 1 | 1
+ 16 | 1 | 1
+ 22 | 1 | 1
+ 27 | 1 | 1
+ 37 | 1 | 1
+ 41 | 1 | 1
+ 42 | 1 | 1
+ 45 | 1 | 1
+ 51 | 1 | 1
+ 55 | 1 | 1
+ 60 | 1 | 1
+ 65 | 1 | 1
+ 66 | 1 | 1
+ 70 | 1 | 1
+ 75 | 1 | 1
+ 77 | 1 | 1
+ 80 | 1 | 1
+ 81 | 1 | 1
+ 90 | 1 | 1
+ 92 | 1 | 1
+ 97 | 1 | 1
+ 5 | 1 | 1
+ 6 | 1 | 1
+ 10 | 1 | 1
+ 11 | 1 | 1
+ 17 | 1 | 1
+ 21 | 1 | 1
+ 25 | 1 | 1
+ 32 | 1 | 1
+ 52 | 1 | 1
+ 56 | 1 | 1
+ 62 | 1 | 1
+ 67 | 1 | 1
+ 82 | 1 | 1
+ 85 | 1 | 1
+ 96 | 1 | 1
+ 100 | 1 | 1
+ 1 | 1 | 1
+ 12 | 1 | 1
+ 15 | 1 | 1
+ 20 | 1 | 1
+ 26 | 1 | 1
+ 30 | 1 | 1
+ 31 | 1 | 1
+ 35 | 1 | 1
+ 36 | 1 | 1
+ 40 | 1 | 1
+ 46 | 1 | 1
+ 47 | 1 | 1
+ 50 | 1 | 1
+ 57 | 1 | 1
+ 61 | 1 | 1
+ 71 | 1 | 1
+ 72 | 1 | 1
+ 76 | 1 | 1
+ 86 | 1 | 1
+ 87 | 1 | 1
+ 91 | 1 | 1
+ 95 | 1 | 1
+(60 rows)
+
+reset optimizer_enable_multiple_distinct_aggs;
+drop table mdqa_part;
diff --git a/src/test/regress/sql/gp_dqa.sql b/src/test/regress/sql/gp_dqa.sql
index fc243d74e5e..6ad414127f3 100644
--- a/src/test/regress/sql/gp_dqa.sql
+++ b/src/test/regress/sql/gp_dqa.sql
@@ -616,3 +616,31 @@ select count(distinct a), count(distinct b) from dqa_f5
group by c;
reset optimizer_enable_multiple_distinct_aggs;
drop table dqa_f4;
drop table dqa_f5;
+
+-- Test MDQA on a partitioned table.
+-- Pre-fix, CXformGbAggWithMDQA2Join declared every column the child could
+-- produce on the CTE Producer, so unused and system columns with EUnknown
+-- usage leaked into the producer's column list and crashed ORCA on the
+-- partitioned-table path (failed assertion "col_ref->GetUsage() !=
+-- CColRef::EUnknown" in assert builds, SIGSEGV in release builds).
+set optimizer_enable_multiple_distinct_aggs=on;
+
+create table mdqa_part(a int, b int, c int, d int)
+distributed by (a)
+partition by range(a) (
+ start (0) end (100) every (50),
+ default partition other
+);
+insert into mdqa_part select i, i%5, i%3, i%7 from generate_series(1, 100) i;
+create index mdqa_part_b_idx on mdqa_part(b);
+analyze mdqa_part;
+
+explain (costs off)
+select a, count(distinct b) as cnt_b, count(distinct c) as cnt_c
+from mdqa_part where b between 0 and 2 group by a;
+
+select a, count(distinct b) as cnt_b, count(distinct c) as cnt_c
+from mdqa_part where b between 0 and 2 group by a;
+
+reset optimizer_enable_multiple_distinct_aggs;
+drop table mdqa_part;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]