calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject [3/3] calcite git commit: [CALCITE-941] Named, optional and DEFAULT arguments to function calls
Date Sat, 31 Oct 2015 23:06:12 GMT
[CALCITE-941] Named, optional and DEFAULT arguments to function calls


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

Branch: refs/heads/master
Commit: d012b245e4e040ae94bb3d7045cf4d71af8ac279
Parents: 4c3eb7c
Author: Julian Hyde <jhyde@apache.org>
Authored: Tue Oct 27 22:04:05 2015 -0700
Committer: Julian Hyde <jhyde@apache.org>
Committed: Sat Oct 31 15:09:05 2015 -0700

----------------------------------------------------------------------
 core/src/main/codegen/templates/Parser.jj       |  42 +++++-
 .../calcite/adapter/enumerable/RexImpTable.java |  22 +--
 .../calcite/prepare/CalciteCatalogReader.java   |  12 +-
 .../apache/calcite/runtime/CalciteResource.java |   9 ++
 .../calcite/schema/FunctionParameter.java       |  21 +++
 .../schema/impl/AggregateFunctionImpl.java      |  31 ++--
 .../schema/impl/ReflectiveFunctionBase.java     |  88 +++++++----
 .../calcite/schema/impl/ScalarFunctionImpl.java |   2 +-
 .../org/apache/calcite/sql/SqlAsOperator.java   |  13 +-
 .../org/apache/calcite/sql/SqlCallBinding.java  |  77 ++++++++++
 .../org/apache/calcite/sql/SqlFunction.java     |  57 ++++++-
 .../java/org/apache/calcite/sql/SqlKind.java    |  13 +-
 .../org/apache/calcite/sql/SqlOperator.java     |  13 ++
 .../java/org/apache/calcite/sql/SqlUtil.java    |  76 +++++++---
 .../sql/advise/SqlAdvisorGetHintsFunction.java  |   8 +-
 .../sql/fun/SqlArgumentAssignmentOperator.java  |  52 +++++++
 .../apache/calcite/sql/fun/SqlCastFunction.java |   6 +-
 .../calcite/sql/fun/SqlDefaultOperator.java     |  48 ++++++
 .../apache/calcite/sql/fun/SqlItemOperator.java |   4 +-
 .../apache/calcite/sql/fun/SqlLikeOperator.java |   2 +-
 .../sql/fun/SqlLiteralChainOperator.java        |   3 +-
 .../calcite/sql/fun/SqlMapValueConstructor.java |   2 +-
 .../sql/fun/SqlMultisetMemberOfOperator.java    |   6 +-
 .../sql/fun/SqlMultisetQueryConstructor.java    |   2 +-
 .../sql/fun/SqlMultisetValueConstructor.java    |   2 +-
 .../calcite/sql/fun/SqlOverlapsOperator.java    |  13 +-
 .../calcite/sql/fun/SqlQuarterFunction.java     |   4 +-
 .../calcite/sql/fun/SqlStdOperatorTable.java    |  13 ++
 .../calcite/sql/fun/SqlSubstringFunction.java   |   3 +-
 .../apache/calcite/sql/fun/SqlTrimFunction.java |   7 +-
 .../sql/type/AssignableOperandTypeChecker.java  |  17 ++-
 .../sql/type/CompositeOperandTypeChecker.java   |   9 ++
 .../sql/type/FamilyOperandTypeChecker.java      |  19 ++-
 .../org/apache/calcite/sql/type/InferTypes.java |   2 +-
 .../sql/type/LiteralOperandTypeChecker.java     |   6 +-
 .../sql/type/MultisetOperandTypeChecker.java    |  10 +-
 .../apache/calcite/sql/type/OperandTypes.java   |  38 ++++-
 .../sql/type/SameOperandTypeChecker.java        |   6 +-
 .../sql/type/SetopOperandTypeChecker.java       |  10 +-
 .../calcite/sql/type/SqlOperandCountRanges.java |   5 +-
 .../calcite/sql/type/SqlOperandTypeChecker.java |   3 +
 .../sql/validate/SqlUserDefinedFunction.java    |   7 +
 .../calcite/sql/validate/SqlValidator.java      |   8 +-
 .../calcite/sql/validate/SqlValidatorImpl.java  |  29 ++--
 .../calcite/sql2rel/SqlToRelConverter.java      |   4 +-
 .../org/apache/calcite/util/Compatible.java     |  18 +++
 .../apache/calcite/util/ImmutableIntList.java   |  20 +--
 .../org/apache/calcite/util/ReflectUtil.java    |  63 ++++----
 .../apache/calcite/util/mapping/Mappings.java   |  11 ++
 .../calcite/runtime/CalciteResource.properties  |   3 +
 .../calcite/sql/parser/SqlParserTest.java       |  34 +++++
 .../java/org/apache/calcite/test/JdbcTest.java  | 150 ++++++++++++++++---
 .../java/org/apache/calcite/util/UtilTest.java  |  13 ++
 .../calcite/linq4j/function/Functions.java      |  30 +++-
 .../calcite/linq4j/function/Parameter.java      |  86 +++++++++++
 site/_docs/reference.md                         |  93 ++++++++++++
 56 files changed, 1110 insertions(+), 235 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/codegen/templates/Parser.jj
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj
index 756ed6a..1e27217 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -790,10 +790,8 @@ SqlNodeList ParenthesizedQueryOrCommaList(
 }
 
 /**
- * Parses function parameter lists including DISTINCT keyword recognition
- *
- * <p>This is pretty much the same as ParenthesizedQueryOrCommaList but allows
- * the DISTINCT keyword to follow the left paren and not be followed by a comma.
+ * Parses function parameter lists including DISTINCT keyword recognition,
+ * DEFAULT, and named argument assignment.
  */
 List FunctionParameterList(
     ExprContext exprContext) :
