You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by ja...@apache.org on 2026/09/02 16:24:09 UTC
(pinot) branch master updated: Support null handling in dictionary-based and multi-value group key generation (#19390)
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 46a07c77cfd Support null handling in dictionary-based and multi-value group key generation (#19390)
46a07c77cfd is described below
commit 46a07c77cfd199ab0013611d16435b95fc0e030b
Author: Xiaotian (Jackie) Jiang <17...@users.noreply.github.com>
AuthorDate: Wed Sep 2 09:24:01 2026 -0700
Support null handling in dictionary-based and multi-value group key generation (#19390)
---
.../groupby/DefaultGroupByExecutor.java | 29 +-
.../groupby/DictionaryBasedGroupKeyGenerator.java | 136 +-
.../groupby/GroupingSetsGroupKeyGenerator.java | 17 +
.../NoDictionaryMultiColumnGroupKeyGenerator.java | 212 ++-
.../NoDictionarySingleColumnGroupKeyGenerator.java | 222 ++--
.../DictionaryBasedGroupKeyGeneratorTest.java | 123 +-
.../queries/NullHandlingEnabledQueriesTest.java | 1370 +++++++++++---------
7 files changed, 1203 insertions(+), 906 deletions(-)
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/DefaultGroupByExecutor.java b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/DefaultGroupByExecutor.java
index 5bad8a3fc48..f4349c1171a 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/DefaultGroupByExecutor.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/DefaultGroupByExecutor.java
@@ -41,10 +41,14 @@ import org.apache.pinot.core.query.request.context.QueryContext;
/// This class implements group by aggregation.
-/// It is optimized for performance, and uses the best possible algorithm/data-structure
-/// for a given query based on the following parameters:
+/// It is optimized for performance, and uses the best possible algorithm/data-structure for a given query based on the
+/// following parameters:
+/// - Whether all group-by columns are dictionary encoded.
/// - Maximum number of group keys possible.
/// - Single/Multi valued columns.
+///
+/// Null handling does not affect the choice: every group key generator gives a null a group of its own when it is
+/// enabled.
@SuppressWarnings({"rawtypes", "unchecked"})
public class DefaultGroupByExecutor implements GroupByExecutor {
// Thread local (reusable) array for single-valued group keys
@@ -68,11 +72,6 @@ public class DefaultGroupByExecutor implements GroupByExecutor {
this(queryContext, queryContext.getAggregationFunctions(), groupByExpressions, projectOperator, null);
}
- public DefaultGroupByExecutor(QueryContext queryContext, AggregationFunction[] aggregationFunctions,
- ExpressionContext[] groupByExpressions, BaseProjectOperator<?> projectOperator) {
- this(queryContext, aggregationFunctions, groupByExpressions, projectOperator, null);
- }
-
public DefaultGroupByExecutor(QueryContext queryContext, AggregationFunction[] aggregationFunctions,
ExpressionContext[] groupByExpressions, BaseProjectOperator<?> projectOperator,
@Nullable GroupKeyGenerator groupKeyGenerator) {
@@ -90,8 +89,8 @@ public class DefaultGroupByExecutor implements GroupByExecutor {
// isDictionaryEncoded() flag rather than gating on dictionary nullness alone.
hasNoDictionaryGroupByExpression |= !columnContext.isDictionaryEncoded();
}
- /// Grouping-set queries expand each row into one group per grouping set, so they always use the
- /// multi-value (int[][]) executor path even though the union group-by columns are single-valued.
+ // Grouping-set queries expand each row into one group per grouping set, so they always use the
+ // multi-value (int[][]) executor path even though the union group-by columns are single-valued.
boolean groupingSets = queryContext.isGroupingSets();
_hasMVGroupByExpression = hasMVGroupByExpression || groupingSets;
@@ -105,12 +104,14 @@ public class DefaultGroupByExecutor implements GroupByExecutor {
if (groupKeyGenerator != null) {
_groupKeyGenerator = groupKeyGenerator;
} else if (groupingSets) {
- _groupKeyGenerator = new GroupingSetsGroupKeyGenerator(projectOperator, groupByExpressions,
- queryContext.getGroupingSets(), numGroupsLimit, _nullHandlingEnabled);
+ _groupKeyGenerator =
+ new GroupingSetsGroupKeyGenerator(projectOperator, groupByExpressions, queryContext.getGroupingSets(),
+ numGroupsLimit, _nullHandlingEnabled);
} else {
- if (hasNoDictionaryGroupByExpression || _nullHandlingEnabled) {
+ // Null handling does not steer this choice: every generator below gives a null an id of its own, so the
+ // encoding of the group-by columns decides on its own which one to use.
+ if (hasNoDictionaryGroupByExpression) {
if (groupByExpressions.length == 1) {
- // TODO(nhejazi): support MV and dictionary based when null handling is enabled.
_groupKeyGenerator =
new NoDictionarySingleColumnGroupKeyGenerator(projectOperator, groupByExpressions[0], numGroupsLimit,
_nullHandlingEnabled, groupByExpressionSizesFromPredicates);
@@ -121,7 +122,7 @@ public class DefaultGroupByExecutor implements GroupByExecutor {
}
} else {
_groupKeyGenerator = new DictionaryBasedGroupKeyGenerator(projectOperator, groupByExpressions, numGroupsLimit,
- maxInitialResultHolderCapacity, groupByExpressionSizesFromPredicates);
+ maxInitialResultHolderCapacity, _nullHandlingEnabled, groupByExpressionSizesFromPredicates);
}
}
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/DictionaryBasedGroupKeyGenerator.java b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/DictionaryBasedGroupKeyGenerator.java
index 22c3229cb8c..823f11ce971 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/DictionaryBasedGroupKeyGenerator.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/DictionaryBasedGroupKeyGenerator.java
@@ -37,7 +37,10 @@ import org.apache.pinot.core.common.BlockValSet;
import org.apache.pinot.core.operator.BaseProjectOperator;
import org.apache.pinot.core.operator.ColumnContext;
import org.apache.pinot.core.operator.blocks.ValueBlock;
+import org.apache.pinot.segment.spi.datasource.DataSource;
import org.apache.pinot.segment.spi.index.reader.Dictionary;
+import org.roaringbitmap.PeekableIntIterator;
+import org.roaringbitmap.RoaringBitmap;
/// Class for generating group keys (groupId-stringKey pair) for a given list of dictionary encoded group-by columns.
@@ -46,6 +49,12 @@ import org.apache.pinot.segment.spi.index.reader.Dictionary;
///
/// The raw key is generated from the dictionary ids of the group-by columns.
///
+/// With null handling enabled, a column that can produce a null reserves one further dictionary id, one past its
+/// last real id, to stand for it, so its cardinality counts one more than the dictionary holds. A null then composes
+/// into the raw key like any other value and is read back out as SQL `NULL`. A column read from a segment that tracks
+/// no nulls reserves nothing, and neither does any column when null handling is disabled, which leaves the
+/// cardinalities, the raw key arithmetic and the block reads exactly as they are without this.
+///
/// - If the maximum number of possible group keys is less than a threshold (10K), directly use the raw key as the
/// group id. (ARRAY_BASED)
/// - If the maximum number of possible group keys is larger than the threshold, but still fit into integer, generate
@@ -83,12 +92,22 @@ public class DictionaryBasedGroupKeyGenerator implements GroupKeyGenerator {
private final int[] _cardinalities;
private final boolean[] _isSingleValueColumn;
private final Dictionary[] _dictionaries;
-
+ // Dictionary id standing for a null value in each group-by column, or -1 for a column that produces none. Reserving
+ // the id one past the column's last real id is what keeps nulls apart from the column's default null value, which is
+ // the value a null row is physically stored as. Null when no column reserves one at all.
+ @Nullable
+ private final int[] _nullDictIds;
// The first dimension is the index of group-by column
// Reusable buffer for single-value column dictionary ids
private final int[][] _singleValueDictIds;
+ // Reusable buffers holding a block's dictionary ids with the null rows rewritten, filled in on the first block of
+ // a column that actually contains nulls, and null whenever no column reserves a null dictionary id
+ @Nullable
+ private final int[][] _nullReplacedSingleValueDictIds;
// Reusable buffer for multi-value column dictionary ids
private final int[][][] _multiValueDictIds;
+ @Nullable
+ private final int[][][] _nullReplacedMultiValueDictIds;
private final Object[][] _internedDictionaryValues;
@@ -97,7 +116,7 @@ public class DictionaryBasedGroupKeyGenerator implements GroupKeyGenerator {
public DictionaryBasedGroupKeyGenerator(BaseProjectOperator<?> projectOperator,
ExpressionContext[] groupByExpressions, int numGroupsLimit, int arrayBasedThreshold,
- @Nullable Map<ExpressionContext, Integer> groupByExpressionSizesFromPredicates) {
+ boolean nullHandlingEnabled, @Nullable Map<ExpressionContext, Integer> groupByExpressionSizesFromPredicates) {
_groupByExpressions = groupByExpressions;
_numGroupByExpressions = groupByExpressions.length;
@@ -106,6 +125,8 @@ public class DictionaryBasedGroupKeyGenerator implements GroupKeyGenerator {
_dictionaries = new Dictionary[_numGroupByExpressions];
_singleValueDictIds = new int[_numGroupByExpressions][];
_multiValueDictIds = new int[_numGroupByExpressions][][];
+ int[] nullDictIds = nullHandlingEnabled ? new int[_numGroupByExpressions] : null;
+ boolean anyNullDictId = false;
// no need to intern dictionary values when there is only one group by expression because
// only one call will be made to the dictionary to extract each raw value.
_internedDictionaryValues = _numGroupByExpressions > 1 ? new Object[_numGroupByExpressions][] : null;
@@ -118,6 +139,24 @@ public class DictionaryBasedGroupKeyGenerator implements GroupKeyGenerator {
_dictionaries[i] = columnContext.getDictionary();
assert _dictionaries[i] != null;
int cardinality = _dictionaries[i].length();
+ if (nullDictIds != null) {
+ // Reserve an id unless the column is known to produce no null. A column read straight from a segment says so
+ // through its null value vector, which is the same vector a query reads nulls from. A transform exposes no
+ // data source to consult and can still hand out a null bitmap of its own, so it always reserves one.
+ //
+ // This decides nullability once, from one project operator, while a shared generator can be handed blocks
+ // from others: FilteredGroupByOperator builds a single generator for every filtered aggregation. Those
+ // operators must therefore agree on which group-by columns can produce a null. They do today, because a
+ // star-tree is only chosen for a null handling query when no column it touches holds a null.
+ DataSource dataSource = columnContext.getDataSource();
+ boolean tracksNulls = dataSource == null || dataSource.getNullValueVector() != null;
+ if (tracksNulls) {
+ nullDictIds[i] = cardinality++;
+ anyNullDictId = true;
+ } else {
+ nullDictIds[i] = -1;
+ }
+ }
_cardinalities[i] = cardinality;
cardinalityMap.put(groupByExpression, cardinality);
if (_internedDictionaryValues != null && cardinality < MAX_DICTIONARY_INTERN_TABLE_SIZE) {
@@ -132,6 +171,15 @@ public class DictionaryBasedGroupKeyGenerator implements GroupKeyGenerator {
}
_isSingleValueColumn[i] = columnContext.isSingleValue();
}
+ if (anyNullDictId) {
+ _nullDictIds = nullDictIds;
+ _nullReplacedSingleValueDictIds = new int[_numGroupByExpressions][];
+ _nullReplacedMultiValueDictIds = new int[_numGroupByExpressions][][];
+ } else {
+ _nullDictIds = null;
+ _nullReplacedSingleValueDictIds = null;
+ _nullReplacedMultiValueDictIds = null;
+ }
if (groupByExpressionSizesFromPredicates != null) {
Pair<Boolean, Long> optimizedCardinality = getOptimizedGroupByCardinality(groupByExpressionSizesFromPredicates,
cardinalityMap);
@@ -216,25 +264,89 @@ public class DictionaryBasedGroupKeyGenerator implements GroupKeyGenerator {
@Override
public void generateKeysForBlock(ValueBlock valueBlock, int[] groupKeys) {
// Fetch dictionary ids in the given block for all group-by columns
+ int numDocs = valueBlock.getNumDocs();
for (int i = 0; i < _numGroupByExpressions; i++) {
- BlockValSet blockValueSet = valueBlock.getBlockValueSet(_groupByExpressions[i]);
- _singleValueDictIds[i] = blockValueSet.getDictionaryIdsSV();
+ _singleValueDictIds[i] = getSingleValueDictIds(valueBlock.getBlockValueSet(_groupByExpressions[i]), i, numDocs);
}
- _rawKeyHolder.processSingleValue(valueBlock.getNumDocs(), groupKeys);
+ _rawKeyHolder.processSingleValue(numDocs, groupKeys);
}
@Override
public void generateKeysForBlock(ValueBlock valueBlock, int[][] groupKeys) {
// Fetch dictionary ids in the given block for all group-by columns
+ int numDocs = valueBlock.getNumDocs();
for (int i = 0; i < _numGroupByExpressions; i++) {
BlockValSet blockValueSet = valueBlock.getBlockValueSet(_groupByExpressions[i]);
if (_isSingleValueColumn[i]) {
- _singleValueDictIds[i] = blockValueSet.getDictionaryIdsSV();
+ _singleValueDictIds[i] = getSingleValueDictIds(blockValueSet, i, numDocs);
} else {
- _multiValueDictIds[i] = blockValueSet.getDictionaryIdsMV();
+ _multiValueDictIds[i] = getMultiValueDictIds(blockValueSet, i, numDocs);
}
}
- _rawKeyHolder.processMultiValue(valueBlock.getNumDocs(), groupKeys);
+ _rawKeyHolder.processMultiValue(numDocs, groupKeys);
+ }
+
+ /// Returns the block's single-value dictionary ids, with every null row moved onto the column's reserved null
+ /// dictionary id so that nulls form one group of their own.
+ ///
+ /// The block owns the array it hands out and shares it with everything else reading that column in this block, so
+ /// the ids are copied before being rewritten rather than replaced in place. Returns the block's own array untouched
+ /// when the column reserves no null dictionary id or the block holds no null.
+ private int[] getSingleValueDictIds(BlockValSet blockValSet, int index, int numDocs) {
+ int[] dictIds = blockValSet.getDictionaryIdsSV();
+ if (_nullDictIds == null || _nullDictIds[index] < 0) {
+ return dictIds;
+ }
+ int nullDictId = _nullDictIds[index];
+ RoaringBitmap nullBitmap = blockValSet.getNullBitmap();
+ if (nullBitmap == null || nullBitmap.isEmpty()) {
+ return dictIds;
+ }
+ assert _nullReplacedSingleValueDictIds != null;
+ int[] nullReplacedDictIds = _nullReplacedSingleValueDictIds[index];
+ if (nullReplacedDictIds == null || nullReplacedDictIds.length < numDocs) {
+ nullReplacedDictIds = new int[numDocs];
+ _nullReplacedSingleValueDictIds[index] = nullReplacedDictIds;
+ }
+ System.arraycopy(dictIds, 0, nullReplacedDictIds, 0, numDocs);
+ PeekableIntIterator nullIterator = nullBitmap.getIntIterator();
+ while (nullIterator.hasNext()) {
+ nullReplacedDictIds[nullIterator.next()] = nullDictId;
+ }
+ return nullReplacedDictIds;
+ }
+
+ /// Returns the block's multi-value dictionary ids, with every null row replaced by a single entry holding the
+ /// column's reserved null dictionary id, so the row contributes one null group instead of being read as the
+ /// column's default null value.
+ ///
+ /// Only the outer array is copied: the rows that are not null are handed on pointing at the arrays the block
+ /// already gave out. Returns the block's own array untouched when the column reserves no null dictionary id or the
+ /// block holds no null.
+ private int[][] getMultiValueDictIds(BlockValSet blockValSet, int index, int numDocs) {
+ int[][] dictIds = blockValSet.getDictionaryIdsMV();
+ if (_nullDictIds == null || _nullDictIds[index] < 0) {
+ return dictIds;
+ }
+ int nullDictId = _nullDictIds[index];
+ RoaringBitmap nullBitmap = blockValSet.getNullBitmap();
+ if (nullBitmap == null || nullBitmap.isEmpty()) {
+ return dictIds;
+ }
+ assert _nullReplacedMultiValueDictIds != null;
+ int[][] nullReplacedDictIds = _nullReplacedMultiValueDictIds[index];
+ if (nullReplacedDictIds == null || nullReplacedDictIds.length < numDocs) {
+ nullReplacedDictIds = new int[numDocs][];
+ _nullReplacedMultiValueDictIds[index] = nullReplacedDictIds;
+ }
+ System.arraycopy(dictIds, 0, nullReplacedDictIds, 0, numDocs);
+ PeekableIntIterator nullIterator = nullBitmap.getIntIterator();
+ while (nullIterator.hasNext()) {
+ // A fresh array per row rather than one shared between them: a raw key holder writes its group ids back over
+ // the array it is handed for a row whose only group-by column is this one
+ nullReplacedDictIds[nullIterator.next()] = new int[]{nullDictId};
+ }
+ return nullReplacedDictIds;
}
@Override
@@ -589,7 +701,9 @@ public class DictionaryBasedGroupKeyGenerator implements GroupKeyGenerator {
private Object[] getKeys(int rawKey) {
// Specialize single group-by column case
if (_numGroupByExpressions == 1) {
- return new Object[]{_dictionaries[0].getInternal(rawKey)};
+ return new Object[]{
+ _nullDictIds == null || rawKey != _nullDictIds[0] ? _dictionaries[0].getInternal(rawKey) : null
+ };
} else {
Object[] groupKeys = new Object[_numGroupByExpressions];
for (int i = 0; i < _numGroupByExpressions; i++) {
@@ -601,7 +715,11 @@ public class DictionaryBasedGroupKeyGenerator implements GroupKeyGenerator {
}
}
+ @Nullable
private Object getRawValue(int dictionaryIndex, int dictId) {
+ if (_nullDictIds != null && dictId == _nullDictIds[dictionaryIndex]) {
+ return null;
+ }
Dictionary dictionary = _dictionaries[dictionaryIndex];
Object[] table = _internedDictionaryValues[dictionaryIndex];
if (table == null) {
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/GroupingSetsGroupKeyGenerator.java b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/GroupingSetsGroupKeyGenerator.java
index b01db55b01f..680e958ab4c 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/GroupingSetsGroupKeyGenerator.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/GroupingSetsGroupKeyGenerator.java
@@ -34,6 +34,7 @@ import org.apache.pinot.core.query.aggregation.groupby.utils.ValueToIdMapFactory
import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.apache.pinot.spi.utils.ByteArray;
import org.apache.pinot.spi.utils.FixedIntArray;
+import org.roaringbitmap.PeekableIntIterator;
import org.roaringbitmap.RoaringBitmap;
@@ -86,6 +87,8 @@ public class GroupingSetsGroupKeyGenerator implements GroupKeyGenerator {
/// Reusable single-element id list for a rolled-up (non-participating) column on the MV path. Per-instance
/// (segment-confined, never shared across query threads) and treated as read-only: expandGroupIds copies its
/// element into the composite key and never mutates it.
+ /// Stands for a NULL key component, whether because the grouping set excludes the column or because the row's
+ /// value is NULL. Shared by every row and set: the key expansion reads it and never writes to it.
private final int[] _nullComponent = {ID_FOR_NULL};
public GroupingSetsGroupKeyGenerator(BaseProjectOperator<?> projectOperator,
@@ -281,6 +284,17 @@ public class GroupingSetsGroupKeyGenerator implements GroupKeyGenerator {
throw new IllegalArgumentException(
"Illegal multi-value data type for grouping-sets group key generator: " + _storedTypes[col]);
}
+ if (_nullHandlingEnabled) {
+ // A null row's values were resolved above and are discarded here. Only the composed key decides a group, so the
+ // ids they took in the on-the-fly dictionary go unused rather than becoming groups of their own.
+ RoaringBitmap nullBitmap = blockValSet.getNullBitmap();
+ if (nullBitmap != null && !nullBitmap.isEmpty()) {
+ PeekableIntIterator nullIterator = nullBitmap.getIntIterator();
+ while (nullIterator.hasNext()) {
+ ids[nullIterator.next()] = _nullComponent;
+ }
+ }
+ }
return ids;
}
@@ -291,6 +305,9 @@ public class GroupingSetsGroupKeyGenerator implements GroupKeyGenerator {
BlockValSet blockValSet = valueBlock.getBlockValueSet(_groupByExpressions[col]);
ValueToIdMap dictionary = _onTheFlyDictionaries[col];
RoaringBitmap nullBitmap = _nullHandlingEnabled ? blockValSet.getNullBitmap() : null;
+ if (nullBitmap != null && nullBitmap.isEmpty()) {
+ nullBitmap = null;
+ }
switch (_storedTypes[col]) {
case INT:
int[] intValues = blockValSet.getIntValuesSV();
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/NoDictionaryMultiColumnGroupKeyGenerator.java b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/NoDictionaryMultiColumnGroupKeyGenerator.java
index a10de9f47a5..1b6cf547d43 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/NoDictionaryMultiColumnGroupKeyGenerator.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/NoDictionaryMultiColumnGroupKeyGenerator.java
@@ -25,6 +25,7 @@ import it.unimi.dsi.fastutil.objects.ObjectIterator;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
+import javax.annotation.Nullable;
import org.apache.pinot.common.request.context.ExpressionContext;
import org.apache.pinot.core.common.BlockValSet;
import org.apache.pinot.core.operator.BaseProjectOperator;
@@ -36,18 +37,23 @@ import org.apache.pinot.segment.spi.index.reader.Dictionary;
import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.apache.pinot.spi.utils.ByteArray;
import org.apache.pinot.spi.utils.FixedIntArray;
+import org.roaringbitmap.PeekableIntIterator;
import org.roaringbitmap.RoaringBitmap;
-/// Implementation of [GroupKeyGenerator] interface using actual value based
-/// group keys, instead of dictionary ids. This implementation is used for group-by key
-/// generation when one or more of the group-by columns do not have dictionary.
+/// Implementation of [GroupKeyGenerator] interface using actual value based group keys, instead of dictionary ids.
+/// This implementation is used for group-by key generation when one or more of the group-by columns do not have
+/// dictionary.
///
-/// TODO:
-/// 1. Add support for multi-valued group-by columns.
-/// 2. Add support for trimming group-by results.
+/// With null handling enabled, a null row's column contributes a reserved id to the composed key instead of the id of
+/// its stored value, so nulls form groups of their own and are read back as SQL `NULL`. Both the single-value and the
+/// multi-value key paths recognize nulls. Nullness is read from the block's null bitmap rather than from the id, so a
+/// dictionary-encoded column beside a raw one still composes its own dictionary ids instead of paying for an
+/// on-the-fly dictionary.
public class NoDictionaryMultiColumnGroupKeyGenerator implements GroupKeyGenerator {
private static final int ID_FOR_NULL = INVALID_ID - 1;
+ /// Shared by every null row and column: the key composition reads these arrays and never writes to them.
+ private static final int[] NULL_KEY_COMPONENT = {ID_FOR_NULL};
private final ExpressionContext[] _groupByExpressions;
private final int _numGroupByExpressions;
@@ -79,8 +85,7 @@ public class NoDictionaryMultiColumnGroupKeyGenerator implements GroupKeyGenerat
// Take the dict-id path only when the forward index is dict-encoded. A column with EncodingType.RAW +
// dictionaryIndex exposes a Dictionary but BlockValSet#getDictionaryIdsSV throws on its RAW forward
// index — fall back to an on-the-fly dictionary on raw values for that case.
- Dictionary dictionary = _nullHandlingEnabled || !columnContext.isDictionaryEncoded() ? null
- : columnContext.getDictionary();
+ Dictionary dictionary = columnContext.isDictionaryEncoded() ? columnContext.getDictionary() : null;
if (dictionary != null) {
_dictionaries[i] = dictionary;
} else {
@@ -148,125 +153,59 @@ public class NoDictionaryMultiColumnGroupKeyGenerator implements GroupKeyGenerat
}
}
}
- int[] keyValues = new int[_numGroupByExpressions];
- // note that we are mutating its backing array for memory efficiency
- FixedIntArray flyweightKey = new FixedIntArray(keyValues);
+ // All null when null handling is disabled, so the per-column check below never matches. The check stays inside
+ // the row loop rather than forking the loop per mode: every iteration pays for a hash-map operation, which dwarfs
+ // a predicted branch.
+ RoaringBitmap[] nullBitmaps = new RoaringBitmap[_numGroupByExpressions];
if (_nullHandlingEnabled) {
- RoaringBitmap[] nullBitmaps = new RoaringBitmap[_numGroupByExpressions];
for (int i = 0; i < _numGroupByExpressions; i++) {
- nullBitmaps[i] = valueBlock.getBlockValueSet(_groupByExpressions[i]).getNullBitmap();
+ RoaringBitmap nullBitmap = valueBlock.getBlockValueSet(_groupByExpressions[i]).getNullBitmap();
+ // Normalize an empty bitmap to null so the per-row check is a plain null comparison
+ nullBitmaps[i] = nullBitmap != null && !nullBitmap.isEmpty() ? nullBitmap : null;
}
- for (int row = 0; row < numDocs; row++) {
- int numGroups = _groupKeyMap.size();
- boolean hasInvalidKeyValue = false;
- if (numGroups < _numGroupsLimit) {
- for (int col = 0; col < _numGroupByExpressions; col++) {
- if (nullBitmaps[col] != null && nullBitmaps[col].contains(row)) {
- keyValues[col] = ID_FOR_NULL;
- } else {
- Object columnValues = values[col];
- ValueToIdMap onTheFlyDictionary = _onTheFlyDictionaries[col];
- int keyValue;
- if (columnValues instanceof int[]) {
- keyValue = onTheFlyDictionary.put(((int[]) columnValues)[row]);
- } else if (columnValues instanceof long[]) {
- keyValue = onTheFlyDictionary.put(((long[]) columnValues)[row]);
- } else if (columnValues instanceof float[]) {
- keyValue = onTheFlyDictionary.put(((float[]) columnValues)[row]);
- } else if (columnValues instanceof double[]) {
- keyValue = onTheFlyDictionary.put(((double[]) columnValues)[row]);
- } else if (columnValues instanceof byte[][]) {
- keyValue = onTheFlyDictionary.put(new ByteArray(((byte[][]) columnValues)[row]));
- } else {
- keyValue = onTheFlyDictionary.put(((Object[]) columnValues)[row]);
- }
- keyValues[col] = keyValue;
- }
- }
- } else {
- for (int col = 0; col < _numGroupByExpressions; col++) {
- if (nullBitmaps[col] != null && nullBitmaps[col].contains(row)) {
- keyValues[col] = ID_FOR_NULL;
- } else {
- Object columnValues = values[col];
- ValueToIdMap onTheFlyDictionary = _onTheFlyDictionaries[col];
- int keyValue;
- if (columnValues instanceof int[]) {
- keyValue = onTheFlyDictionary.getId(((int[]) columnValues)[row]);
- } else if (columnValues instanceof long[]) {
- keyValue = onTheFlyDictionary.getId(((long[]) columnValues)[row]);
- } else if (columnValues instanceof float[]) {
- keyValue = onTheFlyDictionary.getId(((float[]) columnValues)[row]);
- } else if (columnValues instanceof double[]) {
- keyValue = onTheFlyDictionary.getId(((double[]) columnValues)[row]);
- } else if (columnValues instanceof byte[][]) {
- keyValue = onTheFlyDictionary.getId(new ByteArray(((byte[][]) columnValues)[row]));
- } else {
- keyValue = onTheFlyDictionary.getId(((Object[]) columnValues)[row]);
- }
- if (keyValue == INVALID_ID) {
- hasInvalidKeyValue = true;
- break;
- }
- }
- }
- }
- if (hasInvalidKeyValue) {
- groupKeys[row] = INVALID_ID;
- } else {
- int groupId = getGroupIdForKey(flyweightKey);
- if (groupId == numGroups) {
- // When a new group is added, create a new FixedIntArray
- keyValues = new int[_numGroupByExpressions];
- flyweightKey = new FixedIntArray(keyValues);
- }
- groupKeys[row] = groupId;
- }
- }
- } else {
- for (int row = 0; row < numDocs; row++) {
- int numGroups = _groupKeyMap.size();
- boolean hasInvalidKeyValue = false;
- if (numGroups < _numGroupsLimit) {
- for (int col = 0; col < _numGroupByExpressions; col++) {
+ }
+ int[] keyValues = new int[_numGroupByExpressions];
+ // note that we are mutating its backing array for memory efficiency
+ FixedIntArray flyweightKey = new FixedIntArray(keyValues);
+ for (int row = 0; row < numDocs; row++) {
+ int numGroups = _groupKeyMap.size();
+ boolean hasInvalidKeyValue = false;
+ if (numGroups < _numGroupsLimit) {
+ for (int col = 0; col < _numGroupByExpressions; col++) {
+ if (isNull(nullBitmaps[col], row)) {
+ keyValues[col] = ID_FOR_NULL;
+ } else {
Object columnValues = values[col];
ValueToIdMap onTheFlyDictionary = _onTheFlyDictionaries[col];
- int keyValue;
- if (columnValues instanceof int[]) {
- int columnValue = ((int[]) columnValues)[row];
- keyValue = onTheFlyDictionary != null ? onTheFlyDictionary.put(columnValue) : columnValue;
- } else if (columnValues instanceof long[]) {
- keyValue = onTheFlyDictionary.put(((long[]) columnValues)[row]);
- } else if (columnValues instanceof float[]) {
- keyValue = onTheFlyDictionary.put(((float[]) columnValues)[row]);
- } else if (columnValues instanceof double[]) {
- keyValue = onTheFlyDictionary.put(((double[]) columnValues)[row]);
- } else if (columnValues instanceof byte[][]) {
- keyValue = onTheFlyDictionary.put(new ByteArray(((byte[][]) columnValues)[row]));
- } else {
- keyValue = onTheFlyDictionary.put(((Object[]) columnValues)[row]);
- }
- keyValues[col] = keyValue;
+ keyValues[col] = switch (columnValues) {
+ // A dictionary-encoded column has no on-the-fly dictionary: its values are dictionary ids already, used
+ // as key values directly
+ case int[] ints -> onTheFlyDictionary != null ? onTheFlyDictionary.put(ints[row]) : ints[row];
+ case long[] longs -> onTheFlyDictionary.put(longs[row]);
+ case float[] floats -> onTheFlyDictionary.put(floats[row]);
+ case double[] doubles -> onTheFlyDictionary.put(doubles[row]);
+ case byte[][] bytes -> onTheFlyDictionary.put(new ByteArray(bytes[row]));
+ default -> onTheFlyDictionary.put(((Object[]) columnValues)[row]);
+ };
}
- } else {
- for (int col = 0; col < _numGroupByExpressions; col++) {
+ }
+ } else {
+ for (int col = 0; col < _numGroupByExpressions; col++) {
+ if (isNull(nullBitmaps[col], row)) {
+ keyValues[col] = ID_FOR_NULL;
+ } else {
Object columnValues = values[col];
ValueToIdMap onTheFlyDictionary = _onTheFlyDictionaries[col];
- int keyValue;
- if (columnValues instanceof int[]) {
- int columnValue = ((int[]) columnValues)[row];
- keyValue = onTheFlyDictionary != null ? onTheFlyDictionary.getId(columnValue) : columnValue;
- } else if (columnValues instanceof long[]) {
- keyValue = onTheFlyDictionary.getId(((long[]) columnValues)[row]);
- } else if (columnValues instanceof float[]) {
- keyValue = onTheFlyDictionary.getId(((float[]) columnValues)[row]);
- } else if (columnValues instanceof double[]) {
- keyValue = onTheFlyDictionary.getId(((double[]) columnValues)[row]);
- } else if (columnValues instanceof byte[][]) {
- keyValue = onTheFlyDictionary.getId(new ByteArray(((byte[][]) columnValues)[row]));
- } else {
- keyValue = onTheFlyDictionary.getId(((Object[]) columnValues)[row]);
- }
+ int keyValue = switch (columnValues) {
+ // A dictionary-encoded column has no on-the-fly dictionary: its values are dictionary ids already, used
+ // as key values directly
+ case int[] ints -> onTheFlyDictionary != null ? onTheFlyDictionary.getId(ints[row]) : ints[row];
+ case long[] longs -> onTheFlyDictionary.getId(longs[row]);
+ case float[] floats -> onTheFlyDictionary.getId(floats[row]);
+ case double[] doubles -> onTheFlyDictionary.getId(doubles[row]);
+ case byte[][] bytes -> onTheFlyDictionary.getId(new ByteArray(bytes[row]));
+ default -> onTheFlyDictionary.getId(((Object[]) columnValues)[row]);
+ };
if (keyValue == INVALID_ID) {
hasInvalidKeyValue = true;
break;
@@ -274,21 +213,25 @@ public class NoDictionaryMultiColumnGroupKeyGenerator implements GroupKeyGenerat
keyValues[col] = keyValue;
}
}
- if (hasInvalidKeyValue) {
- groupKeys[row] = INVALID_ID;
- } else {
- int groupId = getGroupIdForKey(flyweightKey);
- if (groupId == numGroups) {
- // When a new group is added, create a new FixedIntArray
- keyValues = new int[_numGroupByExpressions];
- flyweightKey = new FixedIntArray(keyValues);
- }
- groupKeys[row] = groupId;
+ }
+ if (hasInvalidKeyValue) {
+ groupKeys[row] = INVALID_ID;
+ } else {
+ int groupId = getGroupIdForKey(flyweightKey);
+ if (groupId == numGroups) {
+ // When a new group is added, create a new FixedIntArray
+ keyValues = new int[_numGroupByExpressions];
+ flyweightKey = new FixedIntArray(keyValues);
}
+ groupKeys[row] = groupId;
}
}
}
+ private static boolean isNull(@Nullable RoaringBitmap nullBitmap, int row) {
+ return nullBitmap != null && nullBitmap.contains(row);
+ }
+
@Override
public void generateKeysForBlock(ValueBlock valueBlock, int[][] groupKeys) {
int numDocs = valueBlock.getNumDocs();
@@ -414,6 +357,17 @@ public class NoDictionaryMultiColumnGroupKeyGenerator implements GroupKeyGenerat
}
}
}
+ if (_nullHandlingEnabled) {
+ // A null row's own value was resolved above and is discarded here. Only the composed key decides a group, so
+ // the id it took in the on-the-fly dictionary goes unused rather than becoming a group of its own.
+ RoaringBitmap nullBitmap = blockValSet.getNullBitmap();
+ if (nullBitmap != null && !nullBitmap.isEmpty()) {
+ PeekableIntIterator nullIterator = nullBitmap.getIntIterator();
+ while (nullIterator.hasNext()) {
+ keys[nullIterator.next()][i] = NULL_KEY_COMPONENT;
+ }
+ }
+ }
}
for (int i = 0; i < numDocs; i++) {
groupKeys[i] = getGroupIdsForKeys(keys[i]);
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/NoDictionarySingleColumnGroupKeyGenerator.java b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/NoDictionarySingleColumnGroupKeyGenerator.java
index d6b0bfcce93..98f83c5f846 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/NoDictionarySingleColumnGroupKeyGenerator.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/groupby/NoDictionarySingleColumnGroupKeyGenerator.java
@@ -30,7 +30,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import java.math.BigDecimal;
-import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import javax.annotation.Nullable;
@@ -44,22 +43,24 @@ import org.apache.pinot.spi.utils.ByteArray;
import org.roaringbitmap.RoaringBitmap;
-/// Implementation of [GroupKeyGenerator] interface for single group by column,
-/// in absence of dictionary for the group by column.
+/// Implementation of [GroupKeyGenerator] interface for single group by column, in absence of dictionary for the group
+/// by column.
+///
+/// With null handling enabled, a null row forms a group of its own instead of joining the group of the column's default
+/// null value, which is what a null row is physically stored as. The object-keyed maps hold the null key directly,
+/// while the primitive-keyed maps cannot, so the null group id is tracked beside them. Both the single-value and the
+/// multi-value key paths recognize nulls.
@SuppressWarnings({"rawtypes", "unchecked"})
public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenerator {
private final ExpressionContext _groupByExpression;
private final DataType _storedType;
private final Map _groupKeyMap;
private final int _globalGroupIdUpperBound;
- // TODO(nhejazi): Most of the logic between _nullHandlingEnabled=true/false is not sharable, so consider making a
- // base implementation, and 2 derived classes, one for null enabled, one for disabled.
private final boolean _nullHandlingEnabled;
-
- private Integer _groupIdForNullValue = null;
private final boolean _isSingleValueExpression;
- private int _numGroups = 0;
+ private Integer _groupIdForNullValue;
+ private int _numGroups;
public NoDictionarySingleColumnGroupKeyGenerator(BaseProjectOperator<?> projectOperator,
ExpressionContext groupByExpression, int numGroupsLimit, boolean nullHandlingEnabled,
@@ -86,56 +87,53 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
@Override
public void generateKeysForBlock(ValueBlock valueBlock, int[] groupKeys) {
BlockValSet blockValSet = valueBlock.getBlockValueSet(_groupByExpression);
- if (_nullHandlingEnabled) {
- RoaringBitmap nullBitmap = blockValSet.getNullBitmap();
- if (nullBitmap != null && !nullBitmap.isEmpty()) {
- generateKeysForBlockNullHandlingEnabled(valueBlock, groupKeys, nullBitmap);
- return;
- }
- }
int numDocs = valueBlock.getNumDocs();
+ RoaringBitmap nullBitmap = getNullBitmap(blockValSet);
+ // Resolved once rather than per row, and only when the block holds a null, so that reading a block without one
+ // never records a null group
+ int nullKey = nullBitmap != null ? getKeyForNull() : INVALID_ID;
switch (_storedType) {
case INT:
int[] intValues = blockValSet.getIntValuesSV();
for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(intValues[i]);
+ groupKeys[i] = isNull(nullBitmap, i) ? nullKey : getKeyForValue(intValues[i]);
}
break;
case LONG:
long[] longValues = blockValSet.getLongValuesSV();
for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(longValues[i]);
+ groupKeys[i] = isNull(nullBitmap, i) ? nullKey : getKeyForValue(longValues[i]);
}
break;
case FLOAT:
float[] floatValues = blockValSet.getFloatValuesSV();
for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(floatValues[i]);
+ groupKeys[i] = isNull(nullBitmap, i) ? nullKey : getKeyForValue(floatValues[i]);
}
break;
case DOUBLE:
double[] doubleValues = blockValSet.getDoubleValuesSV();
for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(doubleValues[i]);
+ groupKeys[i] = isNull(nullBitmap, i) ? nullKey : getKeyForValue(doubleValues[i]);
}
break;
case BIG_DECIMAL:
BigDecimal[] bigDecimalValues = blockValSet.getBigDecimalValuesSV();
for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(bigDecimalValues[i]);
+ groupKeys[i] = isNull(nullBitmap, i) ? nullKey : getKeyForValue(bigDecimalValues[i]);
}
break;
case STRING:
String[] stringValues = blockValSet.getStringValuesSV();
for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(stringValues[i]);
+ groupKeys[i] = isNull(nullBitmap, i) ? nullKey : getKeyForValue(stringValues[i]);
}
break;
case BYTES:
byte[][] bytesValues = blockValSet.getBytesValuesSV();
for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(new ByteArray(bytesValues[i]));
+ groupKeys[i] = isNull(nullBitmap, i) ? nullKey : getKeyForValue(new ByteArray(bytesValues[i]));
}
break;
default:
@@ -143,86 +141,14 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
}
}
- public void generateKeysForBlockNullHandlingEnabled(ValueBlock valueBlock, int[] groupKeys,
- RoaringBitmap nullBitmap) {
- assert nullBitmap != null;
- BlockValSet blockValSet = valueBlock.getBlockValueSet(_groupByExpression);
- int numDocs = valueBlock.getNumDocs();
-
- switch (_storedType) {
- case INT:
- int[] intValues = blockValSet.getIntValuesSV();
- if (nullBitmap.getCardinality() < numDocs) {
- for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = nullBitmap.contains(i) ? getKeyForNullValue() : getKeyForValue(intValues[i]);
- }
- } else if (numDocs > 0) {
- Arrays.fill(groupKeys, 0, numDocs, getKeyForNullValue());
- }
- break;
- case LONG:
- long[] longValues = blockValSet.getLongValuesSV();
- if (nullBitmap.getCardinality() < numDocs) {
- for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = nullBitmap.contains(i) ? getKeyForNullValue() : getKeyForValue(longValues[i]);
- }
- } else if (numDocs > 0) {
- Arrays.fill(groupKeys, 0, numDocs, getKeyForNullValue());
- }
- break;
- case FLOAT:
- float[] floatValues = blockValSet.getFloatValuesSV();
- if (nullBitmap.getCardinality() < numDocs) {
- for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = nullBitmap.contains(i) ? getKeyForNullValue() : getKeyForValue(floatValues[i]);
- }
- } else if (numDocs > 0) {
- Arrays.fill(groupKeys, 0, numDocs, getKeyForNullValue());
- }
- break;
- case DOUBLE:
- double[] doubleValues = blockValSet.getDoubleValuesSV();
- if (nullBitmap.getCardinality() < numDocs) {
- for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = nullBitmap.contains(i) ? getKeyForNullValue() : getKeyForValue(doubleValues[i]);
- }
- } else if (numDocs > 0) {
- Arrays.fill(groupKeys, 0, numDocs, getKeyForNullValue());
- }
- break;
- case BIG_DECIMAL:
- BigDecimal[] bigDecimalValues = blockValSet.getBigDecimalValuesSV();
- if (nullBitmap.getCardinality() < numDocs) {
- for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(nullBitmap.contains(i) ? null : bigDecimalValues[i]);
- }
- } else if (numDocs > 0) {
- Arrays.fill(groupKeys, 0, numDocs, getKeyForValue((BigDecimal) null));
- }
- break;
- case STRING:
- String[] stringValues = blockValSet.getStringValuesSV();
- if (nullBitmap.getCardinality() < numDocs) {
- for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(nullBitmap.contains(i) ? null : stringValues[i]);
- }
- } else if (numDocs > 0) {
- Arrays.fill(groupKeys, 0, numDocs, getKeyForValue((String) null));
- }
- break;
- case BYTES:
- byte[][] bytesValues = blockValSet.getBytesValuesSV();
- if (nullBitmap.getCardinality() < numDocs) {
- for (int i = 0; i < numDocs; i++) {
- groupKeys[i] = getKeyForValue(nullBitmap.contains(i) ? null : new ByteArray(bytesValues[i]));
- }
- } else if (numDocs > 0) {
- Arrays.fill(groupKeys, 0, numDocs, getKeyForValue((ByteArray) null));
- }
- break;
- default:
- throw new IllegalArgumentException("Illegal data type for no-dictionary key generator: " + _storedType);
+ /// Returns the block's null bitmap, or `null` when null handling is disabled or no row in the block is null.
+ @Nullable
+ private RoaringBitmap getNullBitmap(BlockValSet blockValSet) {
+ if (!_nullHandlingEnabled) {
+ return null;
}
+ RoaringBitmap nullBitmap = blockValSet.getNullBitmap();
+ return nullBitmap != null && !nullBitmap.isEmpty() ? nullBitmap : null;
}
/// Helper method to create the group-key map, depending on the data type.
@@ -269,42 +195,70 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
public void generateKeysForBlock(ValueBlock valueBlock, int[][] groupKeys) {
int numDocs = valueBlock.getNumDocs();
BlockValSet blockValSet = valueBlock.getBlockValueSet(_groupByExpression);
+ RoaringBitmap nullBitmap = getNullBitmap(blockValSet);
+ // Resolved once rather than per row, and only when the block holds a null, so that reading a block without one
+ // never records a null group
+ int nullKey = nullBitmap != null ? getKeyForNull() : INVALID_ID;
if (_isSingleValueExpression) {
switch (_storedType) {
case INT:
int[] intValues = blockValSet.getIntValuesSV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
groupKeys[i] = new int[]{getKeyForValue(intValues[i])};
}
break;
case LONG:
long[] longValues = blockValSet.getLongValuesSV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
groupKeys[i] = new int[]{getKeyForValue(longValues[i])};
}
break;
case FLOAT:
float[] floatValues = blockValSet.getFloatValuesSV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
groupKeys[i] = new int[]{getKeyForValue(floatValues[i])};
}
break;
case DOUBLE:
double[] doubleValues = blockValSet.getDoubleValuesSV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
groupKeys[i] = new int[]{getKeyForValue(doubleValues[i])};
}
break;
case STRING:
String[] stringValues = blockValSet.getStringValuesSV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
groupKeys[i] = new int[]{getKeyForValue(stringValues[i])};
}
break;
case BYTES:
byte[][] byteValues = blockValSet.getBytesValuesSV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
groupKeys[i] = new int[]{getKeyForValue(new ByteArray(byteValues[i]))};
}
break;
@@ -316,6 +270,10 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
case INT:
int[][] intValues = blockValSet.getIntValuesMV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
int mvSize = intValues[i].length;
int[] mvKeys = new int[mvSize];
for (int j = 0; j < mvSize; j++) {
@@ -327,6 +285,10 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
case LONG:
long[][] longValues = blockValSet.getLongValuesMV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
int mvSize = longValues[i].length;
int[] mvKeys = new int[mvSize];
for (int j = 0; j < mvSize; j++) {
@@ -338,6 +300,10 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
case FLOAT:
float[][] floatValues = blockValSet.getFloatValuesMV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
int mvSize = floatValues[i].length;
int[] mvKeys = new int[mvSize];
for (int j = 0; j < mvSize; j++) {
@@ -349,6 +315,10 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
case DOUBLE:
double[][] doubleValues = blockValSet.getDoubleValuesMV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
int mvSize = doubleValues[i].length;
int[] mvKeys = new int[mvSize];
for (int j = 0; j < mvSize; j++) {
@@ -360,6 +330,10 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
case STRING:
String[][] stringValues = blockValSet.getStringValuesMV();
for (int i = 0; i < numDocs; i++) {
+ if (isNull(nullBitmap, i)) {
+ groupKeys[i] = new int[]{nullKey};
+ continue;
+ }
int mvSize = stringValues[i].length;
int[] mvKeys = new int[mvSize];
for (int j = 0; j < mvSize; j++) {
@@ -374,29 +348,38 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
}
}
+ /// Returns the group id of a null value. The primitive maps cannot hold a null key so it is tracked beside them,
+ /// while the object maps hold it as a key of their own.
+ private int getKeyForNull() {
+ return switch (_storedType) {
+ case BIG_DECIMAL -> getKeyForValue((BigDecimal) null);
+ case STRING -> getKeyForValue((String) null);
+ case BYTES -> getKeyForValue((ByteArray) null);
+ default -> getKeyForNullValue();
+ };
+ }
+
+ private static boolean isNull(@Nullable RoaringBitmap nullBitmap, int row) {
+ return nullBitmap != null && nullBitmap.contains(row);
+ }
+
+ /// The group id of a null value is handed out beside [#_groupKeyMap] rather than stored in it, because the
+ /// primitive-keyed maps cannot hold a null key, so the group count has to come from the id counter itself.
@Override
public int getCurrentGroupKeyUpperBound() {
- return _groupKeyMap.size();
+ return _numGroups;
}
@Override
public Iterator<GroupKey> getGroupKeys() {
- switch (_storedType) {
- case INT:
- return new IntGroupKeyIterator((Int2IntOpenHashMap) _groupKeyMap, _groupIdForNullValue);
- case LONG:
- return new LongGroupKeyIterator((Long2IntOpenHashMap) _groupKeyMap, _groupIdForNullValue);
- case FLOAT:
- return new FloatGroupKeyIterator((Float2IntOpenHashMap) _groupKeyMap, _groupIdForNullValue);
- case DOUBLE:
- return new DoubleGroupKeyIterator((Double2IntOpenHashMap) _groupKeyMap, _groupIdForNullValue);
- case BIG_DECIMAL:
- case STRING:
- case BYTES:
- return new ObjectGroupKeyIterator((Object2IntOpenHashMap) _groupKeyMap);
- default:
- throw new IllegalStateException();
- }
+ return switch (_storedType) {
+ case INT -> new IntGroupKeyIterator((Int2IntOpenHashMap) _groupKeyMap, _groupIdForNullValue);
+ case LONG -> new LongGroupKeyIterator((Long2IntOpenHashMap) _groupKeyMap, _groupIdForNullValue);
+ case FLOAT -> new FloatGroupKeyIterator((Float2IntOpenHashMap) _groupKeyMap, _groupIdForNullValue);
+ case DOUBLE -> new DoubleGroupKeyIterator((Double2IntOpenHashMap) _groupKeyMap, _groupIdForNullValue);
+ case BIG_DECIMAL, STRING, BYTES -> new ObjectGroupKeyIterator((Object2IntOpenHashMap) _groupKeyMap);
+ default -> throw new IllegalStateException();
+ };
}
private int getKeyForNullValue() {
@@ -412,7 +395,7 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
@Override
public int getNumKeys() {
- return _groupKeyMap.size();
+ return _numGroups;
}
private int getKeyForValue(int value) {
@@ -503,7 +486,6 @@ public class NoDictionarySingleColumnGroupKeyGenerator implements GroupKeyGenera
@Override
public GroupKey next() {
- // TODO(nhejazi): revisit to avoid adding overhead to the regular case where null handling is not enabled.
if (_groupKeyForNullValue != null) {
_groupKey._groupId = _groupKeyForNullValue;
_groupKey._keys = new Object[]{null};
diff --git a/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/groupby/DictionaryBasedGroupKeyGeneratorTest.java b/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/groupby/DictionaryBasedGroupKeyGeneratorTest.java
index 5b460b22a4e..f77711f320e 100644
--- a/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/groupby/DictionaryBasedGroupKeyGeneratorTest.java
+++ b/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/groupby/DictionaryBasedGroupKeyGeneratorTest.java
@@ -58,6 +58,7 @@ import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
@@ -74,6 +75,8 @@ public class DictionaryBasedGroupKeyGeneratorTest {
private static final int[][] MV_GROUP_KEY_BUFFER = new int[NUM_GROUPS][];
private static final String FILTER_COLUMN = "docId";
private static final String[] SV_COLUMNS = {"s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10"};
+ /// Null in every row, so the only dictionary id it contributes to a group key is the reserved null id.
+ private static final String NULL_COLUMN = "n1";
private static final String[] MV_COLUMNS = {"m1", "m2"};
private final long _randomSeed = System.currentTimeMillis();
@@ -95,6 +98,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
for (int i = 0; i < UNIQUE_ROWS; i++) {
GenericRow row = new GenericRow();
row.putValue(FILTER_COLUMN, i);
+ row.putValue(NULL_COLUMN, null);
for (String svColumn : SV_COLUMNS) {
row.putValue(svColumn, value);
value += 1 + _random.nextInt(MAX_STEP_LENGTH);
@@ -117,6 +121,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
// Create an index segment with the random values
Schema schema = new Schema();
schema.addField(new DimensionFieldSpec(FILTER_COLUMN, DataType.INT, true));
+ schema.addField(new DimensionFieldSpec(NULL_COLUMN, DataType.INT, true));
for (String singleValueColumn : SV_COLUMNS) {
schema.addField(new DimensionFieldSpec(singleValueColumn, DataType.INT, true));
}
@@ -128,6 +133,8 @@ public class DictionaryBasedGroupKeyGeneratorTest {
SegmentGeneratorConfig config = new SegmentGeneratorConfig(tableConfig, schema);
config.setOutDir(INDEX_DIR_PATH);
+ // Writes the null value vector that a generator reads a column's nullability from
+ config.setDefaultNullHandlingEnabled(true);
config.setSegmentName(SEGMENT_NAME);
SegmentIndexCreationDriverImpl driver = new SegmentIndexCreationDriverImpl();
@@ -140,11 +147,12 @@ public class DictionaryBasedGroupKeyGeneratorTest {
int docId2 = docId1 + 1 + _random.nextInt(50);
// NOTE: put all columns into group-by so that transform operator has expressions for all columns
String query =
- String.format("SELECT COUNT(*) FROM testTable WHERE %s IN (%d, %d) GROUP BY %s, %s", FILTER_COLUMN, docId1,
- docId2, StringUtils.join(SV_COLUMNS, ", "), StringUtils.join(MV_COLUMNS, ", "));
+ String.format("SELECT COUNT(*) FROM testTable WHERE %s IN (%d, %d) GROUP BY %s, %s, %s", FILTER_COLUMN,
+ docId1, docId2, NULL_COLUMN, StringUtils.join(SV_COLUMNS, ", "), StringUtils.join(MV_COLUMNS, ", "));
QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
List<ExpressionContext> expressions = new ArrayList<>();
+ expressions.add(ExpressionContext.forIdentifier(NULL_COLUMN));
for (String column : SV_COLUMNS) {
expressions.add(ExpressionContext.forIdentifier(column));
}
@@ -166,7 +174,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
- Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, null);
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, false, null);
assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(), UNIQUE_ROWS, _errorMessage);
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), UNIQUE_ROWS, _errorMessage);
@@ -175,6 +183,8 @@ public class DictionaryBasedGroupKeyGeneratorTest {
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), UNIQUE_ROWS, _errorMessage);
compareSingleValueBuffer();
testGetGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), 2);
+
+ dictionaryBasedGroupKeyGenerator.close();
}
@Test
@@ -186,7 +196,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
- Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, null);
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, false, null);
assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT, _errorMessage);
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);
@@ -211,7 +221,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
- Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, null);
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, false, null);
assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT, _errorMessage);
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);
@@ -236,7 +246,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
- Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, null);
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, false, null);
assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT, _errorMessage);
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);
@@ -264,6 +274,77 @@ public class DictionaryBasedGroupKeyGeneratorTest {
}
}
+ /// A column that can hold a null reserves one dictionary id beyond the ones its dictionary holds, which is what
+ /// lets a null take a group of its own. Every row of [#NULL_COLUMN] is null, so its dictionary holds the single
+ /// default null value and the reserved id brings the column's cardinality to two.
+ @Test
+ public void testArrayBasedNullHandling() {
+ String[] groupByColumns = {NULL_COLUMN};
+
+ DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
+ new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
+ Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, true, null);
+ assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(), 2, _errorMessage);
+
+ dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_valueBlock, SV_GROUP_KEY_BUFFER);
+ assertNullGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), 1);
+ dictionaryBasedGroupKeyGenerator.close();
+ }
+
+ /// The reserved id has to survive being folded into a long raw key alongside other columns' ids.
+ @Test
+ public void testLongMapBasedNullHandling() {
+ // Cardinality product larger than Integer.MAX_VALUE but smaller than Long.MAX_VALUE
+ String[] groupByColumns = {NULL_COLUMN, "s1", "s2", "s3", "s4", "s5"};
+
+ DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
+ new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
+ Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, true, null);
+ assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
+ Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT, _errorMessage);
+
+ dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_valueBlock, SV_GROUP_KEY_BUFFER);
+ assertNullGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), 2);
+ dictionaryBasedGroupKeyGenerator.close();
+ assertEquals(DictionaryBasedGroupKeyGenerator.THREAD_LOCAL_LONG_MAP.get().size(), 0);
+ }
+
+ /// The same, for the holder that keeps the ids as an array because their product does not fit into a long.
+ @Test
+ public void testArrayMapBasedNullHandling() {
+ // Cardinality product larger than Long.MAX_VALUE
+ String[] groupByColumns = {NULL_COLUMN, "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10"};
+
+ DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
+ new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
+ Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, true, null);
+ assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
+ Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT, _errorMessage);
+
+ dictionaryBasedGroupKeyGenerator.generateKeysForBlock(_valueBlock, SV_GROUP_KEY_BUFFER);
+ assertNullGroupKeys(dictionaryBasedGroupKeyGenerator.getGroupKeys(), 2);
+ dictionaryBasedGroupKeyGenerator.close();
+ assertEquals(DictionaryBasedGroupKeyGenerator.THREAD_LOCAL_INT_ARRAY_MAP.get().size(), 0);
+ }
+
+ /// Asserts that the generator produced the given number of distinct keys and that every one of them reads the
+ /// all-null column back as SQL NULL rather than as the value stored for a null row.
+ private void assertNullGroupKeys(Iterator<GroupKeyGenerator.GroupKey> groupKeyIterator, int numUniqueKeys) {
+ int count = 0;
+ Set<List<Object>> groupKeySet = new HashSet<>();
+ while (groupKeyIterator.hasNext()) {
+ count++;
+ GroupKeyGenerator.GroupKey groupKey = groupKeyIterator.next();
+ assertNull(groupKey._keys[0], _errorMessage);
+ groupKeySet.add(Arrays.asList(groupKey._keys));
+ }
+ assertEquals(count, numUniqueKeys, _errorMessage);
+ assertEquals(groupKeySet.size(), numUniqueKeys, _errorMessage);
+ }
+
@Test
public void testArrayBasedMultiValue() {
// Cardinality product (100 - 1,000) smaller than arrayBasedThreshold
@@ -273,7 +354,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
- Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, null);
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, false, null);
int groupKeyUpperBound = dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound();
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), groupKeyUpperBound, _errorMessage);
@@ -294,7 +375,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
- Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, null);
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, false, null);
assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT, _errorMessage);
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);
@@ -321,7 +402,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
- Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, null);
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, false, null);
assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT, _errorMessage);
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);
@@ -347,7 +428,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT,
- Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, null);
+ Server.DEFAULT_QUERY_EXECUTOR_MAX_INITIAL_RESULT_HOLDER_CAPACITY, false, null);
assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(),
Server.DEFAULT_QUERY_EXECUTOR_NUM_GROUPS_LIMIT, _errorMessage);
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);
@@ -371,7 +452,7 @@ public class DictionaryBasedGroupKeyGeneratorTest {
// NOTE: arrayBasedThreshold must be smaller or equal to numGroupsLimit
DictionaryBasedGroupKeyGenerator dictionaryBasedGroupKeyGenerator =
new DictionaryBasedGroupKeyGenerator(_projectOperator, getExpressions(groupByColumns), numGroupsLimit,
- numGroupsLimit, null);
+ numGroupsLimit, false, null);
assertEquals(dictionaryBasedGroupKeyGenerator.getGlobalGroupKeyUpperBound(), numGroupsLimit, _errorMessage);
assertEquals(dictionaryBasedGroupKeyGenerator.getCurrentGroupKeyUpperBound(), 0, _errorMessage);
@@ -441,6 +522,26 @@ public class DictionaryBasedGroupKeyGeneratorTest {
assertEquals(groupKeySet.size(), numUniqueKeys, _errorMessage);
}
+ /// A map that grew past the caching threshold is rebuilt at its initial capacity instead of being kept as an
+ /// oversized cleared table, and must come back fully usable with group ids starting over.
+ @Test
+ public void testIntGroupIdMapClearAndTrim() {
+ DictionaryBasedGroupKeyGenerator.IntGroupIdMap map = new DictionaryBasedGroupKeyGenerator.IntGroupIdMap();
+ // Above the caching threshold of 0.75 * 2^20 entries
+ int numEntries = 800_000;
+ for (int i = 0; i < numEntries; i++) {
+ assertEquals(map.getGroupId(i, Integer.MAX_VALUE), i);
+ }
+ assertEquals(map.size(), numEntries);
+
+ map.clearAndTrim();
+
+ assertEquals(map.size(), 0);
+ assertEquals(map.getGroupId(123, Integer.MAX_VALUE), 0);
+ assertEquals(map.getGroupId(123, Integer.MAX_VALUE), 0);
+ assertEquals(map.size(), 1);
+ }
+
@Test
public void testMapDefaultValue() {
assertEquals(DictionaryBasedGroupKeyGenerator.THREAD_LOCAL_LONG_MAP.get().defaultReturnValue(),
diff --git a/pinot-core/src/test/java/org/apache/pinot/queries/NullHandlingEnabledQueriesTest.java b/pinot-core/src/test/java/org/apache/pinot/queries/NullHandlingEnabledQueriesTest.java
index 5a37f159b62..0afe4ef6ad3 100644
--- a/pinot-core/src/test/java/org/apache/pinot/queries/NullHandlingEnabledQueriesTest.java
+++ b/pinot-core/src/test/java/org/apache/pinot/queries/NullHandlingEnabledQueriesTest.java
@@ -23,8 +23,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import javax.annotation.Nullable;
import org.apache.commons.io.FileUtils;
-import org.apache.pinot.common.response.broker.BrokerResponseNative;
import org.apache.pinot.common.response.broker.ResultTable;
import org.apache.pinot.core.plan.DocIdSetPlanNode;
import org.apache.pinot.segment.local.indexsegment.immutable.ImmutableSegmentLoader;
@@ -36,6 +36,7 @@ import org.apache.pinot.segment.spi.creator.SegmentGeneratorConfig;
import org.apache.pinot.spi.config.table.TableConfig;
import org.apache.pinot.spi.config.table.TableType;
import org.apache.pinot.spi.data.FieldSpec;
+import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.apache.pinot.spi.data.Schema;
import org.apache.pinot.spi.data.readers.GenericRow;
import org.apache.pinot.spi.utils.ReadMode;
@@ -44,10 +45,7 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.*;
public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
@@ -56,10 +54,22 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
private static final String SEGMENT_NAME = "testSegment";
private static final String COLUMN1 = "column1";
private static final String COLUMN2 = "column2";
+ private static final TableConfig TABLE_CONFIG =
+ new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
+ private static final TableConfig TABLE_CONFIG_WITH_RAW_COLUMN =
+ new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME)
+ .setNoDictionaryColumns(List.of(COLUMN1))
+ .build();
+ private static final TableConfig TABLE_CONFIG_WITH_SORTED_COLUMN =
+ new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).setSortedColumn(COLUMN1).build();
+ private static final TableConfig TABLE_CONFIG_WITH_INVERTED_INDEX_COLUMN =
+ new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME)
+ .setInvertedIndexColumns(List.of(COLUMN1))
+ .build();
private static final int NUM_OF_SEGMENT_COPIES = 4;
- private final List<GenericRow> _rows = new ArrayList<>();
private static final Map<String, String> QUERY_OPTIONS = Map.of("enableNullHandling", "true");
+ private final List<GenericRow> _rows = new ArrayList<>();
private IndexSegment _indexSegment;
private List<IndexSegment> _indexSegments;
@@ -113,6 +123,22 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
_rows.add(row);
}
+ private static Schema.SchemaBuilder schemaBuilder() {
+ return new Schema.SchemaBuilder().setSchemaName(RAW_TABLE_NAME);
+ }
+
+ /// Returns the result rows of the given query, executed with null handling enabled.
+ private List<Object[]> getRows(String query) {
+ return getRows(query, QUERY_OPTIONS);
+ }
+
+ private List<Object[]> getRows(String query, @Nullable Map<String, String> queryOptions) {
+ //noinspection LanguageMismatch
+ ResultTable resultTable = getBrokerResponse(query, queryOptions).getResultTable();
+ assertNotNull(resultTable, "Failed to get result table for query: " + query);
+ return resultTable.getRows();
+ }
+
@DataProvider(name = "BooleanAssertionFunctions")
public static Object[][] getBooleanAssertionFunctionsParameters() {
return new Object[][]{
@@ -136,15 +162,12 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRow(data);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.BOOLEAN).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT %s(%s) FROM testTable LIMIT 1", function, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().get(0)[0], queryResult);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.get(0)[0], queryResult);
}
@Test
@@ -157,22 +180,314 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(1);
insertRow(2);
insertRow(2);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, COUNT(*) FROM testTable GROUP BY %s ORDER BY 1 DESC NULLS LAST", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 3);
assertEquals(rows.get(0), new Object[]{2, (long) 2 * NUM_OF_SEGMENT_COPIES});
assertEquals(rows.get(1), new Object[]{1, (long) NUM_OF_SEGMENT_COPIES});
assertEquals(rows.get(2), new Object[]{null, (long) 3 * NUM_OF_SEGMENT_COPIES});
}
+ /// A row holding the column's default null value must not join the null group.
+ ///
+ /// Ingestion stores that default in the forward index for a null row, so both share a dictionary id and only the
+ /// null vector tells them apart. Grouping therefore has to move nulls onto an id of their own.
+ @Test
+ public void testGroupByKeepsNullApartFromTheDefaultNullValue()
+ throws Exception {
+ initializeRows();
+ insertRow(1);
+ insertRow(null);
+ insertRow(FieldSpec.DEFAULT_DIMENSION_NULL_VALUE_OF_INT);
+ insertRow(null);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
+ String query =
+ String.format("SELECT %s, COUNT(*) FROM testTable GROUP BY %s ORDER BY 1 NULLS LAST", COLUMN1, COLUMN1);
+
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 3);
+ assertEquals(rows.get(0),
+ new Object[]{FieldSpec.DEFAULT_DIMENSION_NULL_VALUE_OF_INT, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{1, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{null, (long) 2 * NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// A multi-value row expands into one group per value it holds, so a row whose column is null contributes a single
+ /// null group rather than reading as the column's default null value, which is what a null row is stored as.
+ @Test
+ public void testGroupByMultiValueColumnHoldingNulls()
+ throws Exception {
+ initializeRows();
+ insertRow(new Object[]{1, 2});
+ insertRow(new Object[]{2, 3});
+ insertRow(null);
+ insertRow(null);
+ Schema schema = schemaBuilder().addMultiValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
+ String query =
+ String.format("SELECT %s, COUNT(*) FROM testTable GROUP BY %s ORDER BY 1 NULLS LAST", COLUMN1, COLUMN1);
+
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 4);
+ assertEquals(rows.get(0), new Object[]{1, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{2, (long) 2 * NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{3, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(3), new Object[]{null, (long) 2 * NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// A column with no dictionary resolves group keys through an on-the-fly dictionary rather than dictionary ids,
+ /// and its null rows still hold the column's default null value, so the same null-vs-default separation applies.
+ @Test
+ public void testGroupByRawColumnKeepsNullApartFromTheDefaultNullValue()
+ throws Exception {
+ initializeRows();
+ insertRow(1);
+ insertRow(null);
+ insertRow(FieldSpec.DEFAULT_DIMENSION_NULL_VALUE_OF_INT);
+ insertRow(null);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
+ String query =
+ String.format("SELECT %s, COUNT(*) FROM testTable GROUP BY %s ORDER BY 1 NULLS LAST", COLUMN1, COLUMN1);
+
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 3);
+ assertEquals(rows.get(0),
+ new Object[]{FieldSpec.DEFAULT_DIMENSION_NULL_VALUE_OF_INT, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{1, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{null, (long) 2 * NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// A STRING group key is held in an object-keyed map, which stores the null group under a null key instead of
+ /// tracking it beside the map the way the primitive-keyed maps do.
+ @Test
+ public void testGroupByRawStringColumnHoldingNulls()
+ throws Exception {
+ initializeRows();
+ insertRow("a");
+ insertRow("b");
+ insertRow(null);
+ insertRow(null);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.STRING).build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
+ String query =
+ String.format("SELECT %s, COUNT(*) FROM testTable GROUP BY %s ORDER BY 1 NULLS LAST", COLUMN1, COLUMN1);
+
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 3);
+ assertEquals(rows.get(0), new Object[]{"a", (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{"b", (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{null, (long) 2 * NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// A dictionary-backed transform must keep a null apart from the column's default null value, exactly as reading
+ /// the column directly does.
+ ///
+ /// A transform hands out its own null bitmap but exposes no data source to inspect, so nullability cannot be ruled
+ /// out for it the way it can for a column read straight from a segment.
+ @Test
+ public void testGroupByDictionaryBackedTransformKeepsNullApartFromTheDefaultNullValue()
+ throws Exception {
+ initializeRows();
+ insertRow(new Object[]{1});
+ insertRow(null);
+ insertRow(new Object[]{FieldSpec.DEFAULT_DIMENSION_NULL_VALUE_OF_INT});
+ Schema schema = schemaBuilder().addMultiValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
+ String transform = String.format("filterMv(%s, 'v <= 1')", COLUMN1);
+ String query = String.format("SELECT %s, COUNT(*) FROM testTable GROUP BY %s ORDER BY 1 NULLS LAST", transform,
+ transform);
+
+ List<Object[]> rows = getRows(query);
+
+ assertEquals(rows.size(), 3);
+ assertEquals(rows.get(0)[0], FieldSpec.DEFAULT_DIMENSION_NULL_VALUE_OF_INT);
+ assertEquals(rows.get(1)[0], 1);
+ assertNull(rows.get(2)[0], "The null row must not join the group of the column's default null value");
+ }
+
+ /// Grouping sets resolve each column's values to ids of their own, and the multi-value resolver has to recognize a
+ /// null row there too, so it forms its own group instead of joining the column's default null value.
+ @Test
+ public void testGroupingSetsOverMultiValueColumnHoldingNulls()
+ throws Exception {
+ initializeRows();
+ insertRow(new Object[]{1});
+ insertRow(null);
+ insertRow(new Object[]{FieldSpec.DEFAULT_DIMENSION_NULL_VALUE_OF_INT});
+ Schema schema = schemaBuilder().addMultiValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
+ String query = String.format(
+ "SELECT %s, COUNT(*) FROM testTable GROUP BY GROUPING SETS ((%s)) ORDER BY 1 NULLS LAST", COLUMN1, COLUMN1);
+
+ List<Object[]> rows = getRows(query);
+
+ assertEquals(rows.size(), 3);
+ assertEquals(rows.get(0), new Object[]{FieldSpec.DEFAULT_DIMENSION_NULL_VALUE_OF_INT,
+ (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{1, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{null, (long) NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// The group id of a null value is handed out beside the group key map, so a generator that counted only the map
+ /// would under-report its groups and let a group id run past the result holder it sized.
+ @Test
+ public void testNullGroupIsCountedWhenSizingTheResultHolder()
+ throws Exception {
+ initializeRows();
+ insertRow(new Object[]{1});
+ insertRow(new Object[]{2});
+ insertRow(null);
+ Schema schema = schemaBuilder().addMultiValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
+ String query =
+ String.format("SELECT %s, COUNT(*) FROM testTable GROUP BY %s ORDER BY 1 NULLS LAST", COLUMN1, COLUMN1);
+ // Sized so that the null group is the first id past the holder's initial capacity
+ Map<String, String> queryOptions =
+ Map.of("enableNullHandling", "true", "maxInitialResultHolderCapacity", "2");
+
+ List<Object[]> rows = getRows(query, queryOptions);
+
+ assertEquals(rows.size(), 3);
+ assertEquals(rows.get(0), new Object[]{1, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{2, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{null, (long) NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// One column without a dictionary sends both columns down the on-the-fly path, where a null contributes a reserved
+ /// id to the composed key, in any combination across the two columns.
+ @Test
+ public void testGroupByRawAndDictionaryColumnsHoldingNulls()
+ throws Exception {
+ initializeRows();
+ insertRowWithTwoColumns(1, 10);
+ insertRowWithTwoColumns(1, null);
+ insertRowWithTwoColumns(null, 10);
+ insertRowWithTwoColumns(null, null);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
+ String query =
+ String.format("SELECT %s, %s, COUNT(*) FROM testTable GROUP BY %s, %s ORDER BY 1 NULLS LAST, 2 NULLS LAST",
+ COLUMN1, COLUMN2, COLUMN1, COLUMN2);
+
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 4);
+ assertEquals(rows.get(0), new Object[]{1, 10, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{1, null, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{null, 10, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(3), new Object[]{null, null, (long) NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// A column with no dictionary is grouped through an on-the-fly one, and a multi-value column of that kind takes
+ /// the path that reads whole rows at a time, which has to consult the null bitmap just as the others do.
+ @Test
+ public void testGroupByRawMultiValueColumnHoldingNulls()
+ throws Exception {
+ initializeRows();
+ insertRow(new Object[]{1, 2});
+ insertRow(new Object[]{2, 3});
+ insertRow(null);
+ insertRow(null);
+ Schema schema = schemaBuilder().addMultiValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
+ String query =
+ String.format("SELECT %s, COUNT(*) FROM testTable GROUP BY %s ORDER BY 1 NULLS LAST", COLUMN1, COLUMN1);
+
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 4);
+ assertEquals(rows.get(0), new Object[]{1, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{2, (long) 2 * NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{3, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(3), new Object[]{null, (long) 2 * NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// Once the group limit is reached, a row of an existing group must still land in that group. The at-limit path
+ /// resolves each column's key value without being allowed to create one, and has to compose the looked-up values
+ /// rather than whatever the key buffer held before.
+ @Test
+ public void testGroupLimitStillRoutesRowsToTheirExistingGroup()
+ throws Exception {
+ initializeRows();
+ insertRowWithTwoColumns(1, 10);
+ insertRowWithTwoColumns(2, 20);
+ insertRowWithTwoColumns(2, 20);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
+ String query =
+ String.format("SELECT %s, %s, COUNT(*) FROM testTable GROUP BY %s, %s ORDER BY 1", COLUMN1, COLUMN2, COLUMN1,
+ COLUMN2);
+ Map<String, String> queryOptions = Map.of("enableNullHandling", "true", "numGroupsLimit", "2");
+
+ List<Object[]> rows = getRows(query, queryOptions);
+ assertEquals(rows.size(), 2);
+ assertEquals(rows.get(0), new Object[]{1, 10, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{2, 20, (long) 2 * NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// One column without a dictionary sends every column down the on-the-fly path, so a null has to be recognized
+ /// there for the dictionary-encoded column beside it as well.
+ @Test
+ public void testGroupByRawMultiValueColumnBesideADictionaryColumn()
+ throws Exception {
+ initializeRows();
+ insertRowWithTwoColumns(new Object[]{1, 2}, 10);
+ insertRowWithTwoColumns(null, 10);
+ insertRowWithTwoColumns(new Object[]{1}, null);
+ Schema schema = schemaBuilder()
+ .addMultiValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
+ String query =
+ String.format("SELECT %s, %s, COUNT(*) FROM testTable GROUP BY %s, %s ORDER BY 1 NULLS LAST, 2 NULLS LAST",
+ COLUMN1, COLUMN2, COLUMN1, COLUMN2);
+
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 4);
+ assertEquals(rows.get(0), new Object[]{1, 10, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{1, null, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{2, 10, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(3), new Object[]{null, 10, (long) NUM_OF_SEGMENT_COPIES});
+ }
+
+ /// Several columns compose their dictionary ids into a single key using each column's cardinality, so the id
+ /// reserved for null has to be counted in every one of them for the composition to stay unambiguous.
+ @Test
+ public void testGroupByTwoColumnsHoldingNulls()
+ throws Exception {
+ initializeRows();
+ insertRowWithTwoColumns(1, 10);
+ insertRowWithTwoColumns(1, null);
+ insertRowWithTwoColumns(null, 10);
+ insertRowWithTwoColumns(null, null);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
+ String query =
+ String.format("SELECT %s, %s, COUNT(*) FROM testTable GROUP BY %s, %s ORDER BY 1 NULLS LAST, 2 NULLS LAST",
+ COLUMN1, COLUMN2, COLUMN1, COLUMN2);
+
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 4);
+ assertEquals(rows.get(0), new Object[]{1, 10, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(1), new Object[]{1, null, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(2), new Object[]{null, 10, (long) NUM_OF_SEGMENT_COPIES});
+ assertEquals(rows.get(3), new Object[]{null, null, (long) NUM_OF_SEGMENT_COPIES});
+ }
+
@Test
public void testHavingFilterIsNull()
throws Exception {
@@ -180,18 +495,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(1, 1);
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(null, 1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, COUNT(%s) FROM testTable GROUP BY %s HAVING %s IS NULL LIMIT 100", COLUMN1, COLUMN2,
COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0), new Object[]{null, (long) 2 * NUM_OF_SEGMENT_COPIES});
}
@@ -203,18 +516,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(1, 1);
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(null, 1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, COUNT(%s) FROM testTable GROUP BY %s HAVING %s IS NOT NULL LIMIT 100", COLUMN1,
COLUMN2, COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0), new Object[]{1, (long) NUM_OF_SEGMENT_COPIES});
}
@@ -226,18 +537,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(true, 1);
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(null, 1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.BOOLEAN)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, COUNT(%s) FROM testTable GROUP BY %s HAVING (NOT %s) IS NULL LIMIT 100", COLUMN1,
COLUMN2, COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0), new Object[]{null, (long) 2 * NUM_OF_SEGMENT_COPIES});
}
@@ -249,18 +558,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(true, 1);
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(null, 1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.BOOLEAN)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, COUNT(%s) FROM testTable GROUP BY %s HAVING NOT (%s IS NULL) LIMIT 100", COLUMN1,
COLUMN2, COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0), new Object[]{true, (long) NUM_OF_SEGMENT_COPIES});
}
@@ -272,18 +579,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(1, 1);
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(null, 1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format(
"SELECT %s, COUNT(%s) FROM testTable GROUP BY %s HAVING (%s IS NULL) AND (COUNT(%s) is NOT NULL) LIMIT 100",
COLUMN1, COLUMN2, COLUMN1, COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0), new Object[]{null, (long) 2 * NUM_OF_SEGMENT_COPIES});
}
@@ -295,18 +600,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(1, 1);
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(null, 1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format(
"SELECT %s, COUNT(%s) FROM testTable GROUP BY %s HAVING (%s IS NULL) OR (COUNT(%s) is NULL) LIMIT 100", COLUMN1,
COLUMN2, COLUMN1, COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0), new Object[]{null, (long) 2 * NUM_OF_SEGMENT_COPIES});
}
@@ -318,16 +621,13 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRow(1);
insertRow(null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCT %s FROM testTable ORDER BY %s NULLS FIRST", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertNull(resultTable.getRows().get(0)[0]);
- assertNotNull(resultTable.getRows().get(1)[0]);
+ List<Object[]> rows = getRows(query);
+ assertNull(rows.get(0)[0]);
+ assertNotNull(rows.get(1)[0]);
}
@Test
@@ -337,16 +637,13 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRow(1);
insertRow(null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCT %s FROM testTable ORDER BY %s NULLS LAST", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertNotNull(resultTable.getRows().get(0)[0]);
- assertNull(resultTable.getRows().get(1)[0]);
+ List<Object[]> rows = getRows(query);
+ assertNotNull(rows.get(0)[0]);
+ assertNull(rows.get(1)[0]);
}
@Test
@@ -356,15 +653,12 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRow(Integer.MIN_VALUE);
insertRow(null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCT %s FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 2);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 2);
}
@Test
@@ -377,16 +671,15 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(null, 2);
insertRowWithTwoColumns(null, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCT %s,%s FROM testTable", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 4);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 4);
}
@Test
@@ -398,21 +691,20 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(null, 2);
insertRowWithTwoColumns(1, 1);
insertRowWithTwoColumns(null, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT DISTINCT %s,%s FROM testTable ORDER BY %s,%s", COLUMN1, COLUMN2, COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 4);
- assertEquals(resultTable.getRows().get(0), new Object[]{1, 1});
- assertEquals(resultTable.getRows().get(1), new Object[]{null, 1});
- assertEquals(resultTable.getRows().get(2), new Object[]{null, 2});
- assertEquals(resultTable.getRows().get(3), new Object[]{null, null});
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 4);
+ assertEquals(rows.get(0), new Object[]{1, 1});
+ assertEquals(rows.get(1), new Object[]{null, 1});
+ assertEquals(rows.get(2), new Object[]{null, 2});
+ assertEquals(rows.get(3), new Object[]{null, null});
}
@Test
@@ -424,52 +716,48 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(null, 2);
insertRowWithTwoColumns(1, 1);
insertRowWithTwoColumns(null, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT DISTINCT %s,%s FROM testTable ORDER BY %s NULLS FIRST, %s DESC NULLS LAST", COLUMN1,
COLUMN2, COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 4);
- assertEquals(resultTable.getRows().get(0), new Object[]{null, 2});
- assertEquals(resultTable.getRows().get(1), new Object[]{null, 1});
- assertEquals(resultTable.getRows().get(2), new Object[]{null, null});
- assertEquals(resultTable.getRows().get(3), new Object[]{1, 1});
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 4);
+ assertEquals(rows.get(0), new Object[]{null, 2});
+ assertEquals(rows.get(1), new Object[]{null, 1});
+ assertEquals(rows.get(2), new Object[]{null, null});
+ assertEquals(rows.get(3), new Object[]{1, 1});
}
@DataProvider(name = "NumberTypes")
public static Object[][] getPrimitiveDataTypes() {
return new Object[][]{
- {FieldSpec.DataType.INT}, {FieldSpec.DataType.LONG}, {FieldSpec.DataType.DOUBLE}, {FieldSpec.DataType.FLOAT}
+ {DataType.INT}, {DataType.LONG}, {DataType.DOUBLE}, {DataType.FLOAT}
};
}
@Test(dataProvider = "NumberTypes")
- public void testSelectDistinctWithLimit(FieldSpec.DataType dataType)
+ public void testSelectDistinctWithLimit(DataType dataType)
throws Exception {
initializeRows();
insertRow(null);
insertRow(1);
insertRow(2);
insertRow(3);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCT %s FROM testTable ORDER BY %s LIMIT 3", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 3);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 3);
}
@Test(dataProvider = "NumberTypes")
- public void testSelectDistinctOrderByWithLimit(FieldSpec.DataType dataType)
+ public void testSelectDistinctOrderByWithLimit(DataType dataType)
throws Exception {
double delta = 0.01;
initializeRows();
@@ -477,232 +765,203 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(1);
insertRow(2);
insertRow(3);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCT %s FROM testTable ORDER BY %s LIMIT 3", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 3);
- assertTrue(Math.abs(((Number) resultTable.getRows().get(0)[0]).doubleValue() - 1.0) < delta);
- assertTrue(Math.abs(((Number) resultTable.getRows().get(1)[0]).doubleValue() - 2.0) < delta);
- assertTrue(Math.abs(((Number) resultTable.getRows().get(2)[0]).doubleValue() - 3.0) < delta);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 3);
+ assertTrue(Math.abs(((Number) rows.get(0)[0]).doubleValue() - 1.0) < delta);
+ assertTrue(Math.abs(((Number) rows.get(1)[0]).doubleValue() - 2.0) < delta);
+ assertTrue(Math.abs(((Number) rows.get(2)[0]).doubleValue() - 3.0) < delta);
}
@DataProvider(name = "ObjectTypes")
public static Object[][] getObjectDataTypes() {
return new Object[][]{
- {FieldSpec.DataType.STRING, "a"}, {
- FieldSpec.DataType.BIG_DECIMAL, 1
- }, {
- FieldSpec.DataType.BYTES, "a string".getBytes()
- }
+ {DataType.STRING, "a"},
+ {DataType.BIG_DECIMAL, 1},
+ {DataType.BYTES, "a string".getBytes()}
};
}
@Test(dataProvider = "ObjectTypes")
- public void testObjectSingleColumnDistinctOrderByNullsFirst(FieldSpec.DataType dataType, Object value)
+ public void testObjectSingleColumnDistinctOrderByNullsFirst(DataType dataType, Object value)
throws Exception {
initializeRows();
insertRow(null);
insertRow(value);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCT %s FROM testTable ORDER BY %s NULLS FIRST LIMIT 1", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertNull(resultTable.getRows().get(0)[0]);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertNull(rows.get(0)[0]);
}
@Test(dataProvider = "ObjectTypes")
- public void testObjectSingleColumnDistinctOrderByNullsLast(FieldSpec.DataType dataType, Object value)
+ public void testObjectSingleColumnDistinctOrderByNullsLast(DataType dataType, Object value)
throws Exception {
initializeRows();
insertRow(null);
insertRow(value);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCT %s FROM testTable ORDER BY %s NULLS LAST LIMIT 1", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertNotNull(resultTable.getRows().get(0)[0]);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertNotNull(rows.get(0)[0]);
}
@Test(dataProvider = "NumberTypes")
- public void testDistinctCountDictNumberTypes(FieldSpec.DataType dataType)
+ public void testDistinctCountDictNumberTypes(DataType dataType)
throws Exception {
initializeRows();
insertRow(null);
insertRow(1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCTCOUNT(%s) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertEquals(resultTable.getRows().get(0)[0], 1);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0)[0], 1);
}
@Test(dataProvider = "NumberTypes")
- public void testDistinctCountNonDictNumberTypes(FieldSpec.DataType dataType)
+ public void testDistinctCountNonDictNumberTypes(DataType dataType)
throws Exception {
initializeRows();
insertRow(null);
insertRow(1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME)
- .setNoDictionaryColumns(List.of(COLUMN1)).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
String query = String.format("SELECT DISTINCTCOUNT(%s) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertEquals(resultTable.getRows().get(0)[0], 1);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0)[0], 1);
}
@Test(dataProvider = "NumberTypes")
- public void testGroupByDistinctCountDictNumberTypes(FieldSpec.DataType dataType)
+ public void testGroupByDistinctCountDictNumberTypes(DataType dataType)
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, "key");
insertRowWithTwoColumns(1, "key");
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.STRING).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, dataType)
+ .addSingleValueDimension(COLUMN2, DataType.STRING)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCTCOUNT(%s), %s FROM testTable GROUP BY %s", COLUMN1, COLUMN2, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertEquals(resultTable.getRows().get(0), new Object[]{1, "key"});
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0), new Object[]{1, "key"});
}
@Test(dataProvider = "NumberTypes")
- public void testGroupByDistinctCountNonDictNumberTypes(FieldSpec.DataType dataType)
+ public void testGroupByDistinctCountNonDictNumberTypes(DataType dataType)
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, "key");
insertRowWithTwoColumns(1, "key");
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME)
- .setNoDictionaryColumns(List.of(COLUMN1)).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.STRING).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, dataType)
+ .addSingleValueDimension(COLUMN2, DataType.STRING)
+ .build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
String query = String.format("SELECT DISTINCTCOUNT(%s), %s FROM testTable GROUP BY %s", COLUMN1, COLUMN2, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertEquals(resultTable.getRows().get(0), new Object[]{1, "key"});
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0), new Object[]{1, "key"});
}
@Test(dataProvider = "NumberTypes")
- public void testGroupByMvDistinctCountNonDictNumberTypes(FieldSpec.DataType dataType)
+ public void testGroupByMvDistinctCountNonDictNumberTypes(DataType dataType)
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, new String[]{"key1", "key2"});
insertRowWithTwoColumns(1, new String[]{"key1", "key2"});
insertRowWithTwoColumns(2, new String[]{"key2"});
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME)
- .setNoDictionaryColumns(List.of(COLUMN1)).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType)
- .addMultiValueDimension(COLUMN2, FieldSpec.DataType.STRING).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, dataType)
+ .addMultiValueDimension(COLUMN2, DataType.STRING)
+ .build();
+ setUpSegments(TABLE_CONFIG_WITH_RAW_COLUMN, schema);
String query =
String.format("SELECT DISTINCTCOUNT(%s), %s FROM testTable GROUP BY %s ORDER BY %s", COLUMN1, COLUMN2, COLUMN2,
COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().get(0), new Object[]{1, "key1"});
- assertEquals(resultTable.getRows().get(1), new Object[]{2, "key2"});
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.get(0), new Object[]{1, "key1"});
+ assertEquals(rows.get(1), new Object[]{2, "key2"});
}
@Test(dataProvider = "NumberTypes")
- public void testGroupByMvDistinctCountDictNumberTypes(FieldSpec.DataType dataType)
+ public void testGroupByMvDistinctCountDictNumberTypes(DataType dataType)
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, new String[]{"key1", "key2"});
insertRowWithTwoColumns(1, new String[]{"key1", "key2"});
insertRowWithTwoColumns(2, new String[]{"key2"});
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType)
- .addMultiValueDimension(COLUMN2, FieldSpec.DataType.STRING).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, dataType)
+ .addMultiValueDimension(COLUMN2, DataType.STRING)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT DISTINCTCOUNT(%s), %s FROM testTable GROUP BY %s ORDER BY %s", COLUMN1, COLUMN2, COLUMN2,
COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().get(0), new Object[]{1, "key1"});
- assertEquals(resultTable.getRows().get(1), new Object[]{2, "key2"});
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.get(0), new Object[]{1, "key1"});
+ assertEquals(rows.get(1), new Object[]{2, "key2"});
}
@DataProvider(name = "DistinctCountObjectTypes")
public static Object[][] getDistinctAggregationObjectTypes() {
return new Object[][]{
- {FieldSpec.DataType.STRING, "a"}, {
- FieldSpec.DataType.BYTES, "a string".getBytes()
- }
+ {DataType.STRING, "a"},
+ {DataType.BYTES, "a string".getBytes()}
};
}
@Test(dataProvider = "DistinctCountObjectTypes")
- public void testObjectDistinctCountObjectTypes(FieldSpec.DataType dataType, Object value)
+ public void testObjectDistinctCountObjectTypes(DataType dataType, Object value)
throws Exception {
initializeRows();
insertRow(null);
insertRow(value);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCTCOUNT(%s) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertEquals(resultTable.getRows().get(0)[0], 1);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0)[0], 1);
}
@Test(dataProvider = "DistinctCountObjectTypes")
- public void testGroupByDistinctCountObjectTypes(FieldSpec.DataType dataType, Object value)
+ public void testGroupByDistinctCountObjectTypes(DataType dataType, Object value)
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, "key");
insertRowWithTwoColumns(value, "key");
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.STRING).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, dataType)
+ .addSingleValueDimension(COLUMN2, DataType.STRING)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCTCOUNT(%s), %s FROM testTable GROUP BY %s", COLUMN1, COLUMN2, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertEquals(resultTable.getRows().get(0), new Object[]{1, "key"});
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0), new Object[]{1, "key"});
}
@Test
@@ -713,16 +972,13 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(1);
insertRow(2);
insertRow(2);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCTSUM(%s) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertEquals(resultTable.getRows().get(0)[0], (double) 3);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0)[0], (double) 3);
}
@Test
@@ -733,16 +989,13 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(1);
insertRow(2);
insertRow(2);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT DISTINCTAVG(%s) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), 1);
- assertEquals(resultTable.getRows().get(0)[0], 1.5);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0)[0], 1.5);
}
@Test
@@ -750,16 +1003,13 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRow(null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT (CASE WHEN %s IS NULL THEN 1 END) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- assertEquals(resultTable.getRows().size(), NUM_OF_SEGMENT_COPIES);
- assertEquals(resultTable.getRows().get(0)[0], 1);
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
+ assertEquals(rows.get(0)[0], 1);
}
private boolean contains(List<Object[]> rows, Object[] target) {
@@ -781,18 +1031,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(1, 1);
insertRowWithTwoColumns(1, null);
insertRowWithTwoColumns(1, Integer.MIN_VALUE);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT count(*), %s, %s FROM testTable GROUP BY %s, %s", COLUMN1, COLUMN2, COLUMN1,
COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 5);
assertTrue(contains(rows, new Object[]{(long) NUM_OF_SEGMENT_COPIES, null, null}));
assertTrue(contains(rows, new Object[]{(long) 2 * NUM_OF_SEGMENT_COPIES, null, 1}));
@@ -811,18 +1059,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(1, 1);
insertRowWithTwoColumns(1, null);
insertRowWithTwoColumns(1, Integer.MIN_VALUE);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT count(*), %s, %s FROM testTable GROUP BY %s, %s LIMIT 3", COLUMN1, COLUMN2, COLUMN1,
COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 3);
}
@@ -835,17 +1081,13 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(1);
insertRow(2);
insertRow(3);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT count(*), %s FROM testTable GROUP BY %s ORDER BY %s ASC NULLS LAST", COLUMN1, COLUMN1,
COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 4);
assertEquals(rows.get(0), new Object[]{(long) 2 * NUM_OF_SEGMENT_COPIES, 1});
assertEquals(rows.get(1), new Object[]{(long) NUM_OF_SEGMENT_COPIES, 2});
@@ -862,17 +1104,13 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(1);
insertRow(2);
insertRow(3);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT count(*), %s FROM testTable GROUP BY %s ORDER BY %s DESC NULLS FIRST LIMIT 3", COLUMN1,
COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 3);
assertEquals(rows.get(0), new Object[]{(long) NUM_OF_SEGMENT_COPIES, null});
assertEquals(rows.get(1), new Object[]{(long) NUM_OF_SEGMENT_COPIES, 3});
@@ -884,16 +1122,12 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRow(null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT (CASE WHEN %s = -2147483648 THEN 1 ELSE 2 END) + 0 FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.get(0), new Object[]{(double) 2});
}
@@ -904,17 +1138,12 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(null);
insertRow(false);
insertRow(true);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME)
- .setInvertedIndexColumns(List.of(COLUMN1)).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.BOOLEAN).build();
+ setUpSegments(TABLE_CONFIG_WITH_INVERTED_INDEX_COLUMN, schema);
String query =
String.format("SELECT * FROM testTable WHERE %s = false", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{false});
}
@@ -926,17 +1155,12 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(null);
insertRow(false);
insertRow(true);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME)
- .setSortedColumn(COLUMN1).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.BOOLEAN).build();
+ setUpSegments(TABLE_CONFIG_WITH_SORTED_COLUMN, schema);
String query =
String.format("SELECT * FROM testTable WHERE %s = false", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{false});
}
@@ -947,16 +1171,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRow(-1);
insertRow(null);
- TableConfig tableConfig =
- new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).setSortedColumn(COLUMN1).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG_WITH_SORTED_COLUMN, schema);
String query = String.format("SELECT * FROM testTable WHERE %s < 0", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{-1});
}
@@ -967,16 +1186,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRow(null);
insertRow(Integer.MIN_VALUE);
- TableConfig tableConfig =
- new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).setSortedColumn(COLUMN1).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG_WITH_SORTED_COLUMN, schema);
String query = String.format("SELECT * FROM testTable WHERE %s = %d", COLUMN1, Integer.MIN_VALUE);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{Integer.MIN_VALUE});
}
@@ -992,18 +1206,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(-1, 1);
insertRowWithTwoColumns(1, null);
insertRowWithTwoColumns(null, -1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE OR(%s > 0, %s < 0) LIMIT 100", COLUMN1, COLUMN2, COLUMN1,
COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES * 3);
}
@@ -1014,15 +1226,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(null);
insertRow(-1);
insertRow(1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT %s FROM testTable WHERE NOT(%s = 1) LIMIT 100", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{-1});
}
@@ -1038,18 +1246,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(-1, 1);
insertRowWithTwoColumns(1, null);
insertRowWithTwoColumns(null, -1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE NOT(AND(%s > 0, %s < 0)) LIMIT 100", COLUMN1, COLUMN2,
COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 3 * NUM_OF_SEGMENT_COPIES);
}
@@ -1064,18 +1270,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(-1, 1);
insertRowWithTwoColumns(1, null);
insertRowWithTwoColumns(null, -1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE NOT(OR(%s > 0, %s < 0)) LIMIT 100", COLUMN1, COLUMN2, COLUMN1,
COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{-1, 1});
}
@@ -1086,16 +1290,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRow(false);
insertRow(true);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME)
- .setInvertedIndexColumns(List.of(COLUMN1)).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.BOOLEAN).build();
+ setUpSegments(TABLE_CONFIG_WITH_INVERTED_INDEX_COLUMN, schema);
String query = String.format("SELECT * FROM testTable WHERE NOT(%s = false)", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{true});
}
@@ -1108,15 +1307,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(Integer.MIN_VALUE);
insertRow(1);
insertRow(-1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT %s FROM testTable WHERE add(%s, 0) < 0", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES * 2);
}
@@ -1128,15 +1323,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRow(Integer.MIN_VALUE);
insertRow(1);
insertRow(-1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT %s FROM testTable WHERE NOT(add(%s, 0) > 0)", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES * 2);
}
@@ -1152,18 +1343,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(-1, null);
insertRowWithTwoColumns(null, -1);
insertRowWithTwoColumns(1, 1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE GREATEST(%s, %s) < 0 LIMIT 100", COLUMN1, COLUMN2, COLUMN1,
COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES * 2);
}
@@ -1175,17 +1364,15 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(null, i);
}
insertRowWithTwoColumns(1, DocIdSetPlanNode.MAX_DOC_PER_CALL);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE add(%s, 0) > 0 LIMIT 10", COLUMN1, COLUMN2, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{1, DocIdSetPlanNode.MAX_DOC_PER_CALL});
}
@@ -1198,17 +1385,15 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(1, null);
insertRowWithTwoColumns(-1, 1);
insertRowWithTwoColumns(Integer.MIN_VALUE, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s FROM testTable WHERE NOT(add(%s, 0) > 0) AND %s IS NULL", COLUMN1, COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{Integer.MIN_VALUE});
}
@@ -1218,15 +1403,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRow(new Integer[]{1, 2, 3});
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addMultiValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addMultiValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT * FROM testTable WHERE NOT(VALUEIN(%s, 2, 3) > 2) LIMIT 100", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query, null);
assertEquals(rows.size(), 0);
}
@@ -1237,17 +1418,15 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(1, 2);
insertRowWithTwoColumns(-1, 3);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE ADD(%s, 0) IS NULL LIMIT 100", COLUMN1, COLUMN2, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{null, 1});
}
@@ -1259,17 +1438,15 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(null, 2);
insertRowWithTwoColumns(1, 3);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE ADD(%s, 0) IS NOT NULL LIMIT 100", COLUMN1, COLUMN2, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{1, 3});
}
@@ -1281,18 +1458,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(null, 2);
insertRowWithTwoColumns(1, 3);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE NOT(ADD(%s, 0) IS NULL) LIMIT 100", COLUMN1, COLUMN2,
COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{1, 3});
}
@@ -1303,18 +1478,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRowWithTwoColumns(null, 1);
insertRowWithTwoColumns(2, 3);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE NOT(ADD(%s, 0) IS NOT NULL) LIMIT 100", COLUMN1, COLUMN2,
COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{null, 1});
}
@@ -1326,17 +1499,15 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(true, 1);
insertRowWithTwoColumns(null, 2);
insertRowWithTwoColumns(false, 3);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.BOOLEAN)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE (NOT %s) IS NULL LIMIT 100", COLUMN1, COLUMN2, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{null, 2});
}
@@ -1349,18 +1520,16 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(1, null);
insertRowWithTwoColumns(-1, 1);
insertRowWithTwoColumns(null, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT %s, %s FROM testTable WHERE (add(%s, 0) IS NULL) AND (%s IS NULL)", COLUMN1, COLUMN2,
COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{null, null});
}
@@ -1371,17 +1540,15 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRowWithTwoColumns(new Integer[]{1, 2, 3}, 1);
insertRowWithTwoColumns(new Integer[]{2, 3, 4}, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addMultiValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addMultiValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT * FROM testTable WHERE (VALUEIN(%s, 2, 3) IN (2, 3)) AND (%s = 1)", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{new Integer[]{1, 2, 3}, 1});
}
@@ -1391,15 +1558,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRow(new Integer[]{1, 2, 3});
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addMultiValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addMultiValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT * FROM testTable WHERE (VALUEIN(%s, 2, 3) IS NULL)", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 0);
}
@@ -1408,15 +1571,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRow(new Integer[]{1, 2, 3});
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addMultiValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addMultiValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT * FROM testTable WHERE (VALUEIN(%s, 2, 3) IS NOT NULL)", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{new Integer[]{1, 2, 3}});
}
@@ -1427,15 +1586,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRow("abc");
insertRow(null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.STRING).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.STRING).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT STARTSWITH(%s, NULL) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 2 * NUM_OF_SEGMENT_COPIES);
for (int i = 0; i < 2 * NUM_OF_SEGMENT_COPIES; i++) {
assertEquals(rows.get(i), new Object[]{null});
@@ -1447,35 +1602,27 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRow(1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.INT).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT between(%s, NULL, 2) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), NUM_OF_SEGMENT_COPIES);
assertEquals(rows.get(0), new Object[]{null});
}
@Test(dataProvider = "NumberTypes")
- public void testStddevPop(FieldSpec.DataType dataType)
+ public void testStddevPop(DataType dataType)
throws Exception {
initializeRows();
insertRow(null);
insertRow(1);
insertRow(2);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, dataType).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT STDDEV_POP(%s) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0)[0], 0.5);
}
@@ -1489,15 +1636,14 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
insertRowWithTwoColumns(null, 20);
insertRowWithTwoColumns(3, null);
insertRowWithTwoColumns(4, 40);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT COVAR_POP(%s, %s) FROM testTable", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- List<Object[]> rows = brokerResponse.getResultTable().getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
// Only rows 0 and 3 contribute: mean(xy) - mean(x)mean(y) = 85 - 2.5 * 25
assertEquals(rows.get(0)[0], 22.5);
@@ -1509,15 +1655,14 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRowWithTwoColumns(null, 10);
insertRowWithTwoColumns(null, 20);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT COVAR_POP(%s, %s) FROM testTable", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- List<Object[]> rows = brokerResponse.getResultTable().getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
assertNull(rows.get(0)[0]);
}
@@ -1529,59 +1674,54 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
initializeRows();
insertRowWithTwoColumns(null, 10);
insertRowWithTwoColumns(null, 20);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.INT).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.INT)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT COVAR_POP(%s, %s) FROM testTable", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query);
-
- List<Object[]> rows = brokerResponse.getResultTable().getRows();
+ List<Object[]> rows = getRows(query, null);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0)[0], 0.0);
}
@Test(dataProvider = "NumberTypes")
- public void testGroupByStddevPop(FieldSpec.DataType dataType)
+ public void testGroupByStddevPop(DataType dataType)
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, "key");
insertRowWithTwoColumns(1, "key");
insertRowWithTwoColumns(2, "key");
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.STRING).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, dataType)
+ .addSingleValueDimension(COLUMN2, DataType.STRING)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT STDDEV_POP(%s), %s FROM testTable GROUP BY %s", COLUMN1, COLUMN2, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0), new Object[]{0.5, "key"});
}
@Test(dataProvider = "NumberTypes")
- public void testGroupByMvStddevPop(FieldSpec.DataType dataType)
+ public void testGroupByMvStddevPop(DataType dataType)
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, new String[]{"key1", "key2"});
insertRowWithTwoColumns(1, new String[]{"key1", "key2"});
insertRowWithTwoColumns(2, new String[]{"key1"});
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, dataType)
- .addMultiValueDimension(COLUMN2, FieldSpec.DataType.STRING).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, dataType)
+ .addMultiValueDimension(COLUMN2, DataType.STRING)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT STDDEV_POP(%s), %s FROM testTable GROUP BY %s ORDER BY %s", COLUMN1, COLUMN2, COLUMN2,
COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 2);
assertEquals(rows.get(0), new Object[]{0.5, "key1"});
assertEquals(rows.get(1), new Object[]{0.0, "key2"});
@@ -1592,20 +1732,18 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, "key1");
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.INT)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.STRING).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.INT)
+ .addSingleValueDimension(COLUMN2, DataType.STRING)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query =
String.format("SELECT STDDEV_POP(%s), %s FROM testTable GROUP BY %s ORDER BY %s", COLUMN1, COLUMN2, COLUMN2,
COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
- assertEquals(rows.get(0)[0], null);
+ assertNull(rows.get(0)[0]);
}
@Test
@@ -1613,17 +1751,13 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRow(null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.DOUBLE).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.DOUBLE).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT STDDEV_POP(%s) FROM testTable", COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query);
assertEquals(rows.size(), 1);
- assertEquals(rows.get(0)[0], null);
+ assertNull(rows.get(0)[0]);
}
@Test
@@ -1631,15 +1765,11 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRow(1);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.DOUBLE).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder().addSingleValueDimension(COLUMN1, DataType.DOUBLE).build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT STDDEV_POP(%s) FROM testTable WHERE %s != 1", COLUMN1, COLUMN1);
- BrokerResponseNative brokerResponse = getBrokerResponse(query);
-
- ResultTable resultTable = brokerResponse.getResultTable();
- List<Object[]> rows = resultTable.getRows();
+ List<Object[]> rows = getRows(query, null);
assertEquals(rows.size(), 1);
assertEquals(rows.get(0)[0], Double.NEGATIVE_INFINITY);
}
@@ -1649,15 +1779,14 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRowWithTwoColumns(true, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.BOOLEAN)
+ .addSingleValueDimension(COLUMN2, DataType.BOOLEAN)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT AND(%s, %s) FROM testTable LIMIT 1", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- assertEquals(brokerResponse.getResultTable().getRows().get(0)[0], null);
+ assertNull(getRows(query).get(0)[0]);
}
@Test
@@ -1665,15 +1794,14 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRowWithTwoColumns(false, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.BOOLEAN)
+ .addSingleValueDimension(COLUMN2, DataType.BOOLEAN)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT AND(%s, %s) FROM testTable LIMIT 1", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- assertEquals(brokerResponse.getResultTable().getRows().get(0)[0], false);
+ assertFalse((boolean) getRows(query).get(0)[0]);
}
@Test
@@ -1681,15 +1809,14 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.BOOLEAN)
+ .addSingleValueDimension(COLUMN2, DataType.BOOLEAN)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT AND(%s, %s) FROM testTable LIMIT 1", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- assertEquals(brokerResponse.getResultTable().getRows().get(0)[0], null);
+ assertNull(getRows(query).get(0)[0]);
}
@Test
@@ -1697,15 +1824,14 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRowWithTwoColumns(true, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.BOOLEAN)
+ .addSingleValueDimension(COLUMN2, DataType.BOOLEAN)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT OR(%s, %s) FROM testTable LIMIT 1", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- assertEquals(brokerResponse.getResultTable().getRows().get(0)[0], true);
+ assertTrue((boolean) getRows(query).get(0)[0]);
}
@Test
@@ -1713,15 +1839,14 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRowWithTwoColumns(false, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.BOOLEAN)
+ .addSingleValueDimension(COLUMN2, DataType.BOOLEAN)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT OR(%s, %s) FROM testTable LIMIT 1", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- assertEquals(brokerResponse.getResultTable().getRows().get(0)[0], null);
+ assertNull(getRows(query).get(0)[0]);
}
@Test
@@ -1729,15 +1854,14 @@ public class NullHandlingEnabledQueriesTest extends BaseQueriesTest {
throws Exception {
initializeRows();
insertRowWithTwoColumns(null, null);
- TableConfig tableConfig = new TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
- Schema schema = new Schema.SchemaBuilder().addSingleValueDimension(COLUMN1, FieldSpec.DataType.BOOLEAN)
- .addSingleValueDimension(COLUMN2, FieldSpec.DataType.BOOLEAN).build();
- setUpSegments(tableConfig, schema);
+ Schema schema = schemaBuilder()
+ .addSingleValueDimension(COLUMN1, DataType.BOOLEAN)
+ .addSingleValueDimension(COLUMN2, DataType.BOOLEAN)
+ .build();
+ setUpSegments(TABLE_CONFIG, schema);
String query = String.format("SELECT OR(%s, %s) FROM testTable LIMIT 1", COLUMN1, COLUMN2);
- BrokerResponseNative brokerResponse = getBrokerResponse(query, QUERY_OPTIONS);
-
- assertEquals(brokerResponse.getResultTable().getRows().get(0)[0], null);
+ assertNull(getRows(query).get(0)[0]);
}
@AfterMethod
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org