You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2016/03/08 07:13:21 UTC

[1/5] calcite git commit: Deprecate SqlLiteral.SqlSymbol; SqlSymbol can now wrap any Enum

Repository: calcite
Updated Branches:
  refs/heads/master a547222bd -> 4ac82a30b


Deprecate SqlLiteral.SqlSymbol; SqlSymbol can now wrap any Enum


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

Branch: refs/heads/master
Commit: 9c62adac2a218b428e322e8467263cec0ed9874b
Parents: a547222
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Mar 4 13:51:02 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 7 21:20:51 2016 -0800

----------------------------------------------------------------------
 .../calcite/rel/rel2sql/SqlImplementor.java     |  3 +--
 .../apache/calcite/sql/JoinConditionType.java   |  2 +-
 .../java/org/apache/calcite/sql/JoinType.java   |  2 +-
 .../org/apache/calcite/sql/SemiJoinType.java    |  2 +-
 .../java/org/apache/calcite/sql/SqlExplain.java |  6 ++---
 .../org/apache/calcite/sql/SqlExplainLevel.java |  2 +-
 .../java/org/apache/calcite/sql/SqlInsert.java  |  6 +++--
 .../apache/calcite/sql/SqlInsertKeyword.java    |  2 +-
 .../java/org/apache/calcite/sql/SqlJoin.java    | 10 ++++----
 .../java/org/apache/calcite/sql/SqlLiteral.java | 27 +++++++++++---------
 .../java/org/apache/calcite/sql/SqlSelect.java  |  3 ++-
 .../apache/calcite/sql/SqlSelectKeyword.java    |  2 +-
 .../java/org/apache/calcite/sql/SqlWindow.java  |  8 +++---
 .../calcite/sql/fun/SqlBetweenOperator.java     |  3 +--
 .../apache/calcite/sql/fun/SqlTrimFunction.java |  2 +-
 15 files changed, 42 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
