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 225933d485 [CALCITE-7052] When conformance specifies isGroupbyAlias = 
true the validator rejects legal queries
225933d485 is described below

commit 225933d485130a65f1846f0d0c69b048195bbb56
Author: Mihai Budiu <[email protected]>
AuthorDate: Mon Jun 16 01:41:03 2025 +0200

    [CALCITE-7052] When conformance specifies isGroupbyAlias = true the 
validator rejects legal queries
    
    Signed-off-by: Mihai Budiu <[email protected]>
---
 .../calcite/sql/validate/SqlValidatorImpl.java     | 118 ++++--
 .../apache/calcite/test/SqlToRelConverterTest.java |  29 ++
 .../org/apache/calcite/test/SqlValidatorTest.java  |  40 +-
 .../apache/calcite/test/SqlToRelConverterTest.xml  |  37 +-
 core/src/test/resources/sql/aliasing.iq            | 465 +++++++++++++++++++++
 core/src/test/resources/sql/misc.iq                |  18 -
 6 files changed, 633 insertions(+), 74 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 dae940982a..69b2baf2d4 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
@@ -7236,6 +7236,30 @@ public SqlNode go(SqlNode root) {
           () -> this + " returned null for " + root);
     }
 
+    /** True if the exception ex indicates that name lookup has failed. */
+    public static boolean isNotFoundException(Exception ex) {
+      if (!(ex instanceof CalciteContextException)) {
+        return false;
+      }
+      String message = ex.getMessage();
+      if (message == null || !message.contains("not found")) {
+        return false;
+      }
+      return true;
+    }
+
+    /** True if the exception ex indicates that a column is ambiguous. */
+    public static boolean isAmbiguousException(Exception ex) {
+      if (!(ex instanceof CalciteContextException)) {
+        return false;
+      }
+      String message = ex.getMessage();
+      if (message == null || !message.contains("is ambiguous")) {
+        return false;
+      }
+      return true;
+    }
+
     @Override public @Nullable SqlNode visit(SqlIdentifier id) {
       // First check for builtin functions which don't have
       // parentheses, like "LOCALTIME".
@@ -7452,11 +7476,7 @@ private SelectExpander(SelectExpander expander) {
         try {
           return super.visit(id);
         } catch (Exception ex) {
-          if (!(ex instanceof CalciteContextException)) {
-            throw ex;
-          }
-          String message = ex.getMessage();
-          if (message != null && !message.contains("not found")) {
+          if (!isNotFoundException(ex)) {
             throw ex;
           }
           // This point is reached only if the name lookup failed using 
standard rules
@@ -7540,7 +7560,10 @@ static class ExtendedExpander extends Expander {
     final SqlSelect select;
     final SqlNode root;
     final Clause clause;
-    // Retain only expandable aliases or ordinals to prevent their expansion 
in a SQL call expr.
+    // This contains the ordinal nodes in a GROUP BY that may need to be 
expanded
+    // into column names when using a conformance that allows ordinals in 
group bys
+    // E.g., For GROUP BY 1, 1 will be in this list
+    // For GROUP BY CUBE(1), 1 will also be in this list
     final Set<SqlNode> aliasOrdinalExpandSet = Sets.newIdentityHashSet();
 
     ExtendedExpander(SqlValidatorImpl validator, SqlValidatorScope scope,
@@ -7550,7 +7573,7 @@ static class ExtendedExpander extends Expander {
       this.root = root;
       this.clause = clause;
       if (clause == Clause.GROUP_BY) {
-        addExpandableExpressions();
+        addExpandableOrdinals();
       }
     }
 
@@ -7561,18 +7584,54 @@ static class ExtendedExpander extends Expander {
 
       final SelectScope selectScope = 
validator.getRawSelectScopeNonNull(select);
       final boolean replaceAliases = 
clause.shouldReplaceAliases(validator.config);
-      if (!replaceAliases || (clause == Clause.GROUP_BY && 
!aliasOrdinalExpandSet.contains(id))) {
-        SqlNode node = expandCommonColumn(select, id, selectScope, validator);
-        if (node != id) {
-          return node;
+      try {
+        // First try a standard expansion
+        if (clause == Clause.GROUP_BY) {
+          SqlNode node = expandCommonColumn(select, id, selectScope, 
validator);
+          if (node != id) {
+            return node;
+          }
+          return super.visit(id);
         }
-        return super.visit(id);
+      } catch (Exception ex) {
+        // This behavior is from MySQL:
+        // - if there is no column in the FROM with the name used in the GROUP 
BY
+        //   then look for a column alias in the SELECT
+        // - if there are multiple columns in the FROM with the name used in 
the GROUP BY,
+        //   then also look for a column alias in the SELECT
+        if (!Expander.isNotFoundException(ex) && 
!Expander.isAmbiguousException(ex)) {
+          throw ex;
+        }
+        if (!replaceAliases) {
+          throw ex;
+        }
+        // Continue execution, trying to replace alias
       }
 
-      String name = id.getSimple();
-      SqlNode expr = null;
       final SqlNameMatcher nameMatcher =
           validator.catalogReader.nameMatcher();
+
+      if (clause == Clause.HAVING) {
+        if (!replaceAliases) {
+          return id;
+        }
+
+        // Do not expand aliases in HAVING if they are being grouped on
+        SqlNodeList list = select.getGroup();
+        if (list != null) {
+          // HAVING can be used without GROUP BY
+          for (SqlNode node : list) {
+            if (node instanceof SqlIdentifier) {
+              SqlIdentifier grouped = (SqlIdentifier) node;
+              if (nameMatcher.matches(id.getSimple(), 
Util.last(grouped.names))) {
+                return id;
+              }
+            }
+          }
+        }
+      }
+      String name = id.getSimple();
+      SqlNode expr = null;
       int n = 0;
       for (SqlNode s : SqlNonNullableAccessors.getSelectList(select)) {
         final @Nullable String alias = SqlValidatorUtil.alias(s);
@@ -7598,8 +7657,10 @@ static class ExtendedExpander extends Expander {
 
       // expr cannot be null; in that case n = 0 would have returned
       requireNonNull(expr, "expr");
-      if (validator.getConformance().isSelectAlias()
-              != SqlConformance.SelectAliasLookup.UNSUPPORTED) {
+      if ((clause == Clause.SELECT
+          && (validator.getConformance().isSelectAlias()
+          != SqlConformance.SelectAliasLookup.UNSUPPORTED))
+          || clause == Clause.GROUP_BY) {
         Map<String, SqlNode> expansions = new HashMap<>();
         final Expander expander = new SelectExpander(validator, selectScope, 
select, expansions);
         expr = expander.go(expr);
@@ -7641,18 +7702,15 @@ static class ExtendedExpander extends Expander {
           break;
         }
       }
-
       return super.visit(literal);
     }
 
     /**
-     * Add all possible expandable 'group by' expression to set, which is
-     * used to check whether expr could be expanded as alias or ordinal.
+     * Add all possible expandable 'group by' ordinals to {@link 
aliasOrdinalExpandSet}.
      */
     @RequiresNonNull({"root"})
-    private void addExpandableExpressions(@UnknownInitialization 
ExtendedExpander this) {
+    private void addExpandableOrdinals(@UnknownInitialization ExtendedExpander 
this) {
       switch (root.getKind()) {
-      case IDENTIFIER:
       case LITERAL:
         aliasOrdinalExpandSet.add(root);
         break;
@@ -7662,7 +7720,7 @@ private void 
addExpandableExpressions(@UnknownInitialization ExtendedExpander th
         if (root instanceof SqlBasicCall) {
           List<SqlNode> operandList = ((SqlBasicCall) root).getOperandList();
           for (SqlNode sqlNode : operandList) {
-            addIdentifierOrdinal2ExpandSet(sqlNode);
+            addOrdinal2ExpandSet(sqlNode);
           }
         }
         break;
@@ -7672,18 +7730,18 @@ private void 
addExpandableExpressions(@UnknownInitialization ExtendedExpander th
     }
 
     /**
-     * Identifier or literal in grouping sets, rollup, cube will be eligible 
for alias.
+     * Literal in grouping sets, rollup, cube will be expanded.
      *
      * @param sqlNode expression within grouping sets, rollup, cube
      */
-    private void addIdentifierOrdinal2ExpandSet(@UnknownInitialization 
ExtendedExpander this,
+    private void addOrdinal2ExpandSet(@UnknownInitialization ExtendedExpander 
this,
         SqlNode sqlNode) {
       if (sqlNode.getKind() == SqlKind.ROW) {
         List<SqlNode> rowOperandList = ((SqlCall) sqlNode).getOperandList();
         for (SqlNode node : rowOperandList) {
-          addIdentifierOrdinal2ExpandSet(node);
+          addOrdinal2ExpandSet(node);
         }
-      } else if (sqlNode.getKind() == SqlKind.IDENTIFIER || sqlNode.getKind() 
== SqlKind.LITERAL) {
+      } else if (sqlNode.getKind() == SqlKind.LITERAL) {
         aliasOrdinalExpandSet.add(sqlNode);
       }
     }
@@ -8218,14 +8276,10 @@ private enum Clause {
     boolean shouldReplaceAliases(Config config) {
       switch (this) {
       case GROUP_BY:
-        return config.conformance().isGroupByAlias()
-                || (config.conformance().isSelectAlias()
-                != SqlConformance.SelectAliasLookup.UNSUPPORTED);
+        return config.conformance().isGroupByAlias();
 
       case HAVING:
-        return config.conformance().isHavingAlias()
-                || (config.conformance().isSelectAlias()
-                != SqlConformance.SelectAliasLookup.UNSUPPORTED);
+        return config.conformance().isHavingAlias();
 
       case QUALIFY:
         return true;
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 02afa42041..761433d147 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -461,7 +461,12 @@ public static void checkActualAndReferenceFiles() {
   }
 
   @Test void testGroupByAliasEqualToColumnName() {
+    // If the alias (deptno) matches an existing column, it is not used in the 
GROUP BY
     sql("select empno, ename as deptno from emp group by empno, deptno")
+        .withConformance(SqlConformanceEnum.LENIENT)
+        .throws_("Expression 'ENAME' is not being grouped");
+    // If the alias is a new one, it is used in the GROUP BY
+    sql("select empno, ename as x from emp group by empno, x")
         .withConformance(SqlConformanceEnum.LENIENT).ok();
   }
 
@@ -508,6 +513,30 @@ public static void checkActualAndReferenceFiles() {
         .ok();
   }
 
+  /**
+   * Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-4512";>[CALCITE-4512]
+   * GROUP BY expression with argument name same with SELECT field and alias 
causes
+   * validation error</a>.
+   */
+  @Test void testGroupByExprArgFieldSameWithAlias3() {
+    // Same as the test above, but different conformance.
+    // Must produce the exact same plan.
+    final String sql = "SELECT deptno / 2 AS deptno, deptno / 2 as empno, 
sum(sal)\n"
+        + "FROM emp\n"
+        + "GROUP BY GROUPING SETS "
+        + "((deptno), (empno, deptno / 2), (2, 1), ((1, 2), (deptno, deptno / 
2)))";
+    sql(sql)
+        .withConformance(
+            // This ensures that numbers in grouping sets are interpreted as 
column numbers
+            new SqlDelegatingConformance(SqlConformanceEnum.DEFAULT) {
+              @Override public boolean isGroupByOrdinal() {
+                return true;
+              }
+            })
+        .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 e7a5699b8e..958be01b8b 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -293,6 +293,26 @@ static SqlOperatorTable operatorTableFor(SqlLibrary 
library) {
         .fails("(?s).*Illegal TIMESTAMP literal.*");
   }
 
+  /**
+   * Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-7052";>[CALCITE-7052]
+   * When conformance specifies isGroupbyAlias = true the validator rejects 
legal queries</a>.
+   */
+  @Test void testHavingTableAlias() {
+    sql("select ename as deptno from emp as e join dept as d on "
+        + "e.deptno = d.deptno group by ^deptno^")
+        .fails("Column 'DEPTNO' is ambiguous");
+    sql("select ename as deptno from emp as e join dept as d on "
+        + "e.deptno = d.deptno group by ^deptno^")
+        .withConformance(SqlConformanceEnum.LENIENT)
+        .ok();
+    sql("SELECT ALL - cor0.empno AS empno "
+        + "FROM emp AS cor0 GROUP BY empno HAVING NOT ( cor0.empno ) IS NULL")
+        .withConformance(SqlConformanceEnum.LENIENT)
+        .ok();
+    sql("select floor(empno/2) as empno from emp group by empno")
+        .withConformance(SqlConformanceEnum.LENIENT).ok();
+  }
+
   /** PostgreSQL and Redshift allow TIMESTAMP literals that contain only a
    * date part. */
   @Test void testShortTimestampLiteral() {
@@ -6556,6 +6576,7 @@ public boolean isBangEqualAllowed() {
         .withConformance(lenient).ok();
     sql("select ename as deptno from emp as e join dept as d on "
         + "e.deptno = d.deptno group by ^deptno^")
+        .withConformance(strict).fails("Column 'DEPTNO' is ambiguous")
         .withConformance(lenient).ok();
     sql("select t.e, count(*) from (select empno as e from emp) t group by e")
         .withConformance(strict).ok()
@@ -6589,12 +6610,14 @@ public boolean isBangEqualAllowed() {
     sql("select deptno + empno as d, deptno + empno + mgr from emp"
         + " group by d,mgr")
         .withConformance(lenient).ok();
-    // When alias is equal to one or more columns in the query then giving
-    // priority to alias. But Postgres may throw ambiguous column error or give
-    // priority to column name.
+    // Alias is not used since there is a single column in the SELECT already 
matching
     sql("select count(*) from (\n"
-        + "  select ename AS deptno FROM emp GROUP BY deptno) t")
-        .withConformance(lenient).ok();
+        + "  select ^ename^ AS deptno FROM emp GROUP BY deptno) t")
+        .withConformance(strict)
+        .fails("Expression 'ENAME' is not being grouped")
+        .withConformance(lenient)
+        .fails("Expression 'ENAME' is not being grouped");
+    // When alias matches multiple columns in the SELECT, alias takes 
precedence
     sql("select count(*) from "
         + "(select ename AS deptno FROM emp, dept GROUP BY deptno) t")
         .withConformance(lenient).ok();
@@ -6806,9 +6829,10 @@ public boolean isBangEqualAllowed() {
     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
-    // priority to alias, but PostgreSQL throws ambiguous column error or gives
-    // priority to column name.
+    // When alias matches multiple columns in the query, alias has priority.
+    sql("select ename AS deptno FROM emp, dept GROUP BY ^deptno^ HAVING deptno 
= 2")
+        .withConformance(strict).fails("Column 'DEPTNO' is ambiguous")
+        .withConformance(lenient).ok();
     sql("select count(empno) as deptno from emp having ^deptno^ > 10")
         .withConformance(strict).fails("Expression 'DEPTNO' is not being 
grouped")
         .withConformance(lenient).ok();
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 105ba0f9e4..cde9a7b197 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -2302,12 +2302,12 @@ LogicalAggregate(group=[{0}])
     <Resource name="plan">
       <![CDATA[
 LogicalAggregate(group=[{0, 1}])
-  LogicalProject(EMPNO=[$0], DEPTNO=[$1])
+  LogicalProject(EMPNO=[$0], X=[$1])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
     </Resource>
     <Resource name="sql">
-      <![CDATA[select empno, ename as deptno from emp group by empno, deptno]]>
+      <![CDATA[select empno, ename as x from emp group by empno, x]]>
     </Resource>
   </TestCase>
   <TestCase name="testGroupByAliasOfSubExpressionsInProject">
@@ -2476,20 +2476,25 @@ GROUP BY GROUPING SETS ((deptno), (empno, deptno / 2), 
(2, 1), ((1, 2), (deptno,
     </Resource>
     <Resource name="plan">
       <![CDATA[
-LogicalProject(DEPTNO=[$0], EMPNO=[$0], EXPR$2=[$1])
-  LogicalUnion(all=[true])
-    LogicalAggregate(group=[{0}], EXPR$2=[SUM($1)])
-      LogicalProject(EMPNO=[/($7, 2)], SAL=[$5])
-        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-    LogicalAggregate(group=[{0}], EXPR$2=[SUM($1)])
-      LogicalProject(EMPNO=[/($7, 2)], SAL=[$5])
-        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-    LogicalAggregate(group=[{0}], EXPR$2=[SUM($1)])
-      LogicalProject(EMPNO=[/($7, 2)], SAL=[$5])
-        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-    LogicalAggregate(group=[{0}], EXPR$2=[SUM($1)])
-      LogicalProject(EMPNO=[/($7, 2)], SAL=[$5])
-        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+LogicalProject(DEPTNO=[$2], EMPNO=[$2], EXPR$2=[$3])
+  LogicalAggregate(group=[{0, 1, 2}], groups=[[{0, 2}, {0}, {1, 2}, {2}]], 
EXPR$2=[SUM($3)])
+    LogicalProject(DEPTNO=[$7], EMPNO=[$0], $f2=[/($7, 2)], SAL=[$5])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testGroupByExprArgFieldSameWithAlias3">
+    <Resource name="sql">
+      <![CDATA[SELECT deptno / 2 AS deptno, deptno / 2 as empno, sum(sal)
+FROM emp
+GROUP BY GROUPING SETS ((deptno), (empno, deptno / 2), (2, 1), ((1, 2), 
(deptno, deptno / 2)))]]>
+    </Resource>
+    <Resource name="plan">
+      <![CDATA[
+LogicalProject(DEPTNO=[$2], EMPNO=[$2], EXPR$2=[$3])
+  LogicalAggregate(group=[{0, 1, 2}], groups=[[{0, 2}, {0}, {1, 2}, {2}]], 
EXPR$2=[SUM($3)])
+    LogicalProject(DEPTNO=[$7], EMPNO=[$0], $f2=[/($7, 2)], SAL=[$5])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
     </Resource>
   </TestCase>
diff --git a/core/src/test/resources/sql/aliasing.iq 
b/core/src/test/resources/sql/aliasing.iq
new file mode 100644
index 0000000000..2d36e2b4ae
--- /dev/null
+++ b/core/src/test/resources/sql/aliasing.iq
@@ -0,0 +1,465 @@
+# aliasing.iq - Test for column aliases in GROUP BY, HAVING, SELECT
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# They exercise various aliasing options for GROUP BY, HAVING, and SELECT.
+
+!use scott
+!set outputformat mysql
+
+# [CALCITE-4512] GROUP BY expression with argument name same with SELECT field 
and alias causes validation error
+SELECT floor(empno/2) as empno
+FROM emp
+GROUP BY floor(empno/2);
+
+SELECT FLOOR("EMP"."EMPNO" / 2) AS "EMPNO"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY FLOOR("EMP"."EMPNO" / 2)
+!explain-validated-on calcite
+#
++-------+
+| EMPNO |
++-------+
+|  3684 |
+|  3749 |
+|  3760 |
+|  3783 |
+|  3827 |
+|  3849 |
+|  3891 |
+|  3894 |
+|  3919 |
+|  3922 |
+|  3938 |
+|  3950 |
+|  3951 |
+|  3967 |
++-------+
+(14 rows)
+
+!ok
+
+!use scott-lenient
+
+# Result should be the same as above
+# Validated using MySQL
+SELECT floor(empno/2) as empno
+FROM emp
+GROUP BY floor(empno/2);
+
+SELECT FLOOR("EMP"."EMPNO" / 2) AS "EMPNO"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY FLOOR("EMP"."EMPNO" / 2)
+!explain-validated-on calcite
+#
++-------+
+| EMPNO |
++-------+
+|  3684 |
+|  3749 |
+|  3760 |
+|  3783 |
+|  3827 |
+|  3849 |
+|  3891 |
+|  3894 |
+|  3919 |
+|  3922 |
+|  3938 |
+|  3950 |
+|  3951 |
+|  3967 |
++-------+
+(14 rows)
+
+!ok
+
+# Test cases for CALCITE-7052
+# When conformance specifies isGroupbyAlias = true the validator rejects legal 
queries
+# Result validated using MySQL
+SELECT floor(empno/2) as empno
+FROM emp
+GROUP BY empno;
+
+SELECT FLOOR("EMP"."EMPNO" / 2) AS "EMPNO"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY "EMP"."EMPNO"
+!explain-validated-on calcite
+#
++-------+
+| EMPNO |
++-------+
+|  3684 |
+|  3749 |
+|  3760 |
+|  3783 |
+|  3827 |
+|  3849 |
+|  3891 |
+|  3894 |
+|  3919 |
+|  3922 |
+|  3938 |
+|  3950 |
+|  3951 |
+|  3967 |
++-------+
+(14 rows)
+
+!ok
+
+# Result validated using MySQL
+SELECT floor(empno/100) as empno
+FROM emp
+GROUP BY empno;
+
+SELECT FLOOR("EMP"."EMPNO" / 100) AS "EMPNO"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY "EMP"."EMPNO"
+!explain-validated-on calcite
+#
++-------+
+| EMPNO |
++-------+
+|    73 |
+|    74 |
+|    75 |
+|    75 |
+|    76 |
+|    76 |
+|    77 |
+|    77 |
+|    78 |
+|    78 |
+|    78 |
+|    79 |
+|    79 |
+|    79 |
++-------+
+(14 rows)
+
+!ok
+
+# Result validated using MySQL
+SELECT floor(empno/100) as empno
+FROM emp
+GROUP BY floor(empno/100);
+
+SELECT FLOOR("EMP"."EMPNO" / 100) AS "EMPNO"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY FLOOR("EMP"."EMPNO" / 100)
+!explain-validated-on calcite
+#
++-------+
+| EMPNO |
++-------+
+|    73 |
+|    74 |
+|    75 |
+|    76 |
+|    77 |
+|    78 |
+|    79 |
++-------+
+(7 rows)
+
+!ok
+
+# Result validated using MySQL
+SELECT floor(empno/100) as X
+FROM emp
+GROUP BY X;
+
+SELECT FLOOR("EMP"."EMPNO" / 100) AS "X"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY FLOOR("EMP"."EMPNO" / 100)
+!explain-validated-on calcite
+#
++----+
+| X  |
++----+
+| 73 |
+| 74 |
+| 75 |
+| 76 |
+| 77 |
+| 78 |
+| 79 |
++----+
+(7 rows)
+
+!ok
+
+# MySQL also gives an error, but a different error message
+SELECT sum(empno) as X
+FROM emp
+GROUP BY X;
+Aggregate expression is illegal in GROUP BY clause
+!error
+
+# Validated on MySQL, by replacing / with DIV, which does integer division in 
MySQL
+SELECT sum(empno / 100) as empno
+FROM EMP
+GROUP BY empno / 100;
+
+SELECT SUM("EMP"."EMPNO" / 100) AS "EMPNO"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY "EMP"."EMPNO" / 100
+!explain-validated-on calcite
+#
++-------+
+| EMPNO |
++-------+
+|    73 |
+|    74 |
+|   150 |
+|   152 |
+|   154 |
+|   234 |
+|   237 |
++-------+
+(7 rows)
+
+!ok
+
+# Validated on MySQL, by replacing / with DIV
+SELECT sum(empno / 100), EMPNO / 100 as X
+FROM EMP
+GROUP BY X
+ORDER BY X;
+
+SELECT SUM("EMP"."EMPNO" / 100), "EMP"."EMPNO" / 100 AS "X"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY "EMP"."EMPNO" / 100
+ORDER BY "X"
+!explain-validated-on calcite
+#
++--------+----+
+| EXPR$0 | X  |
++--------+----+
+|     73 | 73 |
+|     74 | 74 |
+|    150 | 75 |
+|    152 | 76 |
+|    154 | 77 |
+|    234 | 78 |
+|    237 | 79 |
++--------+----+
+(7 rows)
+
+!ok
+
+# Validated on MySQL, by replacing / with DIV
+SELECT sum(empno / 100), EMPNO / 100 as X
+FROM EMP
+GROUP BY X
+HAVING X > 75;
+
+SELECT SUM("EMP"."EMPNO" / 100), "EMP"."EMPNO" / 100 AS "X"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY "EMP"."EMPNO" / 100
+HAVING "EMP"."EMPNO" / 100 > 75
+!explain-validated-on calcite
+#
++--------+----+
+| EXPR$0 | X  |
++--------+----+
+|    152 | 76 |
+|    154 | 77 |
+|    234 | 78 |
+|    237 | 79 |
++--------+----+
+(4 rows)
+
+!ok
+
+# Validated on MySQL, by replacing / with DIV
+SELECT sum(empno / 100), EMPNO / 100 as empno
+FROM EMP
+GROUP BY empno
+HAVING empno > 75;
+
+SELECT SUM("EMP"."EMPNO" / 100), "EMP"."EMPNO" / 100 AS "EMPNO"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY "EMP"."EMPNO"
+HAVING CAST("EMP"."EMPNO" AS INTEGER) > 75
+!explain-validated-on calcite
+#
++--------+-------+
+| EXPR$0 | EMPNO |
++--------+-------+
+|     73 |    73 |
+|     74 |    74 |
+|     75 |    75 |
+|     75 |    75 |
+|     76 |    76 |
+|     76 |    76 |
+|     77 |    77 |
+|     77 |    77 |
+|     78 |    78 |
+|     78 |    78 |
+|     78 |    78 |
+|     79 |    79 |
+|     79 |    79 |
+|     79 |    79 |
++--------+-------+
+(14 rows)
+
+!ok
+
+# Validated on MySQL
+SELECT empno AS X
+FROM EMP, DEPT
+GROUP BY X
+HAVING empno > 75;
+
+SELECT "EMP"."EMPNO" AS "X"
+FROM "scott"."EMP" AS "EMP",
+    "scott"."DEPT" AS "DEPT"
+GROUP BY "EMP"."EMPNO"
+HAVING CAST("EMP"."EMPNO" AS INTEGER) > 75
+!explain-validated-on calcite
+#
++------+
+| X    |
++------+
+| 7369 |
+| 7499 |
+| 7521 |
+| 7566 |
+| 7654 |
+| 7698 |
+| 7782 |
+| 7788 |
+| 7839 |
+| 7844 |
+| 7876 |
+| 7900 |
+| 7902 |
+| 7934 |
++------+
+(14 rows)
+
+!ok
+
+# Validated on MySQL by replacing / with DIV
+SELECT empno AS X
+FROM EMP, DEPT
+GROUP BY empno / 100
+HAVING empno > 75;
+Expression 'EMPNO' is not being grouped
+!error
+
+# Validated on MySQL by replacing / with DIV
+SELECT empno / 100 AS X
+FROM EMP, DEPT
+GROUP BY empno / 100
+HAVING empno > 75;
+Expression 'EMPNO' is not being grouped
+!error
+
+# Validated on MySQL by changing MOD to %
+SELECT MAX(empno)
+FROM EMP
+GROUP BY deptno
+HAVING MOD(MAX(empno), 2) = 0;
+
+SELECT MAX("EMP"."EMPNO")
+FROM "scott"."EMP" AS "EMP"
+GROUP BY "EMP"."DEPTNO"
+HAVING MOD(MAX("EMP"."EMPNO"), 2) = 0
+!explain-validated-on calcite
+#
++--------+
+| EXPR$0 |
++--------+
+|   7900 |
+|   7902 |
+|   7934 |
++--------+
+(3 rows)
+
+!ok
+
+# Validated on MySQL by changing MOD to %
+SELECT MAX(empno) AS X
+FROM EMP
+GROUP BY deptno
+HAVING MOD(X, 2) = 0;
+
+SELECT MAX("EMP"."EMPNO") AS "X"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY "EMP"."DEPTNO"
+HAVING MOD(MAX("EMP"."EMPNO"), 2) = 0
+!explain-validated-on calcite
+#
++------+
+| X    |
++------+
+| 7900 |
+| 7902 |
+| 7934 |
++------+
+(3 rows)
+
+!ok
+
+# Validated on MySQL by changing MOD to %
+# The alias 'deptno' is substituted in HAVING
+SELECT MAX(empno) AS deptno
+FROM EMP
+HAVING MOD(deptno, 2) = 0;
+
+SELECT MAX("EMP"."EMPNO") AS "DEPTNO"
+FROM "scott"."EMP" AS "EMP"
+HAVING MOD(MAX("EMP"."EMPNO"), 2) = 0
+!explain-validated-on calcite
+#
++--------+
+| DEPTNO |
++--------+
+|   7934 |
++--------+
+(1 row)
+
+!ok
+
+# Validated on MySQL by changing MOD to %
+# The alias 'deptno' if not substituted in HAVING because it is grouped on
+SELECT MAX(empno) AS deptno
+FROM EMP
+GROUP BY deptno
+HAVING MOD(deptno, 2) = 0;
+
+SELECT MAX("EMP"."EMPNO") AS "DEPTNO"
+FROM "scott"."EMP" AS "EMP"
+GROUP BY "EMP"."DEPTNO"
+HAVING MOD("EMP"."DEPTNO", 2) = 0
+!explain-validated-on calcite
+#
++--------+
+| DEPTNO |
++--------+
+|   7900 |
+|   7902 |
+|   7934 |
++--------+
+(3 rows)
+
+!ok
+
+# End aliasing.iq
diff --git a/core/src/test/resources/sql/misc.iq 
b/core/src/test/resources/sql/misc.iq
index 4879f1eab8..6db6e0bd45 100644
--- a/core/src/test/resources/sql/misc.iq
+++ b/core/src/test/resources/sql/misc.iq
@@ -2467,24 +2467,6 @@ FROM "hr"."emps";
 
 !ok
 
-!use post
-
-# [CALCITE-4512] GROUP BY expression with argument name same with SELECT field 
and alias causes validation error
-SELECT floor(empno/2) as empno
-FROM emps
-GROUP BY floor(empno/2);
-+-------+
-| EMPNO |
-+-------+
-|    50 |
-|    55 |
-|    60 |
-|    65 |
-+-------+
-(4 rows)
-
-!ok
-
 # [CALCITE-6566] JDBC adapter should generate PI function with parentheses in 
most dialects
 
 !use scott-mysql

Reply via email to