This is an automated email from the ASF dual-hosted git repository.
mbudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 7865c86efb [CALCITE-6677] HAVING clauses fail validation when type
coercion is applied to GROUP BY clause
7865c86efb is described below
commit 7865c86efb9b45656bb099147f4ab1b297b84fcf
Author: Mihai Budiu <[email protected]>
AuthorDate: Wed Nov 6 16:41:42 2024 -0800
[CALCITE-6677] HAVING clauses fail validation when type coercion is applied
to GROUP BY clause
Signed-off-by: Mihai Budiu <[email protected]>
---
.../calcite/sql/validate/SqlValidatorImpl.java | 4 ++--
.../org/apache/calcite/test/SqlValidatorTest.java | 24 +++++++++++++++++-----
2 files changed, 21 insertions(+), 7 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index 44c0dce6d9..af109c47ea 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -4100,7 +4100,6 @@ public class SqlValidatorImpl implements
SqlValidatorWithHints {
validateWhereClause(select);
validateGroupClause(select);
- validateHavingClause(select);
validateWindowClause(select);
validateQualifyClause(select);
handleOffsetFetch(select.getOffset(), select.getFetch());
@@ -4111,6 +4110,7 @@ public class SqlValidatorImpl implements
SqlValidatorWithHints {
final RelDataType rowType =
validateSelectList(selectItems, select, targetRowType);
ns.setType(rowType);
+ validateHavingClause(select);
// Deduce which columns must be filtered.
ns.mustFilterFields = ImmutableBitSet.of();
@@ -4995,8 +4995,8 @@ public class SqlValidatorImpl implements
SqlValidatorWithHints {
if (SqlUtil.containsCall(having, call -> call.getOperator() instanceof
SqlOverOperator)) {
throw newValidationError(originalHaving,
RESOURCE.windowInHavingNotAllowed());
}
- havingScope.checkAggregateExpr(having, true);
inferUnknownTypes(booleanType, havingScope, having);
+ havingScope.checkAggregateExpr(having, true);
having.validate(this, havingScope);
final RelDataType type = deriveType(havingScope, having);
if (!SqlTypeUtil.inBooleanFamily(type)) {
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 1576537df3..89ae082113 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -4024,6 +4024,20 @@ public class SqlValidatorTest extends
SqlValidatorTestCase {
.type("RecordType(CHAR(2) NOT NULL A, INTEGER NOT NULL B) NOT NULL");
}
+ /** Test case for <a
href="https://issues.apache.org/jira/browse/CALCITE-6677">[CALCITE-6677]
+ * HAVING clauses fail validation when type coercion is applied to GROUP BY
clause</a>. */
+ @Test void testCoercionCast() {
+ SqlValidatorFixture f =
+ // Needed for the IF function
+ fixture().withOperatorTable(operatorTableFor(SqlLibrary.BIG_QUERY));
+ final String sql =
+ "select if(EMP.empno <= CAST(18 AS DOUBLE), 'youth', 'adult') as
adult_or_child\n"
+ + "from EMP \n"
+ + "GROUP BY if(EMP.empno <= CAST(18 AS DOUBLE), 'youth', 'adult')\n"
+ + "HAVING if(EMP.empno <= CAST(18 AS DOUBLE), 'youth', 'adult') =
'adult'";
+ f.withSql(sql).ok();
+ }
+
@Test void testMeasureRef() {
// A measure can be used in the SELECT clause of a GROUP BY query even
// though it is not a GROUP BY key.
@@ -5587,7 +5601,7 @@ public class SqlValidatorTest extends
SqlValidatorTestCase {
}
@Test void testHaving() {
- sql("select * from emp having ^sum(sal)^")
+ sql("select empno from emp group by empno having ^sum(sal)^")
.fails("HAVING clause must be a condition");
sql("select ^*^ from emp having sum(sal) > 10")
.fails("Expression 'EMP\\.EMPNO' is not being grouped");
@@ -6467,7 +6481,7 @@ public class SqlValidatorTest extends
SqlValidatorTestCase {
sql("select emp.empno as e from emp group by empno having ^e^ > 10")
.withConformance(strict).fails("Column 'E' not found in any table")
.withConformance(lenient).ok();
- sql("select e.empno from emp as e group by 1 having ^e.empno^ > 10")
+ sql("select ^e.empno^ from emp as e group by 1 having e.empno > 10")
.withConformance(strict).fails("Expression 'E.EMPNO' is not being
grouped")
.withConformance(lenient).ok();
// When alias is equal to one or more columns in the query then giving
@@ -6477,7 +6491,7 @@ public class SqlValidatorTest extends
SqlValidatorTestCase {
.withConformance(strict).fails("Expression 'DEPTNO' is not being
grouped")
.withConformance(lenient).ok();
// Alias in aggregate is not allowed.
- sql("select empno as e from emp having max(^e^) > 10")
+ sql("select empno as e from emp group by empno having max(^e^) > 10")
.withConformance(strict).fails("Column 'E' not found in any table")
.withConformance(lenient).fails("Column 'E' not found in any table");
sql("select count(empno) as e from emp having ^e^ > 10")
@@ -6995,7 +7009,7 @@ public class SqlValidatorTest extends
SqlValidatorTestCase {
.withConformance(lenient)
.fails("Window expressions are not permitted in the HAVING clause;"
+ " use the QUALIFY clause instead");
- sql("select empno from emp having ^max(empno) OVER () > 1^")
+ sql("select empno from emp group by empno having ^max(empno) OVER () > 1^")
.fails("Window expressions are not permitted in the HAVING clause;"
+ " use the QUALIFY clause instead");
}
@@ -8183,7 +8197,7 @@ public class SqlValidatorTest extends
SqlValidatorTestCase {
sql("SELECT deptno FROM emp GROUP BY deptno HAVING deptno > 55").ok();
sql("SELECT DISTINCT deptno, 33 FROM emp\n"
+ "GROUP BY deptno HAVING deptno > 55").ok();
- sql("SELECT DISTINCT deptno, 33 FROM emp HAVING ^deptno^ > 55")
+ sql("SELECT DISTINCT ^deptno^, 33 FROM emp HAVING deptno > 55")
.fails("Expression 'DEPTNO' is not being grouped");
// same query under a different conformance finds a different error first
sql("SELECT DISTINCT ^deptno^, 33 FROM emp HAVING deptno > 55")