index 03cc708..1f116b2 100644
--- a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
+++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
@@ -452,8 +452,7 @@ public abstract class SqlImplementor {
       case LITERAL:
         final RexLiteral literal = (RexLiteral) rex;
         if (literal.getTypeName() == SqlTypeName.SYMBOL) {
-          final SqlLiteral.SqlSymbol symbol =
-              (SqlLiteral.SqlSymbol) literal.getValue();
+          final Enum symbol = (Enum) literal.getValue();
           return SqlLiteral.createSymbol(symbol, POS);
         }
         switch (literal.getTypeName().getFamily()) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/JoinConditionType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/JoinConditionType.java b/core/src/main/java/org/apache/calcite/sql/JoinConditionType.java
index 6521944..3b449b0 100644
--- a/core/src/main/java/org/apache/calcite/sql/JoinConditionType.java
+++ b/core/src/main/java/org/apache/calcite/sql/JoinConditionType.java
@@ -21,7 +21,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 /**
  * Enumerates the types of condition in a join expression.
  */
-public enum JoinConditionType implements SqlLiteral.SqlSymbol {
+public enum JoinConditionType {
   /**
    * Join clause has no condition, for example "FROM EMP, DEPT"
    */

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/JoinType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/JoinType.java b/core/src/main/java/org/apache/calcite/sql/JoinType.java
index 993c279..0e4cc05 100644
--- a/core/src/main/java/org/apache/calcite/sql/JoinType.java
+++ b/core/src/main/java/org/apache/calcite/sql/JoinType.java
@@ -21,7 +21,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 /**
  * Enumerates the types of join.
  */
-public enum JoinType implements SqlLiteral.SqlSymbol {
+public enum JoinType {
   /**
    * Inner join.
    */

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SemiJoinType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SemiJoinType.java b/core/src/main/java/org/apache/calcite/sql/SemiJoinType.java
index 50b3659..38cabba 100644
--- a/core/src/main/java/org/apache/calcite/sql/SemiJoinType.java
+++ b/core/src/main/java/org/apache/calcite/sql/SemiJoinType.java
@@ -24,7 +24,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
  * Enumeration representing different join types used in correlation
  * relations.
  */
-public enum SemiJoinType implements SqlLiteral.SqlSymbol {
+public enum SemiJoinType {
   /**
    * Inner join
    */

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SqlExplain.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlExplain.java b/core/src/main/java/org/apache/calcite/sql/SqlExplain.java
index 7004caf..fc0e710 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlExplain.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlExplain.java
@@ -40,7 +40,7 @@ public class SqlExplain extends SqlCall {
   /**
    * The level of abstraction with which to display the plan.
    */
-  public static enum Depth implements SqlLiteral.SqlSymbol {
+  public enum Depth {
     TYPE, LOGICAL, PHYSICAL;
 
     /**
@@ -120,14 +120,14 @@ public class SqlExplain extends SqlCall {
    * @return detail level to be generated
    */
   public SqlExplainLevel getDetailLevel() {
-    return detailLevel.symbolValue();
+    return detailLevel.symbolValue(SqlExplainLevel.class);
   }
 
   /**
    * Returns the level of abstraction at which this plan should be displayed.
    */
   public Depth getDepth() {
-    return depth.symbolValue();
+    return depth.symbolValue(Depth.class);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SqlExplainLevel.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlExplainLevel.java b/core/src/main/java/org/apache/calcite/sql/SqlExplainLevel.java
index 4186393..0f3464f 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlExplainLevel.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlExplainLevel.java
@@ -21,7 +21,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 /**
  * SqlExplainLevel defines detail levels for EXPLAIN PLAN.
  */
-public enum SqlExplainLevel implements SqlLiteral.SqlSymbol {
+public enum SqlExplainLevel {
   /**
    * Suppress all attributes.
    */

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SqlInsert.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlInsert.java b/core/src/main/java/org/apache/calcite/sql/SqlInsert.java
index 7b58c8f..19472a7 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlInsert.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlInsert.java
@@ -80,7 +80,8 @@ public class SqlInsert extends SqlCall {
       keywords = (SqlNodeList) operand;
       break;
     case 1:
-      targetTable = (SqlIdentifier) operand;
+      assert operand instanceof SqlIdentifier;
+      targetTable = operand;
       break;
     case 2:
       source = operand;
@@ -121,7 +122,8 @@ public class SqlInsert extends SqlCall {
 
   public final SqlNode getModifierNode(SqlInsertKeyword modifier) {
     for (SqlNode keyword : keywords) {
-      SqlInsertKeyword keyword2 = ((SqlLiteral) keyword).symbolValue();
+      SqlInsertKeyword keyword2 =
+          ((SqlLiteral) keyword).symbolValue(SqlInsertKeyword.class);
       if (keyword2 == modifier) {
         return keyword;
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SqlInsertKeyword.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlInsertKeyword.java b/core/src/main/java/org/apache/calcite/sql/SqlInsertKeyword.java
index e4704c7..68b3629 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlInsertKeyword.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlInsertKeyword.java
@@ -23,7 +23,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
  *
  * <p>Standard SQL has no such keywords, but extension projects may define them.
  */
-public enum SqlInsertKeyword implements SqlLiteral.SqlSymbol {
+public enum SqlInsertKeyword {
   UPSERT;
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SqlJoin.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlJoin.java b/core/src/main/java/org/apache/calcite/sql/SqlJoin.java
index 12b1fb0..104d315 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlJoin.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlJoin.java
@@ -66,9 +66,9 @@ public class SqlJoin extends SqlCall {
     this.conditionType = Preconditions.checkNotNull(conditionType);
     this.condition = condition;
 
-    assert natural.getTypeName() == SqlTypeName.BOOLEAN;
-    assert conditionType.symbolValue() instanceof JoinConditionType;
-    assert joinType.symbolValue() instanceof JoinType;
+    Preconditions.checkArgument(natural.getTypeName() == SqlTypeName.BOOLEAN);
+    Preconditions.checkNotNull(conditionType.symbolValue(JoinConditionType.class));
+    Preconditions.checkNotNull(joinType.symbolValue(JoinType.class));
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -117,7 +117,7 @@ public class SqlJoin extends SqlCall {
 
   /** Returns a {@link JoinConditionType}, never null. */
   public final JoinConditionType getConditionType() {
-    return conditionType.symbolValue();
+    return conditionType.symbolValue(JoinConditionType.class);
   }
 
   public SqlLiteral getConditionTypeNode() {
@@ -126,7 +126,7 @@ public class SqlJoin extends SqlCall {
 
   /** Returns a {@link JoinType}, never null. */
   public final JoinType getJoinType() {
-    return joinType.symbolValue();
+    return joinType.symbolValue(JoinType.class);
   }
 
   public SqlLiteral getJoinTypeNode() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
index f535c53..347ea1a 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
@@ -126,7 +126,7 @@ import static org.apache.calcite.util.Static.RESOURCE;
  * the SQL standard, and is not exposed to end-users. It is used to hold a
  * symbol, such as the LEADING flag in a call to the function <code>
  * TRIM([LEADING|TRAILING|BOTH] chars FROM string)</code>.</td>
- * <td>A class which implements the {@link SqlSymbol} interface</td>
+ * <td>An {@link Enum}</td>
  * </tr>
  * <tr>
  * <td>{@link SqlTypeName#INTERVAL_DAY_TIME}</td>
@@ -205,9 +205,8 @@ public class SqlLiteral extends SqlNode {
     case CHAR:
       return value instanceof NlsString;
     case SYMBOL:
-      return (value instanceof SqlSymbol)
-          || (value instanceof SqlSampleSpec)
-          || (value instanceof TimeUnitRange);
+      return (value instanceof Enum)
+          || (value instanceof SqlSampleSpec);
     case MULTISET:
       return true;
     case INTEGER: // not allowed -- use Decimal
@@ -234,18 +233,24 @@ public class SqlLiteral extends SqlNode {
    * do.
    *
    * @see #booleanValue()
-   * @see #symbolValue()
+   * @see #symbolValue(Class)
    */
   public Object getValue() {
     return value;
   }
 
   /** Returns the value as a symbol. */
-  public <E extends SqlSymbol> E symbolValue() {
+  @Deprecated // to be removed before 2.0
+  public <E extends Enum<E>> E symbolValue_() {
     //noinspection unchecked
     return (E) value;
   }
 
+  /** Returns the value as a symbol. */
+  public <E extends Enum<E>> E symbolValue(Class<E> class_) {
+    return class_.cast(value);
+  }
+
   /** Returns the value as a boolean. */
   public boolean booleanValue() {
     return (Boolean) value;
@@ -255,7 +260,7 @@ public class SqlLiteral extends SqlNode {
    * Extracts the {@link SqlSampleSpec} value from a symbol literal.
    *
    * @throws ClassCastException if the value is not a symbol literal
-   * @see #createSymbol(SqlSymbol, SqlParserPos)
+   * @see #createSymbol(Enum, SqlParserPos)
    */
   public static SqlSampleSpec sampleValue(SqlNode node) {
     return (SqlSampleSpec) ((SqlLiteral) node).value;
@@ -450,11 +455,9 @@ public class SqlLiteral extends SqlNode {
    * <code>TRAILING</code> keyword in the call <code>Trim(TRAILING 'x' FROM
    * 'Hello world!')</code>.
    *
-   * @see #symbolValue()
+   * @see #symbolValue(Class)
    */
-  public static SqlLiteral createSymbol(
-      SqlLiteral.SqlSymbol o,
-      SqlParserPos pos) {
+  public static SqlLiteral createSymbol(Enum<?> o, SqlParserPos pos) {
     return new SqlLiteral(o, SqlTypeName.SYMBOL, pos);
   }
 
@@ -580,7 +583,6 @@ public class SqlLiteral extends SqlNode {
     case DECIMAL:
     case DOUBLE:
     case BINARY:
-
       // should be handled in subtype
       throw Util.unexpected(typeName);
 
@@ -876,6 +878,7 @@ public class SqlLiteral extends SqlNode {
    * unparsed, which is sometimes not the same as the enumerated value's name
    * (e.g. "UNBOUNDED PRECEDING" versus "UnboundedPreceeding").
    */
+  @Deprecated // to be removed before 2.0
   public interface SqlSymbol {
     String name();
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSelect.java b/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
index 2fa09e5..d1cb249 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
@@ -131,7 +131,8 @@ public class SqlSelect extends SqlCall {
 
   public final SqlNode getModifierNode(SqlSelectKeyword modifier) {
     for (SqlNode keyword : keywordList) {
-      SqlSelectKeyword keyword2 = ((SqlLiteral) keyword).symbolValue();
+      SqlSelectKeyword keyword2 =
+          ((SqlLiteral) keyword).symbolValue(SqlSelectKeyword.class);
       if (keyword2 == modifier) {
         return keyword;
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SqlSelectKeyword.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSelectKeyword.java b/core/src/main/java/org/apache/calcite/sql/SqlSelectKeyword.java
index 1ca4158..b83c832 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlSelectKeyword.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlSelectKeyword.java
@@ -21,7 +21,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 /**
  * Defines the keywords which can occur immediately after the "SELECT" keyword.
  */
-public enum SqlSelectKeyword implements SqlLiteral.SqlSymbol {
+public enum SqlSelectKeyword {
   DISTINCT,
   ALL,
   STREAM;

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
index a4150c4..86adcc6 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java
@@ -362,7 +362,7 @@ public class SqlWindow extends SqlCall {
    */
   public static boolean isCurrentRow(SqlNode node) {
     return (node instanceof SqlLiteral)
-        && ((SqlLiteral) node).symbolValue() == Bound.CURRENT_ROW;
+        && ((SqlLiteral) node).symbolValue(Bound.class) == Bound.CURRENT_ROW;
   }
 
   /**
@@ -370,7 +370,7 @@ public class SqlWindow extends SqlCall {
    */
   public static boolean isUnboundedPreceding(SqlNode node) {
     return (node instanceof SqlLiteral)
-        && ((SqlLiteral) node).symbolValue() == Bound.UNBOUNDED_PRECEDING;
+        && ((SqlLiteral) node).symbolValue(Bound.class) == Bound.UNBOUNDED_PRECEDING;
   }
 
   /**
@@ -378,7 +378,7 @@ public class SqlWindow extends SqlCall {
    */
   public static boolean isUnboundedFollowing(SqlNode node) {
     return (node instanceof SqlLiteral)
-        && ((SqlLiteral) node).symbolValue() == Bound.UNBOUNDED_FOLLOWING;
+        && ((SqlLiteral) node).symbolValue(Bound.class) == Bound.UNBOUNDED_FOLLOWING;
   }
 
   /**
@@ -772,7 +772,7 @@ public class SqlWindow extends SqlCall {
    * An enumeration of types of bounds in a window: <code>CURRENT ROW</code>,
    * <code>UNBOUNDED PRECEDING</code>, and <code>UNBOUNDED FOLLOWING</code>.
    */
-  enum Bound implements SqlLiteral.SqlSymbol {
+  enum Bound {
     CURRENT_ROW("CURRENT ROW"),
     UNBOUNDED_PRECEDING("UNBOUNDED PRECEDING"),
     UNBOUNDED_FOLLOWING("UNBOUNDED FOLLOWING");

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
index 4dff351..c4358d1 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
@@ -23,7 +23,6 @@ import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlCallBinding;
 import org.apache.calcite.sql.SqlInfixOperator;
 import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlOperatorBinding;
@@ -93,7 +92,7 @@ public class SqlBetweenOperator extends SqlInfixOperator {
   /**
    * Defines the "SYMMETRIC" and "ASYMMETRIC" keywords.
    */
-  public enum Flag implements SqlLiteral.SqlSymbol {
+  public enum Flag {
     ASYMMETRIC, SYMMETRIC
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/9c62adac/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 606c21e..629d954 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
@@ -63,7 +63,7 @@ public class SqlTrimFunction extends SqlFunction {
   /**
    * Defines the enumerated values "LEADING", "TRAILING", "BOTH".
    */
-  public enum Flag implements SqlLiteral.SqlSymbol {
+  public enum Flag {
     BOTH(1, 1), LEADING(1, 0), TRAILING(0, 1);
 
     private final int left;


[3/5] calcite git commit: In TimeUnit add WEEK, QUARTER, MICROSECOND values, and change type of multiplier

Posted by jh...@apache.org.
In TimeUnit add WEEK, QUARTER, MICROSECOND values, and change type of multiplier


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

Branch: refs/heads/master
Commit: cf5d07bde81a7c6a82bdab34ec798d0bf01ac01c
Parents: eead3d2
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Mar 7 15:46:31 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 7 21:25:01 2016 -0800

----------------------------------------------------------------------
 .../apache/calcite/avatica/util/TimeUnit.java   | 38 +++++++++++++-------
 .../calcite/avatica/util/TimeUnitRange.java     |  8 ++++-
 .../java/org/apache/calcite/rex/RexBuilder.java | 11 +++---
 .../sql2rel/StandardConvertletTable.java        | 33 ++++++++---------
 4 files changed, 52 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/cf5d07bd/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java
----------------------------------------------------------------------
diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java b/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java
index b249232..574aa45 100644
--- a/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java
+++ b/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java
@@ -20,28 +20,42 @@ import java.math.BigDecimal;
 
 /**
  * Enumeration of time units used to construct an interval.
+ *
+ * <p>Only {@link #YEAR}, {@link #YEAR}, {@link #MONTH}, {@link #DAY},
+ * {@link #HOUR}, {@link #MINUTE}, {@link #SECOND} can be the unit of a SQL
+ * interval.
+ *
+ * <p>The others ({@link #QUARTER}, {@link #WEEK}, {@link #MILLISECOND} and
+ * {@link #MICROSECOND}) are convenient to use it internally, when converting to
+ * and from UNIX timestamps. And also may be arguments to the
+ * {@code TIMESTAMPADD} and {@code TIMESTAMPDIFF} functions.
  */
 public enum TimeUnit {
-  YEAR(true, ' ', 12 /* months */, null),
-  MONTH(true, '-', 1 /* months */, BigDecimal.valueOf(12)),
-  DAY(false, '-', DateTimeUtils.MILLIS_PER_DAY, null),
-  HOUR(false, ' ', DateTimeUtils.MILLIS_PER_HOUR, BigDecimal.valueOf(24)),
-  MINUTE(false, ':', DateTimeUtils.MILLIS_PER_MINUTE, BigDecimal.valueOf(60)),
-  SECOND(false, ':', DateTimeUtils.MILLIS_PER_SECOND, BigDecimal.valueOf(60)),
+  YEAR(true, ' ', BigDecimal.valueOf(12) /* months */, null),
+  MONTH(true, '-', BigDecimal.ONE /* months */, BigDecimal.valueOf(12)),
+  DAY(false, '-', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_DAY), null),
+  HOUR(false, ' ', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_HOUR),
+      BigDecimal.valueOf(24)),
+  MINUTE(false, ':', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_MINUTE),
+      BigDecimal.valueOf(60)),
+  SECOND(false, ':', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_SECOND),
+      BigDecimal.valueOf(60)),
 
-  /** Unlike the other units, MILLISECOND may not be the unit of a SQL interval.
-   * Still, it is convenient to use it internally, when converting to and from
-   * UNIX timestamps. */
-  MILLISECOND(false, '.', 1, BigDecimal.valueOf(1));
+  QUARTER(true, '*', BigDecimal.valueOf(3) /* months */, BigDecimal.valueOf(4)),
+  WEEK(false, '*', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_DAY * 7),
+      BigDecimal.valueOf(53)),
+  MILLISECOND(false, '.', BigDecimal.ONE, BigDecimal.valueOf(1000)),
+  MICROSECOND(false, '.', BigDecimal.ONE.scaleByPowerOfTen(-3),
+      BigDecimal.valueOf(1000000));
 
   public final boolean yearMonth;
   public final char separator;
-  public final long multiplier;
+  public final BigDecimal multiplier;
   private final BigDecimal limit;
 
   private static final TimeUnit[] CACHED_VALUES = values();
 
-  TimeUnit(boolean yearMonth, char separator, long multiplier,
+  TimeUnit(boolean yearMonth, char separator, BigDecimal multiplier,
       BigDecimal limit) {
     this.yearMonth = yearMonth;
     this.separator = separator;

http://git-wip-us.apache.org/repos/asf/calcite/blob/cf5d07bd/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java
----------------------------------------------------------------------
diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java b/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java
index 4d9b322..ddfe9f7 100644
--- a/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java
+++ b/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java
@@ -36,7 +36,13 @@ public enum TimeUnitRange {
   HOUR_TO_SECOND(TimeUnit.HOUR, TimeUnit.SECOND),
   MINUTE(TimeUnit.MINUTE, null),
   MINUTE_TO_SECOND(TimeUnit.MINUTE, TimeUnit.SECOND),
-  SECOND(TimeUnit.SECOND, null);
+  SECOND(TimeUnit.SECOND, null),
+
+  // non-standard time units cannot participate in ranges
+  QUARTER(TimeUnit.QUARTER, null),
+  WEEK(TimeUnit.WEEK, null),
+  MILLISECOND(TimeUnit.MILLISECOND, null),
+  MICROSECOND(TimeUnit.MICROSECOND, null);
 
   public final TimeUnit startUnit;
   public final TimeUnit endUnit;

http://git-wip-us.apache.org/repos/asf/calcite/blob/cf5d07bd/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index dd147a5..b0cc27e 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -525,7 +525,7 @@ public class RexBuilder {
         case INTERVAL_DAY_TIME:
           assert value instanceof BigDecimal;
           BigDecimal value2 = (BigDecimal) value;
-          final long multiplier =
+          final BigDecimal multiplier =
               literal.getType().getIntervalQualifier().getStartUnit()
                   .multiplier;
           typeName = type.getSqlTypeName();
@@ -534,8 +534,7 @@ public class RexBuilder {
           case INTEGER:
             typeName = SqlTypeName.BIGINT;
           }
-          value = value2.divide(BigDecimal.valueOf(multiplier), 0,
-              BigDecimal.ROUND_HALF_DOWN);
+          value = value2.divide(multiplier, 0, BigDecimal.ROUND_HALF_DOWN);
         }
         final RexLiteral literal2 =
             makeLiteral(value, type, typeName);
@@ -595,8 +594,7 @@ public class RexBuilder {
               .getFractionalSecondPrecision(typeFactory.getTypeSystem()),
           3);
     }
-    BigDecimal multiplier = BigDecimal.valueOf(endUnit.multiplier)
-        .divide(BigDecimal.TEN.pow(scale));
+    BigDecimal multiplier = endUnit.multiplier.scaleByPowerOfTen(-scale);
     RexNode value = decodeIntervalOrDecimal(exp);
     if (multiplier.longValue() != 1) {
       value = makeCall(
@@ -627,8 +625,7 @@ public class RexBuilder {
               .getFractionalSecondPrecision(typeFactory.getTypeSystem()),
           3);
     }
-    BigDecimal multiplier = BigDecimal.valueOf(endUnit.multiplier)
-        .divide(BigDecimal.TEN.pow(scale));
+    BigDecimal multiplier = endUnit.multiplier.scaleByPowerOfTen(-scale);
     RelDataType decimalType =
         getTypeFactory().createSqlType(SqlTypeName.DECIMAL,
             scale + intervalType.getPrecision(),

http://git-wip-us.apache.org/repos/asf/calcite/blob/cf5d07bd/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
index 99452bf..5d1957f 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -16,7 +16,6 @@
  */
 package org.apache.calcite.sql2rel;
 
-import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.avatica.util.TimeUnit;
 import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.plan.RelOptUtil;
@@ -465,8 +464,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
         RexLiteral castedInterval =
             cx.getRexBuilder().makeIntervalLiteral(
                 sourceValue.multiply(
-                    BigDecimal.valueOf(
-                        intervalQualifier.getStartUnit().multiplier),
+                    intervalQualifier.getStartUnit().multiplier,
                     MathContext.UNLIMITED),
                 intervalQualifier);
         return castToValidatedType(cx, call, castedInterval);
@@ -515,7 +513,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
       final SqlIntervalLiteral literal = call.operand(0);
       SqlIntervalLiteral.IntervalValue interval =
           (SqlIntervalLiteral.IntervalValue) literal.getValue();
-      long val =
+      BigDecimal val =
           interval.getIntervalQualifier().getStartUnit().multiplier;
       RexNode rexInterval = cx.convertExpression(literal);
 
@@ -530,7 +528,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
               zero);
 
       RexNode pad =
-          rexBuilder.makeExactLiteral(BigDecimal.valueOf(val - 1));
+          rexBuilder.makeExactLiteral(val.subtract(BigDecimal.ONE));
       RexNode cast = rexBuilder.makeReinterpretCast(
           rexInterval.getType(), pad, rexBuilder.makeLiteral(false));
       SqlOperator op =
@@ -545,8 +543,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
           : rexBuilder.makeCall(SqlStdOperatorTable.CASE,
               cond, sum, rexInterval);
 
-      RexNode factor =
-          rexBuilder.makeExactLiteral(BigDecimal.valueOf(val));
+      RexNode factor = rexBuilder.makeExactLiteral(val);
       RexNode div =
           rexBuilder.makeCall(
               SqlStdOperatorTable.DIVIDE_INTEGER,
@@ -596,7 +593,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
       case INTERVAL_DAY_TIME:
         break;
       case TIMESTAMP:
-        res = divide(rexBuilder, res, DateTimeUtils.MILLIS_PER_DAY);
+        res = divide(rexBuilder, res, TimeUnit.DAY.multiplier);
         // fall through
       case DATE:
         return rexBuilder.makeCall(resType, SqlStdOperatorTable.EXTRACT_DATE,
@@ -636,16 +633,16 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
             ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), x));
     res = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, res,
         rexBuilder.makeExactLiteral(BigDecimal.ONE));
-    res = divide(rexBuilder, res, 3);
+    res = divide(rexBuilder, res, TimeUnit.QUARTER.multiplier);
     res = rexBuilder.makeCall(SqlStdOperatorTable.PLUS, res,
         rexBuilder.makeExactLiteral(BigDecimal.ONE));
     return res;
   }
 
-  private static long getFactor(TimeUnit unit) {
+  private static BigDecimal getFactor(TimeUnit unit) {
     switch (unit) {
     case DAY:
-      return 1;
+      return BigDecimal.ONE;
     case HOUR:
       return TimeUnit.DAY.multiplier;
     case MINUTE:
@@ -653,7 +650,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     case SECOND:
       return TimeUnit.MINUTE.multiplier;
     case YEAR:
-      return 1;
+      return BigDecimal.ONE;
     case MONTH:
       return TimeUnit.YEAR.multiplier;
     default:
@@ -662,20 +659,20 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
   }
 
   private RexNode mod(RexBuilder rexBuilder, RelDataType resType, RexNode res,
-      long val) {
-    if (val == 1L) {
+      BigDecimal val) {
+    if (val.equals(BigDecimal.ONE)) {
       return res;
     }
     return rexBuilder.makeCall(SqlStdOperatorTable.MOD, res,
-        rexBuilder.makeExactLiteral(BigDecimal.valueOf(val), resType));
+        rexBuilder.makeExactLiteral(val, resType));
   }
 
-  private RexNode divide(RexBuilder rexBuilder, RexNode res, long val) {
-    if (val == 1L) {
+  private RexNode divide(RexBuilder rexBuilder, RexNode res, BigDecimal val) {
+    if (val.equals(BigDecimal.ONE)) {
       return res;
     }
     return rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE_INTEGER, res,
-        rexBuilder.makeExactLiteral(BigDecimal.valueOf(val)));
+        rexBuilder.makeExactLiteral(val));
   }
 
   public RexNode convertDatetimeMinus(


[4/5] calcite git commit: [CALCITE-1124] Add TIMESTAMPADD, TIMESTAMPDIFF functions (Arina Ielchiieva)

Posted by jh...@apache.org.
[CALCITE-1124] Add TIMESTAMPADD, TIMESTAMPDIFF functions (Arina Ielchiieva)

Close apache/calcite#204


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

Branch: refs/heads/master
Commit: 0b9ea986b847c325da009376d3b9031c9303090e
Parents: cf5d07b
Author: Arina Ielchiieva <ar...@gmail.com>
Authored: Thu Mar 3 17:07:10 2016 +0200
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 7 21:26:48 2016 -0800

----------------------------------------------------------------------
 core/src/main/codegen/templates/Parser.jj       | 135 +++++++++++++++++++
 .../apache/calcite/sql/TimestampInterval.java   |  47 +++++++
 .../calcite/sql/fun/SqlStdOperatorTable.java    |  63 +++++++++
 .../calcite/sql/parser/SqlParserTest.java       |  41 ++++++
 .../calcite/sql/test/SqlOperatorBaseTest.java   |  15 +++
 .../apache/calcite/test/SqlValidatorTest.java   |  48 +++++++
 site/_docs/reference.md                         |  16 +++
 7 files changed, 365 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/0b9ea986/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 ce4920b..01c35bb 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -82,6 +82,7 @@ import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.SqlWindow;
 import org.apache.calcite.sql.SqlWith;
 import org.apache.calcite.sql.SqlWithItem;
+import org.apache.calcite.sql.TimestampInterval;
 import org.apache.calcite.sql.fun.SqlCase;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.fun.SqlTrimFunction;
@@ -3438,6 +3439,64 @@ TimeUnit TimeUnit() :
     }
 }
 
+SqlLiteral TimestampInterval() :
+{
+SqlLiteral.SqlSymbol symbol = null;
+}
+{
+    (
+        ( <FRAC_SECOND> | <MICROSECOND> | <SQL_TSI_FRAC_SECOND> | <SQL_TSI_MICROSECOND> )
+            {
+                symbol = TimestampInterval.MICROSECOND;
+            }
+        |
+        ( <SECOND> | <SQL_TSI_SECOND> )
+            {
+                symbol = TimestampInterval.SECOND;
+            }
+        |
+        ( <MINUTE> | <SQL_TSI_MINUTE> )
+            {
+                symbol = TimestampInterval.MINUTE;
+            }
+        |
+        ( <HOUR> | <SQL_TSI_HOUR> )
+            {
+                symbol = TimestampInterval.HOUR;
+            }
+        |
+        ( <DAY> | <SQL_TSI_DAY> )
+            {
+                symbol = TimestampInterval.DAY;
+            }
+        |
+         (<WEEK> | <SQL_TSI_WEEK> )
+            {
+                symbol = TimestampInterval.WEEK;
+            }
+        |
+        ( <MONTH> | <SQL_TSI_MONTH> )
+            {
+                symbol = TimestampInterval.MONTH;
+            }
+        |
+        ( <QUARTER> | <SQL_TSI_QUARTER> )
+            {
+                symbol = TimestampInterval.QUARTER;
+            }
+        |
+        ( <YEAR> | <SQL_TSI_YEAR> )
+            {
+                symbol = TimestampInterval.YEAR;
+            }
+    )
+    {
+        return SqlLiteral.createSymbol(symbol, getPos());
+    }
+}
+
+
+
 /**
  * Parses a dynamic parameter marker.
  */
@@ -4143,6 +4202,50 @@ SqlNode BuiltinFunctionCall() :
         }
     )
     |
+    (
+        <TIMESTAMPADD>
+            {
+                pos = getPos();
+                SqlLiteral interval;
+            }
+            <LPAREN>
+                interval = TimestampInterval()
+                { args = startList(interval); }
+             <COMMA>
+                 e = Expression(ExprContext.ACCEPT_SUBQUERY)
+                 { args.add(e); }
+             <COMMA>
+                 e = Expression(ExprContext.ACCEPT_SUBQUERY)
+                 { args.add(e); }
+             <RPAREN>
+           {
+              return SqlStdOperatorTable.TIMESTAMP_ADD.createCall(
+                 pos, SqlParserUtil.toNodeArray(args));
+           }
+    )
+    |
+    (
+        <TIMESTAMPDIFF>
+            {
+                pos = getPos();
+                SqlLiteral interval;
+            }
+            <LPAREN>
+                interval = TimestampInterval()
+                { args = startList(interval); }
+             <COMMA>
+                 e = Expression(ExprContext.ACCEPT_SUBQUERY)
+                 { args.add(e); }
+             <COMMA>
+                 e = Expression(ExprContext.ACCEPT_SUBQUERY)
+                 { args.add(e); }
+             <RPAREN>
+           {
+              return SqlStdOperatorTable.TIMESTAMP_DIFF.createCall(
+                 pos, SqlParserUtil.toNodeArray(args));
+           }
+    )
+    |
     {
         SqlNode node;
     }
@@ -4810,6 +4913,7 @@ SqlPostfixOperator PostfixRowOperator() :
     | < FOREIGN: "FOREIGN" >
     | < FORTRAN: "FORTRAN" >
     | < FOUND: "FOUND" >
+    | < FRAC_SECOND: "FRAC_SECOND" >
     | < FREE: "FREE" >
     | < FROM: "FROM" >
     | < FULL: "FULL" >
@@ -4892,6 +4996,7 @@ SqlPostfixOperator PostfixRowOperator() :
     | < MESSAGE_OCTET_LENGTH: "MESSAGE_OCTET_LENGTH" >
     | < MESSAGE_TEXT: "MESSAGE_TEXT" >
     | < METHOD: "METHOD" >
+    | < MICROSECOND: "MICROSECOND" >
     | < MIN: "MIN" >
     | < MINUTE: "MINUTE" >
     | < MINVALUE: "MINVALUE" >
@@ -4975,6 +5080,7 @@ SqlPostfixOperator PostfixRowOperator() :
     | < PRIVILEGES: "PRIVILEGES" >
     | < PROCEDURE: "PROCEDURE" >
     | < PUBLIC: "PUBLIC" >
+    | < QUARTER: "QUARTER" >
     | < RANGE: "RANGE" >
     | < RANK: "RANK" >
     | < READ: "READ" >
@@ -5057,6 +5163,16 @@ SqlPostfixOperator PostfixRowOperator() :
     | < SQLEXCEPTION: "SQLEXCEPTION" >
     | < SQLSTATE: "SQLSTATE" >
     | < SQLWARNING: "SQLWARNING" >
+    | < SQL_TSI_DAY: "SQL_TSI_DAY" >
+    | < SQL_TSI_FRAC_SECOND: "SQL_TSI_FRAC_SECOND" >
+    | < SQL_TSI_HOUR: "SQL_TSI_HOUR" >
+    | < SQL_TSI_MICROSECOND: "SQL_TSI_MICROSECOND" >
+    | < SQL_TSI_MINUTE: "SQL_TSI_MINUTE" >
+    | < SQL_TSI_MONTH: "SQL_TSI_MONTH" >
+    | < SQL_TSI_QUARTER: "SQL_TSI_QUARTER" >
+    | < SQL_TSI_SECOND: "SQL_TSI_SECOND" >
+    | < SQL_TSI_WEEK: "SQL_TSI_WEEK" >
+    | < SQL_TSI_YEAR: "SQL_TSI_YEAR" >
     | < SQRT: "SQRT" >
     | < START: "START" >
     | < STATE: "STATE" >
@@ -5083,6 +5199,8 @@ SqlPostfixOperator PostfixRowOperator() :
     | < TIES: "TIES" >
     | < TIME: "TIME" >
     | < TIMESTAMP: "TIMESTAMP" >
+    | < TIMESTAMPADD: "TIMESTAMPADD" >
+    | < TIMESTAMPDIFF: "TIMESTAMPDIFF" >
     | < TIMEZONE_HOUR: "TIMEZONE_HOUR" >
     | < TIMEZONE_MINUTE: "TIMEZONE_MINUTE" >
     | < TINYINT: "TINYINT" >
@@ -5133,6 +5251,7 @@ SqlPostfixOperator PostfixRowOperator() :
     | < VARYING: "VARYING" >
     | < VERSION: "VERSION" >
     | < VIEW: "VIEW" >
+    | < WEEK: "WEEK" >
     | < WHEN: "WHEN" >
     | < WHENEVER: "WHENEVER" >
     | < WHERE: "WHERE" >
@@ -5254,6 +5373,7 @@ String CommonNonReservedKeyWord() :
         | <FOLLOWING>
         | <FORTRAN>
         | <FOUND>
+        | <FRAC_SECOND>
         | <G>
         | <GENERAL>
         | <GENERATED>
@@ -5286,6 +5406,7 @@ String CommonNonReservedKeyWord() :
         | <MAP>
         | <MATCHED>
         | <MAXVALUE>
+        | <MICROSECOND>
         | <MESSAGE_LENGTH>
         | <MESSAGE_OCTET_LENGTH>
         | <MESSAGE_TEXT>
@@ -5327,6 +5448,7 @@ String CommonNonReservedKeyWord() :
         | <PRIOR>
         | <PRIVILEGES>
         | <PUBLIC>
+        | <QUARTER>
         | <READ>
         | <RELATIVE>
         | <REPEATABLE>
@@ -5362,6 +5484,16 @@ String CommonNonReservedKeyWord() :
         | <SOURCE>
         | <SPACE>
         | <SPECIFIC_NAME>
+        | <SQL_TSI_DAY>
+        | <SQL_TSI_FRAC_SECOND>
+        | <SQL_TSI_HOUR>
+        | <SQL_TSI_MICROSECOND>
+        | <SQL_TSI_MINUTE>
+        | <SQL_TSI_MONTH>
+        | <SQL_TSI_QUARTER>
+        | <SQL_TSI_SECOND>
+        | <SQL_TSI_WEEK>
+        | <SQL_TSI_YEAR>
         | <STATE>
         | <STATEMENT>
         | <STRUCTURE>
@@ -5371,6 +5503,8 @@ String CommonNonReservedKeyWord() :
         | <TABLE_NAME>
         | <TEMPORARY>
         | <TIES>
+        | <TIMESTAMPADD>
+        | <TIMESTAMPDIFF>
         | <TOP_LEVEL_COUNT>
         | <TRANSACTION>
         | <TRANSACTIONS_ACTIVE>
@@ -5393,6 +5527,7 @@ String CommonNonReservedKeyWord() :
         | <USER_DEFINED_TYPE_SCHEMA>
         | <VERSION>
         | <VIEW>
+        | <WEEK>
         | <WRAPPER>
         | <WORK>
         | <WRITE>

http://git-wip-us.apache.org/repos/asf/calcite/blob/0b9ea986/core/src/main/java/org/apache/calcite/sql/TimestampInterval.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/TimestampInterval.java b/core/src/main/java/org/apache/calcite/sql/TimestampInterval.java
new file mode 100644
index 0000000..d586d4a
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/TimestampInterval.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+import org.apache.calcite.sql.parser.SqlParserPos;
+
+/**
+ * Enumerates the timestamp intervals.
+ */
+public enum TimestampInterval implements SqlLiteral.SqlSymbol  {
+
+  MICROSECOND,
+  SECOND,
+  MINUTE,
+  HOUR,
+  DAY,
+  WEEK,
+  MONTH,
+  QUARTER,
+  YEAR;
+
+  /**
+   * Creates a parse-tree node representing an occurrence of this
+   * condition type keyword at a particular position in the parsed
+   * text.
+   */
+  public SqlLiteral symbol(SqlParserPos pos) {
+    return SqlLiteral.createSymbol(this, pos);
+  }
+
+}
+
+// End TimestampInterval.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0b9ea986/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 ece34a5..98d2e85 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
@@ -46,6 +46,7 @@ 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.SqlOperandCountRanges;
+import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.util.ReflectiveSqlOperatorTable;
 import org.apache.calcite.sql.validate.SqlModality;
@@ -1315,6 +1316,68 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
       new SqlCurrentDateFunction();
 
   /**
+   * <p>Timestamp modifying or calculating difference functions.
+   * As first parameter take timestamp interval.
+   * </p>
+   *
+   * <p>Interval can one of the following literals:<br>
+   * <i>FRAC_SECOND, MICROSECOND, SQL_TSI_FRAC_SECOND, SQL_TSI_MICROSECOND</i><br>
+   * <i>SECOND, SQL_TSI_SECOND</i><br>
+   * <i>MINUTE, SQL_TSI_MINUTE</i><br>
+   * <i>HOUR, SQL_TSI_HOUR</i><br>
+   * <i>DAY, SQL_TSI_DAY</i><br>
+   * <i>WEEK, SQL_TSI_WEEK</i><br>
+   * <i>MONTH, SQL_TSI_MONTH</i><br>
+   * <i>QUARTER, SQL_TSI_QUARTER</i><br>
+   * <i>YEAR, SQL_TSI_YEAR</i><br>
+   * </p>
+   */
+
+  /**
+   * <p>The SQL <code>TIMESTAMP_ADD</code> function.
+   * Adds interval to timestamp.</p>
+   *
+   * <p>The SQL syntax is
+   *
+   * <blockquote>
+   * <code>TIMESTAMP_ADD(<i>timestamp interval</i>,<i>quantity</i>,<i>timestamp</i>)</code>
+   * </blockquote><br>
+   *
+   * Returns modified timestamp.</p>
+   */
+  public static final SqlFunction TIMESTAMP_ADD =
+      new SqlFunction(
+          "TIMESTAMPADD",
+          SqlKind.OTHER_FUNCTION,
+          ReturnTypes.ARG2,
+          null,
+          OperandTypes.family(
+              SqlTypeFamily.ANY, SqlTypeFamily.INTEGER, SqlTypeFamily.DATETIME),
+          SqlFunctionCategory.TIMEDATE);
+
+  /**
+   * <p>The SQL <code>TIMESTAMP_DIFF</code> function.
+   * Calculates difference between two timestamps.</p>
+   *
+   * <p>The SQL syntax is
+   *
+   * <blockquote>
+   * <code>TIMESTAMP_DIFF(<i>timestamp interval</i>,<i>timestamp</i>,<i>timestamp</i>)</code>
+   * </blockquote><br>
+   *
+   * Returns difference between two timestamps in indicated timestamp interval.</p>
+   */
+  public static final SqlFunction TIMESTAMP_DIFF = new SqlFunction(
+      "TIMESTAMPDIFF",
+      SqlKind.OTHER_FUNCTION,
+      ReturnTypes.INTEGER_NULLABLE,
+      null,
+      OperandTypes.family(
+          SqlTypeFamily.ANY, SqlTypeFamily.DATETIME, SqlTypeFamily.DATETIME),
+      SqlFunctionCategory.TIMEDATE);
+
+
+  /**
    * Use of the <code>IN_FENNEL</code> operator forces the argument to be
    * evaluated in Fennel. Otherwise acts as identity function.
    */

http://git-wip-us.apache.org/repos/asf/calcite/blob/0b9ea986/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
index 31dbd58..858e8a0 100644
--- a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
@@ -29,6 +29,9 @@ import org.apache.calcite.util.ConversionUtil;
 import org.apache.calcite.util.TestUtil;
 import org.apache.calcite.util.Util;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -39,7 +42,10 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertEquals;
@@ -5525,6 +5531,41 @@ public class SqlParserTest {
         "CAST(INTERVAL '3-2' YEAR TO MONTH AS CHAR(5))");
   }
 
+  @Test public void testTimestampAddAndDiff() {
+    Map<String, List<String>> tsi = ImmutableMap.<String, List<String>>builder()
+        .put("MICROSECOND",
+            Arrays.asList("FRAC_SECOND", "MICROSECOND",
+                "SQL_TSI_FRAC_SECOND", "SQL_TSI_MICROSECOND"))
+        .put("SECOND", Arrays.asList("SECOND", "SQL_TSI_SECOND"))
+        .put("MINUTE", Arrays.asList("MINUTE", "SQL_TSI_MINUTE"))
+        .put("HOUR", Arrays.asList("HOUR", "SQL_TSI_HOUR"))
+        .put("DAY", Arrays.asList("DAY", "SQL_TSI_DAY"))
+        .put("WEEK", Arrays.asList("WEEK", "SQL_TSI_WEEK"))
+        .put("MONTH", Arrays.asList("MONTH", "SQL_TSI_MONTH"))
+        .put("QUARTER", Arrays.asList("QUARTER", "SQL_TSI_QUARTER"))
+        .put("YEAR", Arrays.asList("YEAR", "SQL_TSI_YEAR"))
+        .build();
+
+    List<String> functions = ImmutableList.<String>builder()
+        .add("timestampadd(%1$s, 12, %2$scurrent_timestamp%2$s)")
+        .add("timestampdiff(%1$s, %2$scurrent_timestamp%2$s, %2$scurrent_timestamp%2$s)")
+        .build();
+
+    for (Map.Entry<String, List<String>> intervalGroup : tsi.entrySet()) {
+      for (String function : functions) {
+        for (String interval : intervalGroup.getValue()) {
+          checkExp(String.format(function, interval, ""),
+              String.format(function, intervalGroup.getKey(), "`").toUpperCase());
+        }
+      }
+    }
+
+    checkExpFails("timestampadd(^incorrect^, 1, current_timestamp)",
+        "(?s).*Was expecting one of.*");
+    checkExpFails("timestampdiff(^incorrect^, current_timestamp, current_timestamp)",
+        "(?s).*Was expecting one of.*");
+  }
+
   @Test public void testUnnest() {
     check(
         "select*from unnest(x)",

http://git-wip-us.apache.org/repos/asf/calcite/blob/0b9ea986/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 81bfeed..48311dd 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -4599,6 +4599,21 @@ public abstract class SqlOperatorBaseTest {
         "floor(cast(null as interval year))");
   }
 
+  @Test public void testTimestampAddAdnDiff() {
+    if (!enable) {
+      return;
+    }
+    tester.checkScalar(
+        "timestampadd(MINUTE, 2, timestamp '2016-02-24 12:42:25')",
+        "2016-02-24 12:42:27",
+        "TIMESTAMP(0) NOT NULL");
+    tester.checkScalar(
+        "timestampdiff(YEAR, "
+            + "timestamp '2014-02-24 12:42:25', "
+            + "timestamp '2016-02-24 12:42:25')",
+        "2", "INTEGER NOT NULL");
+  }
+
   @Test public void testDenseRankFunc() {
     tester.setFor(
         SqlStdOperatorTable.DENSE_RANK, VM_FENNEL, VM_JAVA);

http://git-wip-us.apache.org/repos/asf/calcite/blob/0b9ea986/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index b3a8699..c8ba8e9 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -3589,6 +3589,54 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
         "(?s).*Cannot apply '/' to arguments of type '<DECIMAL.4, 3.> / <INTERVAL DAY TO SECOND>'.*");
   }
 
+  @Test public void testTimestampAddAndDiff() {
+    List<String> tsi = ImmutableList.<String>builder()
+        .add("FRAC_SECOND")
+        .add("MICROSECOND")
+        .add("MINUTE")
+        .add("HOUR")
+        .add("DAY")
+        .add("WEEK")
+        .add("MONTH")
+        .add("QUARTER")
+        .add("YEAR")
+        .add("SQL_TSI_FRAC_SECOND")
+        .add("SQL_TSI_MICROSECOND")
+        .add("SQL_TSI_MINUTE")
+        .add("SQL_TSI_HOUR")
+        .add("SQL_TSI_DAY")
+        .add("SQL_TSI_WEEK")
+        .add("SQL_TSI_MONTH")
+        .add("SQL_TSI_QUARTER")
+        .add("SQL_TSI_YEAR")
+        .build();
+
+    List<String> functions = ImmutableList.<String>builder()
+        .add("timestampadd(%s, 12, current_timestamp)")
+        .add("timestampdiff(%s, current_timestamp, current_timestamp)")
+        .build();
+
+    for (String interval : tsi) {
+      for (String function : functions) {
+        checkExp(String.format(function, interval));
+      }
+    }
+
+    checkExpType(
+        "timestampadd(SQL_TSI_WEEK, 2, current_timestamp)", "TIMESTAMP(0) NOT NULL");
+    checkExpType(
+        "timestampadd(SQL_TSI_WEEK, 2, cast(null as timestamp))", "TIMESTAMP(0)");
+    checkExpType(
+        "timestampdiff(SQL_TSI_WEEK, current_timestamp, current_timestamp)", "INTEGER NOT NULL");
+    checkExpType(
+        "timestampdiff(SQL_TSI_WEEK, cast(null as timestamp), current_timestamp)", "INTEGER");
+
+    checkWholeExpFails("timestampadd(incorrect, 1, current_timestamp)",
+        "(?s).*Was expecting one of.*");
+    checkWholeExpFails("timestampdiff(incorrect, current_timestamp, current_timestamp)",
+        "(?s).*Was expecting one of.*");
+  }
+
   @Test public void testNumericOperators() {
     // unary operator
     checkExpType("- cast(1 as TINYINT)", "TINYINT NOT NULL");

http://git-wip-us.apache.org/repos/asf/calcite/blob/0b9ea986/site/_docs/reference.md
----------------------------------------------------------------------
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 7bc9bc3..8785bd5 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -379,6 +379,7 @@ FOLLOWING,
 **FOREIGN**,
 FORTRAN,
 FOUND,
+FRAC_SECOND,
 **FREE**,
 **FROM**,
 **FULL**,
@@ -461,6 +462,7 @@ MESSAGE_LENGTH,
 MESSAGE_OCTET_LENGTH,
 MESSAGE_TEXT,
 **METHOD**,
+MICROSECOND,
 **MIN**,
 **MINUTE**,
 MINVALUE,
@@ -544,6 +546,7 @@ PRIOR,
 PRIVILEGES,
 **PROCEDURE**,
 PUBLIC,
+QUARTER,
 **RANGE**,
 **RANK**,
 READ,
@@ -626,6 +629,16 @@ SPECIFIC_NAME,
 **SQLEXCEPTION**,
 **SQLSTATE**,
 **SQLWARNING**,
+SQL_TSI_DAY,
+SQL_TSI_FRAC_SECOND,
+SQL_TSI_HOUR,
+SQL_TSI_MICROSECOND,
+SQL_TSI_MINUTE,
+SQL_TSI_MONTH,
+SQL_TSI_QUARTER,
+SQL_TSI_SECOND,
+SQL_TSI_WEEK,
+SQL_TSI_YEAR,
 **SQRT**,
 **START**,
 STATE,
@@ -652,6 +665,8 @@ TEMPORARY,
 TIES,
 **TIME**,
 **TIMESTAMP**,
+TIMESTAMPADD,
+TIMESTAMPDIFF,
 **TIMEZONE_HOUR**,
 **TIMEZONE_MINUTE**,
 **TINYINT**,
@@ -702,6 +717,7 @@ USER_DEFINED_TYPE_SCHEMA,
 **VAR_SAMP**,
 VERSION,
 VIEW,
+WEEK,
 **WHEN**,
 **WHENEVER**,
 **WHERE**,


[5/5] calcite git commit: Further to [CALCITE-1124], add implementation of TIMESTAMPADD, TIMESTAMPDIFF

Posted by jh...@apache.org.
Further to [CALCITE-1124], add implementation of TIMESTAMPADD, TIMESTAMPDIFF


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

Branch: refs/heads/master
Commit: 4ac82a30b8ee7ae1afcd83c6f3ef687761536f2e
Parents: 0b9ea98
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Mar 7 21:23:34 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 7 21:26:49 2016 -0800

----------------------------------------------------------------------
 core/src/main/codegen/templates/Parser.jj       | 224 +++++++-------
 .../calcite/adapter/enumerable/RexImpTable.java |  10 +-
 .../apache/calcite/sql/SqlJdbcFunctionCall.java | 294 ++++++++-----------
 .../java/org/apache/calcite/sql/SqlKind.java    |  11 +
 .../apache/calcite/sql/TimestampInterval.java   |  47 ---
 .../calcite/sql/fun/SqlStdOperatorTable.java    |  88 +++---
 .../sql2rel/StandardConvertletTable.java        |  72 ++++-
 .../calcite/sql/parser/SqlParserTest.java       |  18 ++
 .../calcite/sql/test/SqlOperatorBaseTest.java   |  64 ++--
 .../org/apache/calcite/sql/test/SqlTests.java   |  90 +-----
 .../apache/calcite/test/SqlValidatorTest.java   |   7 +-
 site/_docs/reference.md                         |  37 +--
 site/community/index.md                         |   1 +
 13 files changed, 452 insertions(+), 511 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/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 01c35bb..c1df4cb 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -82,7 +82,6 @@ import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.SqlWindow;
 import org.apache.calcite.sql.SqlWith;
 import org.apache.calcite.sql.SqlWithItem;
-import org.apache.calcite.sql.TimestampInterval;
 import org.apache.calcite.sql.fun.SqlCase;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.fun.SqlTrimFunction;
@@ -3439,60 +3438,29 @@ TimeUnit TimeUnit() :
     }
 }
 
-SqlLiteral TimestampInterval() :
-{
-SqlLiteral.SqlSymbol symbol = null;
-}
+TimeUnit TimestampInterval() :
+{}
 {
-    (
-        ( <FRAC_SECOND> | <MICROSECOND> | <SQL_TSI_FRAC_SECOND> | <SQL_TSI_MICROSECOND> )
-            {
-                symbol = TimestampInterval.MICROSECOND;
-            }
-        |
-        ( <SECOND> | <SQL_TSI_SECOND> )
-            {
-                symbol = TimestampInterval.SECOND;
-            }
-        |
-        ( <MINUTE> | <SQL_TSI_MINUTE> )
-            {
-                symbol = TimestampInterval.MINUTE;
-            }
-        |
-        ( <HOUR> | <SQL_TSI_HOUR> )
-            {
-                symbol = TimestampInterval.HOUR;
-            }
-        |
-        ( <DAY> | <SQL_TSI_DAY> )
-            {
-                symbol = TimestampInterval.DAY;
-            }
-        |
-         (<WEEK> | <SQL_TSI_WEEK> )
-            {
-                symbol = TimestampInterval.WEEK;
-            }
-        |
-        ( <MONTH> | <SQL_TSI_MONTH> )
-            {
-                symbol = TimestampInterval.MONTH;
-            }
-        |
-        ( <QUARTER> | <SQL_TSI_QUARTER> )
-            {
-                symbol = TimestampInterval.QUARTER;
-            }
-        |
-        ( <YEAR> | <SQL_TSI_YEAR> )
-            {
-                symbol = TimestampInterval.YEAR;
-            }
-    )
-    {
-        return SqlLiteral.createSymbol(symbol, getPos());
-    }
+    <FRAC_SECOND> { return TimeUnit.MICROSECOND; }
+|   <MICROSECOND> { return TimeUnit.MICROSECOND; }
+|   <SQL_TSI_FRAC_SECOND> { return TimeUnit.MICROSECOND; }
+|   <SQL_TSI_MICROSECOND> { return TimeUnit.MICROSECOND; }
+|   <SECOND> { return TimeUnit.SECOND; }
+|   <SQL_TSI_SECOND> { return TimeUnit.SECOND; }
+|   <MINUTE> { return TimeUnit.MINUTE; }
+|   <SQL_TSI_MINUTE> { return TimeUnit.MINUTE; }
+|   <HOUR> { return TimeUnit.HOUR; }
+|   <SQL_TSI_HOUR> { return TimeUnit.HOUR; }
+|   <DAY> { return TimeUnit.DAY; }
+|   <SQL_TSI_DAY> { return TimeUnit.DAY; }
+|   <WEEK> { return TimeUnit.WEEK; }
+|   <SQL_TSI_WEEK> { return TimeUnit.WEEK; }
+|   <MONTH> { return TimeUnit.MONTH; }
+|   <SQL_TSI_MONTH> { return TimeUnit.MONTH; }
+|   <QUARTER> { return TimeUnit.QUARTER; }
+|   <SQL_TSI_QUARTER> { return TimeUnit.QUARTER; }
+|   <YEAR> { return TimeUnit.YEAR; }
+|   <SQL_TSI_YEAR> { return TimeUnit.YEAR; }
 }
 
 
@@ -3962,6 +3930,8 @@ SqlNode BuiltinFunctionCall() :
     SqlParserPos starPos;
     SqlParserPos namePos;
     SqlDataTypeSpec dt;
+    TimeUnit interval;
+    SqlNode node;
 }
 {
     //~ FUNCTIONS WITH SPECIAL SYNTAX ---------------------------------------
@@ -4202,56 +4172,68 @@ SqlNode BuiltinFunctionCall() :
         }
     )
     |
-    (
-        <TIMESTAMPADD>
-            {
-                pos = getPos();
-                SqlLiteral interval;
-            }
-            <LPAREN>
-                interval = TimestampInterval()
-                { args = startList(interval); }
-             <COMMA>
-                 e = Expression(ExprContext.ACCEPT_SUBQUERY)
-                 { args.add(e); }
-             <COMMA>
-                 e = Expression(ExprContext.ACCEPT_SUBQUERY)
-                 { args.add(e); }
-             <RPAREN>
-           {
-              return SqlStdOperatorTable.TIMESTAMP_ADD.createCall(
-                 pos, SqlParserUtil.toNodeArray(args));
-           }
-    )
+    node = TimestampAddFunctionCall() { return node; }
     |
-    (
-        <TIMESTAMPDIFF>
-            {
-                pos = getPos();
-                SqlLiteral interval;
-            }
-            <LPAREN>
-                interval = TimestampInterval()
-                { args = startList(interval); }
-             <COMMA>
-                 e = Expression(ExprContext.ACCEPT_SUBQUERY)
-                 { args.add(e); }
-             <COMMA>
-                 e = Expression(ExprContext.ACCEPT_SUBQUERY)
-                 { args.add(e); }
-             <RPAREN>
-           {
-              return SqlStdOperatorTable.TIMESTAMP_DIFF.createCall(
-                 pos, SqlParserUtil.toNodeArray(args));
-           }
-    )
+    node = TimestampDiffFunctionCall() { return node; }
     |
-    {
-        SqlNode node;
+    node = ExtendedBuiltinFunctionCall() { return node; }
+}
+
+/**
+ * Parses a call to TIMESTAMPADD.
+ */
+SqlCall TimestampAddFunctionCall() :
+{
+    List<SqlNode> args;
+    SqlNode e;
+    SqlParserPos pos;
+    TimeUnit interval;
+    SqlNode node;
+}
+{
+    <TIMESTAMPADD> {
+        pos = getPos();
     }
-    node = ExtendedBuiltinFunctionCall()
-    {
-        return node;
+    <LPAREN>
+    interval = TimestampInterval() {
+        args = startList(SqlLiteral.createSymbol(interval, getPos()));
+    }
+    <COMMA>
+    e = Expression(ExprContext.ACCEPT_SUBQUERY) { args.add(e); }
+    <COMMA>
+    e = Expression(ExprContext.ACCEPT_SUBQUERY) { args.add(e); }
+    <RPAREN> {
+        return SqlStdOperatorTable.TIMESTAMP_ADD.createCall(
+            pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+    }
+}
+
+/**
+ * Parses a call to TIMESTAMPDIFF.
+ */
+SqlCall TimestampDiffFunctionCall() :
+{
+    List<SqlNode> args;
+    SqlNode e;
+    SqlParserPos pos;
+    TimeUnit interval;
+    SqlNode node;
+}
+{
+    <TIMESTAMPDIFF> {
+        pos = getPos();
+    }
+    <LPAREN>
+    interval = TimestampInterval() {
+        args = startList(SqlLiteral.createSymbol(interval, getPos()));
+    }
+    <COMMA>
+    e = Expression(ExprContext.ACCEPT_SUBQUERY) { args.add(e); }
+    <COMMA>
+    e = Expression(ExprContext.ACCEPT_SUBQUERY) { args.add(e); }
+    <RPAREN> {
+        return SqlStdOperatorTable.TIMESTAMP_DIFF.createCall(
+            pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
     }
 }
 
@@ -4529,25 +4511,37 @@ SqlNode JdbcFunctionCall() :
     String name;
     SqlIdentifier id;
     SqlNodeList args;
+    SqlCall call;
     SqlParserPos pos;
     SqlParserPos starPos;
 }
 {
+    <LBRACE_FN>
+    {
+        pos = getPos();
+    }
     (
-        <LBRACE_FN>
-        {
-            pos = getPos();
+        LOOKAHEAD(1)
+        call = TimestampAddFunctionCall() {
+            name = call.getOperator().getName();
+            args = new SqlNodeList(call.getOperandList(), getPos());
+        }
+    |
+        call = TimestampDiffFunctionCall() {
+            name = call.getOperator().getName();
+            args = new SqlNodeList(call.getOperandList(), getPos());
         }
+    |
         (
             // INSERT is a reserved word, but we need to handle {fn insert}
             <INSERT> { name = unquotedIdentifier(); }
-            |
+        |
             // For cases like {fn power(1,2)} and {fn lower('a')}
             id = ReservedFunctionName() { name = id.getSimple(); }
-            |
+        |
             // For cases like {fn substring('foo', 1,2)}
             name = NonReservedJdbcFunctionName()
-            |
+        |
             name = Identifier()
         )
         (
@@ -4556,16 +4550,16 @@ SqlNode JdbcFunctionCall() :
                 args = new SqlNodeList(starPos);
                 args.add(SqlIdentifier.star(starPos));
             }
-            | LOOKAHEAD(2) <LPAREN> <RPAREN>
-            { args = new SqlNodeList(pos); }
-            | args = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_SUBQUERY)
+        |
+            LOOKAHEAD(2) <LPAREN> <RPAREN> { args = new SqlNodeList(pos); }
+        |
+            args = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_SUBQUERY)
         )
-        <RBRACE>
-        {
-            return new SqlJdbcFunctionCall(name).createCall(
-                pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
-        }
     )
+    <RBRACE> {
+        return new SqlJdbcFunctionCall(name).createCall(
+            pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+    }
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/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 2633490..e03f6b8 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
@@ -142,6 +142,7 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MAP_VALUE_CONSTRUCT
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MAX;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MIN;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MINUS;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MINUS_DATE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MOD;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.MULTIPLY;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.NEXT_VALUE;
@@ -245,6 +246,8 @@ public class RexImpTable {
     // datetime
     defineImplementor(DATETIME_PLUS, NullPolicy.STRICT,
         new DatetimeArithmeticImplementor(), false);
+    defineImplementor(MINUS_DATE, NullPolicy.STRICT,
+        new DatetimeArithmeticImplementor(), false);
     defineMethod(EXTRACT_DATE, BuiltInMethod.UNIX_DATE_EXTRACT.method,
         NullPolicy.STRICT);
     defineImplementor(FLOOR, NullPolicy.STRICT,
@@ -1930,7 +1933,12 @@ public class RexImpTable {
         trop1 = Expressions.convert_(trop1, int.class);
         break;
       }
-      return Expressions.add(trop0, trop1);
+      switch (call.getKind()) {
+      case MINUS:
+        return Expressions.subtract(trop0, trop1);
+      default:
+        return Expressions.add(trop0, trop1);
+      }
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java b/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java
index f6849b7..77bb478 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java
@@ -23,9 +23,10 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorScope;
-import org.apache.calcite.util.Util;
 
-import java.util.HashMap;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+
 import java.util.Map;
 
 import static org.apache.calcite.util.Static.RESOURCE;
@@ -435,13 +436,13 @@ public class SqlJdbcFunctionCall extends SqlFunction {
   public SqlCall getLookupCall() {
     if (null == lookupCall) {
       lookupCall =
-          lookupMakeCallObj.createCall(thisOperands, SqlParserPos.ZERO);
+          lookupMakeCallObj.createCall(SqlParserPos.ZERO, thisOperands);
     }
     return lookupCall;
   }
 
   public String getAllowedSignatures(String name) {
-    return lookupMakeCallObj.operator.getAllowedSignatures(name);
+    return lookupMakeCallObj.getOperator().getAllowedSignatures(name);
   }
 
   public RelDataType deriveType(
@@ -470,37 +471,25 @@ public class SqlJdbcFunctionCall extends SqlFunction {
           RESOURCE.functionUndefined(getName()));
     }
 
-    if (!lookupMakeCallObj.checkNumberOfArg(opBinding.getOperandCount())) {
+    final String message = lookupMakeCallObj.isValidArgCount(callBinding);
+    if (message != null) {
       throw callBinding.newValidationError(
           RESOURCE.wrongNumberOfParam(getName(), thisOperands.length,
-              getArgCountMismatchMsg()));
+              message));
     }
 
-    if (!lookupMakeCallObj.operator.checkOperandTypes(
-        new SqlCallBinding(
-            callBinding.getValidator(),
-            callBinding.getScope(),
-            getLookupCall()),
-        false)) {
+    final SqlCall newCall = getLookupCall();
+    final SqlCallBinding newBinding =
+        new SqlCallBinding(callBinding.getValidator(), callBinding.getScope(),
+            newCall);
+
+    final SqlOperator operator = lookupMakeCallObj.getOperator();
+    if (!operator.checkOperandTypes(newBinding, false)) {
       throw callBinding.newValidationSignatureError();
     }
-    return lookupMakeCallObj.operator.validateOperands(
-        callBinding.getValidator(),
-        callBinding.getScope(),
-        getLookupCall());
-  }
 
-  private String getArgCountMismatchMsg() {
-    StringBuilder ret = new StringBuilder();
-    int[] possible = lookupMakeCallObj.getPossibleArgCounts();
-    for (int i = 0; i < possible.length; i++) {
-      if (i > 0) {
-        ret.append(" or ");
-      }
-      ret.append(possible[i]);
-    }
-    ret.append(" parameter(s)");
-    return ret.toString();
+    return operator.validateOperands(callBinding.getValidator(),
+        callBinding.getScope(), newCall);
   }
 
   public void unparse(
@@ -549,59 +538,84 @@ public class SqlJdbcFunctionCall extends SqlFunction {
 
   //~ Inner Classes ----------------------------------------------------------
 
-  /**
-   * Represent a Strategy Object to create a {@link SqlCall} by providing the
-   * feature of reording, adding/dropping operands.
-   */
-  private static class MakeCall {
-    final SqlOperator operator;
-    final int[] order;
-
+  /** Converts a call to a JDBC function to a call to a regular function. */
+  private interface MakeCall {
     /**
-     * List of the possible numbers of operands this function can take.
+     * Creates and return a {@link SqlCall}. If the MakeCall strategy object
+     * was created with a reording specified the call will be created with
+     * the operands reordered, otherwise no change of ordering is applied
+     *
+     * @param operands Operands
      */
-    final int[] argCounts;
+    SqlCall createCall(SqlParserPos pos, SqlNode... operands);
+
+    SqlOperator getOperator();
+
+    String isValidArgCount(SqlCallBinding binding);
+  }
 
-    private MakeCall(
-        SqlOperator operator,
-        int argCount) {
+  /** Converter that calls a built-in function with the same arguments. */
+  public static class SimpleMakeCall implements SqlJdbcFunctionCall.MakeCall {
+    final SqlOperator operator;
+
+    public SimpleMakeCall(SqlOperator operator) {
       this.operator = operator;
-      this.order = null;
-      this.argCounts = new int[]{argCount};
     }
 
+    public SqlOperator getOperator() {
+      return operator;
+    }
+
+    public SqlCall createCall(SqlParserPos pos, SqlNode... operands) {
+      return operator.createCall(pos, operands);
+    }
+
+    public String isValidArgCount(SqlCallBinding binding) {
+      return null; // any number of arguments is valid
+    }
+  }
+
+  /** Implementation of {@link MakeCall} that can re-order or ignore operands. */
+  private static class PermutingMakeCall extends SimpleMakeCall {
+    final int[] order;
+
     /**
      * Creates a MakeCall strategy object with reordering of operands.
      *
      * <p>The reordering is specified by an int array where the value of
      * element at position <code>i</code> indicates to which element in a
      * new SqlNode[] array the operand goes.
-     *
-     * @param operator Operator
+     *  @param operator Operator
      * @param order    Order
-     * @pre order != null
-     * @pre order[i] &lt; order.length
-     * @pre order.length &gt; 0
-     * @pre argCounts == order.length
      */
-    MakeCall(SqlOperator operator, int argCount, int[] order) {
-      assert order != null && order.length > 0;
+    PermutingMakeCall(SqlOperator operator, int[] order) {
+      super(operator);
+      this.order = Preconditions.checkNotNull(order);
+    }
 
-      // Currently operation overloading when reordering is necessary is
-      // NOT implemented
-      Util.pre(argCount == order.length, "argCounts==order.length");
-      this.operator = operator;
-      this.order = order;
-      this.argCounts = new int[]{order.length};
+    @Override public SqlCall createCall(SqlParserPos pos,
+        SqlNode... operands) {
+      return super.createCall(pos, reorder(operands));
+    }
 
-      // sanity checking ...
-      for (int anOrder : order) {
-        assert anOrder < order.length;
+    @Override public String isValidArgCount(SqlCallBinding binding) {
+      if (order.length == binding.getOperandCount()) {
+        return null; // operand count is valid
+      } else {
+        return getArgCountMismatchMsg(order.length);
       }
     }
 
-    final int[] getPossibleArgCounts() {
-      return this.argCounts;
+    private String getArgCountMismatchMsg(int... possible) {
+      StringBuilder ret = new StringBuilder();
+      for (int i = 0; i < possible.length; i++) {
+        if (i > 0) {
+          ret.append(" or ");
+        }
+        ret.append(possible[i]);
+      }
+      ret.append(" parameter(s)");
+      return ret.toString();
     }
 
     /**
@@ -620,37 +634,6 @@ public class SqlJdbcFunctionCall extends SqlFunction {
       }
       return newOrder;
     }
-
-    /**
-     * Creates and return a {@link SqlCall}. If the MakeCall strategy object
-     * was created with a reording specified the call will be created with
-     * the operands reordered, otherwise no change of ordering is applied
-     *
-     * @param operands Operands
-     */
-    SqlCall createCall(
-        SqlNode[] operands,
-        SqlParserPos pos) {
-      if (null == order) {
-        return operator.createCall(pos, operands);
-      }
-      return operator.createCall(pos, reorder(operands));
-    }
-
-    /**
-     * Returns false if number of arguments are unexpected, otherwise true.
-     * This function is supposed to be called with an {@link SqlNode} array
-     * of operands direct from the oven, e.g no reording or adding/dropping
-     * of operands...else it would make much sense to have this methods
-     */
-    boolean checkNumberOfArg(int length) {
-      for (int argCount : argCounts) {
-        if (argCount == length) {
-          return true;
-        }
-      }
-      return false;
-    }
   }
 
   /**
@@ -663,99 +646,62 @@ public class SqlJdbcFunctionCall extends SqlFunction {
      */
     static final JdbcToInternalLookupTable INSTANCE =
         new JdbcToInternalLookupTable();
-    private final Map<String, MakeCall> map = new HashMap<String, MakeCall>();
+
+    private final Map<String, MakeCall> map;
 
     private JdbcToInternalLookupTable() {
       // A table of all functions can be found at
       // http://java.sun.com/products/jdbc/driverdevs.html
       // which is also provided in the javadoc for this class.
       // See also SqlOperatorTests.testJdbcFn, which contains the list.
-      map.put(
-          "ABS",
-          new MakeCall(SqlStdOperatorTable.ABS, 1));
-      map.put(
-          "EXP",
-          new MakeCall(SqlStdOperatorTable.EXP, 1));
-      map.put(
-          "LOG",
-          new MakeCall(SqlStdOperatorTable.LN, 1));
-      map.put(
-          "LOG10",
-          new MakeCall(SqlStdOperatorTable.LOG10, 1));
-      map.put(
-          "MOD",
-          new MakeCall(SqlStdOperatorTable.MOD, 2));
-      map.put(
-          "POWER",
-          new MakeCall(SqlStdOperatorTable.POWER, 2));
-
-      map.put(
-          "CONCAT",
-          new MakeCall(SqlStdOperatorTable.CONCAT, 2));
-      map.put(
-          "INSERT",
-          new MakeCall(
-              SqlStdOperatorTable.OVERLAY,
-              4,
-              new int[]{0, 2, 3, 1}));
-      map.put(
-          "LCASE",
-          new MakeCall(SqlStdOperatorTable.LOWER, 1));
-      map.put(
-          "LENGTH",
-          new MakeCall(SqlStdOperatorTable.CHARACTER_LENGTH, 1));
-      map.put(
-          "LOCATE",
-          new MakeCall(SqlStdOperatorTable.POSITION, 2));
-      map.put(
-          "LTRIM",
-          new MakeCall(SqlStdOperatorTable.TRIM, 1) {
-            @Override SqlCall createCall(
-                SqlNode[] operands, SqlParserPos pos) {
+      ImmutableMap.Builder<String, MakeCall> map = ImmutableMap.builder();
+      map.put("ABS", simple(SqlStdOperatorTable.ABS));
+      map.put("EXP", simple(SqlStdOperatorTable.EXP));
+      map.put("LOG", simple(SqlStdOperatorTable.LN));
+      map.put("LOG10", simple(SqlStdOperatorTable.LOG10));
+      map.put("MOD", simple(SqlStdOperatorTable.MOD));
+      map.put("POWER", simple(SqlStdOperatorTable.POWER));
+      map.put("CONCAT", simple(SqlStdOperatorTable.CONCAT));
+      map.put("INSERT",
+          new PermutingMakeCall(SqlStdOperatorTable.OVERLAY, new int[]{0, 2, 3, 1}));
+      map.put("LCASE", simple(SqlStdOperatorTable.LOWER));
+      map.put("LENGTH", simple(SqlStdOperatorTable.CHARACTER_LENGTH));
+      map.put("LOCATE", simple(SqlStdOperatorTable.POSITION));
+      map.put("LTRIM",
+          new SimpleMakeCall(SqlStdOperatorTable.TRIM) {
+            @Override public SqlCall createCall(SqlParserPos pos,
+                SqlNode... operands) {
               assert 1 == operands.length;
-              return super.createCall(
-                  new SqlNode[]{
-                    SqlTrimFunction.Flag.LEADING.symbol(SqlParserPos.ZERO),
-                    SqlLiteral.createCharString(" ", null),
-                    operands[0]
-                  },
-                  pos);
+              return super.createCall(pos,
+                  SqlTrimFunction.Flag.LEADING.symbol(SqlParserPos.ZERO),
+                  SqlLiteral.createCharString(" ", null),
+                  operands[0]);
             }
           });
-      map.put(
-          "QUARTER",
-          new MakeCall(SqlStdOperatorTable.QUARTER, 1));
-      map.put(
-          "RTRIM",
-          new MakeCall(SqlStdOperatorTable.TRIM, 1) {
-            @Override SqlCall createCall(
-                SqlNode[] operands, SqlParserPos pos) {
+      map.put("QUARTER", simple(SqlStdOperatorTable.QUARTER));
+      map.put("RTRIM",
+          new SimpleMakeCall(SqlStdOperatorTable.TRIM) {
+            @Override public SqlCall createCall(SqlParserPos pos,
+                SqlNode... operands) {
               assert 1 == operands.length;
-              return super.createCall(
-                  new SqlNode[] {
-                    SqlTrimFunction.Flag.TRAILING.symbol(SqlParserPos.ZERO),
-                    SqlLiteral.createCharString(" ", null),
-                    operands[0]
-                  },
-                  pos);
+              return super.createCall(pos,
+                  SqlTrimFunction.Flag.TRAILING.symbol(SqlParserPos.ZERO),
+                  SqlLiteral.createCharString(" ", null),
+                  operands[0]);
             }
           });
-      map.put(
-          "SUBSTRING",
-          new MakeCall(SqlStdOperatorTable.SUBSTRING, 3));
-      map.put(
-          "UCASE",
-          new MakeCall(SqlStdOperatorTable.UPPER, 1));
-
-      map.put(
-          "CURDATE",
-          new MakeCall(SqlStdOperatorTable.CURRENT_DATE, 0));
-      map.put(
-          "CURTIME",
-          new MakeCall(SqlStdOperatorTable.LOCALTIME, 0));
-      map.put(
-          "NOW",
-          new MakeCall(SqlStdOperatorTable.CURRENT_TIMESTAMP, 0));
+      map.put("SUBSTRING", simple(SqlStdOperatorTable.SUBSTRING));
+      map.put("UCASE", simple(SqlStdOperatorTable.UPPER));
+      map.put("CURDATE", simple(SqlStdOperatorTable.CURRENT_DATE));
+      map.put("CURTIME", simple(SqlStdOperatorTable.LOCALTIME));
+      map.put("NOW", simple(SqlStdOperatorTable.CURRENT_TIMESTAMP));
+      map.put("TIMESTAMPADD", simple(SqlStdOperatorTable.TIMESTAMP_ADD));
+      map.put("TIMESTAMPDIFF", simple(SqlStdOperatorTable.TIMESTAMP_DIFF));
+      this.map = map.build();
+    }
+
+    private MakeCall simple(SqlOperator operator) {
+      return new SimpleMakeCall(operator);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/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 7f34162..07d2bca 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -361,6 +361,16 @@ public enum SqlKind {
    */
   LEAST,
 
+  /**
+   * The "TIMESTAMP_ADD" function (ODBC, SQL Server, MySQL).
+   */
+  TIMESTAMP_ADD,
+
+  /**
+   * The "TIMESTAMP_DIFF" function (ODBC, SQL Server, MySQL).
+   */
+  TIMESTAMP_DIFF,
+
   // prefix operators
 
   /**
@@ -858,6 +868,7 @@ public enum SqlKind {
               EnumSet.of(AS, ARGUMENT_ASSIGNMENT, DEFAULT,
                   DESCENDING, CUBE, ROLLUP, GROUPING_SETS, EXTEND,
                   SELECT, JOIN, OTHER_FUNCTION, CAST, TRIM, FLOOR, CEIL,
+                  TIMESTAMP_ADD, TIMESTAMP_DIFF,
                   LITERAL_CHAIN, JDBC_FN, PRECEDING, FOLLOWING, ORDER_BY,
                   NULLS_FIRST, NULLS_LAST, COLLECTION_TABLE, TABLESAMPLE,
                   VALUES, WITH, WITH_ITEM),

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/core/src/main/java/org/apache/calcite/sql/TimestampInterval.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/TimestampInterval.java b/core/src/main/java/org/apache/calcite/sql/TimestampInterval.java
deleted file mode 100644
index d586d4a..0000000
--- a/core/src/main/java/org/apache/calcite/sql/TimestampInterval.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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;
-
-import org.apache.calcite.sql.parser.SqlParserPos;
-
-/**
- * Enumerates the timestamp intervals.
- */
-public enum TimestampInterval implements SqlLiteral.SqlSymbol  {
-
-  MICROSECOND,
-  SECOND,
-  MINUTE,
-  HOUR,
-  DAY,
-  WEEK,
-  MONTH,
-  QUARTER,
-  YEAR;
-
-  /**
-   * Creates a parse-tree node representing an occurrence of this
-   * condition type keyword at a particular position in the parsed
-   * text.
-   */
-  public SqlLiteral symbol(SqlParserPos pos) {
-    return SqlLiteral.createSymbol(this, pos);
-  }
-
-}
-
-// End TimestampInterval.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/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 98d2e85..c075363 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
@@ -1316,66 +1316,66 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
       new SqlCurrentDateFunction();
 
   /**
-   * <p>Timestamp modifying or calculating difference functions.
-   * As first parameter take timestamp interval.
-   * </p>
-   *
-   * <p>Interval can one of the following literals:<br>
-   * <i>FRAC_SECOND, MICROSECOND, SQL_TSI_FRAC_SECOND, SQL_TSI_MICROSECOND</i><br>
-   * <i>SECOND, SQL_TSI_SECOND</i><br>
-   * <i>MINUTE, SQL_TSI_MINUTE</i><br>
-   * <i>HOUR, SQL_TSI_HOUR</i><br>
-   * <i>DAY, SQL_TSI_DAY</i><br>
-   * <i>WEEK, SQL_TSI_WEEK</i><br>
-   * <i>MONTH, SQL_TSI_MONTH</i><br>
-   * <i>QUARTER, SQL_TSI_QUARTER</i><br>
-   * <i>YEAR, SQL_TSI_YEAR</i><br>
-   * </p>
-   */
-
-  /**
-   * <p>The SQL <code>TIMESTAMP_ADD</code> function.
-   * Adds interval to timestamp.</p>
+   * <p>The <code>TIMESTAMPADD</code> function, which adds an interval to a
+   * timestamp.
    *
    * <p>The SQL syntax is
    *
    * <blockquote>
-   * <code>TIMESTAMP_ADD(<i>timestamp interval</i>,<i>quantity</i>,<i>timestamp</i>)</code>
-   * </blockquote><br>
+   * <code>TIMESTAMPADD(<i>timestamp interval</i>, <i>quantity</i>, <i>timestamp</i>)</code>
+   * </blockquote>
    *
-   * Returns modified timestamp.</p>
+   * <p>The interval time unit can one of the following literals:<ul>
+   * <li>MICROSECOND (and synonyms SQL_TSI_MICROSECOND, FRAC_SECOND,
+   *     SQL_TSI_FRAC_SECOND)
+   * <li>SECOND (and synonym SQL_TSI_SECOND)
+   * <li>MINUTE (and synonym  SQL_TSI_MINUTE)
+   * <li>HOUR (and synonym  SQL_TSI_HOUR)
+   * <li>DAY (and synonym SQL_TSI_DAY)
+   * <li>WEEK (and synonym  SQL_TSI_WEEK)
+   * <li>MONTH (and synonym SQL_TSI_MONTH)
+   * <li>QUARTER (and synonym SQL_TSI_QUARTER)
+   * <li>YEAR (and synonym  SQL_TSI_YEAR)
+   * </ul>
+   *
+   * <p>Returns modified timestamp.
    */
   public static final SqlFunction TIMESTAMP_ADD =
-      new SqlFunction(
-          "TIMESTAMPADD",
-          SqlKind.OTHER_FUNCTION,
-          ReturnTypes.ARG2,
+      new SqlFunction("TIMESTAMPADD", SqlKind.TIMESTAMP_ADD, ReturnTypes.ARG2,
           null,
-          OperandTypes.family(
-              SqlTypeFamily.ANY, SqlTypeFamily.INTEGER, SqlTypeFamily.DATETIME),
-          SqlFunctionCategory.TIMEDATE);
+          OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.INTEGER,
+              SqlTypeFamily.DATETIME), SqlFunctionCategory.TIMEDATE);
 
   /**
-   * <p>The SQL <code>TIMESTAMP_DIFF</code> function.
-   * Calculates difference between two timestamps.</p>
+   * <p>The <code>TIMESTAMPDIFF</code> function, which calculates the difference
+   * between two timestamps.
    *
    * <p>The SQL syntax is
    *
    * <blockquote>
-   * <code>TIMESTAMP_DIFF(<i>timestamp interval</i>,<i>timestamp</i>,<i>timestamp</i>)</code>
-   * </blockquote><br>
+   * <code>TIMESTAMPDIFF(<i>timestamp interval</i>, <i>timestamp</i>, <i>timestamp</i>)</code>
+   * </blockquote>
    *
-   * Returns difference between two timestamps in indicated timestamp interval.</p>
+   * <p>The interval time unit can one of the following literals:<ul>
+   * <li>MICROSECOND (and synonyms SQL_TSI_MICROSECOND, FRAC_SECOND,
+   *     SQL_TSI_FRAC_SECOND)
+   * <li>SECOND (and synonym SQL_TSI_SECOND)
+   * <li>MINUTE (and synonym  SQL_TSI_MINUTE)
+   * <li>HOUR (and synonym  SQL_TSI_HOUR)
+   * <li>DAY (and synonym SQL_TSI_DAY)
+   * <li>WEEK (and synonym  SQL_TSI_WEEK)
+   * <li>MONTH (and synonym SQL_TSI_MONTH)
+   * <li>QUARTER (and synonym SQL_TSI_QUARTER)
+   * <li>YEAR (and synonym  SQL_TSI_YEAR)
+   * </ul>
+   *
+   * <p>Returns difference between two timestamps in indicated timestamp interval.
    */
-  public static final SqlFunction TIMESTAMP_DIFF = new SqlFunction(
-      "TIMESTAMPDIFF",
-      SqlKind.OTHER_FUNCTION,
-      ReturnTypes.INTEGER_NULLABLE,
-      null,
-      OperandTypes.family(
-          SqlTypeFamily.ANY, SqlTypeFamily.DATETIME, SqlTypeFamily.DATETIME),
-      SqlFunctionCategory.TIMEDATE);
-
+  public static final SqlFunction TIMESTAMP_DIFF =
+      new SqlFunction("TIMESTAMPDIFF", SqlKind.TIMESTAMP_DIFF,
+          ReturnTypes.INTEGER_NULLABLE, null,
+          OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.DATETIME,
+              SqlTypeFamily.DATETIME), SqlFunctionCategory.TIMEDATE);
 
   /**
    * Use of the <code>IN_FENNEL</code> operator forces the argument to be

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
index 5d1957f..44d6fe5 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -285,10 +285,13 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
         SqlStdOperatorTable.VAR_SAMP,
         new AvgVarianceConvertlet(SqlKind.VAR_SAMP));
 
-    registerOp(
-        SqlStdOperatorTable.FLOOR, new FloorCeilConvertlet(true));
-    registerOp(
-        SqlStdOperatorTable.CEIL, new FloorCeilConvertlet(false));
+    final SqlRexConvertlet floorCeilConvertlet = new FloorCeilConvertlet();
+    registerOp(SqlStdOperatorTable.FLOOR, floorCeilConvertlet);
+    registerOp(SqlStdOperatorTable.CEIL, floorCeilConvertlet);
+
+    registerOp(SqlStdOperatorTable.TIMESTAMP_ADD,
+        new TimestampAddConvertlet());
+    registerOp(SqlStdOperatorTable.TIMESTAMP_DIFF, new TimestampDiffConvertlet());
 
     // Convert "element(<expr>)" to "$element_slice(<expr>)", if the
     // expression is a multiset of scalars.
@@ -503,10 +506,8 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     return cx.getRexBuilder().makeCast(type, arg);
   }
 
-  protected RexNode convertFloorCeil(
-      SqlRexContext cx,
-      SqlCall call,
-      boolean floor) {
+  protected RexNode convertFloorCeil(SqlRexContext cx, SqlCall call) {
+    final boolean floor = call.getKind() == SqlKind.FLOOR;
     // Rewrite floor, ceil of interval
     if (call.operandCount() == 1
         && call.operand(0) instanceof SqlIntervalLiteral) {
@@ -671,6 +672,19 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     if (val.equals(BigDecimal.ONE)) {
       return res;
     }
+    // If val is between 0 and 1, rather than divide by val, multiply by its
+    // reciprocal. For example, rather than divide by 0.001 multiply by 1000.
+    if (val.compareTo(BigDecimal.ONE) < 0
+        && val.signum() == 1) {
+      try {
+        final BigDecimal reciprocal =
+            BigDecimal.ONE.divide(val, BigDecimal.ROUND_UNNECESSARY);
+        return rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, res,
+            rexBuilder.makeExactLiteral(reciprocal));
+      } catch (ArithmeticException e) {
+        // ignore - reciprocal is not an integer
+      }
+    }
     return rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE_INTEGER, res,
         rexBuilder.makeExactLiteral(val));
   }
@@ -1323,14 +1337,48 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
 
   /** Convertlet that handles {@code FLOOR} and {@code CEIL} functions. */
   private class FloorCeilConvertlet implements SqlRexConvertlet {
-    private final boolean floor;
+    public RexNode convertCall(SqlRexContext cx, SqlCall call) {
+      return convertFloorCeil(cx, call);
+    }
+  }
 
-    public FloorCeilConvertlet(boolean floor) {
-      this.floor = floor;
+  /** Convertlet that handles the {@code TIMESTAMPADD} function. */
+  private class TimestampAddConvertlet implements SqlRexConvertlet {
+    public RexNode convertCall(SqlRexContext cx, SqlCall call) {
+      // TIMESTAMPADD(unit, count, timestamp)
+      //  => timestamp + count * INTERVAL '1' UNIT
+      final RexBuilder rexBuilder = cx.getRexBuilder();
+      final SqlLiteral unitLiteral = call.operand(0);
+      final TimeUnit unit = unitLiteral.symbolValue(TimeUnit.class);
+      return rexBuilder.makeCall(SqlStdOperatorTable.DATETIME_PLUS,
+          cx.convertExpression(call.operand(2)),
+          rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY,
+              rexBuilder.makeIntervalLiteral(unit.multiplier,
+                  new SqlIntervalQualifier(unit, null,
+                      unitLiteral.getParserPosition())),
+              cx.convertExpression(call.operand(1))));
     }
+  }
 
+  /** Convertlet that handles the {@code TIMESTAMPDIFF} function. */
+  private class TimestampDiffConvertlet implements SqlRexConvertlet {
     public RexNode convertCall(SqlRexContext cx, SqlCall call) {
-      return convertFloorCeil(cx, call, floor);
+      // TIMESTAMPDIFF(unit, t1, t2)
+      //    => (t1 - t2) UNIT
+      final RexBuilder rexBuilder = cx.getRexBuilder();
+      final SqlLiteral unitLiteral = call.operand(0);
+      final TimeUnit unit = unitLiteral.symbolValue(TimeUnit.class);
+      final RelDataType intType =
+          cx.getTypeFactory().createSqlType(SqlTypeName.INTEGER);
+      final SqlIntervalQualifier qualifier =
+          new SqlIntervalQualifier(unit, null, SqlParserPos.ZERO);
+      return divide(cx.getRexBuilder(),
+          rexBuilder.makeCast(intType,
+              rexBuilder.makeCall(SqlStdOperatorTable.MINUS_DATE,
+                  cx.convertExpression(call.operand(1)),
+                  cx.convertExpression(call.operand(2)),
+                  cx.getRexBuilder().makeIntervalLiteral(qualifier))),
+          unit.multiplier);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
index 858e8a0..0d7d614 100644
--- a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
@@ -5566,6 +5566,24 @@ public class SqlParserTest {
         "(?s).*Was expecting one of.*");
   }
 
+  @Test public void testTimestampAdd() {
+    final String sql = "select * from t\n"
+        + "where timestampadd(sql_tsi_month, 5, hiredate) < curdate";
+    final String expected = "SELECT *\n"
+        + "FROM `T`\n"
+        + "WHERE (TIMESTAMPADD(MONTH, 5, `HIREDATE`) < `CURDATE`)";
+    sql(sql).ok(expected);
+  }
+
+  @Test public void testTimestampDiff() {
+    final String sql = "select * from t\n"
+        + "where timestampdiff(frac_second, 5, hiredate) < curdate";
+    final String expected = "SELECT *\n"
+        + "FROM `T`\n"
+        + "WHERE (TIMESTAMPDIFF(MICROSECOND, 5, `HIREDATE`) < `CURDATE`)";
+    sql(sql).ok(expected);
+  }
+
   @Test public void testUnnest() {
     check(
         "select*from unnest(x)",

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 48311dd..1c5ec79 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -1727,18 +1727,12 @@ public abstract class SqlOperatorBaseTest {
     if (false) {
       tester.checkScalar("{fn SECOND(time)}", null, "");
     }
-    if (false) {
-      tester.checkScalar(
-          "{fn TIMESTAMPADD(interval, count, timestamp)}",
-          null,
-          "");
-    }
-    if (false) {
-      tester.checkScalar(
-          "{fn TIMESTAMPDIFF(interval, timestamp1, timestamp2)}",
-          null,
-          "");
-    }
+    tester.checkScalar("{fn TIMESTAMPADD(HOUR, 5,"
+        + " TIMESTAMP '2014-03-29 12:34:56')}",
+        "2014-03-29 17:34:56", "TIMESTAMP(0) NOT NULL");
+    tester.checkScalar("{fn TIMESTAMPDIFF(HOUR,"
+        + " TIMESTAMP '2014-03-29 12:34:56',"
+        + " TIMESTAMP '2014-03-29 12:34:56')}", "0", "INTEGER NOT NULL");
     if (false) {
       tester.checkScalar("{fn WEEK(date)}", null, "");
     }
@@ -4599,18 +4593,48 @@ public abstract class SqlOperatorBaseTest {
         "floor(cast(null as interval year))");
   }
 
-  @Test public void testTimestampAddAdnDiff() {
-    if (!enable) {
-      return;
-    }
+  @Test public void testTimestampAdd() {
+    tester.setFor(SqlStdOperatorTable.TIMESTAMP_ADD);
     tester.checkScalar(
-        "timestampadd(MINUTE, 2, timestamp '2016-02-24 12:42:25')",
+        "timestampadd(SQL_TSI_SECOND, 2, timestamp '2016-02-24 12:42:25')",
         "2016-02-24 12:42:27",
         "TIMESTAMP(0) NOT NULL");
     tester.checkScalar(
-        "timestampdiff(YEAR, "
-            + "timestamp '2014-02-24 12:42:25', "
-            + "timestamp '2016-02-24 12:42:25')",
+        "timestampadd(MINUTE, 2, timestamp '2016-02-24 12:42:25')",
+        "2016-02-24 12:44:25",
+        "TIMESTAMP(0) NOT NULL");
+    tester.checkScalar(
+        "timestampadd(HOUR, -2000, timestamp '2016-02-24 12:42:25')",
+        "2015-12-03 04:42:25",
+        "TIMESTAMP(0) NOT NULL");
+    if (!INTERVAL) {
+      return;
+    }
+    tester.checkNull("timestampadd(HOUR, CAST(NULL AS INTEGER),"
+        + " timestamp '2016-02-24 12:42:25')");
+    tester.checkNull(
+        "timestampadd(HOUR, -200, CAST(NULL AS TIMESTAMP))");
+    tester.checkScalar(
+        "timestampadd(MONTH, 3, timestamp '2016-02-24 12:42:25')",
+        "2016-05-24 12:42:25", "TIMESTAMP(0) NOT NULL");
+  }
+
+  @Test public void testTimestampDiff() {
+    tester.setFor(SqlStdOperatorTable.TIMESTAMP_DIFF);
+    tester.checkScalar("timestampdiff(HOUR, "
+        + "timestamp '2016-02-24 12:42:25', "
+        + "timestamp '2016-02-24 15:42:25')",
+        "-3", "INTEGER NOT NULL");
+    tester.checkScalar("timestampdiff(MICROSECOND, "
+        + "timestamp '2016-02-24 12:42:25', "
+        + "timestamp '2016-02-24 12:42:20')",
+        "5000000", "INTEGER NOT NULL");
+    if (!INTERVAL) {
+      return;
+    }
+    tester.checkScalar("timestampdiff(YEAR, "
+        + "timestamp '2014-02-24 12:42:25', "
+        + "timestamp '2016-02-24 12:42:25')",
         "2", "INTEGER NOT NULL");
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java b/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
index 4f15f7d..d5889fb 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
@@ -22,10 +22,8 @@ import org.apache.calcite.sql.type.SqlTypeName;
 
 import java.sql.ResultSet;
 import java.sql.Types;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 import java.util.regex.Pattern;
 
@@ -135,7 +133,7 @@ public abstract class SqlTests {
   public static void compareResultSet(
       ResultSet resultSet,
       Set<String> refSet) throws Exception {
-    Set<String> actualSet = new HashSet<String>();
+    Set<String> actualSet = new HashSet<>();
     final int columnType = resultSet.getMetaData().getColumnType(1);
     final ColumnMetaData.Rep rep = rep(columnType);
     while (resultSet.next()) {
@@ -151,7 +149,13 @@ public abstract class SqlTests {
       case SHORT:
       case INTEGER:
       case LONG:
-        final long l = Long.parseLong(s0);
+        long l;
+        try {
+          l = Long.parseLong(s0);
+        } catch (NumberFormatException e) {
+          // Large integers come out in scientific format, say "5E+06"
+          l = (long) Double.parseDouble(s0);
+        }
         assertThat(resultSet.getByte(1), equalTo((byte) l));
         assertThat(resultSet.getShort(1), equalTo((short) l));
         assertThat(resultSet.getInt(1), equalTo((int) l));
@@ -256,78 +260,6 @@ public abstract class SqlTests {
     }
   }
 
-  /**
-   * Compares the first column of a result set against a String-valued
-   * reference set, taking order into account.
-   *
-   * @param resultSet Result set
-   * @param refList   Expected results
-   * @throws Exception .
-   */
-  public static void compareResultList(
-      ResultSet resultSet,
-      List<String> refList) throws Exception {
-    List<String> actualSet = new ArrayList<String>();
-    while (resultSet.next()) {
-      String s = resultSet.getString(1);
-      actualSet.add(s);
-    }
-    resultSet.close();
-    assertEquals(refList, actualSet);
-  }
-
-  /**
-   * Compares the columns of a result set against several String-valued
-   * reference lists, taking order into account.
-   *
-   * @param resultSet Result set
-   * @param refLists  vararg of List&lt;String&gt;. The first list is compared
-   *                  to the first column, the second list to the second column
-   *                  and so on
-   */
-  public static void compareResultLists(
-      ResultSet resultSet,
-      List<String>... refLists) throws Exception {
-    int numExpectedColumns = refLists.length;
-
-    assertTrue(numExpectedColumns > 0);
-
-    assertTrue(
-        resultSet.getMetaData().getColumnCount() >= numExpectedColumns);
-
-    int numExpectedRows = -1;
-
-    List<List<String>> actualLists = new ArrayList<List<String>>();
-    for (int i = 0; i < numExpectedColumns; i++) {
-      actualLists.add(new ArrayList<String>());
-
-      if (i == 0) {
-        numExpectedRows = refLists[i].size();
-      } else {
-        assertEquals(
-            "num rows differ across ref lists",
-            numExpectedRows,
-            refLists[i].size());
-      }
-    }
-
-    while (resultSet.next()) {
-      for (int i = 0; i < numExpectedColumns; i++) {
-        String s = resultSet.getString(i + 1);
-
-        actualLists.get(i).add(s);
-      }
-    }
-    resultSet.close();
-
-    for (int i = 0; i < numExpectedColumns; i++) {
-      assertEquals(
-          "column mismatch in column " + (i + 1),
-          refLists[i],
-          actualLists.get(i));
-    }
-  }
-
   //~ Inner Classes ----------------------------------------------------------
 
   /**
@@ -382,11 +314,13 @@ public abstract class SqlTests {
       assertTrue(result instanceof Number);
       return new ApproximateResultChecker((Number) result, delta);
     } else {
-      Set<String> refSet = new HashSet<String>();
+      Set<String> refSet = new HashSet<>();
       if (result == null) {
         refSet.add(null);
       } else if (result instanceof Collection) {
-        refSet.addAll((Collection<String>) result);
+        //noinspection unchecked
+        final Collection<String> collection = (Collection<String>) result;
+        refSet.addAll(collection);
       } else {
         refSet.add(result.toString());
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index c8ba8e9..a56237c 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -1133,9 +1133,10 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     checkWholeExpFails(
         "{fn log10('1')}",
         "(?s).*Cannot apply.*fn LOG10..<CHAR.1.>.*");
-    checkWholeExpFails(
-        "{fn log10(1,1)}",
-        "(?s).*Encountered .fn LOG10. with 2 parameter.s.; was expecting 1 parameter.s.*");
+    final String expected = "Cannot apply '\\{fn LOG10\\}' to arguments of"
+        + " type '\\{fn LOG10\\}\\(<INTEGER>, <INTEGER>\\)'\\. "
+        + "Supported form\\(s\\): '\\{fn LOG10\\}\\(<NUMERIC>\\)'";
+    checkWholeExpFails("{fn log10(1,1)}", expected);
     checkWholeExpFails(
         "{fn fn(1)}",
         "(?s).*Function '.fn FN.' is not defined.*");

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/site/_docs/reference.md
----------------------------------------------------------------------
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 8785bd5..af05ad2 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -979,12 +979,15 @@ See also: UNNEST relational operator converts a collection to a relation.
 
 | Operator syntax                | Description
 |:------------------------------ |:-----------
+| {fn ABS(numeric)}              | Returns the absolute value of *numeric*
+| {fn EXP(numeric)}              | Returns *e* raised to the power of *numeric*
+| {fn LOG(numeric)}              | Returns the natural logarithm (base *e*) of *numeric*
 | {fn LOG10(numeric)}            | Returns the base-10 logarithm of *numeric*
+| {fn MOD(numeric1, numeric2)}   | Returns the remainder (modulus) of *numeric1* divided by *numeric2*. The result is negative only if *numeric1* is negative
 | {fn POWER(numeric1, numeric2)} | Returns *numeric1* raised to the power of *numeric2*
 
 Not implemented:
 
-* {fn ABS(numeric)} - Returns the absolute value of *numeric*
 * {fn ACOS(numeric)} - Returns the arc cosine of *numeric*
 * {fn ASIN(numeric)} - Returns the arc sine of *numeric*
 * {fn ATAN(numeric)} - Returns the arc tangent of *numeric*
@@ -993,10 +996,7 @@ Not implemented:
 * {fn COS(numeric)} - Returns the cosine of *numeric*
 * {fn COT(numeric)}
 * {fn DEGREES(numeric)} - Converts *numeric* from radians to degrees
-* {fn EXP(numeric)} - Returns *e* raised to the power of *numeric*
 * {fn FLOOR(numeric)} - Rounds *numeric* down, and returns the largest number that is less than or equal to *numeric*
-* {fn LOG(numeric)} - Returns the natural logarithm (base *e*) of *numeric*
-* {fn MOD(numeric1, numeric2)} - Returns the remainder (modulus) of *numeric1* divided by *numeric2*. The result is negative only if *numeric1* is negative
 * {fn PI()} - Returns a value that is closer than any other value to *pi*
 * {fn RADIANS(numeric)} - Converts *numeric* from degrees to radians
 * {fn RAND(numeric)}
@@ -1011,35 +1011,42 @@ Not implemented:
 
 | Operator syntax | Description
 |:--------------- |:-----------
+| {fn CONCAT(character, character)} | Returns the concatenation of character strings
 | {fn LOCATE(string1, string2)} | Returns the position in *string2* of the first occurrence of *string1*. Searches from the beginning of the second CharacterExpression, unless the startIndex parameter is specified.
 | {fn INSERT(string1, start, length, string2)} | Inserts *string2* into a slot in *string1*
 | {fn LCASE(string)}            | Returns a string in which all alphabetic characters in *string* have been converted to lower case
+| {fn LENGTH(string)} | Returns the number of characters in a string
+| {fn LOCATE(string1, string2 [, integer])} | Returns the position in *string2* of the first occurrence of *string1*. Searches from the beginning of *string2*, unless *integer* is specified.
+| {fn LTRIM(string)} | Returns *string* with leading space characters removed
+| {fn RTRIM(string)} | Returns *string* with trailing space characters removed
+| {fn SUBSTRING(string, offset, length)} | Returns a character string that consists of *length* characters from *string* starting at the *offset* position
+| {fn UCASE(string)} | Returns a string in which all alphabetic characters in *string* have been converted to upper case
 
 Not implemented:
 
 * {fn ASCII(string)} - Convert a single-character string to the corresponding ASCII code, an integer between 0 and 255
 * {fn CHAR(string)}
-* {fn CONCAT(character, character)} - Returns the concatenation of character strings
 * {fn DIFFERENCE(string, string)}
 * {fn LEFT(string, integer)}
-* {fn LENGTH(string)}
-* {fn LOCATE(string1, string2 [, integer])} - Returns the position in *string2* of the first occurrence of *string1*. Searches from the beginning of *string2*, unless *integer* is specified.
-* {fn LTRIM(string)}
 * {fn REPEAT(string, integer)}
 * {fn REPLACE(string, string, string)}
 * {fn RIGHT(string, integer)}
-* {fn RTRIM(string)}
 * {fn SOUNDEX(string)}
 * {fn SPACE(integer)}
-* {fn SUBSTRING(string, integer, integer)}
-* {fn UCASE(string)} - Returns a string in which all alphabetic characters in *string* have been converted to upper case
 
 #### Date/time
 
+| Operator syntax | Description
+|:--------------- |:-----------
+| {fn CURDATE()}  | Equivalent to `CURRENT_DATE`
+| {fn CURTIME()}  | Equivalent to `LOCALTIME`
+| {fn NOW()}      | Equivalent to `LOCALTIMESTAMP`
+| {fn QUARTER(date)} | Equivalent to `EXTRACT(QUARTER FROM date)`. Returns an integer between 1 and 4.
+| {fn TIMESTAMPADD(interval, count, timestamp)} | Adds an interval to a timestamp
+| {fn TIMESTAMPDIFF(interval, timestamp, timestamp)} | Subtracts two timestamps
+
 Not implemented:
 
-* {fn CURDATE()}
-* {fn CURTIME()}
 * {fn DAYNAME(date)}
 * {fn DAYOFMONTH(date)}
 * {fn DAYOFWEEK(date)}
@@ -1048,11 +1055,7 @@ Not implemented:
 * {fn MINUTE(time)}
 * {fn MONTH(date)}
 * {fn MONTHNAME(date)}
-* {fn NOW()}
-* {fn QUARTER(date)}
 * {fn SECOND(time)}
-* {fn TIMESTAMPADD(interval, count, timestamp)}
-* {fn TIMESTAMPDIFF(interval, timestamp, timestamp)}
 * {fn WEEK(date)}
 * {fn YEAR(date)}
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ac82a30/site/community/index.md
----------------------------------------------------------------------
diff --git a/site/community/index.md b/site/community/index.md
index 82aa4ce..ceacb76 100644
--- a/site/community/index.md
+++ b/site/community/index.md
@@ -26,6 +26,7 @@ limitations under the License.
 
 # Upcoming talks
 
+* 2016/03/30 <a href="http://conferences.oreilly.com/strata/hadoop-big-data-ca/public/schedule/detail/48180">Strata + Hadoop World</a>, San Jose (developer showcase)
 * 2016/04/13 <a href="http://hadoopsummit.org/dublin/agenda/">Hadoop Summit</a>, Dublin
 * 2016/04/26 <a href="http://kafka-summit.org/schedule/">Kafka Summit</a>, San Francisco
 * 2016/05/10 <a href="http://events.linuxfoundation.org/events/apache-big-data-north-america/program/schedule">ApacheCon Big Data North America</a>, Vancouver


[2/5] calcite git commit: Update groupId when Calcite POMs reference Avatica modules

Posted by jh...@apache.org.
Update groupId when Calcite POMs reference Avatica modules

Remove Conjars from Avatica's repository list


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

Branch: refs/heads/master
Commit: eead3d21b0ef18f05029cefbb6b4fb888e75c548
Parents: 9c62ada
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Mar 7 15:45:01 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 7 21:21:11 2016 -0800

----------------------------------------------------------------------
 avatica/pom.xml     | 11 -----------
 core/pom.xml        |  4 ++--
 example/csv/pom.xml |  2 +-
 mongodb/pom.xml     |  4 ++--
 piglet/pom.xml      |  2 +-
 pom.xml             | 23 ++++++++++++-----------
 splunk/pom.xml      |  2 +-
 7 files changed, 19 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/eead3d21/avatica/pom.xml
----------------------------------------------------------------------
diff --git a/avatica/pom.xml b/avatica/pom.xml
index 7a747fe..42a72ee 100644
--- a/avatica/pom.xml
+++ b/avatica/pom.xml
@@ -583,17 +583,6 @@ limitations under the License.
         <enabled>false</enabled>
       </snapshots>
     </repository>
-    <repository>
-      <releases>
-        <enabled>true</enabled>
-        <updatePolicy>always</updatePolicy>
-        <checksumPolicy>warn</checksumPolicy>
-      </releases>
-      <id>conjars</id>
-      <name>Conjars</name>
-      <url>http://conjars.org/repo</url>
-      <layout>default</layout>
-    </repository>
   </repositories>
 
   <profiles>

http://git-wip-us.apache.org/repos/asf/calcite/blob/eead3d21/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 8a548dd..9b50ba3 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -38,7 +38,7 @@ limitations under the License.
     <!-- Sorted by groupId, artifactId; calcite dependencies first. Put versions
          in dependencyManagement in the root POM, not here. -->
     <dependency>
-      <groupId>org.apache.calcite</groupId>
+      <groupId>org.apache.calcite.avatica</groupId>
       <artifactId>calcite-avatica</artifactId>
     </dependency>
     <dependency>
@@ -46,7 +46,7 @@ limitations under the License.
       <artifactId>calcite-linq4j</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.calcite</groupId>
+      <groupId>org.apache.calcite.avatica</groupId>
       <artifactId>calcite-avatica-server</artifactId>
       <scope>test</scope>
     </dependency>

http://git-wip-us.apache.org/repos/asf/calcite/blob/eead3d21/example/csv/pom.xml
----------------------------------------------------------------------
diff --git a/example/csv/pom.xml b/example/csv/pom.xml
index 8b0f8de..cee4b53 100644
--- a/example/csv/pom.xml
+++ b/example/csv/pom.xml
@@ -36,7 +36,7 @@ limitations under the License.
 
   <dependencies>
     <dependency>
-      <groupId>org.apache.calcite</groupId>
+      <groupId>org.apache.calcite.avatica</groupId>
       <artifactId>calcite-avatica</artifactId>
     </dependency>
     <dependency>

http://git-wip-us.apache.org/repos/asf/calcite/blob/eead3d21/mongodb/pom.xml
----------------------------------------------------------------------
diff --git a/mongodb/pom.xml b/mongodb/pom.xml
index 3e65fd3..0efaa4f 100644
--- a/mongodb/pom.xml
+++ b/mongodb/pom.xml
@@ -37,7 +37,7 @@ limitations under the License.
     <!-- Sorted by groupId, artifactId; calcite dependencies first. Put versions
          in dependencyManagement in the root POM, not here. -->
     <dependency>
-      <groupId>org.apache.calcite</groupId>
+      <groupId>org.apache.calcite.avatica</groupId>
       <artifactId>calcite-avatica</artifactId>
     </dependency>
     <dependency>
@@ -101,7 +101,7 @@ limitations under the License.
               <failOnWarning>true</failOnWarning>
               <!-- ignore "unused but declared" warnings -->
               <ignoredUnusedDeclaredDependencies>
-                <ignoredUnusedDeclaredDependency>org.apache.calcite:calcite-avatica</ignoredUnusedDeclaredDependency>
+                <ignoredUnusedDeclaredDependency>org.apache.calcite.avatica:calcite-avatica</ignoredUnusedDeclaredDependency>
                 <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-api</ignoredUnusedDeclaredDependency>
                 <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-log4j12</ignoredUnusedDeclaredDependency>
               </ignoredUnusedDeclaredDependencies>

http://git-wip-us.apache.org/repos/asf/calcite/blob/eead3d21/piglet/pom.xml
----------------------------------------------------------------------
diff --git a/piglet/pom.xml b/piglet/pom.xml
index 790910e..37e07cd 100644
--- a/piglet/pom.xml
+++ b/piglet/pom.xml
@@ -37,7 +37,7 @@ limitations under the License.
     <!-- Sorted by groupId, artifactId; calcite dependencies first. Put versions
          in dependencyManagement in the root POM, not here. -->
     <dependency>
-      <groupId>org.apache.calcite</groupId>
+      <groupId>org.apache.calcite.avatica</groupId>
       <artifactId>calcite-avatica</artifactId>
     </dependency>
     <dependency>

http://git-wip-us.apache.org/repos/asf/calcite/blob/eead3d21/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a94707e..0642df4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,6 +53,7 @@ limitations under the License.
 
     <!-- This list is in alphabetical order. -->
     <airlift-tpch.version>0.1</airlift-tpch.version>
+    <avatica.version>1.7.0-SNAPSHOT</avatica.version>
     <build-helper-maven-plugin.version>1.9</build-helper-maven-plugin.version>
     <cassandra-driver-core.version>2.1.9</cassandra-driver-core.version>
     <checksum-maven-plugin.version>1.2</checksum-maven-plugin.version>
@@ -148,32 +149,32 @@ limitations under the License.
 
   <dependencyManagement>
     <dependencies>
-      <!-- Sorted by groupId, artifactId; calcite dependencies first. -->
+      <!-- Sorted by groupId, artifactId; calcite (and avatica) dependencies first. -->
       <dependency>
-        <groupId>org.apache.calcite</groupId>
+        <groupId>org.apache.calcite.avatica</groupId>
         <artifactId>calcite-avatica-metrics</artifactId>
-        <version>${project.version}</version>
+        <version>${avatica.version}</version>
       </dependency>
       <dependency>
-        <groupId>org.apache.calcite</groupId>
+        <groupId>org.apache.calcite.avatica</groupId>
         <artifactId>calcite-avatica</artifactId>
-        <version>${project.version}</version>
+        <version>${avatica.version}</version>
       </dependency>
       <dependency>
-        <groupId>org.apache.calcite</groupId>
+        <groupId>org.apache.calcite.avatica</groupId>
         <artifactId>calcite-avatica-noop</artifactId>
-        <version>${project.version}</version>
+        <version>${avatica.version}</version>
       </dependency>
       <dependency>
-        <groupId>org.apache.calcite</groupId>
+        <groupId>org.apache.calcite.avatica</groupId>
         <artifactId>calcite-avatica</artifactId>
-        <version>${project.version}</version>
+        <version>${avatica.version}</version>
         <type>test-jar</type>
       </dependency>
       <dependency>
-        <groupId>org.apache.calcite</groupId>
+        <groupId>org.apache.calcite.avatica</groupId>
         <artifactId>calcite-avatica-server</artifactId>
-        <version>${project.version}</version>
+        <version>${avatica.version}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>

http://git-wip-us.apache.org/repos/asf/calcite/blob/eead3d21/splunk/pom.xml
----------------------------------------------------------------------
diff --git a/splunk/pom.xml b/splunk/pom.xml
index 5b955b5..7c3fa20 100644
--- a/splunk/pom.xml
+++ b/splunk/pom.xml
@@ -37,7 +37,7 @@ limitations under the License.
     <!-- Sorted by groupId, artifactId; calcite dependencies first. Put versions
          in dependencyManagement in the root POM, not here. -->
     <dependency>
-      <groupId>org.apache.calcite</groupId>
+      <groupId>org.apache.calcite.avatica</groupId>
       <artifactId>calcite-avatica</artifactId>
     </dependency>
     <dependency>