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 2014/12/11 08:56:23 UTC

[1/3] incubator-calcite git commit: [CALCITE-282] Add {fn QUARTER(date)} function (Benoy Antony)

Repository: incubator-calcite
Updated Branches:
  refs/heads/master a640e58cf -> cfa1847bc


[CALCITE-282] Add {fn QUARTER(date)} function (Benoy Antony)

Close apache/incubator-calcite#13


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

Branch: refs/heads/master
Commit: a059f76c79080b0e283cb54e273f1ef89a444282
Parents: a640e58
Author: Benoy Antony <be...@apache.org>
Authored: Wed Dec 10 17:18:06 2014 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Dec 10 18:00:50 2014 -0800

----------------------------------------------------------------------
 .../calcite/sql/fun/SqlQuarterFunction.java     | 65 ++++++++++++++++++++
 .../calcite/sql/fun/SqlStdOperatorTable.java    |  8 +++
 .../sql2rel/StandardConvertletTable.java        | 32 +++++++++-
 .../calcite/sql/test/SqlOperatorBaseTest.java   | 56 +++++++++++++++++
 4 files changed, 160 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a059f76c/core/src/main/java/org/apache/calcite/sql/fun/SqlQuarterFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlQuarterFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlQuarterFunction.java
new file mode 100644
index 0000000..abc2c9f
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlQuarterFunction.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql.fun;
+
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlCallBinding;
+import org.apache.calcite.sql.SqlFunction;
+import org.apache.calcite.sql.SqlFunctionCategory;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperandCountRange;
+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;
+
+/**
+ * SqlQuarterFunction represents the SQL:1999 standard {@code QUARTER}
+ * function. Determines Quarter (1,2,3,4) of a given date.
+ */
+public class SqlQuarterFunction extends SqlFunction {
+  //~ Constructors -----------------------------------------------------------
+
+  public SqlQuarterFunction() {
+    super("QUARTER",
+        SqlKind.OTHER,
+        ReturnTypes.BIGINT_NULLABLE,
+        InferTypes.FIRST_KNOWN,
+        OperandTypes.DATETIME,
+        SqlFunctionCategory.TIMEDATE);
+  }
+
+  //~ Methods ----------------------------------------------------------------
+
+  public SqlOperandCountRange getOperandCountRange() {
+    return SqlOperandCountRanges.of(1);
+  }
+
+  public String getSignatureTemplate(int operandsCount) {
+    assert 1 == operandsCount;
+    return "{0}({1})";
+  }
+
+  public boolean checkOperandTypes(SqlCallBinding callBinding,
+      boolean throwOnFailure) {
+    SqlCall call = callBinding.getCall();
+    return OperandTypes.DATETIME.checkSingleOperandType(callBinding,
+        call.operand(0), 0, throwOnFailure);
+  }
+}
+
+// End SqlQuarterFunction.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a059f76c/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 427ce95..d988c55 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
@@ -1354,6 +1354,14 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
   public static final SqlFunction EXTRACT = new SqlExtractFunction();
 
   /**
+   * The SQL <code>QUARTER</code> operator. Returns the Quarter
+   * from a DATETIME  E.g.<br>
+   * <code>QUARTER(date '2008-9-23')</code> returns <code>
+   * 3</code>
+   */
+  public static final SqlQuarterFunction QUARTER = new SqlQuarterFunction();
+
+  /**
    * The ELEMENT operator, used to convert a multiset with only one item to a
    * "regular" type. Example ... log(ELEMENT(MULTISET[1])) ...
    */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a059f76c/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 987b99b..9c85772 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -18,6 +18,7 @@ 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;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -56,6 +57,7 @@ import org.apache.calcite.sql.fun.SqlMapValueConstructor;
 import org.apache.calcite.sql.fun.SqlMultisetQueryConstructor;
 import org.apache.calcite.sql.fun.SqlMultisetValueConstructor;
 import org.apache.calcite.sql.fun.SqlOverlapsOperator;
+import org.apache.calcite.sql.fun.SqlQuarterFunction;
 import org.apache.calcite.sql.fun.SqlRowOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParserPos;
@@ -549,6 +551,34 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     return res;
   }
 
+  /**
+   * Converts a call to the {@code QUARTER} function.
+   *
+   * <p>Called automatically via reflection.
+   */
+  public RexNode convertQuarter(
+      SqlRexContext cx,
+      SqlQuarterFunction op,
+      SqlCall call) {
+    final List<SqlNode> operands = call.getOperandList();
+    assert operands.size() == 1;
+    RexNode x = cx.convertExpression(operands.get(0));
+    final RexBuilder rexBuilder = cx.getRexBuilder();
+    RelDataType resType =
+        cx.getTypeFactory().createSqlType(SqlTypeName.BIGINT);
+    RexNode res =
+        rexBuilder.makeCall(
+            resType,
+            SqlStdOperatorTable.EXTRACT_DATE,
+            ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), x));
+    res = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, res,
+        rexBuilder.makeExactLiteral(BigDecimal.ONE));
+    res = divide(rexBuilder, res, 3);
+    res = rexBuilder.makeCall(SqlStdOperatorTable.PLUS, res,
+        rexBuilder.makeExactLiteral(BigDecimal.ONE));
+    return res;
+  }
+
   private static long getFactor(TimeUnit unit) {
     switch (unit) {
     case DAY:
@@ -598,7 +628,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     for (RexNode expr : exprs) {
       if (SqlTypeName.INTERVAL_YEAR_MONTH
           == expr.getType().getSqlTypeName()) {
-        Util.needToImplement(
+        throw Util.needToImplement(
             "Datetime subtraction of year month interval");
       }
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/a059f76c/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 8987b75..d5d6d00 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
@@ -4086,6 +4086,62 @@ public abstract class SqlOperatorBaseTest {
     tester.setFor(SqlStdOperatorTable.FUSION, VM_FENNEL, VM_JAVA);
   }
 
+  @Test public void testQuarter() {
+    tester.setFor(
+        SqlStdOperatorTable.QUARTER,
+        VM_FENNEL,
+        VM_JAVA);
+
+    tester.checkScalar(
+        "quarter(date '2008-1-23')",
+        "1",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-2-23')",
+        "1",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-3-23')",
+        "1",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-4-23')",
+        "2",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-5-23')",
+        "2",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-6-23')",
+        "2",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-7-23')",
+        "3",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-8-23')",
+        "3",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-9-23')",
+        "3",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-10-23')",
+        "4",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-11-23')",
+        "4",
+        "BIGINT NOT NULL");
+    tester.checkScalar(
+        "quarter(date '2008-12-23')",
+        "4",
+        "BIGINT NOT NULL");
+  }
+
   @Test public void testExtractFunc() {
     tester.setFor(
         SqlStdOperatorTable.EXTRACT,


[3/3] incubator-calcite git commit: Make JsonHandler and JsonService thread-safe

Posted by jh...@apache.org.
Make JsonHandler and JsonService thread-safe


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

Branch: refs/heads/master
Commit: cfa1847bc916eeb07aa73eadbe0257f2dfbc9212
Parents: 0ab7f5e
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Dec 10 20:23:34 2014 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Dec 10 23:03:32 2014 -0800

----------------------------------------------------------------------
 .../calcite/avatica/remote/JsonHandler.java     | 19 ++++++------------
 .../calcite/avatica/remote/JsonService.java     | 21 ++++++++++----------
 .../avatica/remote/LocalJsonService.java        | 11 +++++-----
 3 files changed, 21 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cfa1847b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java
index 80593e9..dee0636 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java
@@ -16,7 +16,6 @@
  */
 package org.apache.calcite.avatica.remote;
 
-import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
 import java.io.IOException;
@@ -31,15 +30,11 @@ import java.io.StringWriter;
  */
 public class JsonHandler implements Handler {
   private final Service service;
-  protected final ObjectMapper mapper;
-  protected final StringWriter w = new StringWriter();
+
+  protected static final ObjectMapper MAPPER = JsonService.MAPPER;
 
   public JsonHandler(Service service) {
-    super();
     this.service = service;
-    mapper = new ObjectMapper();
-    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
-    mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
   }
 
   public String apply(String jsonRequest) {
@@ -53,15 +48,13 @@ public class JsonHandler implements Handler {
   }
 
   private <T> T decode(String request, Class<T> valueType) throws IOException {
-    return mapper.readValue(request, valueType);
+    return MAPPER.readValue(request, valueType);
   }
 
   private <T> String encode(T response) throws IOException {
-    assert w.getBuffer().length() == 0;
-    mapper.writeValue(w, response);
-    final String s = w.toString();
-    w.getBuffer().setLength(0);
-    return s;
+    final StringWriter w = new StringWriter();
+    MAPPER.writeValue(w, response);
+    return w.toString();
   }
 
   protected RuntimeException handle(IOException e) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cfa1847b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
index 68f8782..3de4ef0 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
@@ -27,13 +27,14 @@ import java.io.StringWriter;
  * that encodes requests and responses as JSON.
  */
 public abstract class JsonService implements Service {
-  protected final ObjectMapper mapper;
-  protected final StringWriter w = new StringWriter();
+  protected static final ObjectMapper MAPPER;
+  static {
+    MAPPER = new ObjectMapper();
+    MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+    MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+  }
 
   public JsonService() {
-    mapper = new ObjectMapper();
-    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
-    mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
   }
 
   /** Derived class should implement this method to transport requests and
@@ -41,15 +42,13 @@ public abstract class JsonService implements Service {
   public abstract String apply(String request);
 
   private <T> T decode(String response, Class<T> valueType) throws IOException {
-    return mapper.readValue(response, valueType);
+    return MAPPER.readValue(response, valueType);
   }
 
   private <T> String encode(T request) throws IOException {
-    assert w.getBuffer().length() == 0;
-    mapper.writeValue(w, request);
-    final String s = w.toString();
-    w.getBuffer().setLength(0);
-    return s;
+    final StringWriter w = new StringWriter();
+    MAPPER.writeValue(w, request);
+    return w.toString();
   }
 
   protected RuntimeException handle(IOException e) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/cfa1847b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalJsonService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalJsonService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalJsonService.java
index 66b4b7d..0af6300 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalJsonService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalJsonService.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.avatica.remote;
 
 import java.io.IOException;
+import java.io.StringWriter;
 
 /**
  * Implementation of {@link org.apache.calcite.avatica.remote.Service}
@@ -31,13 +32,11 @@ public class LocalJsonService extends JsonService {
 
   @Override public String apply(String request) {
     try {
-      Request request2 = mapper.readValue(request, Request.class);
+      Request request2 = MAPPER.readValue(request, Request.class);
       Response response2 = request2.accept(service);
-      assert w.getBuffer().length() == 0;
-      mapper.writeValue(w, response2);
-      final String response = w.toString();
-      w.getBuffer().setLength(0);
-      return response;
+      final StringWriter w = new StringWriter();
+      MAPPER.writeValue(w, response2);
+      return w.toString();
     } catch (IOException e) {
       throw handle(e);
     }


[2/3] incubator-calcite git commit: Fix QUARTER function for null values and JDBC escape syntax

Posted by jh...@apache.org.
Fix QUARTER function for null values and JDBC escape syntax


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

Branch: refs/heads/master
Commit: 0ab7f5ef0f67c8bb96d4460d733ad4e953643085
Parents: a059f76
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Dec 10 17:56:45 2014 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Dec 10 18:02:47 2014 -0800

----------------------------------------------------------------------
 .../java/org/apache/calcite/sql/SqlJdbcFunctionCall.java     | 3 +++
 .../org/apache/calcite/sql2rel/StandardConvertletTable.java  | 7 +++++--
 .../org/apache/calcite/sql/test/SqlOperatorBaseTest.java     | 8 ++++----
 3 files changed, 12 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0ab7f5ef/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 91a8acf..63ffb8d 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java
@@ -723,6 +723,9 @@ public class SqlJdbcFunctionCall extends SqlFunction {
             }
           });
       map.put(
+          "QUARTER",
+          new MakeCall(SqlStdOperatorTable.QUARTER, 1));
+      map.put(
           "RTRIM",
           new MakeCall(SqlStdOperatorTable.TRIM, 1) {
             @Override SqlCall createCall(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0ab7f5ef/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 9c85772..7ecfd37 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -564,8 +564,11 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     assert operands.size() == 1;
     RexNode x = cx.convertExpression(operands.get(0));
     final RexBuilder rexBuilder = cx.getRexBuilder();
-    RelDataType resType =
-        cx.getTypeFactory().createSqlType(SqlTypeName.BIGINT);
+    final RelDataTypeFactory typeFactory = cx.getTypeFactory();
+    final RelDataType resType =
+        typeFactory.createTypeWithNullability(
+            typeFactory.createSqlType(SqlTypeName.BIGINT),
+            x.getType().isNullable());
     RexNode res =
         rexBuilder.makeCall(
             resType,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0ab7f5ef/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 d5d6d00..9e08be8 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
@@ -1478,7 +1478,7 @@ public abstract class SqlOperatorBaseTest {
 
     // Numeric Functions
     if (!enable) {
-      return;
+//      return;
     }
     tester.checkScalar("{fn ABS(-3)}", 3, "INTEGER NOT NULL");
     if (false) {
@@ -1666,9 +1666,8 @@ public abstract class SqlOperatorBaseTest {
       tester.checkScalar("{fn MONTHNAME(date)}", null, "");
     }
     tester.checkType("{fn NOW()}", "TIMESTAMP(0) NOT NULL");
-    if (false) {
-      tester.checkScalar("{fn QUARTER(date)}", null, "");
-    }
+    tester.checkScalar("{fn QUARTER(DATE '2014-12-10')}", "4",
+        "BIGINT NOT NULL");
     if (false) {
       tester.checkScalar("{fn SECOND(time)}", null, "");
     }
@@ -4140,6 +4139,7 @@ public abstract class SqlOperatorBaseTest {
         "quarter(date '2008-12-23')",
         "4",
         "BIGINT NOT NULL");
+    tester.checkNull("quarter(cast(null as date))");
   }
 
   @Test public void testExtractFunc() {