You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@drill.apache.org by ja...@apache.org on 2014/04/20 03:18:42 UTC

[34/51] [abbrv] git commit: Add extract functions

Add 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/dcc102a2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/dcc102a2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/dcc102a2

Branch: refs/heads/master
Commit: dcc102a2a4303d64e919b24d8990c2e115492402
Parents: 3efba1e
Author: vkorukanti <ve...@gmail.com>
Authored: Wed Apr 2 18:48:27 2014 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Sat Apr 19 18:07:11 2014 -0700

----------------------------------------------------------------------
 exec/java-exec/src/main/codegen/config.fmpp     |   1 +
 .../src/main/codegen/data/ExtractTypes.tdd      |  20 +++
 .../src/main/codegen/templates/Extract.java     | 118 ++++++++++++++++
 .../drill/exec/expr/EvaluationVisitor.java      |  16 +--
 .../exec/expr/ExpressionTreeMaterializer.java   | 113 ++++++++-------
 .../physical/impl/TestExtractFunctions.java     | 136 +++++++++++++++++++
 .../test/resources/functions/extractFrom.json   |  46 +++++++
 .../src/test/resources/test_simple_time.json    |   3 +
 8 files changed, 381 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/dcc102a2/exec/java-exec/src/main/codegen/config.fmpp
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/codegen/config.fmpp b/exec/java-exec/src/main/codegen/config.fmpp
index 3f19de0..ef82bf2 100644
--- a/exec/java-exec/src/main/codegen/config.fmpp
+++ b/exec/java-exec/src/main/codegen/config.fmpp
@@ -24,6 +24,7 @@ data: {
     aggrtypes1: tdd(../data/AggrTypes1.tdd),
     aggrtypes2: tdd(../data/AggrTypes2.tdd),
     date: tdd(../data/DateTypes.tdd)
+    extract: tdd(../data/ExtractTypes.tdd)
 }
 freemarkerLinks: {
     includes: includes/

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/dcc102a2/exec/java-exec/src/main/codegen/data/ExtractTypes.tdd
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/codegen/data/ExtractTypes.tdd b/exec/java-exec/src/main/codegen/data/ExtractTypes.tdd
new file mode 100644
index 0000000..70d7861
--- /dev/null
+++ b/exec/java-exec/src/main/codegen/data/ExtractTypes.tdd
@@ -0,0 +1,20 @@
+# 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.
+
+{
+  toTypes: [Second, Minute, Hour, Day, Month, Year],
+  fromTypes: [Date, Time, TimeStamp, Interval, IntervalDay, IntervalYear]
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/dcc102a2/exec/java-exec/src/main/codegen/templates/Extract.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/codegen/templates/Extract.java b/exec/java-exec/src/main/codegen/templates/Extract.java
new file mode 100644
index 0000000..d0e0afe
--- /dev/null
+++ b/exec/java-exec/src/main/codegen/templates/Extract.java
@@ -0,0 +1,118 @@
+/**
+ * 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.
+ */
+<@pp.dropOutputFile />
+<#assign className="GExtract" />
+
+<@pp.changeOutputFile name="/org/apache/drill/exec/expr/fn/impl/${className}.java" />
+
+<#include "/@includes/license.ftl" />
+
+package org.apache.drill.exec.expr.fn.impl;
+
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.*;
+import org.apache.drill.exec.expr.holders.*;
+import org.apache.drill.exec.record.RecordBatch;
+
+public class ${className} {
+
+<#list extract.toTypes as toUnit>
+<#list extract.fromTypes as fromUnit>
+<#if fromUnit == "Date" || fromUnit == "Time" || fromUnit == "TimeStamp">
+  @FunctionTemplate(name = "extract${toUnit}", scope = FunctionTemplate.FunctionScope.SIMPLE,
+      nulls = FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class ${toUnit}From${fromUnit} implements DrillSimpleFunc {
+
+    @Param ${fromUnit}Holder in;
+    @Output BigIntHolder out;
+
+    public void setup(RecordBatch incoming) { }
+
+    public void eval() {
+      org.joda.time.MutableDateTime temp = new org.joda.time.MutableDateTime(in.value, org.joda.time.DateTimeZone.UTC);
+    <#if toUnit == "Second">
+      out.value = temp.getSecondOfMinute();
+    <#elseif toUnit = "Minute">
+      out.value = temp.getMinuteOfHour();
+    <#elseif toUnit = "Hour">
+      out.value = temp.getHourOfDay();
+    <#elseif toUnit = "Day">
+      out.value = temp.getDayOfMonth();
+    <#elseif toUnit = "Month">
+      out.value = temp.getMonthOfYear();
+    <#elseif toUnit = "Year">
+      out.value = temp.getYear();
+    </#if>
+    }
+  }
+<#else>
+  @FunctionTemplate(name = "extract${toUnit}", scope = FunctionTemplate.FunctionScope.SIMPLE,
+      nulls = FunctionTemplate.NullHandling.NULL_IF_NULL)
+  public static class ${toUnit}From${fromUnit} implements DrillSimpleFunc {
+
+    @Param ${fromUnit}Holder in;
+    @Output BigIntHolder out;
+
+    public void setup(RecordBatch incoming) { }
+
+    public void eval() {
+    <#if fromUnit == "Interval">
+
+      int years  = (in.months / org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
+      int months = (in.months % org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
+
+      int millis = in.milliSeconds;
+
+      int hours  = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.hoursToMillis);
+      millis     = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.hoursToMillis);
+
+      int minutes = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.minutesToMillis);
+      millis      = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.minutesToMillis);
+
+      int seconds = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.secondsToMillis);
+      millis      = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.secondsToMillis);
+      org.joda.time.Period temp = new org.joda.time.Period(years, months, 0, in.days, hours, minutes, seconds, millis);
+
+    <#elseif fromUnit == "IntervalDay">
+
+      int millis = in.milliSeconds;
+
+      int hours  = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.hoursToMillis);
+      millis     = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.hoursToMillis);
+
+      int minutes = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.minutesToMillis);
+      millis      = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.minutesToMillis);
+
+      int seconds = millis / (org.apache.drill.exec.expr.fn.impl.DateUtility.secondsToMillis);
+      millis      = millis % (org.apache.drill.exec.expr.fn.impl.DateUtility.secondsToMillis);
+      org.joda.time.Period temp = new org.joda.time.Period(0, 0, 0, in.days, hours, minutes, seconds, millis);
+
+    <#else>
+
+      int years  = (in.value / org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
+      int months = (in.value % org.apache.drill.exec.expr.fn.impl.DateUtility.yearsToMonths);
+      org.joda.time.Period temp = new org.joda.time.Period(years, months, 0, 0, 0, 0, 0, 0);
+
+    </#if>
+      out.value = temp.get${toUnit}s();
+    }
+  }
+  </#if>
+</#list>
+</#list>
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/dcc102a2/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
index b7670ee..aff47db 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
@@ -377,19 +377,9 @@ public class EvaluationVisitor {
 
     @Override
     public HoldingContainer visitCastExpression(CastExpression e, ClassGenerator<?> value) throws RuntimeException {
-      // we create
-      MajorType type = e.getMajorType();
-      String castFuncWithType = "cast" + type.getMinorType().name();
-
-      List<LogicalExpression> newArgs = Lists.newArrayList();
-      newArgs.add(e.getInput());  //input_expr
-
-      //VarLen type
-      if (!Types.isFixedWidthType(type)) {
-        newArgs.add(new ValueExpressions.LongExpression(type.getWidth(), null));
-      }
-      FunctionCall fc = new FunctionCall(castFuncWithType, newArgs, e.getPosition());
-      return fc.accept(this, value);    }
+      throw new UnsupportedOperationException("CastExpression is not expected here. "+
+        "It should have been converted to FunctionHolderExpression in materialization");
+    }
   }
 
   private class ConstantFilter extends EvalVisitor {

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/dcc102a2/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java
index d65ff78..1d8070c 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java
@@ -289,70 +289,65 @@ public class ExpressionTreeMaterializer {
       if(castEqual(e.getPosition(), newMajor, input.getMajorType())) return input; // don't do pointless cast.
       
       
-      if(newMinor == MinorType.LATE || newMinor == MinorType.NULL){
-        // if the type still isn't fully bound, leave as cast expression.
-        return new CastExpression(input, e.getMajorType(), e.getPosition());
-      }else{
-        // if the type is fully bound, convert to functioncall and materialze the function.
-        MajorType type = e.getMajorType();
-        String castFuncWithType = "cast" + type.getMinorType().name();
-
-        List<LogicalExpression> newArgs = Lists.newArrayList();
-        newArgs.add(e.getInput());  //input_expr
-
-        //VarLen type
-        if (!Types.isFixedWidthType(type)) {
-          newArgs.add(new ValueExpressions.LongExpression(type.getWidth(), null));
-        }
-        FunctionCall fc = new FunctionCall(castFuncWithType, newArgs, e.getPosition());
-        return fc.accept(this, value);   
+      if(newMinor == MinorType.LATE){
+        throw new UnsupportedOperationException("LATE binding is not supported");
+      } else if (newMinor == MinorType.NULL){
+        // convert it into null expression
+        return NullExpression.INSTANCE;
       }
-      
-      
-      
+
+      // if the type is fully bound, convert to functioncall and materialze the function.
+      MajorType type = e.getMajorType();
+      String castFuncWithType = "cast" + type.getMinorType().name();
+
+      List<LogicalExpression> newArgs = Lists.newArrayList();
+      newArgs.add(e.getInput());  //input_expr
+
+      //VarLen type
+      if (!Types.isFixedWidthType(type)) {
+        newArgs.add(new ValueExpressions.LongExpression(type.getWidth(), null));
+      }
+      FunctionCall fc = new FunctionCall(castFuncWithType, newArgs, e.getPosition());
+      return fc.accept(this, value);
     }
   
-  private boolean castEqual(ExpressionPosition pos, MajorType from, MajorType to){
-    if(!from.getMinorType().equals(to.getMinorType())) return false;
-    switch(from.getMinorType()){
-    case FLOAT4:
-    case FLOAT8:
-    case INT:
-    case BIGINT:
-    case BIT:
-    case TINYINT:
-    case UINT1:
-    case UINT2:
-    case UINT4:
-    case UINT8:      
-      // nothing else matters.
-      return true;
-     
-    case FIXED16CHAR:
-    case FIXEDBINARY:
-    case FIXEDCHAR:
-      // width always matters
-      this.errorCollector.addGeneralError(pos, "Casting fixed width types are not yet supported..");
-      return false;
-      
-    case VAR16CHAR:
-    case VARBINARY:
-    case VARCHAR:
-      if(to.getWidth() < from.getWidth() && to.getWidth() > 0){
-        this.errorCollector.addGeneralError(pos, "Casting from a longer variable length type to a shorter variable length type is not currently supported.");
-        return false;
-      }else{
+    private boolean castEqual(ExpressionPosition pos, MajorType from, MajorType to){
+      if(!from.getMinorType().equals(to.getMinorType())) return false;
+      switch(from.getMinorType()){
+      case FLOAT4:
+      case FLOAT8:
+      case INT:
+      case BIGINT:
+      case BIT:
+      case TINYINT:
+      case UINT1:
+      case UINT2:
+      case UINT4:
+      case UINT8:
+        // nothing else matters.
         return true;
-      }
 
-    default:
-      errorCollector.addGeneralError(pos, String.format("Casting rules are unknown for type %s.", from));
-      return false;
-    
-    }
+      case FIXED16CHAR:
+      case FIXEDBINARY:
+      case FIXEDCHAR:
+        // width always matters
+        this.errorCollector.addGeneralError(pos, "Casting fixed width types are not yet supported..");
+        return false;
 
-  }
-  
-  }
+      case VAR16CHAR:
+      case VARBINARY:
+      case VARCHAR:
+        if(to.getWidth() < from.getWidth() && to.getWidth() > 0){
+          this.errorCollector.addGeneralError(pos, "Casting from a longer variable length type to a shorter variable length type is not currently supported.");
+          return false;
+        }else{
+          return true;
+        }
 
+      default:
+        errorCollector.addGeneralError(pos, String.format("Casting rules are unknown for type %s.", from));
+        return false;
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/dcc102a2/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestExtractFunctions.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestExtractFunctions.java b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestExtractFunctions.java
new file mode 100644
index 0000000..3e1f7b4
--- /dev/null
+++ b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestExtractFunctions.java
@@ -0,0 +1,136 @@
+/**
+ * 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.physical.impl;
+
+import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+
+import org.apache.drill.common.util.FileUtils;
+import org.apache.drill.exec.client.DrillClient;
+import org.apache.drill.exec.pop.PopUnitTestBase;
+import org.apache.drill.exec.proto.UserProtos;
+import org.apache.drill.exec.record.RecordBatchLoader;
+import org.apache.drill.exec.rpc.user.QueryResultBatch;
+import org.apache.drill.exec.server.Drillbit;
+import org.apache.drill.exec.server.RemoteServiceSet;
+import org.apache.drill.exec.vector.NullableBigIntVector;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+
+import java.util.List;
+
+/* This class tests the existing date types. Simply using date types
+ * by casting from VarChar, performing basic functions and converting
+ * back to VarChar.
+ */
+public class TestExtractFunctions extends PopUnitTestBase {
+  static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TestExtractFunctions.class);
+
+  @Test
+  public void testFromDate() throws Exception {
+    long expectedValues[][] = { {00, 00, 00, 02, 01, 1970}, {00, 00, 00, 28, 12, 2008}, {00, 00, 00, 27, 02, 2000} };
+    testFrom("date", "/test_simple_date.json", "stringdate", expectedValues);
+  }
+
+  @Test
+  @Ignore // failing due to some issue in castTime(varchar)
+  public void testFromTime() throws Exception {
+    long expectedValues[][] = { {33, 20, 10, 00, 00, 0000}, {00, 34, 11, 00, 00, 0000}, {00, 24, 14, 00, 00, 0000} };
+    testFrom("time", "/test_simple_time.json", "stringtime", expectedValues);
+  }
+
+  @Test
+  public void testFromTimeStamp() throws Exception {
+    long expectedValues[][] = { {33, 20, 10, 02, 01, 1970}, {00, 34, 11, 28, 12, 2008}, {00, 24, 14, 27, 02, 2000} };
+    testFrom("timestamp", "/test_simple_date.json", "stringdate", expectedValues);
+  }
+
+  @Test
+  public void testFromInterval() throws Exception {
+    long expectedValues[][] = {
+      { 35, 20, 01, 01, 02, 02},
+      { 00, 00, 00, 00, 02, 02},
+      { 35, 20, 01, 00, 00, 00},
+      { 35, 20, 01, 01, 02, 02},
+      { 35, 00, 00, 00, 00, 00},
+      {-25,-39, 00, 01, 10, 01}
+    };
+    testFrom("interval", "/test_simple_interval.json", "stringinterval", expectedValues);
+  }
+
+  @Test
+  public void testFromIntervalDay() throws Exception {
+    long expectedValues[][] = {
+      { 35, 20, 01, 01, 00, 00},
+      { 00, 00, 00, 00, 00, 00},
+      { 35, 20, 01, 00, 00, 00},
+      { 35, 20, 01, 01, 00, 00},
+      { 35, 00, 00, 00, 00, 00},
+      {-25,-39, 00, 01, 00, 00}
+    };
+    testFrom("intervalday", "/test_simple_interval.json", "stringinterval", expectedValues);
+  }
+
+  @Test
+  public void testFromIntervalYear() throws Exception {
+    long expectedValues[][] = {
+      { 00, 00, 00, 00, 02, 02},
+      { 00, 00, 00, 00, 02, 02},
+      { 00, 00, 00, 00, 00, 00},
+      { 00, 00, 00, 00, 02, 02},
+      { 00, 00, 00, 00, 00, 00},
+      { 00, 00, 00, 00, 10, 01}
+    };
+    testFrom("intervalyear", "/test_simple_interval.json", "stringinterval", expectedValues);
+  }
+
+  private void testFrom(String fromType, String testDataFile, String columnName,
+      long expectedValues[][]) throws Exception {
+    try (RemoteServiceSet serviceSet = RemoteServiceSet.getLocalServiceSet();
+         Drillbit bit = new Drillbit(CONFIG, serviceSet);
+         DrillClient client = new DrillClient(CONFIG, serviceSet.getCoordinator())) {
+
+      // run query.
+      bit.run();
+      client.connect();
+      List<QueryResultBatch> results = client.runQuery(UserProtos.QueryType.PHYSICAL,
+        Files.toString(FileUtils.getResourceAsFile("/functions/extractFrom.json"), Charsets.UTF_8)
+        .replace("#{TEST_TYPE}", fromType)
+        .replace("#{TEST_FILE}", testDataFile)
+        .replace("#{COLUMN_NAME}", columnName));
+
+      RecordBatchLoader batchLoader = new RecordBatchLoader(bit.getContext().getAllocator());
+
+      QueryResultBatch batch = results.get(0);
+      assertTrue(batchLoader.load(batch.getHeader().getDef(), batch.getData()));
+
+      for(int i=0; i<expectedValues.length; i++) {
+        for(int j=0; j<expectedValues[i].length; j++) {
+          NullableBigIntVector vv =
+              (NullableBigIntVector) batchLoader.getValueAccessorById(j, NullableBigIntVector.class).getValueVector();
+          System.out.println("["+i+"]["+j+"]: Expected: " + expectedValues[i][j] + ", Actual: " + vv.getAccessor().get(i));
+          assertEquals(expectedValues[i][j], vv.getAccessor().get(i));
+        }
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/dcc102a2/exec/java-exec/src/test/resources/functions/extractFrom.json
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/resources/functions/extractFrom.json b/exec/java-exec/src/test/resources/functions/extractFrom.json
new file mode 100644
index 0000000..779581e
--- /dev/null
+++ b/exec/java-exec/src/test/resources/functions/extractFrom.json
@@ -0,0 +1,46 @@
+{
+  "head" : {
+    "version" : 1,
+    "generator" : {
+      "type" : "org.apache.drill.exec.planner.logical.DrillImplementor",
+      "info" : ""
+    },
+    "type" : "APACHE_DRILL_PHYSICAL",
+    "resultMode" : "EXEC"
+  },
+  graph:[
+        {
+            @id:1,
+            pop:"fs-scan",
+            format: {type: "json"},
+            storage:{type: "file", connection: "classpath:///"},
+            files:["#{TEST_FILE}"]
+        },
+        {
+            pop:"project",
+            @id:2,
+            child: 1,
+            exprs: [ {
+              ref: "castExp", expr: "cast(#{COLUMN_NAME} as #{TEST_TYPE})"
+            } ]
+        },
+        {
+            pop:"project",
+            @id:3,
+            child: 2,
+            exprs: [
+              { ref: "extractSecond", expr: "extractSecond(castExp)" },
+              { ref: "extractMinute", expr: "extractMinute(castExp)" },
+              { ref: "extractHour", expr: "extractHour(castExp)" },
+              { ref: "extractDay", expr: "extractDay(castExp)" },
+              { ref: "extractMonth", expr: "extractMonth(castExp)" },
+              { ref: "extractYear", expr: "extractYear(castExp)" }
+            ]
+        },
+        {
+            @id: 4,
+            child: 3,
+            pop: "screen"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/dcc102a2/exec/java-exec/src/test/resources/test_simple_time.json
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/resources/test_simple_time.json b/exec/java-exec/src/test/resources/test_simple_time.json
new file mode 100644
index 0000000..1f8b34f
--- /dev/null
+++ b/exec/java-exec/src/test/resources/test_simple_time.json
@@ -0,0 +1,3 @@
+{ "stringtime" : "10:20:33"}
+{ "stringtime" : "11:34:00.129"}
+{ "stringtime" : "14:24:00"}