You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by da...@apache.org on 2020/07/02 04:30:37 UTC

[calcite] branch master updated: [CALCITE-4077] Exception when joined with built-in table functions

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

danny0405 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new c2df42e  [CALCITE-4077] Exception when joined with built-in table functions
c2df42e is described below

commit c2df42eff1615bfcd46ae3db5099c9785b04d420
Author: yuzhao.cyz <yu...@gmail.com>
AuthorDate: Wed Jul 1 18:09:23 2020 +0800

    [CALCITE-4077] Exception when joined with built-in table functions
    
    The scope of SqlWindowTableFunction is special because all its operands
    (except the first) should have the fucntion's first operand's scope, the
    first operand is always an explicit table reference.
    
    While this is not the perfect solution, the more proper way is to
    refactor the CURSOR constructor, and always uses its queries scope. The
    current CURSOR has some problems:
    
    * It always has a type with name SqlTypeName#CURSOR, in the table
    function senario, it is hard to do an auxiliary fields type infernece;
    * It finally translates as an invocation with format "cast($0): CURSOR", the '$0' means
    the first input, which is a wrong translation;
    * It does not belong to the SQL standard.
    
    A 'TABLE' constructor may be a good substitution.
---
 .../org/apache/calcite/sql/SqlHopTableFunction.java  |  6 +++---
 .../apache/calcite/sql/SqlTumbleTableFunction.java   |  8 +++++---
 .../apache/calcite/sql/SqlWindowTableFunction.java   |  9 +++++----
 .../calcite/sql/validate/SqlValidatorImpl.java       | 17 ++++++++++++++++-
 .../apache/calcite/sql2rel/SqlToRelConverter.java    |  2 +-
 .../apache/calcite/test/SqlToRelConverterTest.java   |  8 ++++++++
 .../apache/calcite/test/SqlToRelConverterTest.xml    | 20 ++++++++++++++++++++
 7 files changed, 58 insertions(+), 12 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/sql/SqlHopTableFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlHopTableFunction.java
