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 &#124; DISTINCT ] value)           | Returns the maximum value of 
*value* across all input values
 | MIN( [ ALL &#124; DISTINCT ] value)           | Returns the minimum value of 
*value* across all input values
 | ANY_VALUE( [ ALL &#124; DISTINCT ] value)     | Returns one of the values of 
*value* across all input values; this is NOT specified in the SQL standard
+| BIT_AND( [ ALL &#124; DISTINCT ] value)       | Returns the bitwise AND of 
all non-null input values, or null if none
+| BIT_OR( [ ALL &#124; DISTINCT ] value)        | Returns the bitwise OR of 
all non-null input values, or null if none
 | STDDEV_POP( [ ALL &#124; DISTINCT ] numeric)  | Returns the population 
standard deviation of *numeric* across all input values
 | STDDEV_SAMP( [ ALL &#124; DISTINCT ] numeric) | Returns the sample standard 
deviation of *numeric* across all input values
 | VAR_POP( [ ALL &#124; DISTINCT ] value)       | Returns the population 
variance (square of the population standard deviation) of *numeric* across all 
input values

Reply via email to