This is an automated email from the ASF dual-hosted git repository.
mmior pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push:
new 4814943 [CALCITE-2770] Add support for BIT_AND and BIT_OR aggregate
functions
4814943 is described below
commit 4814943895d609813878763faf0d38adb624eac4
Author: Haisheng Yuan <[email protected]>
AuthorDate: Thu Dec 27 14:18:14 2018 -0600
[CALCITE-2770] Add support for BIT_AND and BIT_OR aggregate functions
---
.../calcite/adapter/enumerable/RexImpTable.java | 34 ++++++++++++
.../java/org/apache/calcite/rel/core/Match.java | 5 ++
.../rel/rules/AggregateUnionTransposeRule.java | 2 +
.../org/apache/calcite/runtime/SqlFunctions.java | 14 +++++
.../main/java/org/apache/calcite/sql/SqlKind.java | 8 ++-
.../calcite/sql/fun/SqlBitOpAggFunction.java | 64 ++++++++++++++++++++++
.../calcite/sql/fun/SqlStdOperatorTable.java | 12 ++++
.../org/apache/calcite/sql/type/OperandTypes.java | 2 +
.../org/apache/calcite/util/BuiltInMethod.java | 2 +
.../calcite/sql/test/SqlOperatorBaseTest.java | 44 +++++++++++++++
core/src/test/resources/sql/agg.iq | 23 ++++++++
site/_docs/reference.md | 2 +
12 files changed, 211 insertions(+), 1 deletion(-)
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 e1da0d0..910bebe 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
@@ -99,6 +99,8 @@ import static
org.apache.calcite.sql.fun.SqlStdOperatorTable.ARRAY_VALUE_CONSTRU
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ASIN;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ATAN;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ATAN2;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BIT_AND;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.BIT_OR;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CARDINALITY;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CASE;
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CAST;
@@ -503,6 +505,9 @@ public class RexImpTable {
aggMap.put(MIN, minMax);
aggMap.put(MAX, minMax);
aggMap.put(ANY_VALUE, minMax);
+ final Supplier<BitOpImplementor> bitop =
constructorSupplier(BitOpImplementor.class);
+ aggMap.put(BIT_AND, bitop);
+ aggMap.put(BIT_OR, bitop);
aggMap.put(SINGLE_VALUE,
constructorSupplier(SingleValueImplementor.class));
aggMap.put(COLLECT, constructorSupplier(CollectImplementor.class));
aggMap.put(FUSION, constructorSupplier(FusionImplementor.class));
@@ -1362,6 +1367,35 @@ public class RexImpTable {
}
}
+ /** Implementor for the {@code BIT_AND} and {@code BIT_OR} aggregate
function. */
+ static class BitOpImplementor extends StrictAggImplementor {
+ @Override protected void implementNotNullReset(AggContext info,
+ AggResetContext reset) {
+ Object initValue = info.aggregation() == BIT_AND ? -1 : 0;
+ Expression start = Expressions.constant(initValue, info.returnType());
+
+ reset.currentBlock().add(
+ Expressions.statement(
+ Expressions.assign(reset.accumulator().get(0), start)));
+ }
+
+ @Override public void implementNotNullAdd(AggContext info,
+ AggAddContext add) {
+ Expression acc = add.accumulator().get(0);
+ Expression arg = add.arguments().get(0);
+ SqlAggFunction aggregation = info.aggregation();
+ final Method method = (aggregation == BIT_AND
+ ? BuiltInMethod.BIT_AND
+ : BuiltInMethod.BIT_OR).method;
+ Expression next = Expressions.call(
+ method.getDeclaringClass(),
+ method.getName(),
+ acc,
+ Expressions.unbox(arg));
+ accAdvance(add, acc, next);
+ }
+ }
+
/** Implementor for the {@code GROUPING} aggregate function. */
static class GroupingImplementor implements AggImplementor {
public List<Type> getStateType(AggContext info) {
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Match.java
b/core/src/main/java/org/apache/calcite/rel/core/Match.java
index 742fa81..f6dddd4 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Match.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Match.java
@@ -28,6 +28,7 @@ import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexPatternFieldRef;
import org.apache.calcite.rex.RexVisitorImpl;
import org.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.sql.fun.SqlBitOpAggFunction;
import org.apache.calcite.sql.fun.SqlMinMaxAggFunction;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.fun.SqlSumAggFunction;
@@ -254,6 +255,10 @@ public abstract class Match extends SingleRel {
case ANY_VALUE:
aggFunction = SqlStdOperatorTable.ANY_VALUE;
break;
+ case BIT_AND:
+ case BIT_OR:
+ aggFunction = new SqlBitOpAggFunction(call.getKind());
+ break;
default:
for (RexNode rex : call.getOperands()) {
rex.accept(this);
diff --git
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
index 0416338..05ba565 100644
---
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
+++
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
@@ -31,6 +31,7 @@ import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.sql.fun.SqlAnyValueAggFunction;
+import org.apache.calcite.sql.fun.SqlBitOpAggFunction;
import org.apache.calcite.sql.fun.SqlCountAggFunction;
import org.apache.calcite.sql.fun.SqlMinMaxAggFunction;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
@@ -65,6 +66,7 @@ public class AggregateUnionTransposeRule extends RelOptRule {
SUPPORTED_AGGREGATES.put(SqlSumAggFunction.class, true);
SUPPORTED_AGGREGATES.put(SqlSumEmptyIsZeroAggFunction.class, true);
SUPPORTED_AGGREGATES.put(SqlAnyValueAggFunction.class, true);
+ SUPPORTED_AGGREGATES.put(SqlBitOpAggFunction.class, true);
}
/** Creates an AggregateUnionTransposeRule. */
diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index 7644d0a..bb1b335 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -852,6 +852,20 @@ public class SqlFunctions {
op, b1.getClass().toString()).ex();
}
+ // &
+
+ /** Helper function for implementing <code>BIT_AND</code> */
+ public static long bitAnd(long b0, long b1) {
+ return b0 & b1;
+ }
+
+ // |
+
+ /** Helper function for implementing <code>BIT_OR</code> */
+ public static long bitOr(long b0, long b1) {
+ return b0 | b1;
+ }
+
// EXP
/** SQL <code>EXP</code> operator applied to double values. */
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 0f38ea6..521e35b 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -924,6 +924,12 @@ public enum SqlKind {
/** The {@code SINGLE_VALUE} aggregate function. */
SINGLE_VALUE,
+ /** The {@code BIT_AND} aggregate function. */
+ BIT_AND,
+
+ /** The {@code BIT_OR} aggregate function. */
+ BIT_OR,
+
/** The {@code ROW_NUMBER} window function. */
ROW_NUMBER,
@@ -1103,7 +1109,7 @@ public enum SqlKind {
LAST_VALUE, COVAR_POP, COVAR_SAMP, REGR_COUNT, REGR_SXX, REGR_SYY,
AVG, STDDEV_POP, STDDEV_SAMP, VAR_POP, VAR_SAMP, NTILE, COLLECT,
FUSION, SINGLE_VALUE, ROW_NUMBER, RANK, PERCENT_RANK, DENSE_RANK,
- CUME_DIST, JSON_ARRAYAGG, JSON_OBJECTAGG);
+ CUME_DIST, JSON_ARRAYAGG, JSON_OBJECTAGG, BIT_AND, BIT_OR);
/**
* Category consisting of all DML operators.
diff --git
a/core/src/main/java/org/apache/calcite/sql/fun/SqlBitOpAggFunction.java
b/core/src/main/java/org/apache/calcite/sql/fun/SqlBitOpAggFunction.java
new file mode 100644
index 0000000..0fe12de
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlBitOpAggFunction.java
@@ -0,0 +1,64 @@
+/*
+ * 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.SqlAggFunction;
+import org.apache.calcite.sql.SqlFunctionCategory;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlSplittableAggFunction;
+import org.apache.calcite.sql.type.OperandTypes;
+import org.apache.calcite.sql.type.ReturnTypes;
+import org.apache.calcite.util.Optionality;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Definition of the <code>BIT_AND</code> and <code>BIT_OR</code> aggregate
functions,
+ * returning the bitwise AND/OR of all non-null input values, or null if none.
+ *
+ * <p>Only INTEGER types are supported:
+ * tinyint, smallint, int, bigint
+ */
+public class SqlBitOpAggFunction extends SqlAggFunction {
+
+ //~ Constructors -----------------------------------------------------------
+
+ /** Creates a SqlBitOpAggFunction. */
+ public SqlBitOpAggFunction(SqlKind kind) {
+ super(kind.name(),
+ null,
+ kind,
+ ReturnTypes.ARG0_NULLABLE_IF_EMPTY,
+ null,
+ OperandTypes.INTEGER,
+ SqlFunctionCategory.NUMERIC,
+ false,
+ false,
+ Optionality.FORBIDDEN);
+ Preconditions.checkArgument(kind == SqlKind.BIT_AND
+ || kind == SqlKind.BIT_OR);
+ }
+
+ @Override public <T> T unwrap(Class<T> clazz) {
+ if (clazz == SqlSplittableAggFunction.class) {
+ return clazz.cast(SqlSplittableAggFunction.SelfSplitter.INSTANCE);
+ }
+ return super.unwrap(clazz);
+ }
+}
+
+// End SqlBitOpAggFunction.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 6c3c596..7ca82ec 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
@@ -1053,6 +1053,18 @@ public class SqlStdOperatorTable extends
ReflectiveSqlOperatorTable {
public static final SqlAggFunction VARIANCE =
new SqlAvgAggFunction("VARIANCE", SqlKind.VAR_SAMP);
+ /**
+ * <code>BIT_AND</code> aggregate function.
+ */
+ public static final SqlAggFunction BIT_AND =
+ new SqlBitOpAggFunction(SqlKind.BIT_AND);
+
+ /**
+ * <code>BIT_OR</code> aggregate function.
+ */
+ public static final SqlAggFunction BIT_OR =
+ new SqlBitOpAggFunction(SqlKind.BIT_OR);
+
//-------------------------------------------------------------
// WINDOW Aggregate Functions
//-------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
index dcdaa63..91f2246 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java
@@ -199,6 +199,8 @@ public abstract class OperandTypes {
public static final SqlSingleOperandTypeChecker NUMERIC =
family(SqlTypeFamily.NUMERIC);
+ public static final SqlSingleOperandTypeChecker INTEGER =
+ family(SqlTypeFamily.INTEGER);
public static final SqlSingleOperandTypeChecker NUMERIC_OPTIONAL_INTEGER =
family(ImmutableList.of(SqlTypeFamily.NUMERIC, SqlTypeFamily.INTEGER),
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index f23a931..cfadcfe 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -328,6 +328,8 @@ public enum BuiltInMethod {
NOT(SqlFunctions.class, "not", Boolean.class),
LESSER(SqlFunctions.class, "lesser", Comparable.class, Comparable.class),
GREATER(SqlFunctions.class, "greater", Comparable.class, Comparable.class),
+ BIT_AND(SqlFunctions.class, "bitAnd", long.class, long.class),
+ BIT_OR(SqlFunctions.class, "bitOr", long.class, long.class),
MODIFIABLE_TABLE_GET_MODIFIABLE_COLLECTION(ModifiableTable.class,
"getModifiableCollection"),
SCANNABLE_TABLE_SCAN(ScannableTable.class, "scan", DataContext.class),
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 90e2372..dbba71c 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
@@ -7761,6 +7761,50 @@ public abstract class SqlOperatorBaseTest {
0d);
}
+ @Test public void testBitAndFunc() {
+ tester.setFor(SqlStdOperatorTable.BIT_AND, VM_FENNEL, VM_JAVA);
+ tester.checkFails("bit_and(^*^)", "Unknown identifier '\\*'", false);
+ tester.checkType("bit_and(1)", "INTEGER");
+ tester.checkType("bit_and(CAST(2 AS TINYINT))", "TINYINT");
+ tester.checkType("bit_and(CAST(2 AS SMALLINT))", "SMALLINT");
+ tester.checkType("bit_and(distinct CAST(2 AS BIGINT))", "BIGINT");
+ tester.checkFails("^bit_and(1.2)^",
+ "Cannot apply 'BIT_AND' to arguments of type 'BIT_AND\\(<DECIMAL\\(2,
1\\)>\\)'\\. Supported form\\(s\\): 'BIT_AND\\(<INTEGER>\\)'",
+ false);
+ tester.checkFails(
+ "^bit_and()^",
+ "Invalid number of arguments to function 'BIT_AND'. Was expecting 1
arguments",
+ false);
+ tester.checkFails(
+ "^bit_and(1, 2)^",
+ "Invalid number of arguments to function 'BIT_AND'. Was expecting 1
arguments",
+ false);
+ final String[] values = {"3", "2", "2"};
+ tester.checkAgg("bit_and(x)", values, 2, 0);
+ }
+
+ @Test public void testBitOrFunc() {
+ tester.setFor(SqlStdOperatorTable.BIT_OR, VM_FENNEL, VM_JAVA);
+ tester.checkFails("bit_or(^*^)", "Unknown identifier '\\*'", false);
+ tester.checkType("bit_or(1)", "INTEGER");
+ tester.checkType("bit_or(CAST(2 AS TINYINT))", "TINYINT");
+ tester.checkType("bit_or(CAST(2 AS SMALLINT))", "SMALLINT");
+ tester.checkType("bit_or(distinct CAST(2 AS BIGINT))", "BIGINT");
+ tester.checkFails("^bit_or(1.2)^",
+ "Cannot apply 'BIT_OR' to arguments of type 'BIT_OR\\(<DECIMAL\\(2,
1\\)>\\)'\\. Supported form\\(s\\): 'BIT_OR\\(<INTEGER>\\)'",
+ false);
+ tester.checkFails(
+ "^bit_or()^",
+ "Invalid number of arguments to function 'BIT_OR'. Was expecting 1
arguments",
+ false);
+ tester.checkFails(
+ "^bit_or(1, 2)^",
+ "Invalid number of arguments to function 'BIT_OR'. Was expecting 1
arguments",
+ false);
+ final String[] values = {"1", "2", "2"};
+ tester.checkAgg("bit_or(x)", values, 3, 0);
+ }
+
/**
* Tests that CAST fails when given a value just outside the valid range for
* that type. For example,
diff --git a/core/src/test/resources/sql/agg.iq
b/core/src/test/resources/sql/agg.iq
index 3d4468d..8b03f47 100755
--- a/core/src/test/resources/sql/agg.iq
+++ b/core/src/test/resources/sql/agg.iq
@@ -2504,6 +2504,29 @@ EnumerableAggregate(group=[{0}], EMPNOS=[COLLECT($1)
WITHIN GROUP ([2])])
EnumerableTableScan(table=[[scott, EMP]])
!plan
+# BIT_AND, BIT_OR aggregate functions
+select bit_and(deptno), bit_or(deptno) from "scott".emp;
++--------+--------+
+| EXPR$0 | EXPR$1 |
++--------+--------+
+| 0 | 30 |
++--------+--------+
+(1 row)
+
+!ok
+
+select deptno, bit_and(empno), bit_or(empno) from "scott".emp group by deptno;
++--------+--------+--------+
+| DEPTNO | EXPR$1 | EXPR$2 |
++--------+--------+--------+
+| 10 | 7686 | 7935 |
+| 20 | 7168 | 8191 |
+| 30 | 7168 | 8191 |
++--------+--------+--------+
+(3 rows)
+
+!ok
+
# [CALCITE-2266] JSON_OBJECTAGG, JSON_ARRAYAGG
!use post
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 167693b..3e0b78f 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -1532,6 +1532,8 @@ and `LISTAGG`).
| MAX( [ ALL | DISTINCT ] value) | Returns the maximum value of
*value* across all input values
| MIN( [ ALL | DISTINCT ] value) | Returns the minimum value of
*value* across all input values
| ANY_VALUE( [ ALL | DISTINCT ] value) | Returns one of the values of
*value* across all input values; this is NOT specified in the SQL standard
+| BIT_AND( [ ALL | DISTINCT ] value) | Returns the bitwise AND of
all non-null input values, or null if none
+| BIT_OR( [ ALL | DISTINCT ] value) | Returns the bitwise OR of
all non-null input values, or null if none
| STDDEV_POP( [ ALL | DISTINCT ] numeric) | Returns the population
standard deviation of *numeric* across all input values
| STDDEV_SAMP( [ ALL | DISTINCT ] numeric) | Returns the sample standard
deviation of *numeric* across all input values
| VAR_POP( [ ALL | DISTINCT ] value) | Returns the population
variance (square of the population standard deviation) of *numeric* across all
input values