DRILL-516: Use custom convertlet table to support extract() functions

Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/3f92e56a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/3f92e56a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/3f92e56a

Branch: refs/heads/master
Commit: 3f92e56aeb768cac90495951befaa0f03f13372e
Parents: a3ad881
Author: Mehant Baid <[email protected]>
Authored: Sat Apr 26 03:52:59 2014 -0700
Committer: Jacques Nadeau <[email protected]>
Committed: Sat May 3 18:59:42 2014 -0700

----------------------------------------------------------------------
 .../drill/exec/planner/logical/DrillOptiq.java  | 30 +++++++++-
 .../exec/planner/sql/DrillConvertletTable.java  | 53 ++++++++++++++++
 .../planner/sql/DrillExtractConvertlet.java     | 63 ++++++++++++++++++++
 .../drill/exec/planner/sql/DrillSqlWorker.java  |  2 +-
 .../java/org/apache/drill/TestTpchPlanning.java |  5 +-
 5 files changed, 148 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/3f92e56a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java
 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java
index 2d0389f..2e61970 100644
--- 
a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java
+++ 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillOptiq.java
@@ -51,7 +51,6 @@ import org.eigenbase.rex.RexRangeRef;
 import org.eigenbase.rex.RexVisitorImpl;
 import org.eigenbase.sql.SqlSyntax;
 import org.eigenbase.sql.fun.SqlStdOperatorTable;
-import org.eigenbase.sql.type.SqlTypeName;
 import org.eigenbase.util.NlsString;
 
 import com.google.common.collect.Lists;
