[CALCITE-1867] Allow user-defined grouped window functions (Timo Walther) Rename SqlGroupFunction to SqlGroupedWindowFunction.
Close apache/calcite#549 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/814de232 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/814de232 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/814de232 Branch: refs/heads/master Commit: 814de2327d3255888a07e1940dbf7dd7bd340b19 Parents: 61f1258 Author: twalthr <[email protected]> Authored: Tue Oct 17 11:30:10 2017 +0200 Committer: Julian Hyde <[email protected]> Committed: Thu Nov 2 15:04:59 2017 -0700 ---------------------------------------------------------------------- .../calcite/sql/fun/SqlGroupFunction.java | 99 --------------- .../sql/fun/SqlGroupedWindowFunction.java | 124 +++++++++++++++++++ .../calcite/sql/fun/SqlStdOperatorTable.java | 42 +++---- 3 files changed, 145 insertions(+), 120 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/814de232/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupFunction.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupFunction.java deleted file mode 100644 index d44267a..0000000 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupFunction.java +++ /dev/null @@ -1,99 +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.fun; - -import org.apache.calcite.sql.SqlFunction; -import org.apache.calcite.sql.SqlFunctionCategory; -import org.apache.calcite.sql.SqlKind; -import org.apache.calcite.sql.SqlOperatorBinding; -import org.apache.calcite.sql.type.ReturnTypes; -import org.apache.calcite.sql.type.SqlOperandTypeChecker; -import org.apache.calcite.sql.validate.SqlMonotonicity; - -import com.google.common.collect.ImmutableList; - -import java.util.List; - -/** - * SQL function that computes keys by which rows can be partitioned and - * aggregated. - * - * <p>Grouped window functions always occur in the GROUP BY clause. They often - * have auxiliary functions that access information about the group. For - * example, {@code HOP} is a group function, and its auxiliary functions are - * {@code HOP_START} and {@code HOP_END}. Here they are used in a streaming - * query: - * - * <blockquote><pre> - * SELECT STREAM HOP_START(rowtime, INTERVAL '1' HOUR), - * HOP_END(rowtime, INTERVAL '1' HOUR), - * MIN(unitPrice) - * FROM Orders - * GROUP BY HOP(rowtime, INTERVAL '1' HOUR), productId - * </pre></blockquote> - */ -class SqlGroupFunction extends SqlFunction { - /** The grouped function, if this an auxiliary function; null otherwise. */ - final SqlGroupFunction groupFunction; - - /** Creates a SqlGroupFunction. - * - * @param kind Kind; also determines function name - * @param groupFunction Group function, if this is an auxiliary; - * null, if this is a group function - * @param operandTypeChecker Operand type checker - */ - SqlGroupFunction(SqlKind kind, SqlGroupFunction groupFunction, - SqlOperandTypeChecker operandTypeChecker) { - super(kind.name(), kind, ReturnTypes.ARG0, null, - operandTypeChecker, SqlFunctionCategory.SYSTEM); - this.groupFunction = groupFunction; - if (groupFunction != null) { - assert groupFunction.groupFunction == null; - } - } - - /** Creates an auxiliary function from this grouped window function. */ - SqlGroupFunction auxiliary(SqlKind kind) { - return new SqlGroupFunction(kind, this, getOperandTypeChecker()); - } - - /** Returns a list of this grouped window function's auxiliary functions. */ - List<SqlGroupFunction> getAuxiliaryFunctions() { - return ImmutableList.of(); - } - - @Override public boolean isGroup() { - // Auxiliary functions are not group functions - return groupFunction == null; - } - - @Override public boolean isGroupAuxiliary() { - return groupFunction != null; - } - - @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) { - // Monotonic iff its first argument is, but not strict. - // - // Note: This strategy happens to works for all current group functions - // (HOP, TUMBLE, SESSION). When there are exceptions to this rule, we'll - // make the method abstract. - return call.getOperandMonotonicity(0).unstrict(); - } -} - -// End SqlGroupFunction.java http://git-wip-us.apache.org/repos/asf/calcite/blob/814de232/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupedWindowFunction.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupedWindowFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupedWindowFunction.java new file mode 100644 index 0000000..8226e95 --- /dev/null +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlGroupedWindowFunction.java @@ -0,0 +1,124 @@ +/* + * 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.SqlFunction; +import org.apache.calcite.sql.SqlFunctionCategory; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlOperatorBinding; +import org.apache.calcite.sql.type.ReturnTypes; +import org.apache.calcite.sql.type.SqlOperandTypeChecker; +import org.apache.calcite.sql.validate.SqlMonotonicity; + +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * SQL function that computes keys by which rows can be partitioned and + * aggregated. + * + * <p>Grouped window functions always occur in the GROUP BY clause. They often + * have auxiliary functions that access information about the group. For + * example, {@code HOP} is a group function, and its auxiliary functions are + * {@code HOP_START} and {@code HOP_END}. Here they are used in a streaming + * query: + * + * <blockquote><pre> + * SELECT STREAM HOP_START(rowtime, INTERVAL '1' HOUR), + * HOP_END(rowtime, INTERVAL '1' HOUR), + * MIN(unitPrice) + * FROM Orders + * GROUP BY HOP(rowtime, INTERVAL '1' HOUR), productId + * </pre></blockquote> + */ +public class SqlGroupedWindowFunction extends SqlFunction { + /** The grouped function, if this an auxiliary function; null otherwise. */ + final SqlGroupedWindowFunction groupFunction; + + /** Creates a SqlGroupedWindowFunction. + * + * @param name Function name + * @param kind Kind + * @param groupFunction Group function, if this is an auxiliary; + * null, if this is a group function + * @param operandTypeChecker Operand type checker + */ + public SqlGroupedWindowFunction(String name, SqlKind kind, SqlGroupedWindowFunction groupFunction, + SqlOperandTypeChecker operandTypeChecker) { + super(name, kind, ReturnTypes.ARG0, null, + operandTypeChecker, SqlFunctionCategory.SYSTEM); + this.groupFunction = groupFunction; + if (groupFunction != null) { + assert groupFunction.groupFunction == null; + } + } + + /** Creates a SqlGroupedWindowFunction. + * + * @param kind Kind; also determines function name + * @param groupFunction Group function, if this is an auxiliary; + * null, if this is a group function + * @param operandTypeChecker Operand type checker + */ + public SqlGroupedWindowFunction(SqlKind kind, SqlGroupedWindowFunction groupFunction, + SqlOperandTypeChecker operandTypeChecker) { + this(kind.name(), kind, groupFunction, operandTypeChecker); + } + + /** Creates an auxiliary function from this grouped window function. + * + * @param kind Kind; also determines function name + */ + public SqlGroupedWindowFunction auxiliary(SqlKind kind) { + return auxiliary(kind.name(), kind); + } + + /** Creates an auxiliary function from this grouped window function. + * + * @param name Function name + * @param kind Kind + */ + public SqlGroupedWindowFunction auxiliary(String name, SqlKind kind) { + return new SqlGroupedWindowFunction(name, kind, this, getOperandTypeChecker()); + } + + /** Returns a list of this grouped window function's auxiliary functions. */ + public List<SqlGroupedWindowFunction> getAuxiliaryFunctions() { + return ImmutableList.of(); + } + + @Override public boolean isGroup() { + // Auxiliary functions are not group functions + return groupFunction == null; + } + + @Override public boolean isGroupAuxiliary() { + return groupFunction != null; + } + + @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) { + // Monotonic iff its first argument is, but not strict. + // + // Note: This strategy happens to works for all current group functions + // (HOP, TUMBLE, SESSION). When there are exceptions to this rule, we'll + // make the method abstract. + return call.getOperandMonotonicity(0).unstrict(); + } +} + +// End SqlGroupedWindowFunction.java http://git-wip-us.apache.org/repos/asf/calcite/blob/814de232/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 c8adf5e..aafc943 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 @@ -2006,63 +2006,63 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable { }; /** The {@code TUMBLE} group function. */ - public static final SqlGroupFunction TUMBLE = - new SqlGroupFunction(SqlKind.TUMBLE, null, + public static final SqlGroupedWindowFunction TUMBLE = + new SqlGroupedWindowFunction(SqlKind.TUMBLE, null, OperandTypes.or(OperandTypes.DATETIME_INTERVAL, OperandTypes.DATETIME_INTERVAL_TIME)) { - @Override List<SqlGroupFunction> getAuxiliaryFunctions() { + @Override public List<SqlGroupedWindowFunction> getAuxiliaryFunctions() { return ImmutableList.of(TUMBLE_START, TUMBLE_END); } }; /** The {@code TUMBLE_START} auxiliary function of * the {@code TUMBLE} group function. */ - public static final SqlGroupFunction TUMBLE_START = + public static final SqlGroupedWindowFunction TUMBLE_START = TUMBLE.auxiliary(SqlKind.TUMBLE_START); /** The {@code TUMBLE_END} auxiliary function of * the {@code TUMBLE} group function. */ - public static final SqlGroupFunction TUMBLE_END = + public static final SqlGroupedWindowFunction TUMBLE_END = TUMBLE.auxiliary(SqlKind.TUMBLE_END); /** The {@code HOP} group function. */ - public static final SqlGroupFunction HOP = - new SqlGroupFunction(SqlKind.HOP, null, + public static final SqlGroupedWindowFunction HOP = + new SqlGroupedWindowFunction(SqlKind.HOP, null, OperandTypes.or(OperandTypes.DATETIME_INTERVAL_INTERVAL, OperandTypes.DATETIME_INTERVAL_INTERVAL_TIME)) { - @Override List<SqlGroupFunction> getAuxiliaryFunctions() { + @Override public List<SqlGroupedWindowFunction> getAuxiliaryFunctions() { return ImmutableList.of(HOP_START, HOP_END); } }; /** The {@code HOP_START} auxiliary function of * the {@code HOP} group function. */ - public static final SqlGroupFunction HOP_START = + public static final SqlGroupedWindowFunction HOP_START = HOP.auxiliary(SqlKind.HOP_START); /** The {@code HOP_END} auxiliary function of * the {@code HOP} group function. */ - public static final SqlGroupFunction HOP_END = + public static final SqlGroupedWindowFunction HOP_END = HOP.auxiliary(SqlKind.HOP_END); /** The {@code SESSION} group function. */ - public static final SqlGroupFunction SESSION = - new SqlGroupFunction(SqlKind.SESSION, null, + public static final SqlGroupedWindowFunction SESSION = + new SqlGroupedWindowFunction(SqlKind.SESSION, null, OperandTypes.or(OperandTypes.DATETIME_INTERVAL, OperandTypes.DATETIME_INTERVAL_TIME)) { - @Override List<SqlGroupFunction> getAuxiliaryFunctions() { + @Override public List<SqlGroupedWindowFunction> getAuxiliaryFunctions() { return ImmutableList.of(SESSION_START, SESSION_END); } }; /** The {@code SESSION_START} auxiliary function of * the {@code SESSION} group function. */ - public static final SqlGroupFunction SESSION_START = + public static final SqlGroupedWindowFunction SESSION_START = SESSION.auxiliary(SqlKind.SESSION_START); /** The {@code SESSION_END} auxiliary function of * the {@code SESSION} group function. */ - public static final SqlGroupFunction SESSION_END = + public static final SqlGroupedWindowFunction SESSION_END = SESSION.auxiliary(SqlKind.SESSION_END); /** {@code |} operator to create alternate patterns @@ -2178,7 +2178,7 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable { /** Returns the group function for which a given kind is an auxiliary * function, or null if it is not an auxiliary function. */ - public static SqlGroupFunction auxiliaryToGroup(SqlKind kind) { + public static SqlGroupedWindowFunction auxiliaryToGroup(SqlKind kind) { switch (kind) { case TUMBLE_START: case TUMBLE_END: @@ -2201,9 +2201,9 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable { * to {@code TUMBLE(rowtime, INTERVAL '1' HOUR))}. */ public static SqlCall convertAuxiliaryToGroupCall(SqlCall call) { final SqlOperator op = call.getOperator(); - if (op instanceof SqlGroupFunction + if (op instanceof SqlGroupedWindowFunction && op.isGroupAuxiliary()) { - return copy(call, ((SqlGroupFunction) op).groupFunction); + return copy(call, ((SqlGroupedWindowFunction) op).groupFunction); } return null; } @@ -2216,12 +2216,12 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable { public static List<Pair<SqlNode, AuxiliaryConverter>> convertGroupToAuxiliaryCalls( SqlCall call) { final SqlOperator op = call.getOperator(); - if (op instanceof SqlGroupFunction + if (op instanceof SqlGroupedWindowFunction && op.isGroup()) { ImmutableList.Builder<Pair<SqlNode, AuxiliaryConverter>> builder = ImmutableList.builder(); - for (final SqlGroupFunction f - : ((SqlGroupFunction) op).getAuxiliaryFunctions()) { + for (final SqlGroupedWindowFunction f + : ((SqlGroupedWindowFunction) op).getAuxiliaryFunctions()) { builder.add( Pair.<SqlNode, AuxiliaryConverter>of(copy(call, f), new AuxiliaryConverter.Impl(f)));