index 43b2b91..a3c67ff 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlHopTableFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlHopTableFunction.java
@@ -24,9 +24,9 @@ import org.apache.calcite.sql.validate.SqlValidator;
 
 /**
  * SqlHopTableFunction implements an operator for hopping. It allows four parameters:
- * 1. a table.
- * 2. a descriptor to provide a watermarked column name from the input table.
- * 3. an interval parameter to specify the length of window shifting.
+ * 1. a table;
+ * 2. a descriptor to provide a watermarked column name from the input table;
+ * 3. an interval parameter to specify the length of window shifting;
  * 4. an interval parameter to specify the length of window size.
  */
 public class SqlHopTableFunction extends SqlWindowTableFunction {
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlTumbleTableFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlTumbleTableFunction.java
index e3a5001..882e7e2 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlTumbleTableFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlTumbleTableFunction.java
@@ -23,9 +23,11 @@ import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlValidator;
 
 /**
- * SqlTumbleTableFunction implements an operator for tumbling. It allows three parameters:
- * 1. a table.
- * 2. a descriptor to provide a watermarked column name from the input table.
+ * SqlTumbleTableFunction implements an operator for tumbling.
+ *
+ * <p>It allows three parameters:
+ * 1. a table;
+ * 2. a descriptor to provide a watermarked column name from the input table;
  * 3. an interval parameter to specify the length of window size.
  */
 public class SqlTumbleTableFunction extends SqlWindowTableFunction {
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWindowTableFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlWindowTableFunction.java
index e86551b..00c715a 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlWindowTableFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlWindowTableFunction.java
@@ -70,8 +70,9 @@ public class SqlWindowTableFunction extends SqlFunction {
   }
 
   /**
-   * The first parameter of table-value function windowing is a TABLE parameter,
-   * which is not scalar. So need to override SqlOperator.argumentMustBeScalar.
+   * Overrides SqlOperator.argumentMustBeScalar because the first parameter of
+   * table-value function windowing is an explicit TABLE parameter,
+   * which is not scalar.
    */
   @Override public boolean argumentMustBeScalar(int ordinal) {
     return ordinal != 0;
@@ -83,8 +84,8 @@ public class SqlWindowTableFunction extends SqlFunction {
    * additional fields:
    *
    * <ol>
-   *  <li>window_start. TIMESTAMP type to indicate a window's start.</li>
-   *  <li>window_end. TIMESTAMP type to indicate a window's end.</li>
+   *  <li>window_start: TIMESTAMP type to indicate a window's start.</li>
+   *  <li>window_end: TIMESTAMP type to indicate a window's end.</li>
    * </ol>
    */
   public static final SqlReturnTypeInference ARG0_TABLE_FUNCTION_WINDOWING =
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 5488898..32dc272 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
@@ -75,6 +75,7 @@ import org.apache.calcite.sql.SqlUnresolvedFunction;
 import org.apache.calcite.sql.SqlUpdate;
 import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.SqlWindow;
+import org.apache.calcite.sql.SqlWindowTableFunction;
 import org.apache.calcite.sql.SqlWith;
 import org.apache.calcite.sql.SqlWithItem;
 import org.apache.calcite.sql.fun.SqlCase;
@@ -2312,7 +2313,21 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       if (newOperand != operand) {
         call.setOperand(0, newOperand);
       }
-      scopes.put(node, parentScope);
+      // If the operator is SqlWindowTableFunction, restricts the scope as
+      // its first operand's (the table) scope.
+      if (operand instanceof SqlBasicCall) {
+        final SqlBasicCall call1 = (SqlBasicCall) operand;
+        final SqlOperator op = call1.getOperator();
+        if (op instanceof SqlWindowTableFunction
+            && call1.operand(0).getKind() == SqlKind.SELECT) {
+          scopes.put(node, getSelectScope(call1.operand(0)));
+          return newNode;
+        }
+      }
+      // Put the usingScope which can be a JoinScope
+      // or a SelectScope, in order to see the left items
+      // of the JOIN tree.
+      scopes.put(node, usingScope);
       return newNode;
 
     case UNNEST:
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index fdb26df..6982de1 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1270,7 +1270,7 @@ public class SqlToRelConverter {
 
       // This is used when converting window table functions:
       //
-      // select * from table(table emps, descriptor(deptno), interval '3' DAY)
+      // select * from table(tumble(table emps, descriptor(deptno), interval '3' DAY))
       //
       bb.cursors.add(converted.r);
       return;
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 114adda..ad41491 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -1813,6 +1813,14 @@ class SqlToRelConverterTest extends SqlToRelTestBase {
     sql(sql).ok();
   }
 
+  @Test void testTableFunctionTumbleWithInnerJoin() {
+    final String sql = "select *\n"
+        + "from table(tumble(table Shipments, descriptor(rowtime), INTERVAL '1' MINUTE)) a\n"
+        + "join table(tumble(table Shipments, descriptor(rowtime), INTERVAL '1' MINUTE)) b\n"
+        + "on a.orderid = b.orderid";
+    sql(sql).ok();
+  }
+
   @Test public void testTableFunctionHop() {
     final String sql = "select *\n"
         + "from table(hop(table Shipments, descriptor(rowtime), "
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 2473830..4b0e074 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -4976,6 +4976,26 @@ LogicalProject(ORDERID=[$0], ROWTIME=[$1], window_start=[$2], window_end=[$3])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testTableFunctionTumbleWithInnerJoin">
+        <Resource name="sql">
+            <![CDATA[select *
+from table(tumble(table Shipments, descriptor(rowtime), INTERVAL '1' MINUTE)) a
+join table(tumble(table Shipments, descriptor(rowtime), INTERVAL '1' MINUTE)) b
+on a.orderid = b.orderid]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalProject(ORDERID=[$0], ROWTIME=[$1], window_start=[$2], window_end=[$3], ORDERID0=[$4], ROWTIME0=[$5], window_start0=[$6], window_end0=[$7])
+  LogicalJoin(condition=[=($0, $4)], joinType=[inner])
+    LogicalTableFunctionScan(invocation=[TUMBLE(DESCRIPTOR($1), 60000:INTERVAL MINUTE)], rowType=[RecordType(INTEGER ORDERID, TIMESTAMP(0) ROWTIME, TIMESTAMP(0) window_start, TIMESTAMP(0) window_end)])
+      LogicalProject(ORDERID=[$0], ROWTIME=[$1])
+        LogicalTableScan(table=[[CATALOG, SALES, SHIPMENTS]])
+    LogicalTableFunctionScan(invocation=[TUMBLE(DESCRIPTOR($1), 60000:INTERVAL MINUTE)], rowType=[RecordType(INTEGER ORDERID, TIMESTAMP(0) ROWTIME, TIMESTAMP(0) window_start, TIMESTAMP(0) window_end)])
+      LogicalProject(ORDERID=[$0], ROWTIME=[$1])
+        LogicalTableScan(table=[[CATALOG, SALES, SHIPMENTS]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testTableFunctionHop">
         <Resource name="sql">
             <![CDATA[select *