This is an automated email from the ASF dual-hosted git repository.

Jackie-Jiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new e4b72a67e4c Check the intermediate result ser/de of every aggregation 
function type (#20248)
e4b72a67e4c is described below

commit e4b72a67e4c8f0937b2e47ee174f9ba5a5307eb5
Author: Xiaotian (Jackie) Jiang <[email protected]>
AuthorDate: Fri Nov 13 16:31:58 2026 -0800

    Check the intermediate result ser/de of every aggregation function type 
(#20248)
---
 .../IntermediateResultByteBufferSerDeTest.java     | 202 ++++++++++++++++++++-
 1 file changed, 194 insertions(+), 8 deletions(-)

diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/IntermediateResultByteBufferSerDeTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/IntermediateResultByteBufferSerDeTest.java
index 5208272911f..5edf828aa6a 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/IntermediateResultByteBufferSerDeTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/IntermediateResultByteBufferSerDeTest.java
@@ -44,8 +44,11 @@ import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.List;
+import java.util.Map;
 import java.util.PriorityQueue;
+import java.util.Set;
 import org.apache.datasketches.cpc.CpcSketch;
 import org.apache.datasketches.frequencies.FrequentItemsSketch;
 import org.apache.datasketches.frequencies.FrequentLongsSketch;
@@ -82,9 +85,18 @@ import 
org.apache.pinot.core.query.aggregation.function.array.ListAggDistinctFun
 import org.apache.pinot.core.query.aggregation.function.array.ListAggFunction;
 import 
org.apache.pinot.core.query.aggregation.function.array.SumArrayDoubleAggregationFunction;
 import 
org.apache.pinot.core.query.aggregation.function.array.SumArrayLongAggregationFunction;
+import 
org.apache.pinot.core.query.aggregation.function.distinct.BaseOffHeapSet;
+import 
org.apache.pinot.core.query.aggregation.function.distinct.OffHeap128BitSet;
+import 
org.apache.pinot.core.query.aggregation.function.distinct.OffHeap32BitSet;
+import 
org.apache.pinot.core.query.aggregation.function.distinct.OffHeap64BitSet;
 import 
org.apache.pinot.core.query.aggregation.function.funnel.FunnelCountAggregationFunctionFactory;
 import org.apache.pinot.core.query.aggregation.function.funnel.FunnelStepEvent;
+import 
org.apache.pinot.core.query.aggregation.function.funnel.FunnelStepEventWithExtraFields;
+import 
org.apache.pinot.core.query.aggregation.function.funnel.window.FunnelCompleteCountAggregationFunction;
+import 
org.apache.pinot.core.query.aggregation.function.funnel.window.FunnelEventsFunctionEvalAggregationFunction;
+import 
org.apache.pinot.core.query.aggregation.function.funnel.window.FunnelMatchStepAggregationFunction;
 import 
org.apache.pinot.core.query.aggregation.function.funnel.window.FunnelMaxStepAggregationFunction;
+import 
org.apache.pinot.core.query.aggregation.function.funnel.window.FunnelStepDurationStatsAggregationFunction;
 import 
org.apache.pinot.core.query.aggregation.utils.exprminmax.ExprMinMaxMeasuringValSetWrapper;
 import 
org.apache.pinot.core.query.aggregation.utils.exprminmax.ExprMinMaxObject;
 import 
org.apache.pinot.core.query.aggregation.utils.exprminmax.ExprMinMaxProjectionValSetWrapper;
@@ -102,8 +114,14 @@ import 
org.apache.pinot.segment.local.customobject.LongLongPair;
 import org.apache.pinot.segment.local.customobject.MinMaxRangePair;
 import org.apache.pinot.segment.local.customobject.PinotFourthMoment;
 import org.apache.pinot.segment.local.customobject.QuantileDigest;
+import org.apache.pinot.segment.local.customobject.SerializedCPCSketch;
 import 
org.apache.pinot.segment.local.customobject.SerializedFrequentLongsSketch;
 import 
org.apache.pinot.segment.local.customobject.SerializedFrequentStringsSketch;
+import org.apache.pinot.segment.local.customobject.SerializedHLL;
+import org.apache.pinot.segment.local.customobject.SerializedHLLPlus;
+import org.apache.pinot.segment.local.customobject.SerializedKLL;
+import org.apache.pinot.segment.local.customobject.SerializedQuantileDigest;
+import org.apache.pinot.segment.local.customobject.SerializedULL;
 import org.apache.pinot.segment.local.customobject.StringLongPair;
 import org.apache.pinot.segment.local.customobject.ThetaSketchAccumulator;
 import org.apache.pinot.segment.local.customobject.TupleIntSketchAccumulator;
@@ -112,6 +130,7 @@ import 
org.apache.pinot.segment.local.customobject.tdigest.NonFiniteAwareTDigest
 import org.apache.pinot.segment.local.customobject.tdigest.SerializedTDigest;
 import org.apache.pinot.segment.local.customobject.tdigest.TDigest;
 import org.apache.pinot.segment.local.utils.GeometryUtils;
+import org.apache.pinot.segment.spi.AggregationFunctionType;
 import org.apache.pinot.segment.spi.memory.PagedPinotOutputStream;
 import org.apache.pinot.spi.data.FieldSpec.DataType;
 import org.apache.pinot.spi.utils.ByteArray;
@@ -121,13 +140,18 @@ import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
 
 
 /// Checks that the serialized intermediate result of an aggregation function 
has the wire type value mixed-version
 /// servers and brokers exchange, writes the payload of its 
[SerializedResult#getBytes] into a heap or direct buffer
 /// and into a paged output stream, filling exactly [SerializedResult#getSize] 
bytes, and that the payload deserializes
 /// to a result with the same final result, which keeps no reference to the 
buffer it was read from.
+///
+/// Every [AggregationFunctionType] is either the type of a function checked 
here or listed in [#EXCLUDED_TYPES] with
+/// the reason it is not, so a new function type cannot go unchecked.
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class IntermediateResultByteBufferSerDeTest {
   private static final ExpressionContext COLUMN = 
ExpressionContext.forIdentifier("column");
@@ -138,6 +162,37 @@ public class IntermediateResultByteBufferSerDeTest {
   private static final int PADDING = 4;
   private static final byte PADDING_BYTE = 0x5a;
 
+  /// The aggregation function types that no function in 
[#intermediateResults] has, mapped to the reason.
+  private static final Map<AggregationFunctionType, String> EXCLUDED_TYPES = 
Map.ofEntries(
+      Map.entry(AggregationFunctionType.COUNT, "LONG intermediate result"),
+      Map.entry(AggregationFunctionType.MIN, "DOUBLE intermediate result"),
+      Map.entry(AggregationFunctionType.MAX, "DOUBLE intermediate result"),
+      Map.entry(AggregationFunctionType.MINSTRING, "STRING intermediate 
result"),
+      Map.entry(AggregationFunctionType.MAXSTRING, "STRING intermediate 
result"),
+      Map.entry(AggregationFunctionType.MINLONG, "LONG intermediate result"),
+      Map.entry(AggregationFunctionType.MAXLONG, "LONG intermediate result"),
+      Map.entry(AggregationFunctionType.SUM, "DOUBLE intermediate result"),
+      Map.entry(AggregationFunctionType.SUM0, "DOUBLE intermediate result"),
+      Map.entry(AggregationFunctionType.SUMINT, "LONG intermediate result"),
+      Map.entry(AggregationFunctionType.SUMLONG, "LONG intermediate result"),
+      Map.entry(AggregationFunctionType.DISTINCTCOUNTOFFHEAP, "checked by 
testDistinctCountOffHeap"),
+      Map.entry(AggregationFunctionType.SEGMENTPARTITIONEDDISTINCTCOUNT, "LONG 
intermediate result"),
+      Map.entry(AggregationFunctionType.FOURTHMOMENT, "no final result; same 
function class as KURTOSIS and SKEWNESS"),
+      Map.entry(AggregationFunctionType.BOOLAND, "INT intermediate result"),
+      Map.entry(AggregationFunctionType.BOOLOR, "INT intermediate result"),
+      Map.entry(AggregationFunctionType.EXPRMIN, "rewritten into 
PINOTPARENTAGGEXPRMIN and PINOTCHILDAGGEXPRMIN"),
+      Map.entry(AggregationFunctionType.EXPRMAX, "rewritten into 
PINOTPARENTAGGEXPRMAX and PINOTCHILDAGGEXPRMAX"),
+      Map.entry(AggregationFunctionType.PINOTPARENTAGGEXPRMIN, "checked by 
testParentExprMinMax"),
+      Map.entry(AggregationFunctionType.PINOTPARENTAGGEXPRMAX, "checked by 
testParentExprMinMax"),
+      Map.entry(AggregationFunctionType.PINOTCHILDAGGEXPRMIN, "LONG 
intermediate result"),
+      Map.entry(AggregationFunctionType.PINOTCHILDAGGEXPRMAX, "LONG 
intermediate result"),
+      Map.entry(AggregationFunctionType.COUNTMV, "LONG intermediate result"),
+      Map.entry(AggregationFunctionType.MINMV, "DOUBLE intermediate result"),
+      Map.entry(AggregationFunctionType.MAXMV, "DOUBLE intermediate result"),
+      Map.entry(AggregationFunctionType.SUMMV, "DOUBLE intermediate result"),
+      Map.entry(AggregationFunctionType.TIMESERIESAGGREGATE, "time series 
engine only, which never serializes it")
+  );
+
   private static final HistogramAggregationFunction HISTOGRAM = new 
HistogramAggregationFunction(
       List.of(COLUMN, ExpressionContext.forLiteral(Literal.doubleValue(0)),
           ExpressionContext.forLiteral(Literal.doubleValue(10)), 
ExpressionContext.forLiteral(Literal.intValue(2))),
@@ -164,12 +219,28 @@ public class IntermediateResultByteBufferSerDeTest {
       List.of(COLUMN, ExpressionContext.forLiteral(Literal.stringValue("MIN")),
           ExpressionContext.forLiteral(Literal.stringValue("STRING"))), false);
   private static final AnyValueAggregationFunction ANY_VALUE = new 
AnyValueAggregationFunction(List.of(COLUMN), false);
-  private static final FunnelMaxStepAggregationFunction FUNNEL_MAX_STEP = new 
FunnelMaxStepAggregationFunction(
-      List.of(TIME_COLUMN, 
ExpressionContext.forLiteral(Literal.longValue(1000L)),
-          ExpressionContext.forLiteral(Literal.intValue(2)), 
ExpressionContext.forIdentifier("step0"),
-          ExpressionContext.forIdentifier("step1")), false);
+  private static final FunnelMaxStepAggregationFunction FUNNEL_MAX_STEP =
+      new FunnelMaxStepAggregationFunction(funnelWindowArguments(), false);
+  private static final FunnelStepDurationStatsAggregationFunction 
FUNNEL_STEP_DURATION_STATS =
+      new FunnelStepDurationStatsAggregationFunction(funnelWindowArguments(
+          
ExpressionContext.forLiteral(Literal.stringValue("durationFunctions=avg"))), 
false);
+  private static final FunnelEventsFunctionEvalAggregationFunction 
FUNNEL_EVENTS_FUNCTION_EVAL =
+      new FunnelEventsFunctionEvalAggregationFunction(funnelWindowArguments(
+          ExpressionContext.forLiteral(Literal.intValue(1)), 
ExpressionContext.forIdentifier("extra")), false);
   private static final AggregationFunction FUNNEL_COUNT = funnelCount();
   private static final AggregationFunction FUNNEL_COUNT_SET = 
funnelCount("set");
+  private static final List<ExpressionContext> PERCENTILE_KLL_ARGUMENTS =
+      List.of(COLUMN, ExpressionContext.forLiteral(Literal.doubleValue(50)));
+
+  /// Returns the arguments of a two-step funnel window function over a 1000 
time unit window, followed by
+  /// `extraArguments`.
+  private static List<ExpressionContext> 
funnelWindowArguments(ExpressionContext... extraArguments) {
+    List<ExpressionContext> arguments = new ArrayList<>(List.of(TIME_COLUMN,
+        ExpressionContext.forLiteral(Literal.longValue(1000L)), 
ExpressionContext.forLiteral(Literal.intValue(2)),
+        ExpressionContext.forIdentifier("step0"), 
ExpressionContext.forIdentifier("step1")));
+    arguments.addAll(List.of(extraArguments));
+    return arguments;
+  }
 
   private static AggregationFunction funnelCount(String... settings) {
     List<ExpressionContext> arguments = new ArrayList<>(List.of(
@@ -290,6 +361,10 @@ public class IntermediateResultByteBufferSerDeTest {
     idSet.add(2);
     PriorityQueue<FunnelStepEvent> funnelStepEvents =
         new PriorityQueue<>(List.of(new FunnelStepEvent(1L, 0), new 
FunnelStepEvent(2L, 1)));
+    PriorityQueue<FunnelStepEventWithExtraFields> 
funnelStepEventsWithExtraFields = new PriorityQueue<>(List.of(
+        new FunnelStepEventWithExtraFields(new FunnelStepEvent(1L, 0), 
List.of("a")),
+        new FunnelStepEventWithExtraFields(new FunnelStepEvent(2L, 1), 
List.of("b"))
+    ));
     return new Object[][]{
         {new ArrayAggIntFunction(COLUMN, DataType.INT, false), new 
IntArrayList(new int[]{1, -2, 7}), 42},
         {new ArrayAggBigDecimalFunction(COLUMN, false),
@@ -315,8 +390,11 @@ public class IntermediateResultByteBufferSerDeTest {
         {new SumArrayDoubleAggregationFunction(List.of(COLUMN), false), new 
double[]{0.25, 8}, 3},
         {HISTOGRAM, new double[]{1, 2}, 3},
         {new PercentileAggregationFunction(COLUMN, 50, false), new 
DoubleArrayList(new double[]{-3.5, 0, 7}), 3},
+        {new PercentileMVAggregationFunction(COLUMN, 50, false), new 
DoubleArrayList(new double[]{-3.5, 0, 7}), 3},
         {PERCENTILE_TDIGEST, tDigest, 10},
+        {new PercentileTDigestMVAggregationFunction(COLUMN, 50, false), 
tDigest, 10},
         {PERCENTILE_RAW_TDIGEST, tDigest, 10},
+        {new PercentileRawTDigestMVAggregationFunction(COLUMN, 50, false), 
tDigest, 10},
         {PERCENTILE_SMART_TDIGEST, new DoubleArrayList(new double[]{1, 2}), 3},
         {PERCENTILE_SMART_TDIGEST, tDigest, 10},
         {DISTINCT_COUNT, new IntOpenHashSet(new int[]{1, 2}), 9},
@@ -327,16 +405,29 @@ public class IntermediateResultByteBufferSerDeTest {
         {DISTINCT_COUNT, new ObjectOpenHashSet<>(new String[]{"a", "b"}), 18},
         {DISTINCT_COUNT, new ObjectOpenHashSet<>(new ByteArray[]{new 
ByteArray(new byte[]{1})}), 19},
         {DISTINCT_COUNT, new IntOpenHashSet(), 9},
+        {new DistinctCountMVAggregationFunction(List.of(COLUMN), false), new 
IntOpenHashSet(new int[]{1, 2}), 9},
+        {new DistinctSumAggregationFunction(List.of(COLUMN), false), new 
IntOpenHashSet(new int[]{1, 2}), 9},
+        {new DistinctSumMVAggregationFunction(List.of(COLUMN), false), new 
DoubleOpenHashSet(new double[]{2.5}), 17},
+        {new DistinctAvgAggregationFunction(List.of(COLUMN), false), new 
LongOpenHashSet(new long[]{1, 2}), 15},
+        {new DistinctAvgMVAggregationFunction(List.of(COLUMN), false), new 
FloatOpenHashSet(new float[]{1.5f}), 16},
         {DISTINCT_COUNT_BITMAP, sparseBitmap, 14},
         {DISTINCT_COUNT_BITMAP, denseBitmap, 14},
+        {new DistinctCountBitmapMVAggregationFunction(List.of(COLUMN), false), 
sparseBitmap, 14},
         {new DistinctCountHLLAggregationFunction(List.of(COLUMN), false), 
hyperLogLog, 6},
+        {new DistinctCountHLLMVAggregationFunction(List.of(COLUMN), false), 
hyperLogLog, 6},
+        {new DistinctCountRawHLLAggregationFunction(List.of(COLUMN), false), 
hyperLogLog, 6},
+        {new DistinctCountRawHLLMVAggregationFunction(List.of(COLUMN), false), 
hyperLogLog, 6},
         {new FastHLLAggregationFunction(List.of(COLUMN), false), hyperLogLog, 
6},
         {new DistinctCountHLLPlusAggregationFunction(List.of(COLUMN), false), 
hyperLogLogPlus, 40},
+        {new DistinctCountHLLPlusMVAggregationFunction(List.of(COLUMN), 
false), hyperLogLogPlus, 40},
+        {new DistinctCountRawHLLPlusAggregationFunction(List.of(COLUMN), 
false), hyperLogLogPlus, 40},
+        {new DistinctCountRawHLLPlusMVAggregationFunction(List.of(COLUMN), 
false), hyperLogLogPlus, 40},
         {DISTINCT_COUNT_SMART_HLL, hyperLogLog, 6},
         {DISTINCT_COUNT_SMART_HLL, new IntOpenHashSet(new int[]{1, 2}), 9},
         {DISTINCT_COUNT_SMART_HLL_PLUS, hyperLogLogPlus, 40},
         {DISTINCT_COUNT_SMART_HLL_PLUS, new LongOpenHashSet(new long[]{1, 2}), 
15},
         {new DistinctCountULLAggregationFunction(List.of(COLUMN), false), 
ultraLogLog, 46},
+        {new DistinctCountRawULLAggregationFunction(List.of(COLUMN), false), 
ultraLogLog, 46},
         {DISTINCT_COUNT_SMART_ULL, ultraLogLog, 46},
         {DISTINCT_COUNT_SMART_ULL, new IntOpenHashSet(new int[]{1, 2}), 9},
         {MODE, int2LongMap, 23},
@@ -358,9 +449,15 @@ public class IntermediateResultByteBufferSerDeTest {
         {funnelCount("partitioned", "sorted"), LongArrayList.wrap(new 
long[]{2, 1}), 43},
         {funnelCount("partitioned", "sorted"), List.of(0L, 0L), 21},
         {FUNNEL_MAX_STEP, funnelStepEvents, 51},
+        {new FunnelCompleteCountAggregationFunction(funnelWindowArguments(), 
false), funnelStepEvents, 51},
+        {new FunnelMatchStepAggregationFunction(funnelWindowArguments(), 
false), funnelStepEvents, 51},
+        {FUNNEL_STEP_DURATION_STATS, funnelStepEvents, 51},
+        {FUNNEL_EVENTS_FUNCTION_EVAL, funnelStepEventsWithExtraFields, 0},
         // Serialized eagerly into its payload bytes
         {new AvgAggregationFunction(List.of(COLUMN), false), new AvgPair(3.0, 
2L), 4},
+        {new AvgMVAggregationFunction(List.of(COLUMN), false), new 
AvgPair(3.0, 2L), 4},
         {new MinMaxRangeAggregationFunction(List.of(COLUMN), false), new 
MinMaxRangePair(1.5, 2.5), 5},
+        {new MinMaxRangeMVAggregationFunction(List.of(COLUMN), false), new 
MinMaxRangePair(1.5, 2.5), 5},
         {new SumPrecisionAggregationFunction(List.of(COLUMN), false), new 
BigDecimal("1.5"), 22},
         {new StUnionAggregationFunction(List.of(COLUMN), false),
             GeometryUtils.GEOMETRY_FACTORY.createPoint(new Coordinate(1, 2)), 
13},
@@ -388,18 +485,40 @@ public class IntermediateResultByteBufferSerDeTest {
             new BytesLongPair(new ByteArray(new byte[]{1, 2}), 2L), 56},
         {new CovarianceAggregationFunction(List.of(COLUMN, COLUMN_2), false, 
false),
             new CovarianceTuple(1.0, 2.0, 3.0, 4L), 32},
+        {new CovarianceAggregationFunction(List.of(COLUMN, COLUMN_2), true, 
false),
+            new CovarianceTuple(1.0, 2.0, 3.0, 4L), 32},
         {new VarianceAggregationFunction(List.of(COLUMN), false, false, 
false), new VarianceTuple(4L, 2.0, 1.0), 33},
+        {new VarianceAggregationFunction(List.of(COLUMN), true, false, false), 
new VarianceTuple(4L, 2.0, 1.0), 33},
+        {new VarianceAggregationFunction(List.of(COLUMN), false, true, false), 
new VarianceTuple(4L, 2.0, 1.0), 33},
+        {new VarianceAggregationFunction(List.of(COLUMN), true, true, false), 
new VarianceTuple(4L, 2.0, 1.0), 33},
         {new FourthMomentAggregationFunction(List.of(COLUMN), 
FourthMomentAggregationFunction.Type.KURTOSIS, false),
             fourthMoment(), 34},
+        {new FourthMomentAggregationFunction(List.of(COLUMN), 
FourthMomentAggregationFunction.Type.SKEWNESS, false),
+            fourthMoment(), 34},
         {new PercentileEstAggregationFunction(COLUMN, 50, false), 
quantileDigest(), 7},
-        {new PercentileKLLAggregationFunction(List.of(COLUMN, 
ExpressionContext.forLiteral(Literal.doubleValue(50))),
-            false), kllSketch(), 36},
+        {new PercentileEstMVAggregationFunction(COLUMN, 50, false), 
quantileDigest(), 7},
+        {new PercentileRawEstAggregationFunction(COLUMN, 50, false), 
quantileDigest(), 7},
+        {new PercentileRawEstMVAggregationFunction(COLUMN, 50, false), 
quantileDigest(), 7},
+        {new PercentileKLLAggregationFunction(PERCENTILE_KLL_ARGUMENTS, 
false), kllSketch(), 36},
+        {new PercentileKLLMVAggregationFunction(PERCENTILE_KLL_ARGUMENTS, 
false), kllSketch(), 36},
+        {new PercentileRawKLLAggregationFunction(PERCENTILE_KLL_ARGUMENTS, 
false), kllSketch(), 36},
+        {new PercentileRawKLLMVAggregationFunction(PERCENTILE_KLL_ARGUMENTS, 
false), kllSketch(), 36},
         {new FrequentLongsSketchAggregationFunction(List.of(COLUMN), false), 
frequentLongsSketch(), 39},
         {new FrequentStringsSketchAggregationFunction(List.of(COLUMN), false), 
frequentStringsSketch(), 38},
         {new DistinctCountCPCSketchAggregationFunction(List.of(COLUMN), 
false), cpcSketchAccumulator(), 49},
+        {new DistinctCountRawCPCSketchAggregationFunction(List.of(COLUMN), 
false), cpcSketchAccumulator(), 49},
         {new IntegerTupleSketchAggregationFunction(List.of(COLUMN), 
IntegerSummary.Mode.Sum, false),
             tupleIntSketchAccumulator(), 48},
-        {new DistinctCountThetaSketchAggregationFunction(List.of(COLUMN), 
false), List.of(thetaSketchAccumulator()), 21}
+        {new 
DistinctCountIntegerTupleSketchAggregationFunction(List.of(COLUMN), 
IntegerSummary.Mode.Sum, false),
+            tupleIntSketchAccumulator(), 48},
+        {new SumValuesIntegerTupleSketchAggregationFunction(List.of(COLUMN), 
IntegerSummary.Mode.Sum, false),
+            tupleIntSketchAccumulator(), 48},
+        {new AvgValueIntegerTupleSketchAggregationFunction(List.of(COLUMN), 
IntegerSummary.Mode.Sum, false),
+            tupleIntSketchAccumulator(), 48},
+        {new DistinctCountThetaSketchAggregationFunction(List.of(COLUMN), 
false),
+            List.of(thetaSketchAccumulator()), 21},
+        {new DistinctCountRawThetaSketchAggregationFunction(List.of(COLUMN), 
false),
+            List.of(thetaSketchAccumulator()), 21}
     };
   }
 
@@ -452,6 +571,28 @@ public class IntermediateResultByteBufferSerDeTest {
     
assertEquals(comparableForm(function.extractFinalResult(deserializedFromOffset)),
 expectedFinalResult);
   }
 
+  /// Every aggregation function type is the type of a function in 
[#intermediateResults] or has a reason in
+  /// [#EXCLUDED_TYPES], and not both.
+  @Test
+  public void testEveryTypeIsCheckedOrExcluded() {
+    Set<AggregationFunctionType> checkedTypes = 
EnumSet.noneOf(AggregationFunctionType.class);
+    for (Object[] row : intermediateResults()) {
+      checkedTypes.add(((AggregationFunction) row[0]).getType());
+    }
+    List<AggregationFunctionType> uncheckedTypes = new ArrayList<>();
+    for (AggregationFunctionType type : AggregationFunctionType.values()) {
+      if (!checkedTypes.contains(type) && !EXCLUDED_TYPES.containsKey(type)) {
+        uncheckedTypes.add(type);
+      }
+    }
+    assertTrue(uncheckedTypes.isEmpty(),
+        "Types with neither a function in intermediateResults nor a reason in 
EXCLUDED_TYPES: " + uncheckedTypes);
+    for (Map.Entry<AggregationFunctionType, String> entry : 
EXCLUDED_TYPES.entrySet()) {
+      assertFalse(checkedTypes.contains(entry.getKey()),
+          entry.getKey() + " has a function in intermediateResults and is 
excluded as: " + entry.getValue());
+    }
+  }
+
   /// The parent `EXPRMIN` / `EXPRMAX` function, checked on its bytes since 
[ExprMinMaxObject] has no value equality:
   /// its wire type value, and a deserialized object that serializes to the 
same bytes after its source buffer is
   /// overwritten.
@@ -487,12 +628,57 @@ public class IntermediateResultByteBufferSerDeTest {
     
assertEquals(function.serializeIntermediateResult(deserialized).getBytes(), 
expectedBytes);
   }
 
+  @DataProvider
+  public static Object[][] offHeapSets() {
+    OffHeap32BitSet set32 = new OffHeap32BitSet(4);
+    OffHeap64BitSet set64 = new OffHeap64BitSet(4);
+    OffHeap128BitSet set128 = new OffHeap128BitSet(4);
+    int numValues = 3;
+    // Includes zero, which the sets hold outside their hash tables
+    for (int value = 0; value < numValues; value++) {
+      set32.add(value);
+      set64.add(value);
+      set128.add(value, -value);
+    }
+    // The payload is the number of values followed by the values
+    return new Object[][]{
+        {set32, 0, Integer.BYTES + numValues * Integer.BYTES},
+        {set64, 1, Integer.BYTES + numValues * Long.BYTES},
+        {set128, 2, Integer.BYTES + numValues * 2 * Long.BYTES}
+    };
+  }
+
+  /// The `DISTINCTCOUNTOFFHEAP` function, checked on one serialization of 
each set, since serializing a set frees its
+  /// memory: its wire type value, the payload size, and a payload that 
deserializes to a set with the same final
+  /// result after its source buffer is overwritten.
+  @Test(dataProvider = "offHeapSets")
+  public void testDistinctCountOffHeap(BaseOffHeapSet set, int expectedType, 
int expectedSize) {
+    DistinctCountOffHeapAggregationFunction function =
+        new DistinctCountOffHeapAggregationFunction(List.of(COLUMN), false);
+    int expectedFinalResult = set.size();
+    SerializedResult serialized = function.serializeIntermediateResult(set);
+    assertEquals(serialized.getType(), expectedType);
+    assertEquals(serialized.getSize(), expectedSize);
+    byte[] bytes = serialized.getBytes();
+    assertEquals(bytes.length, expectedSize);
+    BaseOffHeapSet deserialized =
+        function.deserializeIntermediateResult(new CustomObject(expectedType, 
ByteBuffer.wrap(bytes)));
+    Arrays.fill(bytes, PADDING_BYTE);
+    assertEquals(function.extractFinalResult(deserialized).intValue(), 
expectedFinalResult);
+  }
+
   /// Returns a final result in a form that compares by value. The serialized 
sketches have no `equals`, so they
   /// compare by their string form, which is what the broker returns.
   private static Object comparableForm(Object finalResult) {
     if (finalResult instanceof SerializedTDigest
         || finalResult instanceof SerializedFrequentLongsSketch
-        || finalResult instanceof SerializedFrequentStringsSketch) {
+        || finalResult instanceof SerializedFrequentStringsSketch
+        || finalResult instanceof SerializedHLL
+        || finalResult instanceof SerializedHLLPlus
+        || finalResult instanceof SerializedULL
+        || finalResult instanceof SerializedCPCSketch
+        || finalResult instanceof SerializedQuantileDigest
+        || finalResult instanceof SerializedKLL) {
       return finalResult.toString();
     }
     return finalResult;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to