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