This is an automated email from the ASF dual-hosted git repository.
soumyakanti3578 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git
The following commit(s) were added to refs/heads/master by this push:
new 89a6b5c67ec HIVE-26368: DISTINCT keyword from Count UDF is removed
from query plan when CBO is enabled
89a6b5c67ec is described below
commit 89a6b5c67ec8304ddccf996ed0ac64a576952195
Author: Soumyakanti Das <[email protected]>
AuthorDate: Tue Aug 11 11:21:57 2026 -0700
HIVE-26368: DISTINCT keyword from Count UDF is removed from query plan when
CBO is enabled
---
.../rules/HiveExpandDistinctAggregatesRule.java | 15 +-
.../clientpositive/count_distinct_multi_col.q | 70 ++++++
.../llap/count_distinct_multi_col.q.out | 238 +++++++++++++++++++++
3 files changed, 317 insertions(+), 6 deletions(-)
diff --git
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveExpandDistinctAggregatesRule.java
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveExpandDistinctAggregatesRule.java
index 3a46498298b..6dc4ccbd48c 100644
---
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveExpandDistinctAggregatesRule.java
+++
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveExpandDistinctAggregatesRule.java
@@ -161,7 +161,14 @@ public void onMatch(RelOptRuleCall call) {
// arguments then we can use a more efficient form.
final RelMetadataQuery mq = call.getMetadataQuery();
if ((nonDistinctCount == 0) && (argListSets.size() == 1)) {
- for (Integer arg : argListSets.iterator().next()) {
+ List<Integer> argList = argListSets.iterator().next();
+ // When COUNT(DISTINCT a, b, ...) has multiple columns convertMonopole
-> rewriteAggCalls
+ // would produce COUNT(a, b) without DISTINCT at the top level, which is
semantically
+ // wrong and is rejected by GenericUDAFCount.
+ if (argList.size() > 1 && numCountDistinct > 0) {
+ return;
+ }
+ for (Integer arg : argList) {
Set<RelColumnOrigin> colOrigs =
mq.getColumnOrigins(aggregate.getInput(), arg);
if (null != colOrigs) {
for (RelColumnOrigin colOrig : colOrigs) {
@@ -173,12 +180,8 @@ public void onMatch(RelOptRuleCall call) {
}
}
}
- RelNode converted =
- convertMonopole(
- aggregate,
- argListSets.iterator().next());
+ RelNode converted = convertMonopole(aggregate, argList);
call.transformTo(converted);
- return;
}
}
diff --git a/ql/src/test/queries/clientpositive/count_distinct_multi_col.q
b/ql/src/test/queries/clientpositive/count_distinct_multi_col.q
new file mode 100644
index 00000000000..edd20477fb1
--- /dev/null
+++ b/ql/src/test/queries/clientpositive/count_distinct_multi_col.q
@@ -0,0 +1,70 @@
+create table t (col1 string, col2 int, col3 int, col4 date);
+
+insert into t values
+ ('a', 1, 2, '2022-01-01'),
+ ('a', 1, 2, '2022-01-01'),
+ ('a', 1, 2, '2022-01-02'),
+ ('a', 1, 22, '2022-01-02'),
+ ('a', 11, 2, '2022-01-01'),
+ ('a', 11, 2, '2022-01-02');
+
+-- single-column: HiveExpandDistinctAggregatesRule matched -> two
HiveAggregate operators in plan
+explain cbo
+SELECT col1, col2, COUNT(DISTINCT col3) AS cnt
+FROM t
+GROUP BY col1, col2;
+
+SELECT col1, col2, COUNT(DISTINCT col3) AS cnt
+FROM t
+GROUP BY col1, col2
+ORDER BY col1, col2;
+
+-- multi-column: HiveExpandDistinctAggregatesRule !matched -> single
HiveAggregate operator
+explain cbo
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt
+FROM t
+GROUP BY col1, col2;
+
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt
+FROM t
+GROUP BY col1, col2
+ORDER BY col1, col2;
+
+-- multi-column distinct alongside a non-distinct aggregate: single
HiveAggregate operator
+explain cbo
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt, SUM(col3) AS s
+FROM t
+GROUP BY col1, col2;
+
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt, SUM(col3) AS s
+FROM t
+GROUP BY col1, col2
+ORDER BY col1, col2;
+
+-- multiple COUNT DISTINCT with different single-column arg: uses grouping-sets
+explain cbo
+SELECT col1, COUNT(DISTINCT col3) AS c3, COUNT(DISTINCT col2) AS c2
+FROM t
+GROUP BY col1;
+
+SELECT col1, COUNT(DISTINCT col3) AS c3, COUNT(DISTINCT col2) AS c2
+FROM t
+GROUP BY col1;
+
+-- 2 COUNT DISTINCTs each with multiple columns: uses grouping-sets path
+explain cbo
+SELECT col1, COUNT(DISTINCT col2, col3) AS c1, COUNT(DISTINCT col3, col4) AS c2
+FROM t
+GROUP BY col1;
+
+SELECT col1, COUNT(DISTINCT col2, col3) AS c1, COUNT(DISTINCT col3, col4) AS c2
+FROM t
+GROUP BY col1;
+
+-- CTAS
+create table t_ctas as
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt
+FROM t
+GROUP BY col1, col2;
+
+select * from t_ctas ORDER BY col1, col2;
diff --git
a/ql/src/test/results/clientpositive/llap/count_distinct_multi_col.q.out
b/ql/src/test/results/clientpositive/llap/count_distinct_multi_col.q.out
new file mode 100644
index 00000000000..034c1a9f3ac
--- /dev/null
+++ b/ql/src/test/results/clientpositive/llap/count_distinct_multi_col.q.out
@@ -0,0 +1,238 @@
+PREHOOK: query: create table t (col1 string, col2 int, col3 int, col4 date)
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@t
+POSTHOOK: query: create table t (col1 string, col2 int, col3 int, col4 date)
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@t
+PREHOOK: query: insert into t values
+ ('a', 1, 2, '2022-01-01'),
+ ('a', 1, 2, '2022-01-01'),
+ ('a', 1, 2, '2022-01-02'),
+ ('a', 1, 22, '2022-01-02'),
+ ('a', 11, 2, '2022-01-01'),
+ ('a', 11, 2, '2022-01-02')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@t
+POSTHOOK: query: insert into t values
+ ('a', 1, 2, '2022-01-01'),
+ ('a', 1, 2, '2022-01-01'),
+ ('a', 1, 2, '2022-01-02'),
+ ('a', 1, 22, '2022-01-02'),
+ ('a', 11, 2, '2022-01-01'),
+ ('a', 11, 2, '2022-01-02')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@t
+POSTHOOK: Lineage: t.col1 SCRIPT []
+POSTHOOK: Lineage: t.col2 SCRIPT []
+POSTHOOK: Lineage: t.col3 SCRIPT []
+POSTHOOK: Lineage: t.col4 SCRIPT []
+PREHOOK: query: explain cbo
+SELECT col1, col2, COUNT(DISTINCT col3) AS cnt
+FROM t
+GROUP BY col1, col2
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+SELECT col1, col2, COUNT(DISTINCT col3) AS cnt
+FROM t
+GROUP BY col1, col2
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(col1=[$0], col2=[$1], cnt=[$2])
+ HiveAggregate(group=[{0, 1}], agg#0=[count($2)])
+ HiveProject(col1=[$0], col2=[$1], col3=[$2])
+ HiveAggregate(group=[{0, 1, 2}])
+ HiveTableScan(table=[[default, t]], table:alias=[t])
+
+PREHOOK: query: SELECT col1, col2, COUNT(DISTINCT col3) AS cnt
+FROM t
+GROUP BY col1, col2
+ORDER BY col1, col2
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT col1, col2, COUNT(DISTINCT col3) AS cnt
+FROM t
+GROUP BY col1, col2
+ORDER BY col1, col2
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+a 1 2
+a 11 1
+PREHOOK: query: explain cbo
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt
+FROM t
+GROUP BY col1, col2
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt
+FROM t
+GROUP BY col1, col2
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(col1=[$0], col2=[$1], cnt=[$2])
+ HiveAggregate(group=[{0, 1}], agg#0=[count(DISTINCT $2, $3)])
+ HiveTableScan(table=[[default, t]], table:alias=[t])
+
+PREHOOK: query: SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt
+FROM t
+GROUP BY col1, col2
+ORDER BY col1, col2
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt
+FROM t
+GROUP BY col1, col2
+ORDER BY col1, col2
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+a 1 3
+a 11 2
+PREHOOK: query: explain cbo
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt, SUM(col3) AS s
+FROM t
+GROUP BY col1, col2
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt, SUM(col3) AS s
+FROM t
+GROUP BY col1, col2
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(col1=[$0], col2=[$1], cnt=[$2], s=[$3])
+ HiveAggregate(group=[{0, 1}], agg#0=[count(DISTINCT $2, $3)],
agg#1=[sum($2)])
+ HiveTableScan(table=[[default, t]], table:alias=[t])
+
+PREHOOK: query: SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt,
SUM(col3) AS s
+FROM t
+GROUP BY col1, col2
+ORDER BY col1, col2
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt,
SUM(col3) AS s
+FROM t
+GROUP BY col1, col2
+ORDER BY col1, col2
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+a 1 3 28
+a 11 2 4
+PREHOOK: query: explain cbo
+SELECT col1, COUNT(DISTINCT col3) AS c3, COUNT(DISTINCT col2) AS c2
+FROM t
+GROUP BY col1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+SELECT col1, COUNT(DISTINCT col3) AS c3, COUNT(DISTINCT col2) AS c2
+FROM t
+GROUP BY col1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(col1=[$0], c3=[$1], c2=[$2])
+ HiveAggregate(group=[{2}], agg#0=[count($0)], agg#1=[count($1)])
+ HiveProject($f0=[CASE(AND(=($3, 1), IS NOT NULL($1)), 1, null:INTEGER)],
$f1=[CASE(AND(=($3, 2), IS NOT NULL($2)), 1, null:INTEGER)], $f2=[$0])
+ HiveAggregate(group=[{0, 1, 2}], groups=[[{0, 1}, {0, 2}]],
GROUPING__ID=[GROUPING__ID()])
+ HiveProject($f0=[$0], $f1=[$2], $f2=[$1])
+ HiveTableScan(table=[[default, t]], table:alias=[t])
+
+PREHOOK: query: SELECT col1, COUNT(DISTINCT col3) AS c3, COUNT(DISTINCT col2)
AS c2
+FROM t
+GROUP BY col1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT col1, COUNT(DISTINCT col3) AS c3, COUNT(DISTINCT col2)
AS c2
+FROM t
+GROUP BY col1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+a 2 2
+PREHOOK: query: explain cbo
+SELECT col1, COUNT(DISTINCT col2, col3) AS c1, COUNT(DISTINCT col3, col4) AS c2
+FROM t
+GROUP BY col1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+SELECT col1, COUNT(DISTINCT col2, col3) AS c1, COUNT(DISTINCT col3, col4) AS c2
+FROM t
+GROUP BY col1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(col1=[$0], c1=[$1], c2=[$2])
+ HiveAggregate(group=[{2}], agg#0=[count($0)], agg#1=[count($1)])
+ HiveProject($f0=[CASE(=($4, 1), 1, null:INTEGER)], $f1=[CASE(=($4, 4), 1,
null:INTEGER)], $f2=[$0])
+ HiveAggregate(group=[{0, 1, 2, 3}], groups=[[{0, 1, 2}, {0, 2, 3}]],
GROUPING__ID=[GROUPING__ID()])
+ HiveProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3])
+ HiveTableScan(table=[[default, t]], table:alias=[t])
+
+PREHOOK: query: SELECT col1, COUNT(DISTINCT col2, col3) AS c1, COUNT(DISTINCT
col3, col4) AS c2
+FROM t
+GROUP BY col1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT col1, COUNT(DISTINCT col2, col3) AS c1, COUNT(DISTINCT
col3, col4) AS c2
+FROM t
+GROUP BY col1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t
+#### A masked pattern was here ####
+a 3 3
+PREHOOK: query: create table t_ctas as
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt
+FROM t
+GROUP BY col1, col2
+PREHOOK: type: CREATETABLE_AS_SELECT
+PREHOOK: Input: default@t
+PREHOOK: Output: database:default
+PREHOOK: Output: default@t_ctas
+POSTHOOK: query: create table t_ctas as
+SELECT col1, col2, COUNT(DISTINCT col3, col4) AS cnt
+FROM t
+GROUP BY col1, col2
+POSTHOOK: type: CREATETABLE_AS_SELECT
+POSTHOOK: Input: default@t
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@t_ctas
+POSTHOOK: Lineage: t_ctas.cnt EXPRESSION [(t)t.FieldSchema(name:col3,
type:int, comment:null), (t)t.FieldSchema(name:col4, type:date, comment:null), ]
+POSTHOOK: Lineage: t_ctas.col1 SIMPLE [(t)t.FieldSchema(name:col1,
type:string, comment:null), ]
+POSTHOOK: Lineage: t_ctas.col2 SIMPLE [(t)t.FieldSchema(name:col2, type:int,
comment:null), ]
+PREHOOK: query: select * from t_ctas ORDER BY col1, col2
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t_ctas
+#### A masked pattern was here ####
+POSTHOOK: query: select * from t_ctas ORDER BY col1, col2
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t_ctas
+#### A masked pattern was here ####
+a 1 3
+a 11 2