@@ -262,6 +261,33 @@ public class DrillOptiq {
       for(RexNode n : call.getOperands()){
         args.add(n.accept(this));
       }
+      String functionName = call.getOperator().getName().toLowerCase();
+
+      /* Rewrite extract functions in the following manner
+       * extract(year, date '2008-2-23') ---> extractYear(date '2008-2-23')
+       */
+      if (functionName.equals("extract")) {
+
+        // Assert that the first argument to extract is a QuotedString
+        assert args.get(0) instanceof ValueExpressions.QuotedString;
+
+        // Get the unit of time to be extracted
+        String timeUnitStr = 
((ValueExpressions.QuotedString)args.get(0)).value;
+
+        switch (timeUnitStr){
+          case ("YEAR"):
+          case ("MONTH"):
+          case ("DAY"):
+          case ("HOUR"):
+          case ("MINUTE"):
+          case ("SECOND"):
+            String functionPostfix = timeUnitStr.substring(0, 1).toUpperCase() 
+ timeUnitStr.substring(1).toLowerCase();
+            functionName += functionPostfix;
+            return FunctionCallFactory.createExpression(functionName, 
args.subList(1, 2));
+          default:
+            throw new UnsupportedOperationException("extract function supports 
the following time units: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND");
+        }
+      }
 
       // Rewrite DATE_PART functions as extract functions
       if (call.getOperator().getName().equalsIgnoreCase("DATE_PART")) {
@@ -322,6 +348,8 @@ public class DrillOptiq {
         return ValueExpressions.getFloat8(dbl);
       case VARCHAR:
         return 
ValueExpressions.getChar(((NlsString)literal.getValue()).getValue());
+      case SYMBOL:
+        return ValueExpressions.getChar(literal.getValue().toString());
       case DATE:
         return 
(ValueExpressions.getDate((GregorianCalendar)literal.getValue()));
       case TIME:

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/3f92e56a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillConvertletTable.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillConvertletTable.java
 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillConvertletTable.java
new file mode 100644
index 0000000..f1bda60
--- /dev/null
+++ 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillConvertletTable.java
@@ -0,0 +1,53 @@
+/**
+ * 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 org.eigenbase.sql.SqlCall;
+import org.eigenbase.sql.SqlOperator;
+import org.eigenbase.sql.fun.SqlStdOperatorTable;
+import org.eigenbase.sql2rel.SqlRexConvertlet;
+import org.eigenbase.sql2rel.SqlRexConvertletTable;
+import org.eigenbase.sql2rel.StandardConvertletTable;
+
+import java.util.HashMap;
+
+public class DrillConvertletTable implements SqlRexConvertletTable{
+
+  public static HashMap<SqlOperator, SqlRexConvertlet> map = new HashMap<>();
+
+  static {
+    // Use custom convertlet for extract function
+    map.put(SqlStdOperatorTable.EXTRACT, DrillExtractConvertlet.INSTANCE);
+  }
+
+  /*
+   * Lookup the hash table to see if we have a custom convertlet for a given
+   * operator, if we don't use StandardConvertletTable.
+   */
+  @Override
+  public SqlRexConvertlet get(SqlCall call) {
+
+    SqlRexConvertlet convertlet;
+
+    if ((convertlet = map.get(call.getOperator())) != null) {
+      return convertlet;
+    }
+
+    return StandardConvertletTable.INSTANCE.get(call);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/3f92e56a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillExtractConvertlet.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillExtractConvertlet.java
 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillExtractConvertlet.java
new file mode 100644
index 0000000..5d9f257
--- /dev/null
+++ 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillExtractConvertlet.java
@@ -0,0 +1,63 @@
+/**
+ * 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 org.eigenbase.reltype.RelDataType;
+import org.eigenbase.reltype.RelDataTypeFactory;
+import org.eigenbase.rex.RexBuilder;
+import org.eigenbase.rex.RexNode;
+import org.eigenbase.sql.SqlCall;
+import org.eigenbase.sql.SqlNode;
+import org.eigenbase.sql.type.SqlTypeName;
+import org.eigenbase.sql2rel.SqlRexContext;
+import org.eigenbase.sql2rel.SqlRexConvertlet;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class DrillExtractConvertlet implements SqlRexConvertlet {
+
+  public final static DrillExtractConvertlet INSTANCE = new 
DrillExtractConvertlet();
+
+  private DrillExtractConvertlet() {
+  }
+
+  /*
+   * Custom convertlet to handle extract functions. Optiq rewrites
+   * extract functions as divide and modulo functions, based on the
+   * data type. We cannot do that in Drill since we don't know the data type
+   * till we start scanning. So we don't rewrite extract and treat it as
+   * a regular function.
+   */
+  @Override
+  public RexNode convertCall(SqlRexContext cx, SqlCall call) {
+    final RexBuilder rexBuilder = cx.getRexBuilder();
+    final List<SqlNode> operands = call.getOperandList();
+    final List<RexNode> exprs = new LinkedList<>();
+
+    RelDataTypeFactory typeFactory = cx.getTypeFactory();
+    RelDataType returnType = typeFactory.createSqlType(SqlTypeName.BIGINT);
+    //RelDataType nullableReturnType =
+
+    for (SqlNode node: operands) {
+       exprs.add(cx.convertExpression(node));
+    }
+    return rexBuilder.makeCall(returnType, call.getOperator(), exprs);
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/3f92e56a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
index 4336a1f..048d116 100644
--- 
a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
+++ 
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
@@ -78,7 +78,7 @@ public class DrillSqlWorker {
         .defaultSchema(context.getNewDefaultSchema()) //
         .operatorTable(table) //
         .traitDefs(traitDefs) //
-        .convertletTable(StandardConvertletTable.INSTANCE) //
+        .convertletTable(new DrillConvertletTable()) //
         .context(context.getPlannerSettings()) //
         .ruleSets(getRules(context.getStorage())) //
         .build();

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/3f92e56a/exec/java-exec/src/test/java/org/apache/drill/TestTpchPlanning.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/test/java/org/apache/drill/TestTpchPlanning.java 
b/exec/java-exec/src/test/java/org/apache/drill/TestTpchPlanning.java
index 69b770e..1a99fdf 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/TestTpchPlanning.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/TestTpchPlanning.java
@@ -61,19 +61,18 @@ public class TestTpchPlanning extends PlanningBase{
   }
 
   @Test
-  @Ignore // DRILL-516
   public void tpch07() throws Exception{
     testSqlPlanFromFile("queries/tpch/07.sql");
   }
 
   @Test
-  @Ignore // DRILL-516
+  @Ignore // cannot plan exception (was DRILL-516)
   public void tpch08() throws Exception{
     testSqlPlanFromFile("queries/tpch/08.sql");
   }
 
   @Test
-  @Ignore // DRILL-516
+  @Ignore // cannot plan exception (was DRILL-516)
   public void tpch09() throws Exception{
     testSqlPlanFromFile("queries/tpch/09.sql");
   }

Reply via email to