@@ -801,6 +799,7 @@ List FunctionParameterList(
     SqlNode e = null;
     List list = new ArrayList();
     ExprContext firstExprContext = exprContext;
+    SqlIdentifier name = null;
 }
 {
     <LPAREN>
@@ -829,11 +828,26 @@ List FunctionParameterList(
     {
        list.add(e);
     }
-    e = OrderedQueryOrExpr(firstExprContext)
+    [
+        name = SimpleIdentifier() <NAMED_ARGUMENT_ASSIGNMENT>
+    ]
+    (
+        <DEFAULT_KW> {
+            e = SqlStdOperatorTable.DEFAULT.createCall(getPos());
+        }
+    |
+        e = OrderedQueryOrExpr(firstExprContext)
+    )
     {
         if (e != null) {
+            if (name != null) {
+                e = SqlStdOperatorTable.ARGUMENT_ASSIGNMENT.createCall(
+                    name.getParserPosition().plus(e.getParserPosition()),
+                    e, name);
+            }
             list.add(e);
         }
+        name = null;
     }
     (
         <COMMA>
@@ -841,8 +855,23 @@ List FunctionParameterList(
             // a comma-list can't appear where only a query is expected
             checkNonQueryExpression(exprContext);
         }
-        e = Expression(exprContext)
+        [
+            name = SimpleIdentifier() <NAMED_ARGUMENT_ASSIGNMENT>
+        ]
+        (
+            <DEFAULT_KW> {
+                e = SqlStdOperatorTable.DEFAULT.createCall(getPos());
+            }
+        |
+            e = Expression(exprContext)
+        )
         {
+            if (name != null) {
+                e = SqlStdOperatorTable.ARGUMENT_ASSIGNMENT.createCall(
+                    name.getParserPosition().plus(e.getParserPosition()),
+                    e, name);
+                name = null;
+            }
             list.add(e);
         }
     ) *
@@ -5437,6 +5466,7 @@ String CommonNonReservedKeyWord() :
     | < STAR: "*" >
     | < SLASH: "/" >
     | < CONCAT: "||" >
+    | < NAMED_ARGUMENT_ASSIGNMENT: "=>" >
     | < DOUBLE_PERIOD: ".." >
     | < QUOTE: "'" >
     | < DOUBLE_QUOTE: "\"" >

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 6f3de92..07f3f43 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -107,6 +107,7 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_TIMESTAMP;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_USER;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CURRENT_VALUE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DATETIME_PLUS;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DEFAULT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DENSE_RANK;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DIVIDE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DIVIDE_INTEGER;
@@ -293,6 +294,14 @@ public class RexImpTable {
     map.put(ARRAY_VALUE_CONSTRUCTOR, value);
     map.put(ITEM, new ItemImplementor());
 
+    map.put(DEFAULT,
+        new CallImplementor() {
+          public Expression implement(RexToLixTranslator translator,
+              RexCall call, NullAs nullAs) {
+            return Expressions.constant(null);
+          }
+        });
+
     // Sequences
     defineImplementor(CURRENT_VALUE, NullPolicy.STRICT,
         new MethodImplementor(BuiltInMethod.SEQUENCE_CURRENT_VALUE.method),
@@ -822,17 +831,8 @@ public class RexImpTable {
       NullAs nullAs) {
     final List<Expression> translatedOperands =
         translator.translateList(call.getOperands());
-    switch (nullAs) {
-    case NOT_POSSIBLE:
-    case NULL:
-      for (Expression translatedOperand : translatedOperands) {
-        if (Expressions.isConstantNull(translatedOperand)) {
-          return NULL_EXPR;
-        }
-      }
-    }
-    Expression result;
-    result = implementor.implement(translator, call, translatedOperands);
+    Expression result =
+        implementor.implement(translator, call, translatedOperands);
     return nullAs.handle(result);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
index c2a8f7b..9e49d17 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java
@@ -50,6 +50,7 @@ import org.apache.calcite.sql.validate.SqlUserDefinedTableMacro;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.util.Util;
 
+import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
@@ -242,7 +243,7 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
             }));
   }
 
-  private SqlOperator toOp(SqlIdentifier name, Function function) {
+  private SqlOperator toOp(SqlIdentifier name, final Function function) {
     List<RelDataType> argTypes = new ArrayList<>();
     List<SqlTypeFamily> typeFamilies = new ArrayList<>();
     for (FunctionParameter o : function.getParameters()) {
@@ -253,9 +254,16 @@ public class CalciteCatalogReader implements Prepare.CatalogReader {
     }
     final RelDataType returnType;
     if (function instanceof ScalarFunction) {
+      Predicate<Integer> optional =
+          new Predicate<Integer>() {
+            public boolean apply(Integer input) {
+              return function.getParameters().get(input).isOptional();
+            }
+          };
       return new SqlUserDefinedFunction(name,
           ReturnTypes.explicit(Schemas.proto((ScalarFunction) function)),
-          InferTypes.explicit(argTypes), OperandTypes.family(typeFamilies),
+          InferTypes.explicit(argTypes),
+          OperandTypes.family(typeFamilies, optional),
           toSql(argTypes), function);
     } else if (function instanceof AggregateFunction) {
       returnType = ((AggregateFunction) function).getReturnType(typeFactory);

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index 0670948..aa701d9 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -389,6 +389,15 @@ public interface CalciteResource {
   @BaseMessage("DISTINCT/ALL not allowed with {0} function")
   ExInst<SqlValidatorException> functionQuantifierNotAllowed(String a0);
 
+  @BaseMessage("Some but not all arguments are named")
+  ExInst<SqlValidatorException> someButNotAllArgumentsAreNamed();
+
+  @BaseMessage("Duplicate argument name ''{0}''")
+  ExInst<SqlValidatorException> duplicateArgumentName(String name);
+
+  @BaseMessage("DEFAULT is only allowed for optional parameters")
+  ExInst<SqlValidatorException> defaultForOptionalParameter();
+
   @BaseMessage("Not allowed to perform {0} on {1}")
   ExInst<SqlValidatorException> accessNotAllowed(String a0, String a1);
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/schema/FunctionParameter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/FunctionParameter.java b/core/src/main/java/org/apache/calcite/schema/FunctionParameter.java
index 11e50c4..3e95628 100644
--- a/core/src/main/java/org/apache/calcite/schema/FunctionParameter.java
+++ b/core/src/main/java/org/apache/calcite/schema/FunctionParameter.java
@@ -26,6 +26,14 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
  * {@link java.lang.reflect.Parameter} was too confusing.</p>
  */
 public interface FunctionParameter {
+  /** Function to get the name of a parameter. */
+  com.google.common.base.Function<FunctionParameter, String> NAME_FN =
+      new com.google.common.base.Function<FunctionParameter, String>() {
+        public String apply(FunctionParameter p) {
+          return p.getName();
+        }
+      };
+
   /**
    * Zero-based ordinal of this parameter within the member's parameter
    * list.
@@ -49,6 +57,19 @@ public interface FunctionParameter {
    * @return Parameter type.
    */
   RelDataType getType(RelDataTypeFactory typeFactory);
+
+  /**
+   * Returns whether this parameter is optional.
+   *
+   * <p>If true, the value of the parameter can be supplied using the DEFAULT
+   * SQL keyword, or it can be omitted from a function called using argument
+   * assignment, or the function can be called with fewer parameters (if all
+   * parameters after it are optional too).
+   *
+   * <p>If a parameter is optional its default value is NULL. We may in future
+   * allow functions to specify other default values.
+   */
+  boolean isOptional();
 }
 
 // End FunctionParameter.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java b/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java
index 52dc9d5..5c24480 100644
--- a/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java
+++ b/core/src/main/java/org/apache/calcite/schema/impl/AggregateFunctionImpl.java
@@ -23,8 +23,9 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.schema.AggregateFunction;
 import org.apache.calcite.schema.FunctionParameter;
 import org.apache.calcite.schema.ImplementableAggFunction;
-import org.apache.calcite.util.Util;
+import org.apache.calcite.util.ReflectUtil;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.lang.reflect.Method;
@@ -56,6 +57,7 @@ public class AggregateFunctionImpl implements AggregateFunction,
 
   /** Private constructor; use {@link #create}. */
   private AggregateFunctionImpl(Class<?> declaringClass,
+      List<FunctionParameter> params,
       List<Class<?>> valueTypes,
       Class<?> accumulatorType,
       Class<?> resultType,
@@ -64,18 +66,16 @@ public class AggregateFunctionImpl implements AggregateFunction,
       Method mergeMethod,
       Method resultMethod) {
     this.declaringClass = declaringClass;
-    this.isStatic = Modifier.isStatic(initMethod.getModifiers());
     this.valueTypes = ImmutableList.copyOf(valueTypes);
-    this.parameters = ReflectiveFunctionBase.toFunctionParameters(valueTypes);
+    this.parameters = params;
     this.accumulatorType = accumulatorType;
     this.resultType = resultType;
-    this.initMethod = initMethod;
-    this.addMethod = addMethod;
+    this.initMethod = Preconditions.checkNotNull(initMethod);
+    this.addMethod = Preconditions.checkNotNull(addMethod);
     this.mergeMethod = mergeMethod;
     this.resultMethod = resultMethod;
+    this.isStatic = Modifier.isStatic(initMethod.getModifiers());
 
-    assert initMethod != null;
-    assert addMethod != null;
     assert resultMethod != null || accumulatorType == resultType;
   }
 
@@ -100,7 +100,17 @@ public class AggregateFunctionImpl implements AggregateFunction,
       if (addParamTypes.isEmpty() || addParamTypes.get(0) != accumulatorType) {
         throw RESOURCE.firstParameterOfAdd(clazz.getName()).ex();
       }
-      final List<Class<?>> valueTypes = Util.skip(addParamTypes, 1);
+      final ReflectiveFunctionBase.ParameterListBuilder params =
+          ReflectiveFunctionBase.builder();
+      final ImmutableList.Builder<Class<?>> valueTypes =
+          ImmutableList.builder();
+      for (int i = 1; i < addParamTypes.size(); i++) {
+        final Class<?> type = addParamTypes.get(i);
+        final String name = ReflectUtil.getParameterName(addMethod, i);
+        final boolean optional = ReflectUtil.isParameterOptional(addMethod, i);
+        params.add(type, name, optional);
+        valueTypes.add(type);
+      }
 
       // A init()
       // A add(A, V)
@@ -112,8 +122,9 @@ public class AggregateFunctionImpl implements AggregateFunction,
       // TODO: check merge args are (A, A)
       // TODO: check result args are (A)
 
-      return new AggregateFunctionImpl(clazz, valueTypes, accumulatorType,
-          resultType, initMethod, addMethod, mergeMethod, resultMethod);
+      return new AggregateFunctionImpl(clazz, params.build(),
+          valueTypes.build(), accumulatorType, resultType, initMethod,
+          addMethod, mergeMethod, resultMethod);
     }
     return null;
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java b/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java
index 681b69b..ab0daf5 100644
--- a/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java
+++ b/core/src/main/java/org/apache/calcite/schema/impl/ReflectiveFunctionBase.java
@@ -20,13 +20,14 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.schema.Function;
 import org.apache.calcite.schema.FunctionParameter;
+import org.apache.calcite.util.ReflectUtil;
 
 import com.google.common.collect.ImmutableList;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -46,7 +47,7 @@ public abstract class ReflectiveFunctionBase implements Function {
    */
   public ReflectiveFunctionBase(Method method) {
     this.method = method;
-    this.parameters = toFunctionParameters(method.getParameterTypes());
+    this.parameters = builder().addMethodParameters(method).build();
   }
 
   /**
@@ -58,37 +59,6 @@ public abstract class ReflectiveFunctionBase implements Function {
     return parameters;
   }
 
-
-  public static ImmutableList<FunctionParameter> toFunctionParameters(
-      Class... types) {
-    return toFunctionParameters(Arrays.asList(types));
-  }
-
-  public static ImmutableList<FunctionParameter> toFunctionParameters(
-      Iterable<? extends Class> types) {
-    final ImmutableList.Builder<FunctionParameter> res =
-        ImmutableList.builder();
-    int i = 0;
-    for (final Class type : types) {
-      final int ordinal = i;
-      res.add(new FunctionParameter() {
-        public int getOrdinal() {
-          return ordinal;
-        }
-
-        public String getName() {
-          return "arg"  + ordinal;
-        }
-
-        public RelDataType getType(RelDataTypeFactory typeFactory) {
-          return typeFactory.createJavaType(type);
-        }
-      });
-      i++;
-    }
-    return res.build();
-  }
-
   /**
    * Verifies if given class has public constructor with zero arguments.
    * @param clazz class to verify
@@ -118,6 +88,58 @@ public abstract class ReflectiveFunctionBase implements Function {
     }
     return null;
   }
+
+  /** Creates a ParameterListBuilder. */
+  public static ParameterListBuilder builder() {
+    return new ParameterListBuilder();
+  }
+
+  /** Helps build lists of
+   * {@link org.apache.calcite.schema.FunctionParameter}. */
+  public static class ParameterListBuilder {
+    final List<FunctionParameter> builder = new ArrayList<>();
+
+    public ImmutableList<FunctionParameter> build() {
+      return ImmutableList.copyOf(builder);
+    }
+
+    public ParameterListBuilder add(final Class<?> type, final String name) {
+      return add(type, name, false);
+    }
+
+    public ParameterListBuilder add(final Class<?> type, final String name,
+        final boolean optional) {
+      final int ordinal = builder.size();
+      builder.add(
+          new FunctionParameter() {
+            public int getOrdinal() {
+              return ordinal;
+            }
+
+            public String getName() {
+              return name;
+            }
+
+            public RelDataType getType(RelDataTypeFactory typeFactory) {
+              return typeFactory.createJavaType(type);
+            }
+
+            public boolean isOptional() {
+              return optional;
+            }
+          });
+      return this;
+    }
+
+    public ParameterListBuilder addMethodParameters(Method method) {
+      final Class<?>[] types = method.getParameterTypes();
+      for (int i = 0; i < types.length; i++) {
+        add(types[i], ReflectUtil.getParameterName(method, i),
+            ReflectUtil.isParameterOptional(method, i));
+      }
+      return this;
+    }
+  }
 }
 
 // End ReflectiveFunctionBase.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/schema/impl/ScalarFunctionImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/impl/ScalarFunctionImpl.java b/core/src/main/java/org/apache/calcite/schema/impl/ScalarFunctionImpl.java
index c34076e..18f398a 100644
--- a/core/src/main/java/org/apache/calcite/schema/impl/ScalarFunctionImpl.java
+++ b/core/src/main/java/org/apache/calcite/schema/impl/ScalarFunctionImpl.java
@@ -113,7 +113,7 @@ public class ScalarFunctionImpl extends ReflectiveFunctionBase implements
 
   private static CallImplementor createImplementor(final Method method) {
     return RexImpTable.createImplementor(
-        new ReflectiveCallNotNullImplementor(method), NullPolicy.ANY, false);
+        new ReflectiveCallNotNullImplementor(method), NullPolicy.NONE, false);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
index 6f4aaf3..4d9ea95 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
@@ -20,6 +20,9 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.sql.type.InferTypes;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
+import org.apache.calcite.sql.type.SqlOperandTypeChecker;
+import org.apache.calcite.sql.type.SqlOperandTypeInference;
+import org.apache.calcite.sql.type.SqlReturnTypeInference;
 import org.apache.calcite.sql.util.SqlBasicVisitor;
 import org.apache.calcite.sql.util.SqlVisitor;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
@@ -41,7 +44,7 @@ public class SqlAsOperator extends SqlSpecialOperator {
    * Creates an AS operator.
    */
   public SqlAsOperator() {
-    super(
+    this(
         "AS",
         SqlKind.AS,
         20,
@@ -51,6 +54,14 @@ public class SqlAsOperator extends SqlSpecialOperator {
         OperandTypes.ANY_ANY);
   }
 
+  protected SqlAsOperator(String name, SqlKind kind, int prec,
+      boolean leftAssoc, SqlReturnTypeInference returnTypeInference,
+      SqlOperandTypeInference operandTypeInference,
+      SqlOperandTypeChecker operandTypeChecker) {
+    super(name, kind, prec, leftAssoc, returnTypeInference,
+        operandTypeInference, operandTypeChecker);
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   public void unparse(

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
index aaa8c96..36d2195 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
@@ -20,6 +20,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.runtime.CalciteException;
 import org.apache.calcite.runtime.Resources;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.validate.SelectScope;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
@@ -30,6 +31,9 @@ import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Util;
 
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+
 import java.math.BigDecimal;
 import java.util.List;
 
@@ -40,6 +44,8 @@ import static org.apache.calcite.util.Static.RESOURCE;
  * analyzing to the operands of a {@link SqlCall} with a {@link SqlValidator}.
  */
 public class SqlCallBinding extends SqlOperatorBinding {
+  private static final SqlCall DEFAULT_CALL =
+      SqlStdOperatorTable.DEFAULT.createCall(SqlParserPos.ZERO);
   //~ Instance fields --------------------------------------------------------
 
   private final SqlValidator validator;
@@ -112,6 +118,77 @@ public class SqlCallBinding extends SqlOperatorBinding {
     return call;
   }
 
+  /** Returns the operands to a call permuted into the same order as the
+   * formal parameters of the function. */
+  public List<SqlNode> operands() {
+    if (hasAssignment()) {
+      return permutedOperands(call);
+    } else {
+      final List<SqlNode> operandList = call.getOperandList();
+      if (call.getOperator() instanceof SqlFunction) {
+        final List<RelDataType> paramTypes =
+            ((SqlFunction) call.getOperator()).getParamTypes();
+        if (paramTypes != null && operandList.size() < paramTypes.size()) {
+          final List<SqlNode> list = Lists.newArrayList(operandList);
+          while (list.size() < paramTypes.size()) {
+            list.add(DEFAULT_CALL);
+          }
+          return list;
+        }
+      }
+      return operandList;
+    }
+  }
+
+  /** Returns whether arguments have name assignment. */
+  private boolean hasAssignment() {
+    for (SqlNode operand : call.getOperandList()) {
+      if (operand != null
+          && operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /** Returns the operands to a call permuted into the same order as the
+   * formal parameters of the function. */
+  public List<SqlNode> permutedOperands(final SqlCall call) {
+    final SqlFunction operator = (SqlFunction) call.getOperator();
+    return Lists.transform(operator.getParamNames(),
+        new Function<String, SqlNode>() {
+          public SqlNode apply(String paramName) {
+            for (SqlNode operand2 : call.getOperandList()) {
+              final SqlCall call2 = (SqlCall) operand2;
+              assert operand2.getKind() == SqlKind.ARGUMENT_ASSIGNMENT;
+              final SqlIdentifier id = call2.operand(1);
+              if (id.getSimple().equals(paramName)) {
+                return call2.operand(0);
+              }
+            }
+            return DEFAULT_CALL;
+          }
+        });
+  }
+
+  /**
+   * Returns a particular operand.
+   */
+  public SqlNode operand(int i) {
+    return operands().get(i);
+  }
+
+  /** Returns a call that is equivalent except that arguments have been
+   * permuted into the logical order. Any arguments whose default value is being
+   * used are null. */
+  public SqlCall permutedCall() {
+    final List<SqlNode> operandList = operands();
+    if (operandList.equals(call.getOperandList())) {
+      return call;
+    }
+    return call.getOperator().createCall(call.pos, operandList);
+  }
+
   public SqlMonotonicity getOperandMonotonicity(int ordinal) {
     return call.getOperandList().get(ordinal).getMonotonicity(scope);
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
index 6e5d99a..dc63209 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.sql;
 
+import org.apache.calcite.linq4j.function.Function1;
+import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.parser.SqlParserPos;
@@ -38,6 +40,14 @@ import static org.apache.calcite.util.Static.RESOURCE;
  * function-call syntax.
  */
 public class SqlFunction extends SqlOperator {
+  /** Function that generates "arg{n}" for the {@code n}th argument name. */
+  private static final Function1<Integer, String> ARG_FN =
+      new Function1<Integer, String>() {
+        public String apply(Integer a0) {
+          return "arg" + a0;
+        }
+      };
+
   //~ Instance fields --------------------------------------------------------
 
   private final SqlFunctionCategory category;
@@ -152,6 +162,15 @@ public class SqlFunction extends SqlOperator {
     return paramTypes;
   }
 
+  /**
+   * Returns a list of parameter names.
+   *
+   * <p>The default implementation returns {@code [arg0, arg1, ..., argN]}.
+   */
+  public List<String> getParamNames() {
+    return Functions.generate(paramTypes.size(), ARG_FN);
+  }
+
   public void unparse(
       SqlWriter writer,
       SqlCall call,
@@ -216,7 +235,6 @@ public class SqlFunction extends SqlOperator {
       SqlValidatorScope scope,
       SqlCall call,
       boolean convertRowArgToColumnList) {
-    final List<SqlNode> operands = call.getOperandList();
 
     // Scope for operands. Usually the same as 'scope'.
     final SqlValidatorScope operandScope = scope.getOperandScope(call);
@@ -224,11 +242,38 @@ public class SqlFunction extends SqlOperator {
     // Indicate to the validator that we're validating a new function call
     validator.pushFunctionCall();
 
+    // If any arguments are named, construct a map.
+    final ImmutableList.Builder<String> nameBuilder = ImmutableList.builder();
+    final ImmutableList.Builder<SqlNode> argBuilder = ImmutableList.builder();
+    for (SqlNode operand : call.getOperandList()) {
+      if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
+        final List<SqlNode> operandList = ((SqlCall) operand).getOperandList();
+        nameBuilder.add(((SqlIdentifier) operandList.get(1)).getSimple());
+        argBuilder.add(operandList.get(0));
+      }
+    }
+    ImmutableList<String> argNames = nameBuilder.build();
+    final List<SqlNode> args;
+    if (argNames.isEmpty()) {
+      args = call.getOperandList();
+      argNames = null;
+    } else {
+      if (argNames.size() < call.getOperandList().size()) {
+        throw validator.newValidationError(call,
+            RESOURCE.someButNotAllArgumentsAreNamed());
+      }
+      int duplicate = Util.firstDuplicate(argNames);
+      if (duplicate >= 0) {
+        throw validator.newValidationError(call,
+            RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
+      }
+      args = argBuilder.build();
+    }
     try {
       final ImmutableList.Builder<RelDataType> argTypeBuilder =
           ImmutableList.builder();
       boolean containsRowArg = false;
-      for (SqlNode operand : operands) {
+      for (SqlNode operand : args) {
         RelDataType nodeType;
 
         // for row arguments that should be converted to ColumnList
@@ -252,6 +297,7 @@ public class SqlFunction extends SqlOperator {
               validator.getOperatorTable(),
               getNameAsId(),
               argTypes,
+              argNames,
               getFunctionType());
 
       // if we have a match on function name and parameter count, but
@@ -268,14 +314,14 @@ public class SqlFunction extends SqlOperator {
                 getFunctionType())) {
           // remove the already validated node types corresponding to
           // row arguments before re-validating
-          for (SqlNode operand : operands) {
+          for (SqlNode operand : args) {
             if (operand.getKind() == SqlKind.ROW) {
               validator.removeValidatedNodeType(operand);
             }
           }
           return deriveType(validator, scope, call, false);
         } else if (function != null) {
-          validator.validateColumnListParams(function, argTypes, operands);
+          validator.validateColumnListParams(function, argTypes, args);
         }
       }
 
@@ -284,7 +330,8 @@ public class SqlFunction extends SqlOperator {
             argTypes);
       }
       if (function == null) {
-        throw validator.handleUnresolvedFunction(call, this, argTypes);
+        throw validator.handleUnresolvedFunction(call, this, argTypes,
+            argNames);
       }
 
       // REVIEW jvs 25-Mar-2005:  This is, in a sense, expanding

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/SqlKind.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
index fa821f8..5a8a2fa 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -182,6 +182,16 @@ public enum SqlKind {
   AS,
 
   /**
+   * ARGUMENT_ASSIGNMENT operator, {@code =>}
+   */
+  ARGUMENT_ASSIGNMENT,
+
+  /**
+   * DEFAULT operator
+   */
+  DEFAULT,
+
+  /**
    * OVER operator
    */
   OVER,
@@ -710,7 +720,8 @@ public enum SqlKind {
   public static final Set<SqlKind> EXPRESSION =
       EnumSet.complementOf(
           EnumSet.of(
-              AS, DESCENDING, CUBE, ROLLUP, GROUPING_SETS, EXTEND,
+              AS, ARGUMENT_ASSIGNMENT, DEFAULT,
+              DESCENDING, CUBE, ROLLUP, GROUPING_SETS, EXTEND,
               SELECT, JOIN, OTHER_FUNCTION, CAST, TRIM, FLOOR, CEIL,
               LITERAL_CHAIN, JDBC_FN, PRECEDING, FOLLOWING, ORDER_BY,
               NULLS_FIRST, NULLS_LAST, COLLECTION_TABLE, TABLESAMPLE,

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
index ee35b09..df165ca 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.sql;
 
+import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.parser.SqlParserPos;
@@ -547,6 +548,18 @@ public abstract class SqlOperator {
       throw Util.needToImplement(this);
     }
 
+    if (kind != SqlKind.ARGUMENT_ASSIGNMENT) {
+      for (Ord<SqlNode> operand : Ord.zip(callBinding.operands())) {
+        if (operand.e != null
+            && operand.e.getKind() == SqlKind.DEFAULT
+            && !operandTypeChecker.isOptional(operand.i)) {
+          throw callBinding.getValidator().newValidationError(
+              callBinding.getCall(),
+              RESOURCE.defaultForOptionalParameter());
+        }
+      }
+    }
+
     return operandTypeChecker.checkOperandTypes(
         callBinding,
         throwOnFailure);

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
index 405b385..66fb911 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
@@ -16,6 +16,9 @@
  */
 package org.apache.calcite.sql;
 
+import org.apache.calcite.linq4j.Ord;
+import org.apache.calcite.linq4j.function.Function1;
+import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypePrecedenceList;
@@ -43,8 +46,10 @@ import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import static org.apache.calcite.util.Static.RESOURCE;
 
@@ -314,21 +319,21 @@ public abstract class SqlUtil {
    * @param opTab    operator table to search
    * @param funcName name of function being invoked
    * @param argTypes argument types
+   * @param argNames argument names, or null if call by position
    * @param category whether a function or a procedure. (If a procedure is
    *                 being invoked, the overload rules are simpler.)
    * @return matching routine, or null if none found
    * @sql.99 Part 2 Section 10.4
    */
-  public static SqlFunction lookupRoutine(
-      SqlOperatorTable opTab,
-      SqlIdentifier funcName,
-      List<RelDataType> argTypes,
-      SqlFunctionCategory category) {
+  public static SqlFunction lookupRoutine(SqlOperatorTable opTab,
+      SqlIdentifier funcName, List<RelDataType> argTypes,
+      List<String> argNames, SqlFunctionCategory category) {
     List<SqlFunction> list =
         lookupSubjectRoutines(
             opTab,
             funcName,
             argTypes,
+            argNames,
             category);
     if (list.isEmpty()) {
       return null;
@@ -344,15 +349,14 @@ public abstract class SqlUtil {
    * @param opTab    operator table to search
    * @param funcName name of function being invoked
    * @param argTypes argument types
+   * @param argNames argument names, or null if call by position
    * @param category category of routine to look up
    * @return list of matching routines
    * @sql.99 Part 2 Section 10.4
    */
-  public static List<SqlFunction> lookupSubjectRoutines(
-      SqlOperatorTable opTab,
-      SqlIdentifier funcName,
-      List<RelDataType> argTypes,
-      SqlFunctionCategory category) {
+  public static List<SqlFunction> lookupSubjectRoutines(SqlOperatorTable opTab,
+      SqlIdentifier funcName, List<RelDataType> argTypes,
+      List<String> argNames, SqlFunctionCategory category) {
     // start with all routines matching by name
     List<SqlFunction> routines =
         lookupSubjectRoutinesByName(opTab, funcName, category);
@@ -369,7 +373,7 @@ public abstract class SqlUtil {
 
     // second pass:  eliminate routines which don't accept the given
     // argument types
-    filterRoutinesByParameterType(routines, argTypes);
+    filterRoutinesByParameterType(routines, argTypes, argNames);
 
     // see if we can stop now; this is necessary for the case
     // of builtin functions where we don't have param type info
@@ -444,10 +448,10 @@ public abstract class SqlUtil {
   /**
    * @sql.99 Part 2 Section 10.4 Syntax Rule 6.b.iii.2.B
    */
-  private static void filterRoutinesByParameterType(
-      List<SqlFunction> routines,
-      List<RelDataType> argTypes) {
+  private static void filterRoutinesByParameterType(List<SqlFunction> routines,
+      final List<RelDataType> argTypes, List<String> argNames) {
     Iterator<SqlFunction> iter = routines.iterator();
+  loop:
     while (iter.hasNext()) {
       SqlFunction function = iter.next();
       List<RelDataType> paramTypes = function.getParamTypes();
@@ -455,19 +459,45 @@ public abstract class SqlUtil {
         // no parameter information for builtins; keep for now
         continue;
       }
-      assert paramTypes.size() == argTypes.size();
-      boolean keep = true;
-      for (Pair<RelDataType, RelDataType> p : Pair.zip(paramTypes, argTypes)) {
+      final List<RelDataType> permutedArgTypes;
+      if (argNames != null) {
+        // Arguments passed by name. Make sure that the function has parameters
+        // of all of these names.
+        final Map<Integer, Integer> map = new HashMap<>();
+        for (Ord<String> argName : Ord.zip(argNames)) {
+          final int i = function.getParamNames().indexOf(argName.e);
+          if (i < 0) {
+            iter.remove();
+            continue loop;
+          }
+          map.put(i, argName.i);
+        }
+        permutedArgTypes = Functions.generate(paramTypes.size(),
+            new Function1<Integer, RelDataType>() {
+              public RelDataType apply(Integer a0) {
+                if (map.containsKey(a0)) {
+                  return argTypes.get(map.get(a0));
+                } else {
+                  return null;
+                }
+              }
+            });
+      } else {
+        permutedArgTypes = Lists.newArrayList(argTypes);
+        while (permutedArgTypes.size() < argTypes.size()) {
+          paramTypes.add(null);
+        }
+      }
+      for (Pair<RelDataType, RelDataType> p
+          : Pair.zip(paramTypes, permutedArgTypes)) {
         final RelDataType argType = p.right;
         final RelDataType paramType = p.left;
-        if (!SqlTypeUtil.canAssignFrom(paramType, argType)) {
-          keep = false;
-          break;
+        if (argType != null
+            && !SqlTypeUtil.canAssignFrom(paramType, argType)) {
+          iter.remove();
+          continue loop;
         }
       }
-      if (!keep) {
-        iter.remove();
-      }
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorGetHintsFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorGetHintsFunction.java b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorGetHintsFunction.java
index 8e27d5d..ba0cef7 100644
--- a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorGetHintsFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisorGetHintsFunction.java
@@ -72,7 +72,10 @@ public class SqlAdvisorGetHintsFunction
         }, NullPolicy.ANY, false);
 
   private static final List<FunctionParameter> PARAMETERS =
-    ReflectiveFunctionBase.toFunctionParameters(String.class, int.class);
+      ReflectiveFunctionBase.builder()
+          .add(String.class, "sql")
+          .add(int.class, "pos")
+          .build();
 
   public CallImplementor getImplementor() {
     return IMPLEMENTOR;
@@ -107,8 +110,7 @@ public class SqlAdvisorGetHintsFunction
     final String[] replaced = {null};
     final List<SqlMoniker> hints = advisor.getCompletionHints(sql,
       pos, replaced);
-    final List<SqlAdvisorHint> res =
-        new ArrayList<SqlAdvisorHint>(hints.size() + 1);
+    final List<SqlAdvisorHint> res = new ArrayList<>(hints.size() + 1);
     res.add(new SqlAdvisorHint(replaced[0], null, "MATCH"));
     for (SqlMoniker hint : hints) {
       res.add(new SqlAdvisorHint(hint));

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlArgumentAssignmentOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlArgumentAssignmentOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlArgumentAssignmentOperator.java
new file mode 100644
index 0000000..188d4aa
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlArgumentAssignmentOperator.java
@@ -0,0 +1,52 @@
+/*
+ * 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.calcite.sql.fun;
+
+import org.apache.calcite.sql.SqlAsOperator;
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlWriter;
+import org.apache.calcite.sql.type.InferTypes;
+import org.apache.calcite.sql.type.OperandTypes;
+import org.apache.calcite.sql.type.ReturnTypes;
+
+/**
+ * Operator that assigns an argument to a function call to a particular named
+ * parameter.
+ *
+ * <p>Not an expression; just a holder to represent syntax until the validator
+ * has chance to resolve arguments.
+ *
+ * <p>Sub-class of {@link SqlAsOperator} ("AS") out of convenience; to be
+ * consistent with AS, we reverse the arguments.
+ */
+class SqlArgumentAssignmentOperator extends SqlAsOperator {
+  public SqlArgumentAssignmentOperator() {
+    super("=>", SqlKind.ARGUMENT_ASSIGNMENT, 20, true, ReturnTypes.ARG0,
+        InferTypes.RETURN_TYPE, OperandTypes.ANY_ANY);
+  }
+
+  @Override public void unparse(SqlWriter writer, SqlCall call, int leftPrec,
+      int rightPrec) {
+    // Arguments are held in reverse order to be consistent with base class (AS).
+    call.operand(1).unparse(writer, leftPrec, getLeftPrec());
+    writer.keyword(getName());
+    call.operand(0).unparse(writer, getRightPrec(), rightPrec);
+  }
+}
+
+// End SqlArgumentAssignmentOperator.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
index f4e933a..c7ded0b 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
@@ -113,7 +113,7 @@ public class SqlCastFunction extends SqlFunction {
             firstType.isNullable());
     if (opBinding instanceof SqlCallBinding) {
       SqlCallBinding callBinding = (SqlCallBinding) opBinding;
-      SqlNode operand0 = callBinding.getCall().operand(0);
+      SqlNode operand0 = callBinding.operand(0);
 
       // dynamic parameters and null constants need their types assigned
       // to them using the type they are casted to.
@@ -145,8 +145,8 @@ public class SqlCastFunction extends SqlFunction {
   public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
-    final SqlNode left = callBinding.getCall().operand(0);
-    final SqlNode right = callBinding.getCall().operand(1);
+    final SqlNode left = callBinding.operand(0);
+    final SqlNode right = callBinding.operand(1);
     if (SqlUtil.isNullLiteral(left, false)
         || left instanceof SqlDynamicParam) {
       return true;

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlDefaultOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlDefaultOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlDefaultOperator.java
new file mode 100644
index 0000000..5e71a41
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlDefaultOperator.java
@@ -0,0 +1,48 @@
+/*
+ * 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.calcite.sql.fun;
+
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlSpecialOperator;
+import org.apache.calcite.sql.SqlWriter;
+import org.apache.calcite.sql.type.InferTypes;
+import org.apache.calcite.sql.type.OperandTypes;
+import org.apache.calcite.sql.type.ReturnTypes;
+import org.apache.calcite.sql.type.SqlTypeName;
+
+/**
+ * Operator that indicates that an argument to a function call is to take its
+ * default value.
+ *
+ * <p>Not an expression; just a holder to represent syntax until the validator
+ * has chance to resolve arguments.
+ */
+class SqlDefaultOperator extends SqlSpecialOperator {
+  public SqlDefaultOperator() {
+    super("DEFAULT", SqlKind.DEFAULT, 100, true,
+        ReturnTypes.explicit(SqlTypeName.ANY), InferTypes.RETURN_TYPE,
+        OperandTypes.NILADIC);
+  }
+
+  @Override public void unparse(SqlWriter writer, SqlCall call, int leftPrec,
+      int rightPrec) {
+    writer.sep(getName());
+  }
+}
+
+// End SqlDefaultOperator.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlItemOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlItemOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlItemOperator.java
index aafa153..f73ce4a 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlItemOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlItemOperator.java
@@ -84,8 +84,8 @@ class SqlItemOperator extends SqlSpecialOperator {
   @Override public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
-    final SqlNode left = callBinding.getCall().operand(0);
-    final SqlNode right = callBinding.getCall().operand(1);
+    final SqlNode left = callBinding.operand(0);
+    final SqlNode right = callBinding.operand(1);
     if (!ARRAY_OR_MAP.checkSingleOperandType(callBinding, left, 0,
         throwOnFailure)) {
       return false;

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlLikeOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlLikeOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlLikeOperator.java
index 7a5cdd3..1de1407 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLikeOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLikeOperator.java
@@ -127,7 +127,7 @@ public class SqlLikeOperator extends SqlSpecialOperator {
 
     return SqlTypeUtil.isCharTypeComparable(
         callBinding,
-        callBinding.getCall().getOperandList(),
+        callBinding.operands(),
         throwOnFailure);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
index c0e891c..80d2bc3 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java
@@ -79,9 +79,8 @@ public class SqlLiteralChainOperator extends SqlSpecialOperator {
     if (callBinding.getOperandCount() < 2) {
       return true; // nothing to compare
     }
-    final List<SqlNode> operandList = callBinding.getCall().getOperandList();
     RelDataType firstType = null;
-    for (Ord<SqlNode> operand : Ord.zip(operandList)) {
+    for (Ord<SqlNode> operand : Ord.zip(callBinding.operands())) {
       RelDataType type =
           callBinding.getValidator().deriveType(
               callBinding.getScope(),

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
index 2e86321..2945038 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java
@@ -61,7 +61,7 @@ public class SqlMapValueConstructor extends SqlMultisetValueConstructor {
         SqlTypeUtil.deriveAndCollectTypes(
             callBinding.getValidator(),
             callBinding.getScope(),
-            callBinding.getCall().getOperandList());
+            callBinding.operands());
     if (argTypes.size() == 0) {
       throw callBinding.newValidationError(RESOURCE.mapRequiresTwoOrMoreArgs());
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetMemberOfOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetMemberOfOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetMemberOfOperator.java
index 71b5880..56b65ed 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetMemberOfOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetMemberOfOperator.java
@@ -56,7 +56,7 @@ public class SqlMultisetMemberOfOperator extends SqlBinaryOperator {
       boolean throwOnFailure) {
     if (!OperandTypes.MULTISET.checkSingleOperandType(
         callBinding,
-        callBinding.getCall().operand(1),
+        callBinding.operand(1),
         0,
         throwOnFailure)) {
       return false;
@@ -65,12 +65,12 @@ public class SqlMultisetMemberOfOperator extends SqlBinaryOperator {
     MultisetSqlType mt =
         (MultisetSqlType) callBinding.getValidator().deriveType(
             callBinding.getScope(),
-            callBinding.getCall().operand(1));
+            callBinding.operand(1));
 
     RelDataType t0 =
         callBinding.getValidator().deriveType(
             callBinding.getScope(),
-            callBinding.getCall().operand(0));
+            callBinding.operand(0));
     RelDataType t1 = mt.getComponentType();
 
     if (t0.getFamily() != t1.getFamily()) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java
index 9e50507..76b09fe 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java
@@ -89,7 +89,7 @@ public class SqlMultisetQueryConstructor extends SqlSpecialOperator {
         SqlTypeUtil.deriveAndCollectTypes(
             callBinding.getValidator(),
             callBinding.getScope(),
-            callBinding.getCall().getOperandList());
+            callBinding.operands());
     final RelDataType componentType =
         getComponentType(
             callBinding.getTypeFactory(),

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
index c407f58..a517391 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java
@@ -88,7 +88,7 @@ public class SqlMultisetValueConstructor extends SqlSpecialOperator {
         SqlTypeUtil.deriveAndCollectTypes(
             callBinding.getValidator(),
             callBinding.getScope(),
-            callBinding.getCall().getOperandList());
+            callBinding.operands());
     if (argTypes.size() == 0) {
       throw callBinding.newValidationError(RESOURCE.requireAtLeastOneArg());
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlOverlapsOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlOverlapsOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlOverlapsOperator.java
index e3643c1..941a06e 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlOverlapsOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlOverlapsOperator.java
@@ -111,28 +111,27 @@ public class SqlOverlapsOperator extends SqlSpecialOperator {
   public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
-    SqlCall call = callBinding.getCall();
     SqlValidator validator = callBinding.getValidator();
     SqlValidatorScope scope = callBinding.getScope();
     if (!OperandTypes.DATETIME.checkSingleOperandType(
         callBinding,
-        call.operand(0),
+        callBinding.operand(0),
         0,
         throwOnFailure)) {
       return false;
     }
     if (!OperandTypes.DATETIME.checkSingleOperandType(
         callBinding,
-        call.operand(2),
+        callBinding.operand(2),
         0,
         throwOnFailure)) {
       return false;
     }
 
-    RelDataType t0 = validator.deriveType(scope, call.operand(0));
-    RelDataType t1 = validator.deriveType(scope, call.operand(1));
-    RelDataType t2 = validator.deriveType(scope, call.operand(2));
-    RelDataType t3 = validator.deriveType(scope, call.operand(3));
+    RelDataType t0 = validator.deriveType(scope, callBinding.operand(0));
+    RelDataType t1 = validator.deriveType(scope, callBinding.operand(1));
+    RelDataType t2 = validator.deriveType(scope, callBinding.operand(2));
+    RelDataType t3 = validator.deriveType(scope, callBinding.operand(3));
 
     // t0 must be comparable with t2
     if (!SqlTypeUtil.sameNamedType(t0, t2)) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlQuarterFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlQuarterFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlQuarterFunction.java
index abc2c9f..b76c1dd 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlQuarterFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlQuarterFunction.java
@@ -16,7 +16,6 @@
  */
 package org.apache.calcite.sql.fun;
 
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCallBinding;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
@@ -56,9 +55,8 @@ public class SqlQuarterFunction extends SqlFunction {
 
   public boolean checkOperandTypes(SqlCallBinding callBinding,
       boolean throwOnFailure) {
-    SqlCall call = callBinding.getCall();
     return OperandTypes.DATETIME.checkSingleOperandType(callBinding,
-        call.operand(0), 0, throwOnFailure);
+        callBinding.operand(0), 0, throwOnFailure);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 8aff020..fc524c6 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -150,6 +150,19 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
    */
   public static final SqlAsOperator AS = new SqlAsOperator();
 
+  /**
+   * <code>ARGUMENT_ASSIGNMENT</code> operator (<code>=&lt;</code>)
+   * assigns an argument to a function call to a particular named parameter.
+   */
+  public static final SqlSpecialOperator ARGUMENT_ASSIGNMENT =
+      new SqlArgumentAssignmentOperator();
+
+  /**
+   * <code>DEFAULT</code> operator indicates that an argument to a function call
+   * is to take its default value..
+   */
+  public static final SqlSpecialOperator DEFAULT = new SqlDefaultOperator();
+
   /** <code>FILTER</code> operator filters which rows are included in an
    *  aggregate function. */
   public static final SqlFilterOperator FILTER = new SqlFilterOperator();

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
index 73eda82..f669a8a 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
@@ -95,11 +95,10 @@ public class SqlSubstringFunction extends SqlFunction {
   public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
-    SqlCall call = callBinding.getCall();
     SqlValidator validator = callBinding.getValidator();
     SqlValidatorScope scope = callBinding.getScope();
 
-    final List<SqlNode> operands = call.getOperandList();
+    final List<SqlNode> operands = callBinding.operands();
     int n = operands.size();
     assert (3 == n) || (2 == n);
     if (!OperandTypes.STRING.checkSingleOperandType(

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/fun/SqlTrimFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlTrimFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlTrimFunction.java
index f798e3e..0ba461b 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlTrimFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlTrimFunction.java
@@ -158,10 +158,9 @@ public class SqlTrimFunction extends SqlFunction {
     if (!super.checkOperandTypes(callBinding, throwOnFailure)) {
       return false;
     }
-    final List<SqlNode> operands = callBinding.getCall().getOperandList();
-    return SqlTypeUtil.isCharTypeComparable(
-        callBinding,
-        ImmutableList.of(operands.get(1), operands.get(2)), throwOnFailure);
+    return SqlTypeUtil.isCharTypeComparable(callBinding,
+        ImmutableList.of(callBinding.operand(1), callBinding.operand(2)),
+        throwOnFailure);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/AssignableOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/AssignableOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/AssignableOperandTypeChecker.java
index 7ee0a64..6cd3565 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/AssignableOperandTypeChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/AssignableOperandTypeChecker.java
@@ -37,6 +37,7 @@ public class AssignableOperandTypeChecker implements SqlOperandTypeChecker {
   //~ Instance fields --------------------------------------------------------
 
   private final List<RelDataType> paramTypes;
+  private final ImmutableList<String> paramNames;
 
   //~ Constructors -----------------------------------------------------------
 
@@ -45,13 +46,21 @@ public class AssignableOperandTypeChecker implements SqlOperandTypeChecker {
    *
    * @param paramTypes parameter types for operands; index in this array
    *                   corresponds to operand number
+   * @param paramNames parameter names, or null
    */
-  public AssignableOperandTypeChecker(List<RelDataType> paramTypes) {
+  public AssignableOperandTypeChecker(List<RelDataType> paramTypes,
+      List<String> paramNames) {
     this.paramTypes = ImmutableList.copyOf(paramTypes);
+    this.paramNames =
+        paramNames == null ? null : ImmutableList.copyOf(paramNames);
   }
 
   //~ Methods ----------------------------------------------------------------
 
+  public boolean isOptional(int i) {
+    return false;
+  }
+
   public SqlOperandCountRange getOperandCountRange() {
     return SqlOperandCountRanges.of(paramTypes.size());
   }
@@ -59,6 +68,8 @@ public class AssignableOperandTypeChecker implements SqlOperandTypeChecker {
   public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
+    // Do not use callBinding.operands(). We have not resolved to a function
+    // yet, therefore we do not know the ordered parameter names.
     final List<SqlNode> operands = callBinding.getCall().getOperandList();
     for (Pair<RelDataType, SqlNode> pair : Pair.zip(paramTypes, operands)) {
       RelDataType argType =
@@ -84,6 +95,10 @@ public class AssignableOperandTypeChecker implements SqlOperandTypeChecker {
       if (paramType.i > 0) {
         sb.append(", ");
       }
+      if (paramNames != null) {
+        sb.append(paramNames.get(paramType.i))
+            .append(" => ");
+      }
       sb.append("<");
       sb.append(paramType.e.getFamily());
       sb.append(">");

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/CompositeOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/CompositeOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/CompositeOperandTypeChecker.java
index 6a77c95..9bfea87 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/CompositeOperandTypeChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/CompositeOperandTypeChecker.java
@@ -107,6 +107,15 @@ public class CompositeOperandTypeChecker implements SqlOperandTypeChecker {
 
   //~ Methods ----------------------------------------------------------------
 
+  public boolean isOptional(int i) {
+    for (SqlOperandTypeChecker allowedRule : allowedRules) {
+      if (allowedRule.isOptional(i)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   public ImmutableList<? extends SqlOperandTypeChecker> getRules() {
     return allowedRules;
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
index 4bef483..b9cf248 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/FamilyOperandTypeChecker.java
@@ -24,6 +24,7 @@ import org.apache.calcite.sql.SqlOperandCountRange;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlUtil;
 
+import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
@@ -38,18 +39,25 @@ public class FamilyOperandTypeChecker implements SqlSingleOperandTypeChecker {
   //~ Instance fields --------------------------------------------------------
 
   protected final ImmutableList<SqlTypeFamily> families;
+  protected final Predicate<Integer> optional;
 
   //~ Constructors -----------------------------------------------------------
 
   /**
    * Package private. Create using {@link OperandTypes#family}.
    */
-  FamilyOperandTypeChecker(List<SqlTypeFamily> families) {
+  FamilyOperandTypeChecker(List<SqlTypeFamily> families,
+      Predicate<Integer> optional) {
     this.families = ImmutableList.copyOf(families);
+    this.optional = optional;
   }
 
   //~ Methods ----------------------------------------------------------------
 
+  public boolean isOptional(int i) {
+    return optional.apply(i);
+  }
+
   public boolean checkSingleOperandType(
       SqlCallBinding callBinding,
       SqlNode node,
@@ -97,7 +105,7 @@ public class FamilyOperandTypeChecker implements SqlSingleOperandTypeChecker {
       return false;
     }
 
-    for (Ord<SqlNode> op : Ord.zip(callBinding.getCall().getOperandList())) {
+    for (Ord<SqlNode> op : Ord.zip(callBinding.operands())) {
       if (!checkSingleOperandType(
           callBinding,
           op.e,
@@ -110,7 +118,12 @@ public class FamilyOperandTypeChecker implements SqlSingleOperandTypeChecker {
   }
 
   public SqlOperandCountRange getOperandCountRange() {
-    return SqlOperandCountRanges.of(families.size());
+    final int max = families.size();
+    int min = max;
+    while (min > 0 && optional.apply(min - 1)) {
+      --min;
+    }
+    return SqlOperandCountRanges.between(min, max);
   }
 
   public String getAllowedSignatures(SqlOperator op, String opName) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/InferTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/InferTypes.java b/core/src/main/java/org/apache/calcite/sql/type/InferTypes.java
index f4ab473..938a058 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/InferTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/InferTypes.java
@@ -47,7 +47,7 @@ public abstract class InferTypes {
           final RelDataType unknownType =
               callBinding.getValidator().getUnknownType();
           RelDataType knownType = unknownType;
-          for (SqlNode operand : callBinding.getCall().getOperandList()) {
+          for (SqlNode operand : callBinding.operands()) {
             knownType = callBinding.getValidator().deriveType(
                 callBinding.getScope(), operand);
             if (!knownType.equals(unknownType)) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/LiteralOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/LiteralOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/LiteralOperandTypeChecker.java
index ac94f14..e2ddd7d 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/LiteralOperandTypeChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/LiteralOperandTypeChecker.java
@@ -44,6 +44,10 @@ public class LiteralOperandTypeChecker implements SqlSingleOperandTypeChecker {
 
   //~ Methods ----------------------------------------------------------------
 
+  public boolean isOptional(int i) {
+    return false;
+  }
+
   public boolean checkSingleOperandType(
       SqlCallBinding callBinding,
       SqlNode node,
@@ -79,7 +83,7 @@ public class LiteralOperandTypeChecker implements SqlSingleOperandTypeChecker {
       boolean throwOnFailure) {
     return checkSingleOperandType(
         callBinding,
-        callBinding.getCall().operand(0),
+        callBinding.operand(0),
         0,
         throwOnFailure);
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/MultisetOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/MultisetOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/MultisetOperandTypeChecker.java
index 2d04c46..c55a1c5 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/MultisetOperandTypeChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/MultisetOperandTypeChecker.java
@@ -17,7 +17,6 @@
 package org.apache.calcite.sql.type;
 
 import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCallBinding;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperandCountRange;
@@ -36,11 +35,14 @@ import static org.apache.calcite.util.Static.RESOURCE;
 public class MultisetOperandTypeChecker implements SqlOperandTypeChecker {
   //~ Methods ----------------------------------------------------------------
 
+  public boolean isOptional(int i) {
+    return false;
+  }
+
   public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
-    SqlCall call = callBinding.getCall();
-    final SqlNode op0 = call.operand(0);
+    final SqlNode op0 = callBinding.operand(0);
     if (!OperandTypes.MULTISET.checkSingleOperandType(
         callBinding,
         op0,
@@ -49,7 +51,7 @@ public class MultisetOperandTypeChecker implements SqlOperandTypeChecker {
       return false;
     }
 
-    final SqlNode op1 = call.operand(1);
+    final SqlNode op1 = callBinding.operand(1);
     if (!OperandTypes.MULTISET.checkSingleOperandType(
         callBinding,
         op1,

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
index 0d57234..eafd7c6 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
@@ -25,6 +25,8 @@ import org.apache.calcite.sql.SqlOperandCountRange;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlUtil;
 
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 
 import java.math.BigDecimal;
@@ -58,7 +60,17 @@ public abstract class OperandTypes {
    * corresponding family.
    */
   public static FamilyOperandTypeChecker family(SqlTypeFamily... families) {
-    return new FamilyOperandTypeChecker(ImmutableList.copyOf(families));
+    return new FamilyOperandTypeChecker(ImmutableList.copyOf(families),
+        Predicates.<Integer>alwaysFalse());
+  }
+
+  /**
+   * Creates a checker that passes if each operand is a member of a
+   * corresponding family, and allows specified parameters to be optional.
+   */
+  public static FamilyOperandTypeChecker family(List<SqlTypeFamily> families,
+      Predicate<Integer> optional) {
+    return new FamilyOperandTypeChecker(families, optional);
   }
 
   /**
@@ -66,7 +78,7 @@ public abstract class OperandTypes {
    * corresponding family.
    */
   public static FamilyOperandTypeChecker family(List<SqlTypeFamily> families) {
-    return new FamilyOperandTypeChecker(families);
+    return family(families, Predicates.<Integer>alwaysFalse());
   }
 
   /**
@@ -159,6 +171,10 @@ public abstract class OperandTypes {
         return opName + "(...)";
       }
 
+      public boolean isOptional(int i) {
+        return false;
+      }
+
       public Consistency getConsistency() {
         return Consistency.NONE;
       }
@@ -241,7 +257,8 @@ public abstract class OperandTypes {
    * literal.
    */
   public static final SqlSingleOperandTypeChecker POSITIVE_INTEGER_LITERAL =
-      new FamilyOperandTypeChecker(ImmutableList.of(SqlTypeFamily.INTEGER)) {
+      new FamilyOperandTypeChecker(ImmutableList.of(SqlTypeFamily.INTEGER),
+          Predicates.<Integer>alwaysFalse()) {
         public boolean checkSingleOperandType(
             SqlCallBinding callBinding,
             SqlNode node,
@@ -416,7 +433,8 @@ public abstract class OperandTypes {
   public static final SqlSingleOperandTypeChecker MINUS_DATE_OPERATOR =
       new FamilyOperandTypeChecker(
           ImmutableList.of(SqlTypeFamily.DATETIME, SqlTypeFamily.DATETIME,
-              SqlTypeFamily.DATETIME_INTERVAL)) {
+              SqlTypeFamily.DATETIME_INTERVAL),
+          Predicates.<Integer>alwaysFalse()) {
         public boolean checkOperandTypes(
             SqlCallBinding callBinding,
             boolean throwOnFailure) {
@@ -474,7 +492,7 @@ public abstract class OperandTypes {
             boolean throwOnFailure) {
           return checkSingleOperandType(
               callBinding,
-              callBinding.getCall().operand(0),
+              callBinding.operand(0),
               0,
               throwOnFailure);
         }
@@ -487,6 +505,10 @@ public abstract class OperandTypes {
           return "UNNEST(<MULTISET>)";
         }
 
+        public boolean isOptional(int i) {
+          return false;
+        }
+
         public Consistency getConsistency() {
           return Consistency.NONE;
         }
@@ -537,7 +559,7 @@ public abstract class OperandTypes {
             boolean throwOnFailure) {
           return checkSingleOperandType(
               callBinding,
-              callBinding.getCall().operand(0),
+              callBinding.operand(0),
               0,
               throwOnFailure);
         }
@@ -551,6 +573,10 @@ public abstract class OperandTypes {
               ImmutableList.of("RECORDTYPE(SINGLE FIELD)"));
         }
 
+        public boolean isOptional(int i) {
+          return false;
+        }
+
         public Consistency getConsistency() {
           return Consistency.NONE;
         }

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeChecker.java
index dbbd393..b88ea2e 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeChecker.java
@@ -53,6 +53,10 @@ public class SameOperandTypeChecker implements SqlSingleOperandTypeChecker {
     return Consistency.NONE;
   }
 
+  public boolean isOptional(int i) {
+    return false;
+  }
+
   public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
@@ -84,7 +88,7 @@ public class SameOperandTypeChecker implements SqlSingleOperandTypeChecker {
       if (operatorBinding.isOperandNull(i, false)) {
         if (throwOnFailure) {
           throw callBinding.getValidator().newValidationError(
-              callBinding.getCall().operand(i), RESOURCE.nullIllegal());
+              callBinding.operand(i), RESOURCE.nullIllegal());
         } else {
           return false;
         }

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java
index a38b682..b55d43c 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SetopOperandTypeChecker.java
@@ -41,6 +41,10 @@ import static org.apache.calcite.util.Static.RESOURCE;
 public class SetopOperandTypeChecker implements SqlOperandTypeChecker {
   //~ Methods ----------------------------------------------------------------
 
+  public boolean isOptional(int i) {
+    return false;
+  }
+
   public boolean checkOperandTypes(
       SqlCallBinding callBinding,
       boolean throwOnFailure) {
@@ -70,7 +74,7 @@ public class SetopOperandTypeChecker implements SqlOperandTypeChecker {
 
       if (fields.size() != colCount) {
         if (throwOnFailure) {
-          SqlNode node = callBinding.getCall().operand(i);
+          SqlNode node = callBinding.operand(i);
           if (node instanceof SqlSelect) {
             node = ((SqlSelect) node).getSelectList();
           }
@@ -103,9 +107,7 @@ public class SetopOperandTypeChecker implements SqlOperandTypeChecker {
       if (type == null) {
         if (throwOnFailure) {
           SqlNode field =
-              SqlUtil.getSelectListItem(
-                  callBinding.getCall().operand(0),
-                  i);
+              SqlUtil.getSelectListItem(callBinding.operand(0), i);
           throw validator.newValidationError(field,
               RESOURCE.columnTypeMismatchInSetop(i + 1, // 1-based
                   callBinding.getOperator().getName()));

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/SqlOperandCountRanges.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlOperandCountRanges.java b/core/src/main/java/org/apache/calcite/sql/type/SqlOperandCountRanges.java
index 1420c8a..9018084 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlOperandCountRanges.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlOperandCountRanges.java
@@ -18,6 +18,8 @@ package org.apache.calcite.sql.type;
 
 import org.apache.calcite.sql.SqlOperandCountRange;
 
+import com.google.common.base.Preconditions;
+
 /**
  * Helpers for {@link SqlOperandCountRange}.
  */
@@ -27,7 +29,6 @@ public abstract class SqlOperandCountRanges {
   }
 
   public static SqlOperandCountRange between(int min, int max) {
-    assert min < max;
     return new RangeImpl(min, max);
   }
 
@@ -47,6 +48,8 @@ public abstract class SqlOperandCountRanges {
     public RangeImpl(int min, int max) {
       this.min = min;
       this.max = max;
+      Preconditions.checkArgument(min <= max || max == -1);
+      Preconditions.checkArgument(min >= 0);
     }
 
     public boolean isValidCount(int count) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/type/SqlOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/SqlOperandTypeChecker.java
index 5a9eea4..545b2b2 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlOperandTypeChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlOperandTypeChecker.java
@@ -59,6 +59,9 @@ public interface SqlOperandTypeChecker {
   /** Returns the strategy for making the arguments have consistency types. */
   Consistency getConsistency();
 
+  /** Returns whether the {@code i}th operand is optional. */
+  boolean isOptional(int i);
+
   /** Strategy used to make arguments consistent. */
   enum Consistency {
     /** Do not try to make arguments consistent. */

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedFunction.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedFunction.java
index 49960f1..163687e 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlUserDefinedFunction.java
@@ -18,6 +18,7 @@ package org.apache.calcite.sql.validate;
 
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.schema.Function;
+import org.apache.calcite.schema.FunctionParameter;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlIdentifier;
@@ -27,6 +28,8 @@ import org.apache.calcite.sql.type.SqlOperandTypeInference;
 import org.apache.calcite.sql.type.SqlReturnTypeInference;
 import org.apache.calcite.util.Util;
 
+import com.google.common.collect.Lists;
+
 import java.util.List;
 
 /**
@@ -57,6 +60,10 @@ public class SqlUserDefinedFunction extends SqlFunction {
   public Function getFunction() {
     return function;
   }
+
+  @Override public List<String> getParamNames() {
+    return Lists.transform(function.getParameters(), FunctionParameter.NAME_FN);
+  }
 }
 
 // End SqlUserDefinedFunction.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/d012b245/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
index 7e44b15..9ff5e80 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java
@@ -636,11 +636,11 @@ public interface SqlValidator {
    * @param unresolvedFunction Overloaded function which is the target of the
    *                           call
    * @param argTypes           Types of arguments
+   * @param argNames           Names of arguments, or null if call by position
    */
-  CalciteException handleUnresolvedFunction(
-      SqlCall call,
-      SqlFunction unresolvedFunction,
-      List<RelDataType> argTypes);
+  CalciteException handleUnresolvedFunction(SqlCall call,
+      SqlFunction unresolvedFunction, List<RelDataType> argTypes,
+      List<String> argNames);
 
   /**
    * Expands an expression in the ORDER BY clause into an expression with the


Mime
View raw message