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

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

commit 1a28fd8c666a81bec2a453dbc26150349ac66cc0
Author: Hsuan-Yi Chu <hsua...@usc.edu>
AuthorDate: Mon Mar 21 14:43:54 2016 -0700

    DRILL-4525: Allow SqlBetweenOperator to accept LOWER_OPERAND and 
UPPER_OPERAND with different types
---
 .../sql/DrillCalciteSqlBetweenOperatorWrapper.java | 82 ++++++++++++++++++++++
 .../drill/exec/planner/sql/DrillOperatorTable.java | 18 ++++-
 .../drill/TestFunctionsWithTypeExpoQueries.java    | 44 ++++++++++++
 3 files changed, 142 insertions(+), 2 deletions(-)

diff --git 
a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlBetweenOperatorWrapper.java
 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlBetweenOperatorWrapper.java
new file mode 100644
index 0000000..e26da95
--- /dev/null
+++ 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlBetweenOperatorWrapper.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.planner.sql;
+
+import com.google.common.collect.Lists;
+
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.sql.fun.SqlBetweenOperator;
+import org.apache.calcite.sql.SqlCallBinding;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.type.SqlTypeUtil;
+
+import org.apache.drill.common.types.TypeProtos;
+import org.apache.drill.exec.resolver.TypeCastRules;
+
+import java.util.List;
+
+/**
+ * This class serves as a wrapper class for SqlBetweenOperator. The motivation 
is to plug-in the return type inference and operand
+ * type check algorithms of Drill into Calcite's sql validation procedure.
+ *
+ * Except for the methods which are relevant to the return type inference and 
operand type check algorithms, the wrapper
+ * simply forwards the method calls to the wrapped SqlOperator.
+ *
+ * Note that SqlBetweenOperator cannot be wrapped in {@link 
DrillCalciteSqlOperatorWrapper}. The reason is when RexNode
+ * conversion is happening, StandardConvertletTable.convertBetween expects the 
SqlOperator to be a subclass of SqlBetweenOperator.
+ */
+public class DrillCalciteSqlBetweenOperatorWrapper extends SqlBetweenOperator 
implements DrillCalciteSqlWrapper  {
+  private final SqlBetweenOperator operator;
+
+  public DrillCalciteSqlBetweenOperatorWrapper(SqlBetweenOperator 
sqlBetweenOperator) {
+    super(sqlBetweenOperator.flag, sqlBetweenOperator.isNegated());
+    operator = sqlBetweenOperator;
+  }
+
+  @Override
+  public SqlOperator getOperator() {
+    return operator;
+  }
+
+  /**
+   *
+   * Since Calcite has its rule for type compatibility (see {@link 
SqlTypeUtil#isComparable(RelDataType, RelDataType)}),
+   * which is usually different from Drill's, this method is overridden here 
to avoid Calcite early terminating the
+   * queries.
+   */
+  @Override
+  public boolean checkOperandTypes(
+      SqlCallBinding callBinding,
+      boolean throwOnFailure) {
+    final List<TypeProtos.MinorType> types = Lists.newArrayList();
+    for(int i = 0; i < callBinding.getOperandCount(); ++i) {
+      final TypeProtos.MinorType inMinorType = 
TypeInferenceUtils.getDrillTypeFromCalciteType(callBinding.getOperandType(i));
+      if(inMinorType == TypeProtos.MinorType.LATE) {
+        return true;
+      }
+      types.add(inMinorType);
+    }
+
+    final boolean isCompatible = TypeCastRules.getLeastRestrictiveType(types) 
!= null;
+    if(!isCompatible && throwOnFailure) {
+      throw callBinding.newValidationSignatureError();
+    }
+    return isCompatible;
+  }
+}
diff --git 
a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillOperatorTable.java
 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillOperatorTable.java
index cf858d3..d533c19 100644
--- 
a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillOperatorTable.java
+++ 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillOperatorTable.java
@@ -22,6 +22,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlFunction;
+import org.apache.calcite.sql.fun.SqlBetweenOperator;
 import org.apache.drill.common.expression.FunctionCallFactory;
 import org.apache.drill.exec.expr.fn.DrillFuncHolder;
 import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry;
