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 99e52c5e4ed7..a063e5b8fa9d 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 @@ -4474,6 +4474,21 @@ protected void validateWhereOrOn( SqlNode condition, String clause) { validateNoAggs(aggOrOverOrGroupFinder, condition, clause); + // SqlSelect need to expand alias + condition.accept(new SqlShuttle() { + @Override public @Nullable SqlNode visit(SqlCall call) { + call.getOperandList() + .stream() + .filter(Objects::nonNull) + .forEach(node -> node.accept(this)); + if (call.getKind() == SqlKind.SELECT) { + SqlSelect select = (SqlSelect) call; + validateHavingClause(select); + return select; + } + return call; + } + }); inferUnknownTypes( booleanType, scope, diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java index f7460a661170..fdbaf6e960cb 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -378,6 +378,28 @@ public static void checkActualAndReferenceFiles() { .withConformance(SqlConformanceEnum.LENIENT).ok(); } + /** Test case for + * [CALCITE-5486] + * SubQuery not support HAVING alias in where condition. */ + @Test void testHavingAliasInSubQuery1() { + final String sql = "select * from emp where sal >\n" + + " (select avg(sal) as s" + + " from emp having s > 0" + + " )"; + sql(sql).withConformance(SqlConformanceEnum.LENIENT).ok(); + } + + @Test void testHavingAliasInSubQuery2() { + final String sql = "select * from emp e " + + "left join dept d " + + "on e.deptno = d.deptno " + + "and sal >\n" + + " (select avg(sal) as s" + + " from emp having s > 0" + + " )"; + sql(sql).withConformance(SqlConformanceEnum.LENIENT).ok(); + } + @Test void testAliasInHaving() { sql("select count(empno) as e from emp having e > 1") .withConformance(SqlConformanceEnum.LENIENT).ok(); 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 17cc9306af1c..d7ebbcb86af9 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java @@ -5709,6 +5709,19 @@ public boolean isBangEqualAllowed() { .withConformance(lenient).ok(); } + /** Test case for + * [CALCITE-5486] + * SubQuery not support HAVING alias in where condition. */ + @Test void testHavingAliasInCondition() { + sql("select * from emp where sal >\n" + + " (select avg(sal) as s" + + " from emp having ^s^ > 0" + + " )") + .fails("Column 'S' not found in any table") + .withConformance(SqlConformanceEnum.LENIENT) + .ok(); + } + /** * Tests validation of the ORDER BY clause when DISTINCT is present. */ diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml index b69a9a400c55..169fa596ed6f 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -2598,6 +2598,64 @@ LogicalProject(DEPTNO=[$0]) LogicalAggregate(group=[{0}], agg#0=[SUM($1)], agg#1=[SUM($2)]) LogicalProject(DEPTNO=[$7], $f1=[CASE(SEARCH($7, Sarg[1, 2]), 0, 1)], $f2=[CASE(SEARCH($7, Sarg[3, 4]), 0, 1)]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + + + + + + (select avg(sal) as s from emp having s > 0 )]]> + + + ($5, $9)]) + LogicalJoin(condition=[true], joinType=[left]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + LogicalAggregate(group=[{}], agg#0=[SINGLE_VALUE($0)]) + LogicalFilter(condition=[>($0, 0)]) + LogicalAggregate(group=[{}], S=[AVG($0)]) + LogicalProject(SAL=[$5]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + + + + + + (select avg(sal) as s from emp having s > 0 )]]> + + + ($5, $9)]) + LogicalJoin(condition=[true], joinType=[left]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + LogicalAggregate(group=[{}], agg#0=[SINGLE_VALUE($0)]) + LogicalFilter(condition=[>($0, 0)]) + LogicalAggregate(group=[{}], S=[AVG($0)]) + LogicalProject(SAL=[$5]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + + + + + + (select avg(sal) as s from emp having s > 0 )]]> + + + ($5, $0))], joinType=[left]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + LogicalJoin(condition=[true], joinType=[left]) + LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) + LogicalAggregate(group=[{}], agg#0=[SINGLE_VALUE($0)]) + LogicalFilter(condition=[>($0, 0)]) + LogicalAggregate(group=[{}], S=[AVG($0)]) + LogicalProject(SAL=[$5]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]>