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

xiong 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 a0f16e70f0 [CALCITE-5816] Only return left-hand table columns when 
validate LEFT SEMI JOIN query
a0f16e70f0 is described below

commit a0f16e70f0be491fc52f6a2c430952b2f0d89703
Author: macroguo <[email protected]>
AuthorDate: Mon Jul 3 19:45:39 2023 +0800

    [CALCITE-5816] Only return left-hand table columns when validate LEFT SEMI 
JOIN query
---
 .../src/test/java/org/apache/calcite/test/BabelTest.java | 16 ++++++++++++++++
 babel/src/test/resources/sql/select.iq                   | 15 ++++++++++++++-
 .../org/apache/calcite/sql/validate/JoinNamespace.java   |  3 +++
 .../java/org/apache/calcite/sql/validate/JoinScope.java  | 11 +++++++++++
 4 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/babel/src/test/java/org/apache/calcite/test/BabelTest.java 
b/babel/src/test/java/org/apache/calcite/test/BabelTest.java
index 088d3e3a01..da463df30c 100644
--- a/babel/src/test/java/org/apache/calcite/test/BabelTest.java
+++ b/babel/src/test/java/org/apache/calcite/test/BabelTest.java
@@ -24,6 +24,7 @@ import org.apache.calcite.sql.fun.SqlLibrary;
 import org.apache.calcite.sql.fun.SqlLibraryOperatorTableFactory;
 import org.apache.calcite.sql.parser.SqlParserFixture;
 import org.apache.calcite.sql.parser.babel.SqlBabelParserImpl;
+import org.apache.calcite.sql.validate.SqlConformanceEnum;
 
 import org.junit.jupiter.api.Test;
 
@@ -231,6 +232,21 @@ class BabelTest {
         "EXPR$0=false\n");
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5816";>[CALCITE-5816]
+   * Query with LEFT SEMI JOIN should not refer to RHS columns</a>. */
+  @Test public void testLeftSemiJoin() {
+    final SqlValidatorFixture v = Fixtures.forValidator()
+        .withParserConfig(c -> c.withParserFactory(SqlBabelParserImpl.FACTORY))
+        .withConformance(SqlConformanceEnum.BABEL);
+
+    v.withSql("SELECT * FROM dept LEFT SEMI JOIN emp ON emp.deptno = 
dept.deptno")
+        .type("RecordType(INTEGER NOT NULL DEPTNO, VARCHAR(10) NOT NULL NAME) 
NOT NULL");
+
+    v.withSql("SELECT deptno FROM dept LEFT SEMI JOIN emp ON emp.deptno = 
dept.deptno")
+        .type("RecordType(INTEGER NOT NULL DEPTNO) NOT NULL");
+  }
+
   private void checkSqlResult(String funLibrary, String query, String result) {
     CalciteAssert.that()
         .with(CalciteConnectionProperty.PARSER_FACTORY,
diff --git a/babel/src/test/resources/sql/select.iq 
b/babel/src/test/resources/sql/select.iq
index e82f21d7d4..0d665540c8 100755
--- a/babel/src/test/resources/sql/select.iq
+++ b/babel/src/test/resources/sql/select.iq
@@ -30,14 +30,27 @@ ORDER BY "EMP"."DEPTNO"
 !explain-validated-on all
 
 # LEFT SEMI JOIN (Hive only)
+# Only LHS columns are referenced in SELECT clause
 SELECT *
 FROM emp LEFT SEMI JOIN dept ON emp.deptno = dept.deptno;
 
-SELECT "EMP"."EMPNO", "EMP"."ENAME", "EMP"."JOB", "EMP"."MGR", 
"EMP"."HIREDATE", "EMP"."SAL", "EMP"."COMM", "EMP"."DEPTNO", "DEPT"."DEPTNO" AS 
"DEPTNO0", "DEPT"."DNAME", "DEPT"."LOC"
+SELECT "EMP"."EMPNO", "EMP"."ENAME", "EMP"."JOB", "EMP"."MGR", 
"EMP"."HIREDATE", "EMP"."SAL", "EMP"."COMM", "EMP"."DEPTNO"
 FROM "scott"."EMP" AS "EMP"
     LEFT SEMI JOIN "scott"."DEPT" AS "DEPT" ON "EMP"."DEPTNO" = "DEPT"."DEPTNO"
 !explain-validated-on hive
 
+# Can not reference RHS columns in SELECT clause
+SELECT dept.dname
+FROM emp LEFT SEMI JOIN dept ON emp.deptno = dept.deptno;
+Table 'DEPT' not found
+!error
+
+# Can not reference RHS columns in WHERE clause
+SELECT *
+FROM emp LEFT SEMI JOIN dept ON emp.deptno = dept.deptno where dept.deptno = 
100;
+Table 'DEPT' not found
+!error
+
 # Test CONNECT BY (Oracle only)
 !if (false) {
 SELECT *
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java 
b/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java
index 43564fca16..a869f1167c 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java
@@ -57,6 +57,9 @@ class JoinNamespace extends AbstractNamespace {
       leftType = typeFactory.createTypeWithNullability(leftType, true);
       rightType = typeFactory.createTypeWithNullability(rightType, true);
       break;
+    // LEFT SEMI JOIN can only come from Babel.
+    case LEFT_SEMI_JOIN:
+      return typeFactory.createJoinType(leftType);
     default:
       break;
     }
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java 
b/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java
index bbf3da9d99..deabdbfcbb 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java
@@ -22,6 +22,9 @@ import org.apache.calcite.sql.SqlWindow;
 
 import org.checkerframework.checker.nullness.qual.Nullable;
 
+import static org.apache.calcite.sql.JoinType.LEFT_SEMI_JOIN;
+import static org.apache.calcite.sql.SqlUtil.stripAs;
+
 import static java.util.Objects.requireNonNull;
 
 /**
@@ -66,6 +69,14 @@ public class JoinScope extends ListScope {
   @Override public void addChild(SqlValidatorNamespace ns, String alias,
       boolean nullable) {
     super.addChild(ns, alias, nullable);
+
+    // LEFT SEMI JOIN can only come from Babel.
+    if (join.getJoinType() == LEFT_SEMI_JOIN
+        && stripAs(join.getRight()) == ns.getNode()) {
+      // Ignore the right hand side.
+      return;
+    }
+
     if ((usingScope != null) && (usingScope != parent)) {
       // We're looking at a join within a join. Recursively add this
       // child to its parent scope too. Example:

Reply via email to