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: