drill-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j..@apache.org
Subject [4/6] drill git commit: DRILL-4372: Expose the functions return type to Drill
Date Sun, 20 Mar 2016 04:17:35 GMT
DRILL-4372: Expose the functions return type to Drill

- Drill-Calite version update:
This commit needs to have Calcite's patch (CALCITE-1062) to plugin customized SqlOperator.

- FunctionTemplate
Add FunctionArgumentNumber annotation. This annotation element tells if the number of argument(s) is fixed or arbitrary (e.g., String concatenation function).

Due to this modification, there are some minor changes in DrillFuncHolder, DrillFunctionRegistry and FunctionAttributes.

- Checker
Add a new Checker (which Calcite uses to validate the legitimacy of the number of argument(s) for a function) to allow functions with arbitrary arguments to pass Caclite's validation

- Type conversion between Drill and Calcite
DrillConstExector is given a static method getDrillTypeFromCalcite() to convert Calcite types to Drill's.

- Extract function's return type inference
Unlike other functions, Extract function's return type can be determined solely based on the first argument. A logic is added in to allow this inference to happen

- DrillCalcite wrapper:
>From the aspects of return type inference and argument type checks, Calcite's mechanism is very different from Drill's. In addition, currently, there is no straightforward way for Drill to plug-in customized mechanisms to Calcite. Thus, wrappers are provided to serve the objective.

Except for the mechanisms of type inference and argument type checks, these wrappers just forward any method calls to the wrapped SqlOpertor, SqlFuncion or SqlAggFunction to respond.

A interface DrillCalciteSqlWrapper is also added for the callers of the three wrappers to get the wrapped objects easier.

Due to these wrappers, UnsupportedOperatorsVisitor is modified in a minor manner.

- Calcite's SqlOpertor, SqlFuncion or SqlAggFunction are wrapped in DrillOperatorTable
Instead of returning Caclite's native SqlOpertor, SqlFuncion or SqlAggFunction, return the wrapped ones to ensure customized behaviors can be adopted.

- Type inference mechanism
This mechanism is used across all SqlOpertor, SqlFuncion or SqlAggFunction. Thus, it is factored out as its own method in TypeInferenceUtils

- Upgrade Drill-Calcite

Bump version number to 1.4.0-drill-test-r16

- Implement two argument version of lpad, rpad

- Implement one argument version of ltrim, rtrim, btrim


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

Branch: refs/heads/master
Commit: c0293354ec79b42ff27ce4ad2113a2ff52a934bd
Parents: 245da97
Author: Hsuan-Yi Chu <hsuanyi@usc.edu>
Authored: Thu Mar 3 22:38:04 2016 -0800
Committer: Hsuan-Yi Chu <hsuanyi@usc.edu>
Committed: Wed Mar 16 20:57:16 2016 -0700

----------------------------------------------------------------------
 .../drill/exec/expr/fn/DrillFuncHolder.java     |  26 +-
 .../exec/expr/fn/DrillFunctionRegistry.java     | 107 ++-
 .../expr/fn/FunctionImplementationRegistry.java |   6 +
 .../exec/expr/fn/impl/StringFunctions.java      | 225 +++++++
 .../apache/drill/exec/planner/PlannerPhase.java |  10 +
 .../planner/logical/DrillConstExecutor.java     |  81 +--
 .../drill/exec/planner/logical/DrillOptiq.java  |  12 -
 .../logical/DrillReduceAggregatesRule.java      | 250 +++++--
 .../planner/logical/PreProcessLogicalRel.java   |  75 ++-
 .../visitor/InsertLocalExchangeVisitor.java     |   2 +-
 .../apache/drill/exec/planner/sql/Checker.java  |  35 +-
 .../sql/DrillCalciteSqlAggFunctionWrapper.java  | 162 +++++
 .../sql/DrillCalciteSqlFunctionWrapper.java     | 147 +++++
 .../sql/DrillCalciteSqlOperatorWrapper.java     | 140 ++++
 .../planner/sql/DrillCalciteSqlWrapper.java     |  33 +
 .../exec/planner/sql/DrillConvertletTable.java  |  14 +-
 .../planner/sql/DrillExtractConvertlet.java     |   8 +-
 .../exec/planner/sql/DrillOperatorTable.java    |  92 ++-
 .../exec/planner/sql/DrillSqlAggOperator.java   |  55 +-
 .../exec/planner/sql/DrillSqlOperator.java      |  81 +--
 .../exec/planner/sql/TypeInferenceUtils.java    | 649 +++++++++++++++++++
 .../sql/handlers/CreateTableHandler.java        |   2 +-
 .../planner/sql/handlers/DefaultSqlHandler.java |  10 +-
 .../sql/parser/UnsupportedOperatorsVisitor.java |  21 +-
 .../exec/resolver/DefaultFunctionResolver.java  |  13 +-
 .../exec/resolver/ExactFunctionResolver.java    |  10 +-
 .../drill/exec/resolver/FunctionResolver.java   |  17 +-
 .../exec/resolver/FunctionResolverFactory.java  |   3 -
 .../drill/exec/resolver/TypeCastRules.java      |  18 +-
 .../apache/drill/TestDisabledFunctionality.java |  10 -
 .../drill/TestFunctionsWithTypeExpoQueries.java | 281 +++++++-
 .../exec/expr/fn/impl/TestStringFunctions.java  |  85 +++
 .../testConcatWithMoreThanTwoArgs.tsv           |   5 +
 .../typeExposure/metadata_caching/a.parquet     | Bin 0 -> 439 bytes
 .../typeExposure/metadata_caching/b.parquet     | Bin 0 -> 474 bytes
 .../common/expression/FunctionCallFactory.java  |   2 +-
 .../MajorTypeInLogicalExpression.java           |  63 ++
 pom.xml                                         |   2 +-
 38 files changed, 2424 insertions(+), 328 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java
index a9cdbc7..869a4ac 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java
@@ -19,10 +19,8 @@ package org.apache.drill.exec.expr.fn;
 
 import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
-import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import org.apache.drill.common.exceptions.DrillRuntimeException;
 import org.apache.drill.common.exceptions.UserException;
@@ -264,27 +262,31 @@ public abstract class DrillFuncHolder extends AbstractFuncHolder {
     return this.parameters[i].isFieldReader;
   }
 
-  public MajorType getReturnType(List<LogicalExpression> args) {
+  public MajorType getReturnType(final List<LogicalExpression> logicalExpressions) {
     if (returnValue.type.getMinorType() == MinorType.UNION) {
-      Set<MinorType> subTypes = Sets.newHashSet();
-      for (ValueReference ref : parameters) {
+      final Set<MinorType> subTypes = Sets.newHashSet();
+      for(final ValueReference ref : parameters) {
         subTypes.add(ref.getType().getMinorType());
       }
-      MajorType.Builder builder = MajorType.newBuilder().setMinorType(MinorType.UNION).setMode(DataMode.OPTIONAL);
-      for (MinorType subType : subTypes) {
+
+      final MajorType.Builder builder = MajorType.newBuilder()
+          .setMinorType(MinorType.UNION)
+          .setMode(DataMode.OPTIONAL);
+
+      for(final MinorType subType : subTypes) {
         builder.addSubType(subType);
       }
       return builder.build();
     }
-    if (nullHandling == NullHandling.NULL_IF_NULL) {
+
+    if(nullHandling == NullHandling.NULL_IF_NULL) {
       // if any one of the input types is nullable, then return nullable return type
-      for (LogicalExpression e : args) {
-        if (e.getMajorType().getMode() == TypeProtos.DataMode.OPTIONAL) {
+      for(final LogicalExpression logicalExpression : logicalExpressions) {
+        if(logicalExpression.getMajorType().getMode() == TypeProtos.DataMode.OPTIONAL) {
           return Types.optional(returnValue.type.getMinorType());
         }
       }
     }
-
     return returnValue.type;
   }
 
@@ -405,7 +407,6 @@ public abstract class DrillFuncHolder extends AbstractFuncHolder {
     public String getName() {
       return name;
     }
-
   }
 
   public boolean checkPrecisionRange() {
@@ -419,5 +420,4 @@ public abstract class DrillFuncHolder extends AbstractFuncHolder {
   public ValueReference getReturnValue() {
     return returnValue;
   }
-
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFunctionRegistry.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFunctionRegistry.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFunctionRegistry.java
index 05439b3..76ec90d 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFunctionRegistry.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFunctionRegistry.java
@@ -17,40 +17,61 @@
  */
 package org.apache.drill.exec.expr.fn;
 
-import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 
-import org.apache.calcite.sql.SqlOperator;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.drill.common.scanner.persistence.AnnotatedClassDescriptor;
 import org.apache.drill.common.scanner.persistence.ScanResult;
-import org.apache.drill.exec.expr.DrillFunc;
+import org.apache.drill.common.types.TypeProtos;
 import org.apache.drill.exec.planner.logical.DrillConstExecutor;
 import org.apache.drill.exec.planner.sql.DrillOperatorTable;
 import org.apache.drill.exec.planner.sql.DrillSqlAggOperator;
 import org.apache.drill.exec.planner.sql.DrillSqlOperator;
 
 import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Sets;
 
+/**
+ * Registry of Drill functions.
+ */
 public class DrillFunctionRegistry {
-  static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillFunctionRegistry.class);
+  private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillFunctionRegistry.class);
+
+  // key: function name (lowercase) value: list of functions with that name
+  private final ArrayListMultimap<String, DrillFuncHolder> registeredFunctions = ArrayListMultimap.create();
 
-  private ArrayListMultimap<String, DrillFuncHolder> methods = ArrayListMultimap.create();
+  private static final ImmutableMap<String, Pair<Integer, Integer>> drillFuncToRange = ImmutableMap.<String, Pair<Integer, Integer>> builder()
+      // CONCAT is allowed to take [1, infinity) number of arguments.
+      // Currently, this flexibility is offered by DrillOptiq to rewrite it as
+      // a nested structure
+      .put("CONCAT", Pair.of(1, Integer.MAX_VALUE))
 
-  /* Hash map to prevent registering functions with exactly matching signatures
-   * key: Function Name + Input's Major Type
-   * Value: Class name where function is implemented
-   */
-  private HashMap<String, String> functionSignatureMap = new HashMap<>();
+      // When LENGTH is given two arguments, this function relies on DrillOptiq to rewrite it as
+      // another function based on the second argument (encodingType)
+      .put("LENGTH", Pair.of(1, 2))
+
+      // Dummy functions
+      .put("CONVERT_TO", Pair.of(2, 2))
+      .put("CONVERT_FROM", Pair.of(2, 2))
+      .put("FLATTEN", Pair.of(1, 1)).build();
 
   public DrillFunctionRegistry(ScanResult classpathScan) {
     FunctionConverter converter = new FunctionConverter();
     List<AnnotatedClassDescriptor> providerClasses = classpathScan.getAnnotatedClasses();
+
+    // Hash map to prevent registering functions with exactly matching signatures
+    // key: Function Name + Input's Major Type
+    // value: Class name where function is implemented
+    //
+    final Map<String, String> functionSignatureMap = new HashMap<>();
     for (AnnotatedClassDescriptor func : providerClasses) {
       DrillFuncHolder holder = converter.getHolder(func);
       if (holder != null) {
@@ -64,7 +85,7 @@ public class DrillFunctionRegistry {
         }
         for (String name : names) {
           String functionName = name.toLowerCase();
-          methods.put(functionName, holder);
+          registeredFunctions.put(functionName, holder);
           String functionSignature = functionName + functionInput;
           String existingImplementation;
           if ((existingImplementation = functionSignatureMap.get(functionSignature)) != null) {
@@ -84,7 +105,7 @@ public class DrillFunctionRegistry {
     }
     if (logger.isTraceEnabled()) {
       StringBuilder allFunctions = new StringBuilder();
-      for (DrillFuncHolder method: methods.values()) {
+      for (DrillFuncHolder method: registeredFunctions.values()) {
         allFunctions.append(method.toString()).append("\n");
       }
       logger.trace("Registered functions: [\n{}]", allFunctions);
@@ -92,38 +113,54 @@ public class DrillFunctionRegistry {
   }
 
   public int size(){
-    return methods.size();
+    return registeredFunctions.size();
   }
 
   /** Returns functions with given name. Function name is case insensitive. */
   public List<DrillFuncHolder> getMethods(String name) {
-    return this.methods.get(name.toLowerCase());
+    return this.registeredFunctions.get(name.toLowerCase());
   }
 
   public void register(DrillOperatorTable operatorTable) {
-    SqlOperator op;
-    for (Entry<String, Collection<DrillFuncHolder>> function : methods.asMap().entrySet()) {
-      Set<Integer> argCounts = Sets.newHashSet();
-      String name = function.getKey().toUpperCase();
+    for (Entry<String, Collection<DrillFuncHolder>> function : registeredFunctions.asMap().entrySet()) {
+      final ArrayListMultimap<Pair<Integer, Integer>, DrillFuncHolder> functions = ArrayListMultimap.create();
+      final ArrayListMultimap<Integer, DrillFuncHolder> aggregateFunctions = ArrayListMultimap.create();
+      final String name = function.getKey().toUpperCase();
+      boolean isDeterministic = true;
       for (DrillFuncHolder func : function.getValue()) {
-        if (argCounts.add(func.getParamCount())) {
-          if (func.isAggregating()) {
-            op = new DrillSqlAggOperator(name, func.getParamCount());
+        final int paramCount = func.getParamCount();
+        if(func.isAggregating()) {
+          aggregateFunctions.put(paramCount, func);
+        } else {
+          final Pair<Integer, Integer> argNumberRange;
+          if(drillFuncToRange.containsKey(name)) {
+            argNumberRange = drillFuncToRange.get(name);
           } else {
-            boolean isDeterministic;
-            // prevent Drill from folding constant functions with types that cannot be materialized
-            // into literals
-            if (DrillConstExecutor.NON_REDUCIBLE_TYPES.contains(func.getReturnType().getMinorType())) {
-              isDeterministic = false;
-            } else {
-              isDeterministic = func.isDeterministic();
-            }
-            op = new DrillSqlOperator(name, func.getParamCount(), func.getReturnType(), isDeterministic);
+            argNumberRange = Pair.of(func.getParamCount(), func.getParamCount());
           }
-          operatorTable.add(function.getKey(), op);
+          functions.put(argNumberRange, func);
         }
+
+        if(!func.isDeterministic()) {
+          isDeterministic = false;
+        }
+      }
+      for (Entry<Pair<Integer, Integer>, Collection<DrillFuncHolder>> entry : functions.asMap().entrySet()) {
+        final DrillSqlOperator drillSqlOperator;
+        final Pair<Integer, Integer> range = entry.getKey();
+        final int max = range.getRight();
+        final int min = range.getLeft();
+        drillSqlOperator = new DrillSqlOperator(
+            name,
+            Lists.newArrayList(entry.getValue()),
+            min,
+            max,
+            isDeterministic);
+        operatorTable.add(name, drillSqlOperator);
+      }
+      for (Entry<Integer, Collection<DrillFuncHolder>> entry : aggregateFunctions.asMap().entrySet()) {
+        operatorTable.add(name, new DrillSqlAggOperator(name, Lists.newArrayList(entry.getValue()), entry.getKey()));
       }
     }
   }
-
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionImplementationRegistry.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionImplementationRegistry.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionImplementationRegistry.java
index 5985f0e..2feac1a 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionImplementationRegistry.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionImplementationRegistry.java
@@ -19,6 +19,7 @@ package org.apache.drill.exec.expr.fn;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -40,6 +41,11 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Stopwatch;
 import com.google.common.collect.Lists;
 
+/**
+ * This class offers the registry for functions. Notably, in addition to Drill its functions
+ * (in {@link DrillFunctionRegistry}), other PluggableFunctionRegistry (e.g., {@link org.apache.drill.exec.expr.fn.HiveFunctionRegistry})
+ * is also registered in this class
+ */
 public class FunctionImplementationRegistry implements FunctionLookupContext {
   static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(FunctionImplementationRegistry.class);
 

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java
index f5aeaf6..112f5fd 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/StringFunctions.java
@@ -770,6 +770,65 @@ public class StringFunctions{
     } // end of eval
   }
 
+  /*
+   * Fill up the string to length 'length' by prepending the character ' ' in the beginning of 'text'.
+   * If the string is already longer than length, then it is truncated (on the right).
+   */
+  @FunctionTemplate(name = "lpad", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+  public static class LpadTwoArg implements DrillSimpleFunc {
+    @Param  VarCharHolder text;
+    @Param  BigIntHolder length;
+    @Inject DrillBuf buffer;
+
+    @Output VarCharHolder out;
+    @Workspace byte spaceInByte;
+
+    @Override
+    public void setup() {
+      spaceInByte = 32;
+    }
+
+    @Override
+    public void eval() {
+      final long theLength = length.value;
+      final int lengthNeeded = (int) (theLength <= 0 ? 0 : theLength * 2);
+      buffer = buffer.reallocIfNeeded(lengthNeeded);
+      //get the char length of text.
+      int textCharCount = org.apache.drill.exec.expr.fn.impl.StringFunctionUtil.getUTF8CharLength(text.buffer, text.start, text.end);
+
+      if (theLength <= 0) {
+        //case 1: target length is <=0, then return an empty string.
+        out.buffer = buffer;
+        out.start = out.end = 0;
+      } else if (theLength == textCharCount) {
+        //case 2: target length is same as text's length.
+        out.buffer = text.buffer;
+        out.start = text.start;
+        out.end = text.end;
+      } else if (theLength < textCharCount) {
+        //case 3: truncate text on the right side. It's same as substring(text, 1, length).
+        out.buffer = text.buffer;
+        out.start = text.start;
+        out.end = org.apache.drill.exec.expr.fn.impl.StringFunctionUtil.getUTF8CharPosition(text.buffer, text.start, text.end, (int) theLength);
+      } else if (theLength > textCharCount) {
+        //case 4: copy " " on left. Total # of char to copy : theLength - textCharCount
+        int count = 0;
+        out.buffer = buffer;
+        out.start = out.end = 0;
+
+        while (count < theLength - textCharCount) {
+          out.buffer.setByte(out.end++, spaceInByte);
+          ++count;
+        } // end of while
+
+        //copy "text" into "out"
+        for (int id = text.start; id < text.end; id++) {
+          out.buffer.setByte(out.end++, text.buffer.getByte(id));
+        }
+      }
+    } // end of eval
+  }
+
   /**
    * Fill up the string to length "length" by appending the characters 'fill' at the end of 'text'
    * If the string is already longer than length then it is truncated.
@@ -849,6 +908,68 @@ public class StringFunctions{
   }
 
   /**
+   * Fill up the string to length "length" by appending the characters ' ' at the end of 'text'
+   * If the string is already longer than length then it is truncated.
+   */
+  @FunctionTemplate(name = "rpad", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+  public static class RpadTwoArg implements DrillSimpleFunc {
+    @Param  VarCharHolder text;
+    @Param  BigIntHolder length;
+    @Inject DrillBuf buffer;
+
+    @Output VarCharHolder out;
+    @Workspace byte spaceInByte;
+
+    @Override
+    public void setup() {
+      spaceInByte = 32;
+    }
+
+    @Override
+    public void eval() {
+      final long theLength = length.value;
+      final int lengthNeeded = (int) (theLength <= 0 ? 0 : theLength * 2);
+      buffer = buffer.reallocIfNeeded(lengthNeeded);
+
+      //get the char length of text.
+      int textCharCount = org.apache.drill.exec.expr.fn.impl.StringFunctionUtil.getUTF8CharLength(text.buffer, text.start, text.end);
+
+      if (theLength <= 0) {
+        //case 1: target length is <=0, then return an empty string.
+        out.buffer = buffer;
+        out.start = out.end = 0;
+      } else if (theLength == textCharCount) {
+        //case 2: target length is same as text's length.
+        out.buffer = text.buffer;
+        out.start = text.start;
+        out.end = text.end;
+      } else if (theLength < textCharCount) {
+        //case 3: truncate text on the right side. It's same as substring(text, 1, length).
+        out.buffer = text.buffer;
+        out.start = text.start;
+        out.end = org.apache.drill.exec.expr.fn.impl.StringFunctionUtil.getUTF8CharPosition(text.buffer, text.start, text.end, (int) theLength);
+      } else if (theLength > textCharCount) {
+        //case 4: copy "text" into "out", then copy " " on the right.
+        out.buffer = buffer;
+        out.start = out.end = 0;
+
+        for (int id = text.start; id < text.end; id++) {
+          out.buffer.setByte(out.end++, text.buffer.getByte(id));
+        }
+
+        //copy " " on right. Total # of char to copy : theLength - textCharCount
+        int count = 0;
+
+        while (count < theLength - textCharCount) {
+          out.buffer.setByte(out.end++, spaceInByte);
+          ++count;
+        } // end of while
+
+      }
+    } // end of eval
+  }
+
+  /**
    * Remove the longest string containing only characters from "from"  from the start of "text"
    */
   @FunctionTemplate(name = "ltrim", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
@@ -882,6 +1003,36 @@ public class StringFunctions{
   }
 
   /**
+   * Remove the longest string containing only character " " from the start of "text"
+   */
+  @FunctionTemplate(name = "ltrim", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+  public static class LtrimOneArg implements DrillSimpleFunc {
+    @Param  VarCharHolder text;
+
+    @Output VarCharHolder out;
+    @Workspace byte spaceInByte;
+
+    @Override
+    public void setup() {
+      spaceInByte = 32;
+    }
+
+    @Override
+    public void eval() {
+      out.buffer = text.buffer;
+      out.start = out.end = text.end;
+
+      //Scan from left of "text", stop until find a char not " "
+      for (int id = text.start; id < text.end; ++id) {
+      if (text.buffer.getByte(id) != spaceInByte) { // Found the 1st char not " ", stop
+          out.start = id;
+          break;
+        }
+      }
+    } // end of eval
+  }
+
+  /**
    * Remove the longest string containing only characters from "from"  from the end of "text"
    */
   @FunctionTemplate(name = "rtrim", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
@@ -918,6 +1069,39 @@ public class StringFunctions{
   }
 
   /**
+   * Remove the longest string containing only character " " from the end of "text"
+   */
+  @FunctionTemplate(name = "rtrim", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+  public static class RtrimOneArg implements DrillSimpleFunc {
+    @Param  VarCharHolder text;
+
+    @Output VarCharHolder out;
+    @Workspace byte spaceInByte;
+
+    @Override
+    public void setup() {
+      spaceInByte = 32;
+    }
+
+    @Override
+    public void eval() {
+      out.buffer = text.buffer;
+      out.start = out.end = text.start;
+
+      //Scan from right of "text", stop until find a char not in " "
+      for (int id = text.end - 1; id >= text.start; --id) {
+        while ((text.buffer.getByte(id) & 0xC0) == 0x80 && id >= text.start) {
+          id--;
+        }
+        if (text.buffer.getByte(id) != spaceInByte) { // Found the 1st char not in " ", stop
+          out.end = id + 1;
+          break;
+        }
+      }
+    } // end of eval
+  }
+
+  /**
    * Remove the longest string containing only characters from "from"  from the start of "text"
    */
   @FunctionTemplate(name = "btrim", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
@@ -964,6 +1148,47 @@ public class StringFunctions{
     } // end of eval
   }
 
+  /**
+   * Remove the longest string containing only character " " from the start of "text"
+   */
+  @FunctionTemplate(name = "btrim", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+  public static class BtrimOneArg implements DrillSimpleFunc {
+    @Param  VarCharHolder text;
+
+    @Output VarCharHolder out;
+    @Workspace byte spaceInByte;
+
+    @Override
+    public void setup() {
+      spaceInByte = 32;
+    }
+
+    @Override
+    public void eval() {
+      out.buffer = text.buffer;
+      out.start = out.end = text.start;
+
+      //Scan from left of "text", stop until find a char not " "
+      for (int id = text.start; id < text.end; ++id) {
+        if (text.buffer.getByte(id) != spaceInByte) { // Found the 1st char not " ", stop
+          out.start = id;
+          break;
+        }
+      }
+
+      //Scan from right of "text", stop until find a char not " "
+      for (int id = text.end - 1; id >= text.start; --id) {
+        while ((text.buffer.getByte(id) & 0xC0) == 0x80 && id >= text.start) {
+          id--;
+        }
+        if (text.buffer.getByte(id) != spaceInByte) { // Found the 1st char not in " ", stop
+          out.end = id + 1;
+          break;
+        }
+      }
+    } // end of eval
+  }
+
   @FunctionTemplate(name = "concatOperator", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
   public static class ConcatOperator implements DrillSimpleFunc {
     @Param  VarCharHolder left;

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/PlannerPhase.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/PlannerPhase.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/PlannerPhase.java
index 7cbed77..7ab7faf 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/PlannerPhase.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/PlannerPhase.java
@@ -135,6 +135,16 @@ public enum PlannerPhase {
     }
   },
 
+  SUM_CONVERSION("Convert SUM to $SUM0") {
+    public RuleSet getRules(OptimizerRulesContext context, Collection<StoragePlugin> plugins) {
+      return PlannerPhase.mergedRuleSets(
+          RuleSets.ofList(
+              DrillReduceAggregatesRule.INSTANCE_SUM),
+          getStorageRules(context, plugins, this)
+          );
+    }
+  },
+
   PARTITION_PRUNING("Partition Prune Planning") {
     public RuleSet getRules(OptimizerRulesContext context, Collection<StoragePlugin> plugins) {
       return PlannerPhase.mergedRuleSets(getPruneScanRules(context), getStorageRules(context, plugins, this));

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillConstExecutor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillConstExecutor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillConstExecutor.java
index 78d2701..96579db 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillConstExecutor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillConstExecutor.java
@@ -58,6 +58,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.NlsString;
 import org.apache.drill.exec.planner.physical.PlannerSettings;
+import org.apache.drill.exec.planner.sql.TypeInferenceUtils;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
@@ -70,34 +71,6 @@ public class DrillConstExecutor implements RelOptPlanner.Executor {
 
   private final PlannerSettings plannerSettings;
 
-  public static ImmutableMap<TypeProtos.MinorType, SqlTypeName> DRILL_TO_CALCITE_TYPE_MAPPING =
-      ImmutableMap.<TypeProtos.MinorType, SqlTypeName> builder()
-      .put(TypeProtos.MinorType.INT, SqlTypeName.INTEGER)
-      .put(TypeProtos.MinorType.BIGINT, SqlTypeName.BIGINT)
-      .put(TypeProtos.MinorType.FLOAT4, SqlTypeName.FLOAT)
-      .put(TypeProtos.MinorType.FLOAT8, SqlTypeName.DOUBLE)
-      .put(TypeProtos.MinorType.VARCHAR, SqlTypeName.VARCHAR)
-      .put(TypeProtos.MinorType.BIT, SqlTypeName.BOOLEAN)
-      .put(TypeProtos.MinorType.DATE, SqlTypeName.DATE)
-      .put(TypeProtos.MinorType.DECIMAL9, SqlTypeName.DECIMAL)
-      .put(TypeProtos.MinorType.DECIMAL18, SqlTypeName.DECIMAL)
-      .put(TypeProtos.MinorType.DECIMAL28SPARSE, SqlTypeName.DECIMAL)
-      .put(TypeProtos.MinorType.DECIMAL38SPARSE, SqlTypeName.DECIMAL)
-      .put(TypeProtos.MinorType.TIME, SqlTypeName.TIME)
-      .put(TypeProtos.MinorType.TIMESTAMP, SqlTypeName.TIMESTAMP)
-      .put(TypeProtos.MinorType.VARBINARY, SqlTypeName.VARBINARY)
-      .put(TypeProtos.MinorType.INTERVALYEAR, SqlTypeName.INTERVAL_YEAR_MONTH)
-      .put(TypeProtos.MinorType.INTERVALDAY, SqlTypeName.INTERVAL_DAY_TIME)
-      .put(TypeProtos.MinorType.MAP, SqlTypeName.MAP)
-      .put(TypeProtos.MinorType.LIST, SqlTypeName.ARRAY)
-      .put(TypeProtos.MinorType.LATE, SqlTypeName.ANY)
-      // These are defined in the Drill type system but have been turned off for now
-      .put(TypeProtos.MinorType.TINYINT, SqlTypeName.TINYINT)
-      .put(TypeProtos.MinorType.SMALLINT, SqlTypeName.SMALLINT)
-      // Calcite types currently not supported by Drill, nor defined in the Drill type list:
-      //      - CHAR, SYMBOL, MULTISET, DISTINCT, STRUCTURED, ROW, OTHER, CURSOR, COLUMN_LIST
-      .build();
-
   // This is a list of all types that cannot be folded at planning time for various reasons, most of the types are
   // currently not supported at all. The reasons for the others can be found in the evaluation code in the reduce method
   public static final List<Object> NON_REDUCIBLE_TYPES = ImmutableList.builder().add(
@@ -132,30 +105,6 @@ public class DrillConstExecutor implements RelOptPlanner.Executor {
     this.plannerSettings = plannerSettings;
   }
 
-  private RelDataType createCalciteTypeWithNullability(RelDataTypeFactory typeFactory,
-                                                       SqlTypeName sqlTypeName,
-                                                       boolean isNullable) {
-    RelDataType type;
-    if (sqlTypeName == SqlTypeName.INTERVAL_DAY_TIME) {
-      type = typeFactory.createSqlIntervalType(
-          new SqlIntervalQualifier(
-              TimeUnit.DAY,
-              TimeUnit.MINUTE,
-              SqlParserPos.ZERO));
-    } else if (sqlTypeName == SqlTypeName.INTERVAL_YEAR_MONTH) {
-      type = typeFactory.createSqlIntervalType(
-          new SqlIntervalQualifier(
-              TimeUnit.YEAR,
-              TimeUnit.MONTH,
-             SqlParserPos.ZERO));
-    } else if (sqlTypeName == SqlTypeName.VARCHAR) {
-      type = typeFactory.createSqlType(sqlTypeName, TypeHelper.VARCHAR_DEFAULT_CAST_LEN);
-    } else {
-      type = typeFactory.createSqlType(sqlTypeName);
-    }
-    return typeFactory.createTypeWithNullability(type, isNullable);
-  }
-
   @Override
   public void reduce(RexBuilder rexBuilder, List<RexNode> constExps, List<RexNode> reducedValues) {
     for (RexNode newCall : constExps) {
@@ -183,7 +132,7 @@ public class DrillConstExecutor implements RelOptPlanner.Executor {
       RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
 
       if (materializedExpr.getMajorType().getMode() == TypeProtos.DataMode.OPTIONAL && TypeHelper.isNull(output)) {
-        SqlTypeName sqlTypeName = DRILL_TO_CALCITE_TYPE_MAPPING.get(materializedExpr.getMajorType().getMinorType());
+        SqlTypeName sqlTypeName = TypeInferenceUtils.getCalciteTypeFromDrillType(materializedExpr.getMajorType().getMinorType());
         if (sqlTypeName == null) {
           String message = String.format("Error reducing constant expression, unsupported type: %s.",
               materializedExpr.getMajorType().getMinorType());
@@ -198,25 +147,25 @@ public class DrillConstExecutor implements RelOptPlanner.Executor {
           case INT:
             reducedValues.add(rexBuilder.makeLiteral(
                 new BigDecimal(((IntHolder)output).value),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.INTEGER, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.INTEGER, newCall.getType().isNullable()),
                 false));
             break;
           case BIGINT:
             reducedValues.add(rexBuilder.makeLiteral(
                 new BigDecimal(((BigIntHolder)output).value),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.BIGINT, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.BIGINT, newCall.getType().isNullable()),
                 false));
             break;
           case FLOAT4:
             reducedValues.add(rexBuilder.makeLiteral(
                 new BigDecimal(((Float4Holder)output).value),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.FLOAT, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.FLOAT, newCall.getType().isNullable()),
                 false));
             break;
           case FLOAT8:
             reducedValues.add(rexBuilder.makeLiteral(
                 new BigDecimal(((Float8Holder)output).value),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.DOUBLE, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.DOUBLE, newCall.getType().isNullable()),
                 false));
             break;
           case VARCHAR:
@@ -226,25 +175,25 @@ public class DrillConstExecutor implements RelOptPlanner.Executor {
           case BIT:
             reducedValues.add(rexBuilder.makeLiteral(
                 ((BitHolder)output).value == 1 ? true : false,
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.BOOLEAN, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.BOOLEAN, newCall.getType().isNullable()),
                 false));
             break;
           case DATE:
             reducedValues.add(rexBuilder.makeLiteral(
                 new DateTime(((DateHolder) output).value, DateTimeZone.UTC).toCalendar(null),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.DATE, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.DATE, newCall.getType().isNullable()),
                 false));
             break;
           case DECIMAL9:
             reducedValues.add(rexBuilder.makeLiteral(
                 new BigDecimal(BigInteger.valueOf(((Decimal9Holder) output).value), ((Decimal9Holder)output).scale),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.DECIMAL, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.DECIMAL, newCall.getType().isNullable()),
                 false));
             break;
           case DECIMAL18:
             reducedValues.add(rexBuilder.makeLiteral(
                 new BigDecimal(BigInteger.valueOf(((Decimal18Holder) output).value), ((Decimal18Holder)output).scale),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.DECIMAL, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.DECIMAL, newCall.getType().isNullable()),
                 false));
             break;
           case DECIMAL28SPARSE:
@@ -255,7 +204,7 @@ public class DrillConstExecutor implements RelOptPlanner.Executor {
                     decimal28Out.start * 20,
                     5,
                     decimal28Out.scale),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.DECIMAL, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.DECIMAL, newCall.getType().isNullable()),
                 false
             ));
             break;
@@ -267,14 +216,14 @@ public class DrillConstExecutor implements RelOptPlanner.Executor {
                     decimal38Out.start * 24,
                     6,
                     decimal38Out.scale),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.DECIMAL, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.DECIMAL, newCall.getType().isNullable()),
                 false));
             break;
 
           case TIME:
             reducedValues.add(rexBuilder.makeLiteral(
                 new DateTime(((TimeHolder)output).value, DateTimeZone.UTC).toCalendar(null),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.TIME, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.TIME, newCall.getType().isNullable()),
                 false));
             break;
           case TIMESTAMP:
@@ -284,14 +233,14 @@ public class DrillConstExecutor implements RelOptPlanner.Executor {
           case INTERVALYEAR:
             reducedValues.add(rexBuilder.makeLiteral(
                 new BigDecimal(((IntervalYearHolder)output).value),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.INTERVAL_YEAR_MONTH, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.INTERVAL_YEAR_MONTH, newCall.getType().isNullable()),
                 false));
             break;
           case INTERVALDAY:
             IntervalDayHolder intervalDayOut = (IntervalDayHolder) output;
             reducedValues.add(rexBuilder.makeLiteral(
                 new BigDecimal(intervalDayOut.days * DateUtility.daysToStandardMillis + intervalDayOut.milliseconds),
-                createCalciteTypeWithNullability(typeFactory, SqlTypeName.INTERVAL_DAY_TIME, newCall.getType().isNullable()),
+                TypeInferenceUtils.createCalciteTypeWithNullability(typeFactory, SqlTypeName.INTERVAL_DAY_TIME, newCall.getType().isNullable()),
                 false));
             break;
           // The list of known unsupported types is used to trigger this behavior of re-using the input expression

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/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 bd029bf..cae6796 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
@@ -360,11 +360,6 @@ public class DrillOptiq {
         trimArgs.add(args.get(1));
 
         return FunctionCallFactory.createExpression(trimFunc, trimArgs);
-      } else if (functionName.equals("ltrim") || functionName.equals("rtrim") || functionName.equals("btrim")) {
-        if (argsSize == 1) {
-          args.add(ValueExpressions.getChar(" "));
-        }
-        return FunctionCallFactory.createExpression(functionName, args);
       } else if (functionName.equals("date_part")) {
         // Rewrite DATE_PART functions as extract functions
         // assert that the function has exactly two arguments
@@ -427,13 +422,6 @@ public class DrillOptiq {
       } else if ((functionName.equals("convert_from") || functionName.equals("convert_to"))
                     && args.get(1) instanceof QuotedString) {
         return FunctionCallFactory.createConvert(functionName, ((QuotedString)args.get(1)).value, args.get(0), ExpressionPosition.UNKNOWN);
-      } else if ((functionName.equalsIgnoreCase("rpad")) || functionName.equalsIgnoreCase("lpad")) {
-        // If we have only two arguments for rpad/lpad append a default QuotedExpression as an argument which will be used to pad the string
-        if (argsSize == 2) {
-          String spaceFill = " ";
-          LogicalExpression fill = ValueExpressions.getChar(spaceFill);
-          args.add(fill);
-        }
       }
 
       return FunctionCallFactory.createExpression(functionName, args);

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillReduceAggregatesRule.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillReduceAggregatesRule.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillReduceAggregatesRule.java
index 9ba01a8..3a2510e 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillReduceAggregatesRule.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillReduceAggregatesRule.java
@@ -18,6 +18,7 @@
 
 package org.apache.drill.exec.planner.logical;
 
+import com.google.common.collect.ImmutableList;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
@@ -25,12 +26,14 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.logging.Logger;
 
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.calcite.rel.InvalidRelException;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.logical.LogicalAggregate;
 import org.apache.calcite.sql.fun.SqlCountAggFunction;
-import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.drill.exec.planner.sql.DrillSqlOperator;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.plan.RelOptRule;
@@ -48,12 +51,15 @@ import org.apache.calcite.sql.fun.SqlAvgAggFunction;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.fun.SqlSumAggFunction;
 import org.apache.calcite.sql.fun.SqlSumEmptyIsZeroAggFunction;
-import org.apache.calcite.sql.type.SqlTypeUtil;
+import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.CompositeList;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Util;
 
-import com.google.common.collect.ImmutableList;
+import org.apache.calcite.util.trace.CalciteTrace;
+import org.apache.drill.exec.planner.sql.DrillCalciteSqlAggFunctionWrapper;
+import org.apache.drill.exec.planner.sql.DrillCalciteSqlWrapper;
+import org.apache.drill.exec.planner.sql.DrillSqlOperator;
 
 /**
  * Rule to reduce aggregates to simpler forms. Currently only AVG(x) to
@@ -65,8 +71,11 @@ public class DrillReduceAggregatesRule extends RelOptRule {
   /**
    * The singleton.
    */
+
   public static final DrillReduceAggregatesRule INSTANCE =
       new DrillReduceAggregatesRule(operand(LogicalAggregate.class, any()));
+  public static final DrillConvertSumToSumZero INSTANCE_SUM =
+          new DrillConvertSumToSumZero(operand(DrillAggregateRel.class, any()));
 
   private static final DrillSqlOperator CastHighOp = new DrillSqlOperator("CastHigh", 1, false);
 
@@ -100,8 +109,13 @@ public class DrillReduceAggregatesRule extends RelOptRule {
    */
   private boolean containsAvgStddevVarCall(List<AggregateCall> aggCallList) {
     for (AggregateCall call : aggCallList) {
-      if (call.getAggregation() instanceof SqlAvgAggFunction
-          || call.getAggregation() instanceof SqlSumAggFunction) {
+      SqlAggFunction sqlAggFunction = call.getAggregation();
+      if(sqlAggFunction instanceof DrillCalciteSqlWrapper) {
+        sqlAggFunction = (SqlAggFunction) ((DrillCalciteSqlWrapper) sqlAggFunction).getOperator();
+      }
+
+      if (sqlAggFunction instanceof SqlAvgAggFunction
+          || sqlAggFunction instanceof SqlSumAggFunction) {
         return true;
       }
     }
@@ -198,15 +212,19 @@ public class DrillReduceAggregatesRule extends RelOptRule {
       List<AggregateCall> newCalls,
       Map<AggregateCall, RexNode> aggCallMapping,
       List<RexNode> inputExprs) {
-    if (oldCall.getAggregation() instanceof SqlSumAggFunction) {
+    SqlAggFunction sqlAggFunction = oldCall.getAggregation();
+    if(sqlAggFunction instanceof DrillCalciteSqlWrapper) {
+      sqlAggFunction = (SqlAggFunction) ((DrillCalciteSqlWrapper) sqlAggFunction).getOperator();
+    }
+
+    if (sqlAggFunction instanceof SqlSumAggFunction) {
       // replace original SUM(x) with
       // case COUNT(x) when 0 then null else SUM0(x) end
       return reduceSum(oldAggRel, oldCall, newCalls, aggCallMapping);
     }
-    if (oldCall.getAggregation() instanceof SqlAvgAggFunction) {
-      final SqlAvgAggFunction.Subtype subtype =
-          ((SqlAvgAggFunction) oldCall.getAggregation()).getSubtype();
 
+    if (sqlAggFunction instanceof SqlAvgAggFunction) {
+      final SqlAvgAggFunction.Subtype subtype = ((SqlAvgAggFunction) sqlAggFunction).getSubtype();
       switch (subtype) {
       case AVG:
         // replace original AVG(x) with SUM(x) / COUNT(x)
@@ -274,6 +292,7 @@ public class DrillReduceAggregatesRule extends RelOptRule {
       AggregateCall oldCall,
       List<AggregateCall> newCalls,
       Map<AggregateCall, RexNode> aggCallMapping) {
+    final boolean isWrapper = useWrapper(oldCall);
     final int nGroups = oldAggRel.getGroupCount();
     RelDataTypeFactory typeFactory =
         oldAggRel.getCluster().getTypeFactory();
@@ -283,12 +302,25 @@ public class DrillReduceAggregatesRule extends RelOptRule {
         getFieldType(
             oldAggRel.getInput(),
             iAvgInput);
-    RelDataType sumType =
-        typeFactory.createTypeWithNullability(
-            avgInputType,
-            avgInputType.isNullable() || nGroups == 0);
+
+    final RelDataType sumType;
+    if(isWrapper) {
+      sumType = oldCall.getType();
+    } else {
+      sumType =
+          typeFactory.createTypeWithNullability(
+              avgInputType,
+              avgInputType.isNullable() || nGroups == 0);
+    }
     // SqlAggFunction sumAgg = new SqlSumAggFunction(sumType);
-    SqlAggFunction sumAgg = new SqlSumEmptyIsZeroAggFunction();
+    SqlAggFunction sumAgg;
+    if(isWrapper) {
+      sumAgg = new DrillCalciteSqlAggFunctionWrapper(
+          new SqlSumEmptyIsZeroAggFunction(), sumType);
+    } else {
+      sumAgg = new SqlSumEmptyIsZeroAggFunction();
+    }
+
     AggregateCall sumCall =
         new AggregateCall(
             sumAgg,
@@ -358,8 +390,13 @@ public class DrillReduceAggregatesRule extends RelOptRule {
             SqlStdOperatorTable.DIVIDE,
             numeratorRef,
             denominatorRef);
-    return rexBuilder.makeCast(
-        typeFactory.createSqlType(SqlTypeName.ANY), divideRef);
+
+    if(isWrapper) {
+      return divideRef;
+    } else {
+      return rexBuilder.makeCast(
+          typeFactory.createSqlType(SqlTypeName.ANY), divideRef);
+    }
   }
 
   private RexNode reduceSum(
@@ -367,19 +404,34 @@ public class DrillReduceAggregatesRule extends RelOptRule {
       AggregateCall oldCall,
       List<AggregateCall> newCalls,
       Map<AggregateCall, RexNode> aggCallMapping) {
+    final boolean isWrapper = useWrapper(oldCall);
     final int nGroups = oldAggRel.getGroupCount();
     RelDataTypeFactory typeFactory =
         oldAggRel.getCluster().getTypeFactory();
     RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
-    int arg = oldCall.getArgList().get(0);
-    RelDataType argType =
-        getFieldType(
-            oldAggRel.getInput(),
-            arg);
-    RelDataType sumType =
-        typeFactory.createTypeWithNullability(
-            argType, argType.isNullable());
-    SqlAggFunction sumZeroAgg = new SqlSumEmptyIsZeroAggFunction();
+
+    final RelDataType argType;
+    if(isWrapper) {
+      argType = oldCall.getType();
+    } else {
+      int arg = oldCall.getArgList().get(0);
+      argType =
+          getFieldType(
+              oldAggRel.getInput(),
+              arg);
+    }
+
+    final RelDataType sumType;
+    final SqlAggFunction sumZeroAgg;
+    if(isWrapper) {
+      sumType = oldCall.getType();
+      sumZeroAgg = new DrillCalciteSqlAggFunctionWrapper(
+          new SqlSumEmptyIsZeroAggFunction(), sumType);
+    } else {
+      sumType = typeFactory.createTypeWithNullability(argType, argType.isNullable());
+      sumZeroAgg = new SqlSumEmptyIsZeroAggFunction();
+    }
+
     AggregateCall sumZeroCall =
         new AggregateCall(
             sumZeroAgg,
@@ -436,6 +488,7 @@ public class DrillReduceAggregatesRule extends RelOptRule {
       List<AggregateCall> newCalls,
       Map<AggregateCall, RexNode> aggCallMapping,
       List<RexNode> inputExprs) {
+    final boolean isWrapper = useWrapper(oldCall);
     // stddev_pop(x) ==>
     //   power(
     //     (sum(x * x) - sum(x) * sum(x) / count(x))
@@ -472,13 +525,26 @@ public class DrillReduceAggregatesRule extends RelOptRule {
         typeFactory.createTypeWithNullability(
             argType,
             true);
-    final AggregateCall sumArgSquaredAggCall =
-        new AggregateCall(
-            new SqlSumAggFunction(sumType),
-            oldCall.isDistinct(),
-            ImmutableIntList.of(argSquaredOrdinal),
-            sumType,
-            null);
+    final AggregateCall sumArgSquaredAggCall;
+    if(isWrapper) {
+      sumArgSquaredAggCall =
+          new AggregateCall(
+              new DrillCalciteSqlAggFunctionWrapper(
+                  new SqlSumAggFunction(sumType), sumType),
+              oldCall.isDistinct(),
+              ImmutableIntList.of(argSquaredOrdinal),
+              sumType,
+              null);
+    } else {
+      sumArgSquaredAggCall =
+          new AggregateCall(
+              new SqlSumAggFunction(sumType),
+              oldCall.isDistinct(),
+              ImmutableIntList.of(argSquaredOrdinal),
+              sumType,
+              null);
+    }
+
     final RexNode sumArgSquared =
         rexBuilder.addAggCall(
             sumArgSquaredAggCall,
@@ -488,13 +554,26 @@ public class DrillReduceAggregatesRule extends RelOptRule {
             aggCallMapping,
             ImmutableList.of(argType));
 
-    final AggregateCall sumArgAggCall =
-        new AggregateCall(
-            new SqlSumAggFunction(sumType),
-            oldCall.isDistinct(),
-            ImmutableIntList.of(argOrdinal),
-            sumType,
-            null);
+    final AggregateCall sumArgAggCall;
+    if(isWrapper) {
+      sumArgAggCall =
+          new AggregateCall(
+              new DrillCalciteSqlAggFunctionWrapper(
+                  new SqlSumAggFunction(sumType), sumType),
+              oldCall.isDistinct(),
+              ImmutableIntList.of(argOrdinal),
+              sumType,
+              null);
+    } else {
+      sumArgAggCall =
+          new AggregateCall(
+              new SqlSumAggFunction(sumType),
+              oldCall.isDistinct(),
+              ImmutableIntList.of(argOrdinal),
+              sumType,
+              null);
+    }
+
     final RexNode sumArg =
           rexBuilder.addAggCall(
               sumArgAggCall,
@@ -577,8 +656,12 @@ public class DrillReduceAggregatesRule extends RelOptRule {
      * this if we add cast after rewriting the aggregate we add an additional cast which
      * would cause wrong results. So we simply add a cast to ANY.
      */
-    return rexBuilder.makeCast(
-        typeFactory.createSqlType(SqlTypeName.ANY), result);
+    if(isWrapper) {
+      return result;
+    } else {
+      return rexBuilder.makeCast(
+          typeFactory.createSqlType(SqlTypeName.ANY), result);
+    }
   }
 
   /**
@@ -621,5 +704,88 @@ public class DrillReduceAggregatesRule extends RelOptRule {
     return inputField.getType();
   }
 
+  private boolean useWrapper(AggregateCall aggregateCall) {
+    return aggregateCall.getAggregation() instanceof DrillCalciteSqlWrapper;
+  }
+
+  private static class DrillConvertSumToSumZero extends RelOptRule {
+    protected static final Logger tracer = CalciteTrace.getPlannerTracer();
+
+    public DrillConvertSumToSumZero(RelOptRuleOperand operand) {
+      super(operand);
+    }
+
+    @Override
+    public boolean matches(RelOptRuleCall call) {
+      DrillAggregateRel oldAggRel = (DrillAggregateRel) call.rels[0];
+      for (AggregateCall aggregateCall : oldAggRel.getAggCallList()) {
+        SqlAggFunction sqlAggFunction = aggregateCall.getAggregation();
+        if(sqlAggFunction instanceof DrillCalciteSqlWrapper) {
+          sqlAggFunction = (SqlAggFunction) ((DrillCalciteSqlWrapper) sqlAggFunction).getOperator();
+        }
+
+        if(sqlAggFunction instanceof SqlSumAggFunction
+            && !aggregateCall.getType().isNullable()) {
+          // If SUM(x) is not nullable, the validator must have determined that
+          // nulls are impossible (because the group is never empty and x is never
+          // null). Therefore we translate to SUM0(x).
+          return true;
+        }
+      }
+      return false;
+    }
+
+    @Override
+    public void onMatch(RelOptRuleCall call) {
+      final DrillAggregateRel oldAggRel = (DrillAggregateRel) call.rels[0];
+
+      final Map<AggregateCall, RexNode> aggCallMapping = Maps.newHashMap();
+      final List<AggregateCall> newAggregateCalls = Lists.newArrayList();
+      for (AggregateCall oldAggregateCall : oldAggRel.getAggCallList()) {
+        SqlAggFunction sqlAggFunction = oldAggregateCall.getAggregation();
+        if(sqlAggFunction instanceof DrillCalciteSqlWrapper) {
+          sqlAggFunction = (SqlAggFunction) ((DrillCalciteSqlWrapper) sqlAggFunction).getOperator();
+        }
+
+        if(sqlAggFunction instanceof SqlSumAggFunction
+            && !oldAggregateCall.getType().isNullable()) {
+          final RelDataType argType = oldAggregateCall.getType();
+          final RelDataType sumType = oldAggRel.getCluster().getTypeFactory()
+              .createTypeWithNullability(argType, argType.isNullable());
+          final SqlAggFunction sumZeroAgg = new DrillCalciteSqlAggFunctionWrapper(
+              new SqlSumEmptyIsZeroAggFunction(), sumType);
+          AggregateCall sumZeroCall =
+              new AggregateCall(
+              sumZeroAgg,
+              oldAggregateCall.isDistinct(),
+              oldAggregateCall.getArgList(),
+              sumType,
+              null);
+          oldAggRel.getCluster().getRexBuilder()
+              .addAggCall(sumZeroCall,
+                  oldAggRel.getGroupCount(),
+                  oldAggRel.indicator,
+                  newAggregateCalls,
+                  aggCallMapping,
+                  ImmutableList.of(argType));
+        } else {
+          newAggregateCalls.add(oldAggregateCall);
+        }
+      }
+
+      try {
+        call.transformTo(new DrillAggregateRel(
+            oldAggRel.getCluster(),
+            oldAggRel.getTraitSet(),
+            oldAggRel.getInput(),
+            oldAggRel.indicator,
+            oldAggRel.getGroupSet(),
+            oldAggRel.getGroupSets(),
+            newAggregateCalls));
+      } catch (InvalidRelException e) {
+        tracer.warning(e.toString());
+      }
+    }
+  }
 }
 

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/PreProcessLogicalRel.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/PreProcessLogicalRel.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/PreProcessLogicalRel.java
index 8d4c1b4..1585a56 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/PreProcessLogicalRel.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/PreProcessLogicalRel.java
@@ -18,12 +18,17 @@
 package org.apache.drill.exec.planner.logical;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
+import com.google.common.collect.Lists;
+import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.rex.RexShuttle;
+import org.apache.calcite.rex.RexUtil;
 import org.apache.drill.common.exceptions.UserException;
 import org.apache.drill.exec.exception.UnsupportedOperatorCollector;
 import org.apache.drill.exec.planner.StarColumnHelper;
+import org.apache.drill.exec.planner.sql.DrillCalciteSqlWrapper;
 import org.apache.drill.exec.planner.sql.DrillOperatorTable;
 import org.apache.drill.exec.util.ApproximateStringMatcher;
 import org.apache.drill.exec.work.foreman.SqlUnsupportedException;
@@ -33,7 +38,6 @@ import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttleImpl;
 import org.apache.calcite.rel.logical.LogicalUnion;
-import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexBuilder;
@@ -60,16 +64,18 @@ public class PreProcessLogicalRel extends RelShuttleImpl {
   private RelDataTypeFactory factory;
   private DrillOperatorTable table;
   private UnsupportedOperatorCollector unsupportedOperatorCollector;
+  private final UnwrappingExpressionVisitor unwrappingExpressionVisitor;
 
-  public static PreProcessLogicalRel createVisitor(RelDataTypeFactory factory, DrillOperatorTable table) {
-    return new PreProcessLogicalRel(factory, table);
+  public static PreProcessLogicalRel createVisitor(RelDataTypeFactory factory, DrillOperatorTable table, RexBuilder rexBuilder) {
+    return new PreProcessLogicalRel(factory, table, rexBuilder);
   }
 
-  private PreProcessLogicalRel(RelDataTypeFactory factory, DrillOperatorTable table) {
+  private PreProcessLogicalRel(RelDataTypeFactory factory, DrillOperatorTable table, RexBuilder rexBuilder) {
     super();
     this.factory = factory;
     this.table = table;
     this.unsupportedOperatorCollector = new UnsupportedOperatorCollector();
+    this.unwrappingExpressionVisitor = new UnwrappingExpressionVisitor(rexBuilder);
   }
 
   @Override
@@ -82,12 +88,21 @@ public class PreProcessLogicalRel extends RelShuttleImpl {
         throw new UnsupportedOperationException();
       }
     }
-
     return visitChild(aggregate, 0, aggregate.getInput());
   }
 
   @Override
   public RelNode visit(LogicalProject project) {
+    final List<RexNode> projExpr = Lists.newArrayList();
+    for(RexNode rexNode : project.getChildExps()) {
+      projExpr.add(rexNode.accept(unwrappingExpressionVisitor));
+    }
+
+    project =  project.copy(project.getTraitSet(),
+        project.getInput(),
+        projExpr,
+        project.getRowType());
+
     List<RexNode> exprList = new ArrayList<>();
     boolean rewrite = false;
 
@@ -162,6 +177,29 @@ public class PreProcessLogicalRel extends RelShuttleImpl {
   }
 
   @Override
+  public RelNode visit(LogicalFilter filter) {
+    final RexNode condition = filter.getCondition().accept(unwrappingExpressionVisitor);
+    filter = filter.copy(
+        filter.getTraitSet(),
+        filter.getInput(),
+        condition);
+    return visitChild(filter, 0, filter.getInput());
+  }
+
+  @Override
+  public RelNode visit(LogicalJoin join) {
+    final RexNode conditionExpr = join.getCondition().accept(unwrappingExpressionVisitor);
+    join = join.copy(join.getTraitSet(),
+        conditionExpr,
+        join.getLeft(),
+        join.getRight(),
+        join.getJoinType(),
+        join.isSemiJoinDone());
+
+    return visitChildren(join);
+  }
+
+  @Override
   public RelNode visit(LogicalUnion union) {
     for(RelNode child : union.getInputs()) {
       for(RelDataTypeField dataField : child.getRowType().getFieldList()) {
@@ -214,4 +252,29 @@ public class PreProcessLogicalRel extends RelShuttleImpl {
   public void convertException() throws SqlUnsupportedException {
     unsupportedOperatorCollector.convertException();
   }
+
+  private static class UnwrappingExpressionVisitor extends RexShuttle {
+    private final RexBuilder rexBuilder;
+
+    private UnwrappingExpressionVisitor(RexBuilder rexBuilder) {
+      this.rexBuilder = rexBuilder;
+    }
+
+    @Override
+    public RexNode visitCall(final RexCall call) {
+      final List<RexNode> clonedOperands = visitList(call.operands, new boolean[]{true});
+      final SqlOperator sqlOperator;
+      if(call.getOperator() instanceof DrillCalciteSqlWrapper) {
+        sqlOperator = ((DrillCalciteSqlWrapper) call.getOperator()).getOperator();
+      } else {
+        sqlOperator = call.getOperator();
+      }
+
+      return RexUtil.flatten(rexBuilder,
+          rexBuilder.makeCall(
+              call.getType(),
+              sqlOperator,
+              clonedOperands));
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/InsertLocalExchangeVisitor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/InsertLocalExchangeVisitor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/InsertLocalExchangeVisitor.java
index ad64ed8..a2f44f4 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/InsertLocalExchangeVisitor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/InsertLocalExchangeVisitor.java
@@ -58,7 +58,7 @@ public class InsertLocalExchangeVisitor extends BasePrelVisitor<Prel, Void, Runt
     @Override
     public RexNode createCall(String funcName, List<RexNode> inputFields) {
       final DrillSqlOperator op =
-          new DrillSqlOperator(funcName, inputFields.size(), MajorType.getDefaultInstance(), true);
+          new DrillSqlOperator(funcName, inputFields.size(), true);
       return rexBuilder.makeCall(op, inputFields);
     }
   }

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/Checker.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/Checker.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/Checker.java
index c274d2d..c130e14 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/Checker.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/Checker.java
@@ -17,18 +17,51 @@
  */
 package org.apache.drill.exec.planner.sql;
 
+import com.google.common.collect.Maps;
 import org.apache.calcite.sql.SqlCallBinding;
 import org.apache.calcite.sql.SqlOperandCountRange;
 import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.type.SqlOperandCountRanges;
 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
+import org.apache.commons.lang3.tuple.Pair;
+
+import java.util.Map;
 
 class Checker implements SqlOperandTypeChecker {
   private SqlOperandCountRange range;
 
-  public Checker(int size) {
+  public static final Checker ANY_CHECKER = new Checker();
+  private static final Map<Pair<Integer, Integer>, Checker> checkerMap = Maps.newHashMap();
+
+  public static Checker getChecker(int min, int max) {
+    final Pair<Integer, Integer> range = Pair.of(min, max);
+    if(checkerMap.containsKey(range)) {
+      return checkerMap.get(range);
+    }
+
+    final Checker newChecker;
+    if(min == max) {
+      newChecker = new Checker(min);
+    } else {
+      newChecker = new Checker(min, max);
+    }
+
+    checkerMap.put(range, newChecker);
+    return newChecker;
+  }
+
+  private Checker(int size) {
     range = new FixedRange(size);
   }
 
+  private Checker(int min, int max) {
+    range = SqlOperandCountRanges.between(min, max);
+  }
+
+  private Checker() {
+    range = SqlOperandCountRanges.any();
+  }
+
   @Override
   public boolean checkOperandTypes(SqlCallBinding callBinding, boolean throwOnFailure) {
     return true;

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlAggFunctionWrapper.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlAggFunctionWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlAggFunctionWrapper.java
new file mode 100644
index 0000000..3795dd4
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlAggFunctionWrapper.java
@@ -0,0 +1,162 @@
+/**
+ * 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.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlCallBinding;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.SqlOperatorBinding;
+import org.apache.calcite.sql.SqlSyntax;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.sql.type.SqlReturnTypeInference;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
+import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.sql.validate.SqlValidatorScope;
+
+import org.apache.drill.exec.expr.fn.DrillFuncHolder;
+
+import java.util.List;
+
+/**
+ * This class serves as a wrapper class for SqlAggFunction. 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 SqlAggFunction.
+ */
+public class DrillCalciteSqlAggFunctionWrapper extends SqlAggFunction implements DrillCalciteSqlWrapper {
+  private final SqlAggFunction operator;
+
+  @Override
+  public SqlOperator getOperator() {
+    return operator;
+  }
+
+  private DrillCalciteSqlAggFunctionWrapper(
+      SqlAggFunction sqlAggFunction,
+      SqlReturnTypeInference sqlReturnTypeInference) {
+    super(sqlAggFunction.getName(),
+        sqlAggFunction.getSqlIdentifier(),
+        sqlAggFunction.getKind(),
+        sqlReturnTypeInference,
+        sqlAggFunction.getOperandTypeInference(),
+        Checker.ANY_CHECKER,
+        sqlAggFunction.getFunctionType(),
+        sqlAggFunction.requiresOrder(),
+        sqlAggFunction.requiresOver());
+    this.operator = sqlAggFunction;
+  }
+
+  public DrillCalciteSqlAggFunctionWrapper(
+      SqlAggFunction sqlAggFunction,
+      List<DrillFuncHolder> functions) {
+    this(sqlAggFunction,
+        TypeInferenceUtils.getDrillSqlReturnTypeInference(
+            sqlAggFunction.getName(),
+            functions));
+  }
+
+  public DrillCalciteSqlAggFunctionWrapper(
+      final SqlAggFunction sqlAggFunction,
+      final RelDataType relDataType) {
+    this(sqlAggFunction, new SqlReturnTypeInference() {
+      @Override
+      public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
+        return relDataType;
+      }
+    });
+  }
+
+  @Override
+  public boolean validRexOperands(int count, boolean fail) {
+    return true;
+  }
+
+  @Override
+  public String getAllowedSignatures(String opNameToUse) {
+    return operator.getAllowedSignatures(opNameToUse);
+  }
+
+  @Override
+  public boolean isAggregator() {
+    return operator.isAggregator();
+  }
+
+  @Override
+  public boolean allowsFraming() {
+    return operator.allowsFraming();
+  }
+
+  @Override
+  public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    return operator.getMonotonicity(call);
+  }
+
+  @Override
+  public boolean isDeterministic() {
+    return operator.isDeterministic();
+  }
+
+  @Override
+  public boolean isDynamicFunction() {
+    return operator.isDynamicFunction();
+  }
+
+  @Override
+  public boolean requiresDecimalExpansion() {
+    return operator.requiresDecimalExpansion();
+  }
+
+  @Override
+  public boolean argumentMustBeScalar(int ordinal) {
+    return operator.argumentMustBeScalar(ordinal);
+  }
+
+  @Override
+  public boolean checkOperandTypes(
+      SqlCallBinding callBinding,
+      boolean throwOnFailure) {
+    return true;
+  }
+
+  @Override
+  public SqlSyntax getSyntax() {
+    return operator.getSyntax();
+  }
+
+  @Override
+  public List<String> getParamNames() {
+    return operator.getParamNames();
+  }
+
+  @Override
+  public String getSignatureTemplate(final int operandsCount) {
+    return operator.getSignatureTemplate(operandsCount);
+  }
+
+  @Override
+  public RelDataType deriveType(
+      SqlValidator validator,
+      SqlValidatorScope scope,
+      SqlCall call) {
+    return operator.deriveType(validator,
+        scope,
+        call);
+  }
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlFunctionWrapper.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlFunctionWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlFunctionWrapper.java
new file mode 100644
index 0000000..1c61d08
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlFunctionWrapper.java
@@ -0,0 +1,147 @@
+/**
+ * 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.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlCallBinding;
+import org.apache.calcite.sql.SqlFunction;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.SqlOperatorBinding;
+import org.apache.calcite.sql.SqlSyntax;
+import org.apache.calcite.sql.SqlWriter;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
+import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.sql.validate.SqlValidatorScope;
+
+import org.apache.drill.exec.expr.fn.DrillFuncHolder;
+
+import java.util.List;
+
+/**
+ * This class serves as a wrapper class for SqlFunction. 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 SqlFunction.
+ */
+public class DrillCalciteSqlFunctionWrapper extends SqlFunction implements DrillCalciteSqlWrapper  {
+  private final SqlFunction operator;
+
+  public DrillCalciteSqlFunctionWrapper(
+      final SqlFunction wrappedFunction,
+    final List<DrillFuncHolder> functions) {
+    super(wrappedFunction.getName(),
+        wrappedFunction.getSqlIdentifier(),
+        wrappedFunction.getKind(),
+        TypeInferenceUtils.getDrillSqlReturnTypeInference(
+            wrappedFunction.getName(),
+            functions),
+        wrappedFunction.getOperandTypeInference(),
+        Checker.ANY_CHECKER,
+        wrappedFunction.getParamTypes(),
+        wrappedFunction.getFunctionType());
+    this.operator = wrappedFunction;
+  }
+
+  @Override
+  public SqlOperator getOperator() {
+    return operator;
+  }
+
+  @Override
+  public boolean validRexOperands(int count, boolean fail) {
+    return true;
+  }
+
+  @Override
+  public String getAllowedSignatures(String opNameToUse) {
+    return operator.getAllowedSignatures(opNameToUse);
+  }
+
+  @Override
+  public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    return operator.getMonotonicity(call);
+  }
+
+  @Override
+  public boolean isDeterministic() {
+    return operator.isDeterministic();
+  }
+
+  @Override
+  public boolean isDynamicFunction() {
+    return operator.isDynamicFunction();
+  }
+
+  @Override
+  public boolean requiresDecimalExpansion() {
+    return operator.requiresDecimalExpansion();
+  }
+
+  @Override
+  public boolean argumentMustBeScalar(int ordinal) {
+    return operator.argumentMustBeScalar(ordinal);
+  }
+
+  @Override
+  public boolean checkOperandTypes(
+      SqlCallBinding callBinding,
+      boolean throwOnFailure) {
+    return true;
+  }
+
+  @Override
+  public SqlSyntax getSyntax() {
+    return operator.getSyntax();
+  }
+
+  @Override
+  public List<String> getParamNames() {
+    return operator.getParamNames();
+  }
+
+  @Override
+  public String getSignatureTemplate(final int operandsCount) {
+    return operator.getSignatureTemplate(operandsCount);
+  }
+
+  @Override
+  public RelDataType deriveType(
+      SqlValidator validator,
+      SqlValidatorScope scope,
+      SqlCall call) {
+    return operator.deriveType(validator,
+        scope,
+        call);
+  }
+
+  @Override
+  public String toString() {
+    return operator.toString();
+  }
+
+  @Override
+  public void unparse(
+      SqlWriter writer,
+      SqlCall call,
+      int leftPrec,
+      int rightPrec) {
+    operator.unparse(writer, call, leftPrec, rightPrec);
+  }
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlOperatorWrapper.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlOperatorWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlOperatorWrapper.java
new file mode 100644
index 0000000..28c1cec
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlOperatorWrapper.java
@@ -0,0 +1,140 @@
+/**
+ * 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.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlCallBinding;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.SqlOperatorBinding;
+import org.apache.calcite.sql.SqlSyntax;
+import org.apache.calcite.sql.SqlWriter;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
+import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.sql.validate.SqlValidatorScope;
+import org.apache.drill.exec.expr.fn.DrillFuncHolder;
+
+import java.util.List;
+
+/**
+ * This class serves as a wrapper class for SqlOperator. 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.
+ */
+public class DrillCalciteSqlOperatorWrapper extends SqlOperator implements DrillCalciteSqlWrapper {
+  public final SqlOperator operator;
+
+  public DrillCalciteSqlOperatorWrapper(SqlOperator operator, final String rename, final List<DrillFuncHolder> functions) {
+    super(
+        operator.getName(),
+        operator.getKind(),
+        operator.getLeftPrec(),
+        operator.getRightPrec(),
+        TypeInferenceUtils.getDrillSqlReturnTypeInference(
+            rename,
+            functions),
+        operator.getOperandTypeInference(),
+        Checker.ANY_CHECKER);
+    this.operator = operator;
+  }
+
+  @Override
+  public SqlOperator getOperator() {
+    return operator;
+  }
+
+  @Override
+  public SqlSyntax getSyntax() {
+    return operator.getSyntax();
+  }
+
+  @Override
+  public SqlCall createCall(
+      SqlLiteral functionQualifier,
+      SqlParserPos pos,
+      SqlNode... operands) {
+    return operator.createCall(functionQualifier, pos, operands);
+  }
+
+  @Override
+  public SqlNode rewriteCall(SqlValidator validator, SqlCall call) {
+    return operator.rewriteCall(validator, call);
+  }
+
+
+  @Override
+  public boolean checkOperandTypes(
+      SqlCallBinding callBinding,
+      boolean throwOnFailure) {
+    return true;
+  }
+
+  @Override
+  public boolean validRexOperands(int count, boolean fail) {
+    return true;
+  }
+
+  @Override
+  public String getSignatureTemplate(final int operandsCount) {
+    return operator.getSignatureTemplate(operandsCount);
+  }
+
+  @Override
+  public String getAllowedSignatures(String opNameToUse) {
+    return operator.getAllowedSignatures(opNameToUse);
+  }
+
+  @Override
+  public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    return operator.getMonotonicity(call);
+  }
+
+  @Override
+  public boolean isDeterministic() {
+    return operator.isDeterministic();
+  }
+
+  @Override
+  public boolean requiresDecimalExpansion() {
+    return operator.requiresDecimalExpansion();
+  }
+
+  @Override
+  public boolean argumentMustBeScalar(int ordinal) {
+    return operator.argumentMustBeScalar(ordinal);
+  }
+
+  @Override
+  public String toString() {
+    return operator.toString();
+  }
+
+  @Override
+  public void unparse(
+      SqlWriter writer,
+      SqlCall call,
+      int leftPrec,
+      int rightPrec) {
+    operator.unparse(writer, call, leftPrec, rightPrec);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlWrapper.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlWrapper.java
new file mode 100644
index 0000000..8410e67
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillCalciteSqlWrapper.java
@@ -0,0 +1,33 @@
+/**
+ * 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.apache.calcite.sql.SqlOperator;
+/**
+ * This interface is meant for the users of the wrappers, {@link DrillCalciteSqlOperatorWrapper},
+ * {@link DrillCalciteSqlFunctionWrapper} and {@link DrillCalciteSqlAggFunctionWrapper}, to access the wrapped Calcite
+ * {@link SqlOperator} without knowing exactly which wrapper it is.
+ */
+public interface DrillCalciteSqlWrapper {
+  /**
+   * Get the wrapped {@link SqlOperator}
+   *
+   * @return SqlOperator get the wrapped {@link SqlOperator}
+   */
+  SqlOperator getOperator();
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/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
index 4ade513..6b81bf0 100644
--- 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
@@ -19,6 +19,7 @@ package org.apache.drill.exec.planner.sql;
 
 import java.util.HashMap;
 
+import org.apache.calcite.sql.SqlBasicCall;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlAvgAggFunction;
@@ -49,8 +50,19 @@ public class DrillConvertletTable implements SqlRexConvertletTable{
    */
   @Override
   public SqlRexConvertlet get(SqlCall call) {
-
     SqlRexConvertlet convertlet;
+    if(call.getOperator() instanceof DrillCalciteSqlWrapper) {
+      final SqlOperator wrapper = call.getOperator();
+      final SqlOperator wrapped = ((DrillCalciteSqlWrapper) call.getOperator()).getOperator();
+      if ((convertlet = map.get(wrapped)) != null) {
+        return convertlet;
+      }
+
+      ((SqlBasicCall) call).setOperator(wrapped);
+      SqlRexConvertlet sqlRexConvertlet = StandardConvertletTable.INSTANCE.get(call);
+      ((SqlBasicCall) call).setOperator(wrapper);
+      return sqlRexConvertlet;
+    }
 
     if ((convertlet = map.get(call.getOperator())) != null) {
       return convertlet;

http://git-wip-us.apache.org/repos/asf/drill/blob/c0293354/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
index 7bf2584..61e1e07 100644
--- 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
@@ -25,6 +25,7 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlIntervalQualifier;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql2rel.SqlRexContext;
@@ -50,6 +51,8 @@ public class DrillExtractConvertlet implements SqlRexConvertlet {
     final List<SqlNode> operands = call.getOperandList();
     final List<RexNode> exprs = new LinkedList<>();
 
+    String timeUnit = ((SqlIntervalQualifier) operands.get(0)).timeUnitRange.toString();
+
     RelDataTypeFactory typeFactory = cx.getTypeFactory();
 
     //RelDataType nullableReturnType =
@@ -59,7 +62,10 @@ public class DrillExtractConvertlet implements SqlRexConvertlet {
     }
 
     // Determine NULL-able using 2nd argument's Null-able.
-    RelDataType returnType = typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.BIGINT), exprs.get(1).getType().isNullable());
+    RelDataType returnType = typeFactory.createTypeWithNullability(
+        typeFactory.createSqlType(
+            TypeInferenceUtils.getSqlTypeNameForTimeUnit(timeUnit)),
+            exprs.get(1).getType().isNullable());
 
     return rexBuilder.makeCall(returnType, call.getOperator(), exprs);
   }


Mime
View raw message