This is an automated email from the ASF dual-hosted git repository.

zhenchen 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 6de626697a [CALCITE-7378] Potential incorrect column attribution in 
RelToSqlConverter due to implicit table alias handling
6de626697a is described below

commit 6de626697ae7014d83fac1a6dba3689ae7b0c002
Author: zzwqqq <[email protected]>
AuthorDate: Thu Jan 15 21:22:54 2026 +0800

    [CALCITE-7378] Potential incorrect column attribution in RelToSqlConverter 
due to implicit table alias handling
---
 .../apache/calcite/rel/rel2sql/SqlImplementor.java | 28 ++++++-
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java | 21 +++++-
 core/src/test/resources/sql/sub-query.iq           | 86 ++++++++++++++++++++++
 3 files changed, 133 insertions(+), 2 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java 
b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
index ece87d0b5c..6d60d52aa4 100644
--- a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
+++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
@@ -139,6 +139,7 @@
 import java.util.function.Function;
 import java.util.function.IntFunction;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 import static com.google.common.collect.ImmutableList.toImmutableList;
 
@@ -2242,12 +2243,37 @@ public SqlSelect asSelect() {
       if (node instanceof SqlSelect) {
         return (SqlSelect) node;
       }
-      if (!dialect.hasImplicitTableAlias()) {
+      if (!dialect.hasImplicitTableAlias() || hasConflictTableAlias(node)) {
         return wrapSelect(asFrom());
       }
       return wrapSelect(node);
     }
 
+    private boolean hasConflictTableAlias(SqlNode node) {
+      if (!(node instanceof SqlIdentifier)) {
+        return false;
+      }
+      if (correlTableMap.isEmpty()) {
+        return false;
+      }
+      if (neededAlias == null) {
+        return false;
+      }
+      SqlIdentifier identifier = (SqlIdentifier) node;
+      List<AliasContext> aliasContexts =
+          correlTableMap.values().stream()
+              .filter(context -> context instanceof AliasContext)
+              .map(context -> (AliasContext) context)
+              .collect(Collectors.toList());
+
+      for (AliasContext aliasContext : aliasContexts) {
+        if (aliasContext.aliases.containsKey(Util.last(identifier.names))) {
+          return true;
+        }
+      }
+      return false;
+    }
+
     public void stripTrivialAliases(SqlNode node) {
       switch (node.getKind()) {
       case SELECT:
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index a44d05ce64..aba4ee7eaa 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -6426,6 +6426,25 @@ private void checkLiteral2(String expression, String 
expected) {
     sql(query).withConfig(c -> c.withExpand(false)).ok(expected);
   }
 
+  /** Test cases of
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7378";>[CALCITE-7378]
+   * Potential incorrect column attribution in RelToSqlConverter due to 
implicit
+   * table alias handling</a>. */
+  @Test void testColumnAttributionWithImplicitAlias() {
+    String query = "select \"product_name\" from \"product\" t1 "
+        + "where \"product_id\" not in (select \"product_id\" "
+        + "from \"product\" t2 "
+        + "where t2.\"product_id\" = t1.\"product_id\" "
+        + "and t1.\"product_id\" = 2 and t2.\"product_id\" = 1)";
+    String expected = "SELECT \"product_name\"\n"
+        + "FROM \"foodmart\".\"product\"\n"
+        + "WHERE \"product_id\" NOT IN (SELECT \"product_id\"\n"
+        + "FROM \"foodmart\".\"product\" AS \"product0\"\n"
+        + "WHERE \"product_id\" = \"product\".\"product_id\" "
+        + "AND \"product\".\"product_id\" = 2 AND \"product_id\" = 1)";
+    sql(query).withConfig(c -> c.withExpand(false)).ok(expected);
+  }
+
   /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5711";>[CALCITE-5711]
    * Implement the SINGLE_VALUE aggregation in PostgreSQL Dialect</a>
@@ -11126,7 +11145,7 @@ private void checkLiteral2(String expression, String 
expected) {
         + "FROM \"SCOTT\".\"EMP\"\n"
         + "INNER JOIN \"SCOTT\".\"DEPT\" ON \"EMP\".\"DEPTNO\" = 
\"DEPT\".\"DEPTNO\"\n"
         + "WHERE \"DEPT\".\"DEPTNO\" = (SELECT MIN(\"DEPTNO\")\n"
-        + "FROM \"SCOTT\".\"DEPT\"\n"
+        + "FROM \"SCOTT\".\"DEPT\" AS \"DEPT0\"\n"
         + "WHERE \"DEPTNO\" = \"EMP\".\"DEPTNO\")";
 
     HepProgramBuilder builder = new HepProgramBuilder();
diff --git a/core/src/test/resources/sql/sub-query.iq 
b/core/src/test/resources/sql/sub-query.iq
index e981cc15d3..73b8c939b4 100644
--- a/core/src/test/resources/sql/sub-query.iq
+++ b/core/src/test/resources/sql/sub-query.iq
@@ -7791,6 +7791,92 @@ EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0])
 
 !ok
 
+# [CALCITE-7378] Potential incorrect column attribution in RelToSqlConverter 
due to implicit table alias handling
+!use blank
+CREATE TABLE a (
+  deptno INTEGER NOT NULL,
+  ename VARCHAR(10)
+);
+(0 rows modified)
+
+!update
+
+CREATE TABLE b (
+  deptno INTEGER NOT NULL,
+  ename VARCHAR(10)
+);
+(0 rows modified)
+
+!update
+
+INSERT INTO a VALUES
+  (10, 'ALLEN'),
+  (20, 'WARD'),
+  (30, 'WARD'),
+  (40, 'SMITH');
+(4 rows modified)
+
+!update
+
+INSERT INTO b VALUES
+  (20, 'WARD'),
+  (30, 'WARD'),
+  (30, 'ALLEN'),
+  (10, 'KING');
+(4 rows modified)
+
+!update
+
+SELECT deptno
+FROM b as b1
+WHERE deptno NOT IN (
+    SELECT deptno
+    FROM a
+    WHERE deptno = b1.deptno AND ename = 'WARD' AND b1.ename = 'WARD'
+);
++--------+
+| DEPTNO |
++--------+
+|     10 |
+|     30 |
++--------+
+(2 rows)
+
+!ok
+
+SELECT deptno
+FROM b as a
+WHERE deptno NOT IN (
+    SELECT deptno
+    FROM a
+    WHERE deptno = a.deptno AND ename = 'WARD' AND a.ename = 'WARD'
+);
++--------+
+| DEPTNO |
++--------+
+|     10 |
++--------+
+(1 row)
+
+!ok
+
+SELECT deptno
+FROM b as a
+WHERE deptno NOT IN (
+    SELECT deptno
+    FROM a as a2
+    WHERE deptno = a.deptno AND ename = 'WARD' AND a.ename = 'WARD'
+);
++--------+
+| DEPTNO |
++--------+
+|     10 |
+|     30 |
++--------+
+(2 rows)
+
+!ok
+
 # Reset to default value 20
 !set trimfields true
 

Reply via email to