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 2019/10/17 02:25:36 UTC

[calcite] branch master updated: [CALCITE-3420] NullPointerException throws for implicit type coercion of nested SET operations

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 2ac4415  [CALCITE-3420] NullPointerException throws for implicit type coercion of nested SET operations
2ac4415 is described below

commit 2ac44153c4a521694c4dc975dd37b097184fc998
Author: yuzhao.cyz <yu...@alibaba-inc.com>
AuthorDate: Wed Oct 16 19:06:42 2019 +0800

    [CALCITE-3420] NullPointerException throws for implicit type coercion of nested SET operations
    
    We should update the nested SET operator node type when implicit type
    coercion happens.
    
    This bug fires when the non-first nested SET node triggers the
    implicit type coercion.
---
 .../calcite/sql/validate/implicit/AbstractTypeCoercion.java   |  7 ++++---
 .../calcite/sql/validate/implicit/TypeCoercionImpl.java       | 11 +++++++++--
 .../test/java/org/apache/calcite/test/TypeCoercionTest.java   | 11 +++++++++++
 3 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java b/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java
index acd0cdf..e963c58 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java
@@ -297,22 +297,23 @@ public abstract class AbstractTypeCoercion implements TypeCoercion {
    * @param scope       validator scope
    * @param query       node to inferred type
    * @param columnIndex column index to update
-   * @param targetType1 desired column type
+   * @param desiredType desired column type
    */
   protected void updateInferredColumnType(
       SqlValidatorScope scope,
       SqlNode query,
       int columnIndex,
-      RelDataType targetType1) {
+      RelDataType desiredType) {
     final RelDataType rowType = validator.deriveType(scope, query);
     assert rowType.isStruct();
+    assert columnIndex < rowType.getFieldList().size();
 
     final List<Map.Entry<String, RelDataType>> fieldList = new ArrayList<>();
     for (int i = 0; i < rowType.getFieldCount(); i++) {
       final RelDataTypeField field = rowType.getFieldList().get(i);
       final String name = field.getName();
       final RelDataType type = field.getType();
-      final RelDataType targetType = i == columnIndex ? targetType1 : type;
+      final RelDataType targetType = i == columnIndex ? desiredType : type;
       fieldList.add(Pair.of(name, targetType));
     }
     updateInferredType(query, factory.createStructType(fieldList));
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java
index fe2f347..b5b438d 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java
@@ -106,8 +106,15 @@ public class TypeCoercionImpl extends AbstractTypeCoercion {
     case INTERSECT:
     case EXCEPT:
       // Set operations are binary for now.
-      return rowTypeCoercion(scope, ((SqlCall) query).operand(0), columnIndex, targetType)
-          && rowTypeCoercion(scope, ((SqlCall) query).operand(1), columnIndex, targetType);
+      final SqlCall operand0 = ((SqlCall) query).operand(0);
+      final SqlCall operand1 = ((SqlCall) query).operand(1);
+      final boolean coerced = rowTypeCoercion(scope, operand0, columnIndex, targetType)
+          && rowTypeCoercion(scope, operand1, columnIndex, targetType);
+      // Update the nested SET operator node type.
+      if (coerced) {
+        updateInferredColumnType(scope, query, columnIndex, targetType);
+      }
+      return coerced;
     default:
       return false;
     }
diff --git a/core/src/test/java/org/apache/calcite/test/TypeCoercionTest.java b/core/src/test/java/org/apache/calcite/test/TypeCoercionTest.java
index 53162d6..25d29ba 100644
--- a/core/src/test/java/org/apache/calcite/test/TypeCoercionTest.java
+++ b/core/src/test/java/org/apache/calcite/test/TypeCoercionTest.java
@@ -473,6 +473,17 @@ public class TypeCoercionTest extends SqlValidatorTestCase {
             + " DECIMAL(19, 0) NOT NULL T1_DECIMAL,"
             + " FLOAT NOT NULL T1_SMALLINT,"
             + " DOUBLE NOT NULL T1_DOUBLE) NOT NULL");
+    // (int) union (int) union (varchar(20))
+    sql("select t1_int from t1 "
+        + "union select t2_int from t2 "
+        + "union select t1_varchar20 from t1")
+        .columnType("VARCHAR NOT NULL");
+
+    // (varchar(20)) union (int) union (int)
+    sql("select t1_varchar20 from t1 "
+        + "union select t2_int from t2 "
+        + "union select t1_int from t1")
+        .columnType("VARCHAR NOT NULL");
 
     // intersect
     sql("select t1_int, t1_decimal, t1_smallint, t1_double from t1 "