@@ -174,10 +175,23 @@ public class DrillOperatorTable extends 
SqlStdOperatorTable {
       } else if(calciteOperator instanceof SqlFunction) {
         wrapper = new DrillCalciteSqlFunctionWrapper((SqlFunction) 
calciteOperator,
             getFunctionListWithInference(calciteOperator.getName()));
+      } else if(calciteOperator instanceof SqlBetweenOperator) {
+        // During the procedure of converting to RexNode,
+        // StandardConvertletTable.convertBetween expects the SqlOperator to 
be a subclass of SqlBetweenOperator
+        final SqlBetweenOperator sqlBetweenOperator = (SqlBetweenOperator) 
calciteOperator;
+        wrapper = new 
DrillCalciteSqlBetweenOperatorWrapper(sqlBetweenOperator);
       } else {
-        final String drillOpName = 
FunctionCallFactory.replaceOpWithFuncName(calciteOperator.getName());
+        final String drillOpName;
+        // For UNARY_MINUS (-) or UNARY_PLUS (+), we do not rename them as 
function_add or function_subtract.
+        // Otherwise, Calcite will mix them up with binary operator subtract 
(-) or add (+)
+        if(calciteOperator == SqlStdOperatorTable.UNARY_MINUS || 
calciteOperator == SqlStdOperatorTable.UNARY_PLUS) {
+          drillOpName = calciteOperator.getName();
+        } else {
+          drillOpName = 
FunctionCallFactory.replaceOpWithFuncName(calciteOperator.getName());
+        }
+
         final List<DrillFuncHolder> drillFuncHolders = 
getFunctionListWithInference(drillOpName);
-        if(drillFuncHolders.isEmpty() || calciteOperator == 
SqlStdOperatorTable.UNARY_MINUS || calciteOperator == 
SqlStdOperatorTable.UNARY_PLUS) {
+        if(drillFuncHolders.isEmpty()) {
           continue;
         }
 
diff --git 
a/exec/java-exec/src/test/java/org/apache/drill/TestFunctionsWithTypeExpoQueries.java
 
b/exec/java-exec/src/test/java/org/apache/drill/TestFunctionsWithTypeExpoQueries.java
index d298acc..74676de 100644
--- 
a/exec/java-exec/src/test/java/org/apache/drill/TestFunctionsWithTypeExpoQueries.java
+++ 
b/exec/java-exec/src/test/java/org/apache/drill/TestFunctionsWithTypeExpoQueries.java
@@ -740,4 +740,48 @@ public class TestFunctionsWithTypeExpoQueries extends 
BaseTestQuery {
     final String[] excludedPlan = {};
     PlanTestBase.testPlanMatchingPatterns(query, expectedPlan, excludedPlan);
   }
+
+  @Test // DRILL-4525
+  public void testBetweenDateAndTimeStamp() throws Exception {
+    final String query = "select count(*) as col \n" +
+        "from cp.`employee.json` \n" +
+        "where cast(birth_date as DATE) BETWEEN cast('1970-01-01' AS DATE) AND 
(cast('1999-01-01' AS DATE) + INTERVAL '60' day) \n" +
+        "limit 0";
+
+    final TypeProtos.MajorType majorType = TypeProtos.MajorType.newBuilder()
+        .setMinorType(TypeProtos.MinorType.BIGINT)
+        .setMode(TypeProtos.DataMode.REQUIRED)
+        .build();
+
+    final List<Pair<SchemaPath, TypeProtos.MajorType>> expectedSchema = 
Lists.newArrayList();
+    expectedSchema.add(Pair.of(SchemaPath.getSimplePath("col"), majorType));
+
+    testBuilder()
+        .sqlQuery(query)
+        .schemaBaseLine(expectedSchema)
+        .build()
+        .run();
+  }
+
+  @Test // DRILL-4525
+  public void testBetweenDecimalAndDouble() throws Exception {
+    final String query = "select cast(r_regionkey as Integer) as col \n" +
+        "from cp.`tpch/region.parquet` \n" +
+        "where cast(r_regionkey as double) BETWEEN 1.1 AND 4.5 \n" +
+        "limit 0";
+
+    final TypeProtos.MajorType majorType = TypeProtos.MajorType.newBuilder()
+        .setMinorType(TypeProtos.MinorType.INT)
+        .setMode(TypeProtos.DataMode.OPTIONAL)
+        .build();
+
+    final List<Pair<SchemaPath, TypeProtos.MajorType>> expectedSchema = 
Lists.newArrayList();
+    expectedSchema.add(Pair.of(SchemaPath.getSimplePath("col"), majorType));
+
+    testBuilder()
+        .sqlQuery(query)
+        .schemaBaseLine(expectedSchema)
+        .build()
+        .run();
+  }
 }

-- 
To stop receiving notification emails like this one, please contact
ar...@apache.org.

Reply via email to