blob: dceddbaff436aec7812cd297307cdf9fc3ed51f0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.sql.calcite;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.data.input.InputRow;
import org.apache.druid.data.input.InputRowSchema;
import org.apache.druid.data.input.ResourceInputSource;
import org.apache.druid.data.input.impl.DimensionSchema;
import org.apache.druid.data.input.impl.DimensionsSpec;
import org.apache.druid.data.input.impl.LongDimensionSchema;
import org.apache.druid.data.input.impl.StringDimensionSchema;
import org.apache.druid.data.input.impl.TimestampSpec;
import org.apache.druid.error.DruidExceptionMatcher;
import org.apache.druid.guice.DruidInjectorBuilder;
import org.apache.druid.guice.NestedDataModule;
import org.apache.druid.java.util.common.HumanReadableBytes;
import org.apache.druid.java.util.common.granularity.Granularities;
import org.apache.druid.math.expr.ExprMacroTable;
import org.apache.druid.query.Druids;
import org.apache.druid.query.NestedDataTestUtils;
import org.apache.druid.query.QueryRunnerFactoryConglomerate;
import org.apache.druid.query.TableDataSource;
import org.apache.druid.query.UnnestDataSource;
import org.apache.druid.query.aggregation.CountAggregatorFactory;
import org.apache.druid.query.aggregation.DoubleSumAggregatorFactory;
import org.apache.druid.query.aggregation.ExpressionLambdaAggregatorFactory;
import org.apache.druid.query.aggregation.FilteredAggregatorFactory;
import org.apache.druid.query.aggregation.LongSumAggregatorFactory;
import org.apache.druid.query.dimension.DefaultDimensionSpec;
import org.apache.druid.query.filter.ArrayContainsElementFilter;
import org.apache.druid.query.filter.EqualityFilter;
import org.apache.druid.query.filter.ExpressionDimFilter;
import org.apache.druid.query.filter.LikeDimFilter;
import org.apache.druid.query.groupby.GroupByQuery;
import org.apache.druid.query.groupby.orderby.DefaultLimitSpec;
import org.apache.druid.query.groupby.orderby.OrderByColumnSpec;
import org.apache.druid.query.ordering.StringComparators;
import org.apache.druid.query.scan.ScanQuery;
import org.apache.druid.query.topn.DimensionTopNMetricSpec;
import org.apache.druid.query.topn.TopNQueryBuilder;
import org.apache.druid.segment.AutoTypeColumnSchema;
import org.apache.druid.segment.IndexBuilder;
import org.apache.druid.segment.QueryableIndex;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.RowSignature;
import org.apache.druid.segment.incremental.IncrementalIndexSchema;
import org.apache.druid.segment.join.JoinableFactoryWrapper;
import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
import org.apache.druid.segment.virtual.NestedFieldVirtualColumn;
import org.apache.druid.segment.writeout.OffHeapMemorySegmentWriteOutMediumFactory;
import org.apache.druid.server.SpecificSegmentsQuerySegmentWalker;
import org.apache.druid.sql.calcite.filtration.Filtration;
import org.apache.druid.sql.calcite.util.TestDataBuilder;
import org.apache.druid.timeline.DataSegment;
import org.apache.druid.timeline.partition.LinearShardSpec;
import org.hamcrest.CoreMatchers;
import org.junit.internal.matchers.ThrowableMessageMatcher;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class CalciteNestedDataQueryTest extends BaseCalciteQueryTest
{
private static final String DATA_SOURCE = "nested";
private static final String DATA_SOURCE_MIXED = "nested_mix";
private static final String DATA_SOURCE_MIXED_2 = "nested_mix_2";
private static final String DATA_SOURCE_ARRAYS = "arrays";
private static final String DATA_SOURCE_ALL = "all_auto";
private static final List<ImmutableMap<String, Object>> RAW_ROWS = ImmutableList.of(
ImmutableMap.<String, Object>builder()
.put("t", "2000-01-01")
.put("string", "aaa")
.put("string_sparse", "zzz")
.put("nest", ImmutableMap.of("x", 100L, "y", 2.02, "z", "300", "mixed", 1L, "mixed2", "1"))
.put(
"nester",
ImmutableMap.of("array", ImmutableList.of("a", "b"), "n", ImmutableMap.of("x", "hello"))
)
.put("long", 5L)
.build(),
ImmutableMap.<String, Object>builder()
.put("t", "2000-01-01")
.put("string", "bbb")
.put("long", 4L)
.put("nester", "hello")
.build(),
ImmutableMap.<String, Object>builder()
.put("t", "2000-01-01")
.put("string", "ccc")
.put("string_sparse", "10")
.put("nest", ImmutableMap.of("x", 200L, "y", 3.03, "z", "abcdef", "mixed", 1.1, "mixed2", 1L))
.put("long", 3L)
.build(),
ImmutableMap.<String, Object>builder()
.put("t", "2000-01-01")
.put("string", "ddd")
.put("string_sparse", "yyy")
.put("long", 2L)
.build(),
ImmutableMap.<String, Object>builder()
.put("t", "2000-01-01")
.put("string", "eee")
.put("long", 1L)
.build(),
// repeat on another day
ImmutableMap.<String, Object>builder()
.put("t", "2000-01-02")
.put("string", "aaa")
.put("nest", ImmutableMap.of("x", 100L, "y", 2.02, "z", "400", "mixed2", 1.1))
.put("nester", ImmutableMap.of("array", ImmutableList.of("a", "b"), "n", ImmutableMap.of("x", 1L)))
.put("long", 5L)
.build(),
ImmutableMap.<String, Object>builder()
.put("t", "2000-01-02")
.put("string", "ddd")
.put("long", 2L)
.put("nester", 2L)
.build()
);
private static final InputRowSchema ALL_JSON_COLUMNS = new InputRowSchema(
new TimestampSpec("t", "iso", null),
DimensionsSpec.builder().setDimensions(
ImmutableList.<DimensionSchema>builder()
.add(new AutoTypeColumnSchema("string", null))
.add(new AutoTypeColumnSchema("nest", null))
.add(new AutoTypeColumnSchema("nester", null))
.add(new AutoTypeColumnSchema("long", null))
.add(new AutoTypeColumnSchema("string_sparse", null))
.build()
).build(),
null
);
private static final InputRowSchema JSON_AND_SCALAR_MIX = new InputRowSchema(
new TimestampSpec("t", "iso", null),
DimensionsSpec.builder().setDimensions(
ImmutableList.<DimensionSchema>builder()
.add(new StringDimensionSchema("string"))
.add(new AutoTypeColumnSchema("nest", null))
.add(new AutoTypeColumnSchema("nester", null))
.add(new LongDimensionSchema("long"))
.add(new StringDimensionSchema("string_sparse"))
.build()
).build(),
null
);
private static final List<InputRow> ROWS =
RAW_ROWS.stream().map(raw -> TestDataBuilder.createRow(raw, ALL_JSON_COLUMNS)).collect(Collectors.toList());
private static final List<InputRow> ROWS_MIX =
RAW_ROWS.stream().map(raw -> TestDataBuilder.createRow(raw, JSON_AND_SCALAR_MIX)).collect(Collectors.toList());
@Override
public void configureGuice(DruidInjectorBuilder builder)
{
super.configureGuice(builder);
builder.addModule(new NestedDataModule());
}
@SuppressWarnings("resource")
@Override
public SpecificSegmentsQuerySegmentWalker createQuerySegmentWalker(
final QueryRunnerFactoryConglomerate conglomerate,
final JoinableFactoryWrapper joinableFactory,
final Injector injector
)
{
NestedDataModule.registerHandlersAndSerde();
final QueryableIndex index =
IndexBuilder.create()
.tmpDir(newTempFolder())
.segmentWriteOutMediumFactory(OffHeapMemorySegmentWriteOutMediumFactory.instance())
.schema(
new IncrementalIndexSchema.Builder()
.withMetrics(
new CountAggregatorFactory("cnt")
)
.withDimensionsSpec(ALL_JSON_COLUMNS.getDimensionsSpec())
.withRollup(false)
.build()
)
.rows(ROWS)
.buildMMappedIndex();
final QueryableIndex indexMix11 =
IndexBuilder.create()
.tmpDir(newTempFolder())
.segmentWriteOutMediumFactory(OffHeapMemorySegmentWriteOutMediumFactory.instance())
.schema(
new IncrementalIndexSchema.Builder()
.withMetrics(
new CountAggregatorFactory("cnt")
)
.withDimensionsSpec(ALL_JSON_COLUMNS.getDimensionsSpec())
.withRollup(false)
.build()
)
.rows(ROWS)
.buildMMappedIndex();
final QueryableIndex indexMix12 =
IndexBuilder.create()
.tmpDir(newTempFolder())
.segmentWriteOutMediumFactory(OffHeapMemorySegmentWriteOutMediumFactory.instance())
.schema(
new IncrementalIndexSchema.Builder()
.withMetrics(
new CountAggregatorFactory("cnt")
)
.withDimensionsSpec(JSON_AND_SCALAR_MIX.getDimensionsSpec())
.withRollup(false)
.build()
)
.rows(ROWS_MIX)
.buildMMappedIndex();
final QueryableIndex indexMix21 =
IndexBuilder.create()
.tmpDir(newTempFolder())
.segmentWriteOutMediumFactory(OffHeapMemorySegmentWriteOutMediumFactory.instance())
.schema(
new IncrementalIndexSchema.Builder()
.withMetrics(
new CountAggregatorFactory("cnt")
)
.withDimensionsSpec(JSON_AND_SCALAR_MIX.getDimensionsSpec())
.withRollup(false)
.build()
)
.rows(ROWS_MIX)
.buildMMappedIndex();
final QueryableIndex indexMix22 =
IndexBuilder.create()
.tmpDir(newTempFolder())
.segmentWriteOutMediumFactory(OffHeapMemorySegmentWriteOutMediumFactory.instance())
.schema(
new IncrementalIndexSchema.Builder()
.withMetrics(
new CountAggregatorFactory("cnt")
)
.withDimensionsSpec(ALL_JSON_COLUMNS.getDimensionsSpec())
.withRollup(false)
.build()
)
.rows(ROWS)
.buildMMappedIndex();
final QueryableIndex indexArrays =
IndexBuilder.create()
.tmpDir(newTempFolder())
.segmentWriteOutMediumFactory(OffHeapMemorySegmentWriteOutMediumFactory.instance())
.schema(
new IncrementalIndexSchema.Builder()
.withTimestampSpec(NestedDataTestUtils.AUTO_SCHEMA.getTimestampSpec())
.withDimensionsSpec(NestedDataTestUtils.AUTO_SCHEMA.getDimensionsSpec())
.withMetrics(
new CountAggregatorFactory("cnt")
)
.withRollup(false)
.build()
)
.inputSource(
ResourceInputSource.of(
NestedDataTestUtils.class.getClassLoader(),
NestedDataTestUtils.ARRAY_TYPES_DATA_FILE
)
)
.inputFormat(TestDataBuilder.DEFAULT_JSON_INPUT_FORMAT)
.inputTmpDir(newTempFolder())
.buildMMappedIndex();
final QueryableIndex indexAllTypesAuto =
IndexBuilder.create()
.tmpDir(newTempFolder())
.segmentWriteOutMediumFactory(OffHeapMemorySegmentWriteOutMediumFactory.instance())
.schema(
new IncrementalIndexSchema.Builder()
.withTimestampSpec(NestedDataTestUtils.AUTO_SCHEMA.getTimestampSpec())
.withDimensionsSpec(NestedDataTestUtils.AUTO_SCHEMA.getDimensionsSpec())
.withMetrics(
new CountAggregatorFactory("cnt")
)
.withRollup(false)
.build()
)
.inputSource(
ResourceInputSource.of(
NestedDataTestUtils.class.getClassLoader(),
NestedDataTestUtils.ALL_TYPES_TEST_DATA_FILE
)
)
.inputFormat(TestDataBuilder.DEFAULT_JSON_INPUT_FORMAT)
.inputTmpDir(newTempFolder())
.buildMMappedIndex();
SpecificSegmentsQuerySegmentWalker walker = SpecificSegmentsQuerySegmentWalker.createWalker(injector, conglomerate);
walker.add(
DataSegment.builder()
.dataSource(DATA_SOURCE)
.interval(index.getDataInterval())
.version("1")
.shardSpec(new LinearShardSpec(0))
.size(0)
.build(),
index
).add(
DataSegment.builder()
.dataSource(DATA_SOURCE_MIXED)
.interval(indexMix11.getDataInterval())
.version("1")
.shardSpec(new LinearShardSpec(0))
.size(0)
.build(),
indexMix11
).add(
DataSegment.builder()
.dataSource(DATA_SOURCE_MIXED)
.interval(indexMix12.getDataInterval())
.version("1")
.shardSpec(new LinearShardSpec(1))
.size(0)
.build(),
indexMix12
).add(
DataSegment.builder()
.dataSource(DATA_SOURCE_MIXED_2)
.interval(indexMix21.getDataInterval())
.version("1")
.shardSpec(new LinearShardSpec(0))
.size(0)
.build(),
indexMix21
).add(
DataSegment.builder()
.dataSource(DATA_SOURCE_MIXED_2)
.interval(index.getDataInterval())
.version("1")
.shardSpec(new LinearShardSpec(1))
.size(0)
.build(),
indexMix22
).add(
DataSegment.builder()
.dataSource(DATA_SOURCE_ARRAYS)
.version("1")
.interval(indexArrays.getDataInterval())
.shardSpec(new LinearShardSpec(1))
.size(0)
.build(),
indexArrays
).add(
DataSegment.builder()
.dataSource(DATA_SOURCE_ALL)
.version("1")
.interval(indexAllTypesAuto.getDataInterval())
.shardSpec(new LinearShardSpec(1))
.size(0)
.build(),
indexAllTypesAuto
);
return walker;
}
@Test
public void testGroupByPath()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupJsonValueAny()
{
testQuery(
"SELECT "
+ "JSON_VALUE_ANY(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", null)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByJsonValue()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testTopNPath()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1 LIMIT 10",
ImmutableList.of(
new TopNQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.dimension(
new DefaultDimensionSpec("v0", "d0")
)
.aggregators(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.metric(new DimensionTopNMetricSpec(null, StringComparators.LEXICOGRAPHIC))
.threshold(10)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByOnNestedColumn()
{
cannotVectorize();
testQuery(
"SELECT nester, SUM(strlen(string)) FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn("v0", "strlen(\"string\")", ColumnType.LONG, queryFramework().macroTable())
)
.setDimensions(dimensions(new DefaultDimensionSpec("nester", "d0", ColumnType.NESTED_DATA)))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 9L},
new Object[]{"\"hello\"", 3L},
new Object[]{"2", 3L},
new Object[]{"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":\"hello\"}}", 3L},
new Object[]{"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":1}}", 3L}
)
);
}
@Test
public void testGroupByOnNestedColumnWithOrderBy()
{
cannotVectorize();
testQuery(
"SELECT nester, SUM(strlen(string)) FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn("v0", "strlen(\"string\")", ColumnType.LONG, queryFramework().macroTable())
)
.setDimensions(dimensions(new DefaultDimensionSpec("nester", "d0", ColumnType.NESTED_DATA)))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 9L},
new Object[]{"\"hello\"", 3L},
new Object[]{"2", 3L},
new Object[]{"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":\"hello\"}}", 3L},
new Object[]{"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":1}}", 3L}
)
);
}
@Test
public void testGroupByOnNestedColumnWithOrderByAndLimit()
{
cannotVectorize();
testQuery(
"SELECT nester, SUM(strlen(string)) FROM druid.nested GROUP BY 1 ORDER BY 1 LIMIT 100",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"strlen(\"string\")",
ColumnType.LONG,
queryFramework().macroTable()
)
)
.setDimensions(dimensions(new DefaultDimensionSpec("nester", "d0", ColumnType.NESTED_DATA)))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.setLimitSpec(new DefaultLimitSpec(
ImmutableList.of(new OrderByColumnSpec(
"d0",
OrderByColumnSpec.Direction.ASCENDING,
StringComparators.NATURAL
)),
100
))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 9L},
new Object[]{"\"hello\"", 3L},
new Object[]{"2", 3L},
new Object[]{"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":\"hello\"}}", 3L},
new Object[]{"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":1}}", 3L}
)
);
}
@Test
public void testGroupByOnNestedColumnWithOrderByAndLimit2()
{
cannotVectorize();
testQuery(
"SELECT nester, SUM(strlen(string)) FROM druid.nested GROUP BY 1 ORDER BY 1 LIMIT 2",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"strlen(\"string\")",
ColumnType.LONG,
queryFramework().macroTable()
)
)
.setDimensions(dimensions(new DefaultDimensionSpec("nester", "d0", ColumnType.NESTED_DATA)))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.setLimitSpec(new DefaultLimitSpec(
ImmutableList.of(new OrderByColumnSpec(
"d0",
OrderByColumnSpec.Direction.ASCENDING,
StringComparators.NATURAL
)),
2
))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 9L},
new Object[]{"\"hello\"", 3L}
)
);
}
@Test
public void testGroupByOnNestedColumnWithLimit()
{
cannotVectorize();
testQuery(
"SELECT nester, SUM(strlen(string)) FROM druid.nested GROUP BY 1 LIMIT 100",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"strlen(\"string\")",
ColumnType.LONG,
queryFramework().macroTable()
)
)
.setDimensions(dimensions(new DefaultDimensionSpec("nester", "d0", ColumnType.NESTED_DATA)))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.setLimitSpec(new DefaultLimitSpec(null, 100))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 9L},
new Object[]{"\"hello\"", 3L},
new Object[]{"2", 3L},
new Object[]{"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":\"hello\"}}", 3L},
new Object[]{"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":1}}", 3L}
)
);
}
@Test
public void testGroupByOnNestedColumnWithLimit2()
{
cannotVectorize();
testQuery(
"SELECT nester, SUM(strlen(string)) FROM druid.nested GROUP BY 1 LIMIT 2",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"strlen(\"string\")",
ColumnType.LONG,
queryFramework().macroTable()
)
)
.setDimensions(dimensions(new DefaultDimensionSpec("nester", "d0", ColumnType.NESTED_DATA)))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.setLimitSpec(new DefaultLimitSpec(null, 2))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 9L},
new Object[]{"\"hello\"", 3L}
)
);
}
@Test
public void testGroupByRootPath()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nester, '$'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nester", "$.", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 5L},
new Object[]{"2", 1L},
new Object[]{"hello", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeLong()
{
testQuery(
"SELECT "
+ "long, "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("long", "d0", ColumnType.LONG)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{1L, 1L},
new Object[]{2L, 2L},
new Object[]{3L, 1L},
new Object[]{4L, 1L},
new Object[]{5L, 2L}
),
RowSignature.builder()
.add("long", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeString()
{
testQuery(
"SELECT "
+ "string, "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("string", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"aaa", 2L},
new Object[]{"bbb", 1L},
new Object[]{"ccc", 1L},
new Object[]{"ddd", 2L},
new Object[]{"eee", 1L}
),
RowSignature.builder()
.add("string", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeLongMixed1()
{
testQuery(
"SELECT "
+ "long, "
+ "SUM(cnt) "
+ "FROM druid.nested_mix GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("long", "d0", ColumnType.LONG)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{1L, 2L},
new Object[]{2L, 4L},
new Object[]{3L, 2L},
new Object[]{4L, 2L},
new Object[]{5L, 4L}
),
RowSignature.builder()
.add("long", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeStringMixed1()
{
testQuery(
"SELECT "
+ "string, "
+ "SUM(cnt) "
+ "FROM druid.nested_mix GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("string", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"aaa", 4L},
new Object[]{"bbb", 2L},
new Object[]{"ccc", 2L},
new Object[]{"ddd", 4L},
new Object[]{"eee", 2L}
),
RowSignature.builder()
.add("string", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeStringMixed1Sparse()
{
testQuery(
"SELECT "
+ "string_sparse, "
+ "SUM(cnt) "
+ "FROM druid.nested_mix GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("string_sparse", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 8L},
new Object[]{"10", 2L},
new Object[]{"yyy", 2L},
new Object[]{"zzz", 2L}
),
RowSignature.builder()
.add("string_sparse", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeLongMixed2()
{
testQuery(
"SELECT "
+ "long, "
+ "SUM(cnt) "
+ "FROM druid.nested_mix_2 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED_2)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("long", "d0", ColumnType.LONG)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{1L, 2L},
new Object[]{2L, 4L},
new Object[]{3L, 2L},
new Object[]{4L, 2L},
new Object[]{5L, 4L}
),
RowSignature.builder()
.add("long", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeStringMixed2()
{
testQuery(
"SELECT "
+ "string, "
+ "SUM(cnt) "
+ "FROM druid.nested_mix_2 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED_2)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("string", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"aaa", 4L},
new Object[]{"bbb", 2L},
new Object[]{"ccc", 2L},
new Object[]{"ddd", 4L},
new Object[]{"eee", 2L}
),
RowSignature.builder()
.add("string", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeStringMixed2Sparse()
{
testQuery(
"SELECT "
+ "string_sparse, "
+ "SUM(cnt) "
+ "FROM druid.nested_mix_2 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED_2)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("string_sparse", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 8L},
new Object[]{"10", 2L},
new Object[]{"yyy", 2L},
new Object[]{"zzz", 2L}
),
RowSignature.builder()
.add("string_sparse", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeStringMixed2SparseJsonValueNonExistentPath()
{
testQuery(
"SELECT "
+ "JSON_VALUE(string_sparse, '$[1]'), "
+ "SUM(cnt) "
+ "FROM druid.nested_mix_2 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED_2)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setVirtualColumns(
new NestedFieldVirtualColumn("string_sparse", "$[1]", "v0", ColumnType.STRING)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 14L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testJsonValueArrays()
{
testBuilder()
.sql(
"SELECT "
+ "JSON_VALUE(arrayString, '$' RETURNING VARCHAR ARRAY), "
+ "JSON_VALUE(arrayLong, '$' RETURNING BIGINT ARRAY), "
+ "JSON_VALUE(arrayDouble, '$' RETURNING DOUBLE ARRAY), "
+ "JSON_VALUE(arrayNestedLong, '$[0]' RETURNING BIGINT ARRAY) "
+ "FROM druid.arrays"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE_ARRAYS)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
new NestedFieldVirtualColumn("arrayString", "$", "v0", ColumnType.STRING_ARRAY),
new NestedFieldVirtualColumn("arrayLong", "$", "v1", ColumnType.LONG_ARRAY),
new NestedFieldVirtualColumn("arrayDouble", "$", "v2", ColumnType.DOUBLE_ARRAY),
new NestedFieldVirtualColumn("arrayNestedLong", "$[0]", "v3", ColumnType.LONG_ARRAY)
)
.columns("v0", "v1", "v2", "v3")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{null, Arrays.asList(1L, 2L, 3L), Arrays.asList(1.1D, 2.2D, 3.3D), null},
new Object[]{null, null, null, null},
new Object[]{
Arrays.asList("d", "e"),
Arrays.asList(1L, 4L),
Arrays.asList(2.2D, 3.3D, 4.0D),
Arrays.asList(1L, 2L)
},
new Object[]{Arrays.asList("a", "b"), null, null, Collections.singletonList(1L)},
new Object[]{
Arrays.asList("a", "b"),
Arrays.asList(1L, 2L, 3L),
Arrays.asList(1.1D, 2.2D, 3.3D),
Arrays.asList(1L, 2L, null)
},
new Object[]{
Arrays.asList("b", "c"),
Arrays.asList(1L, 2L, 3L, 4L),
Arrays.asList(1.1D, 3.3D),
Collections.singletonList(1L)
},
new Object[]{
Arrays.asList("a", "b", "c"),
Arrays.asList(2L, 3L),
Arrays.asList(3.3D, 4.4D, 5.5D),
null
},
new Object[]{null, Arrays.asList(1L, 2L, 3L), Arrays.asList(1.1D, 2.2D, 3.3D), null},
new Object[]{null, null, null, null},
new Object[]{
Arrays.asList("d", "e"),
Arrays.asList(1L, 4L),
Arrays.asList(2.2D, 3.3D, 4.0D),
Arrays.asList(1L, 2L)
},
new Object[]{Arrays.asList("a", "b"), null, null, null},
new Object[]{
Arrays.asList("a", "b"),
Arrays.asList(1L, 2L, 3L),
Arrays.asList(1.1D, 2.2D, 3.3D),
Arrays.asList(2L, 3L)
},
new Object[]{
Arrays.asList("b", "c"),
Arrays.asList(1L, 2L, 3L, 4L),
Arrays.asList(1.1D, 3.3D),
Collections.singletonList(1L)
},
new Object[]{Arrays.asList("a", "b", "c"), Arrays.asList(2L, 3L), Arrays.asList(3.3D, 4.4D, 5.5D), null}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.LONG_ARRAY)
.add("EXPR$2", ColumnType.DOUBLE_ARRAY)
.add("EXPR$3", ColumnType.LONG_ARRAY)
.build()
)
.run();
}
@Test
public void testUnnestRootSingleTypeArrayLongNulls()
{
testBuilder()
.sql("SELECT longs FROM druid.arrays, UNNEST(arrayLongNulls) as u(longs)")
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(
UnnestDataSource.create(
TableDataSource.create(DATA_SOURCE_ARRAYS),
expressionVirtualColumn("j0.unnest", "\"arrayLongNulls\"", ColumnType.LONG_ARRAY),
null
)
)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("j0.unnest")
.context(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.legacy(false)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{2L},
new Object[]{3L},
new Object[]{1L},
new Object[]{null},
new Object[]{2L},
new Object[]{9L},
new Object[]{1L},
new Object[]{null},
new Object[]{3L},
new Object[]{1L},
new Object[]{2L},
new Object[]{3L},
new Object[]{2L},
new Object[]{3L},
new Object[]{null},
new Object[]{null},
new Object[]{2L},
new Object[]{9L},
new Object[]{1L},
new Object[]{null},
new Object[]{3L},
new Object[]{1L},
new Object[]{2L},
new Object[]{3L}
)
)
.expectedSignature(
RowSignature.builder()
.add("longs", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testUnnestRootSingleTypeArrayStringNulls()
{
cannotVectorize();
testBuilder()
.sql("SELECT strings FROM druid.arrays, UNNEST(arrayStringNulls) as u(strings)")
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(
UnnestDataSource.create(
TableDataSource.create(DATA_SOURCE_ARRAYS),
expressionVirtualColumn("j0.unnest", "\"arrayStringNulls\"", ColumnType.STRING_ARRAY),
null
)
)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("j0.unnest")
.context(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.legacy(false)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{"a"},
new Object[]{"b"},
new Object[]{"b"},
new Object[]{"b"},
new Object[]{"a"},
new Object[]{"b"},
new Object[]{"d"},
new Object[]{NullHandling.defaultStringValue()},
new Object[]{"b"},
new Object[]{NullHandling.defaultStringValue()},
new Object[]{"b"},
new Object[]{"a"},
new Object[]{"b"},
new Object[]{"b"},
new Object[]{"b"},
new Object[]{NullHandling.defaultStringValue()},
new Object[]{"d"},
new Object[]{NullHandling.defaultStringValue()},
new Object[]{"b"},
new Object[]{NullHandling.defaultStringValue()},
new Object[]{"b"}
)
)
.expectedSignature(
RowSignature.builder()
.add("strings", ColumnType.STRING)
.build()
)
.run();
}
@Test
public void testUnnestRootSingleTypeArrayDoubleNulls()
{
cannotVectorize();
testBuilder()
.sql("SELECT doubles FROM druid.arrays, UNNEST(arrayDoubleNulls) as u(doubles)")
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(
UnnestDataSource.create(
TableDataSource.create(DATA_SOURCE_ARRAYS),
expressionVirtualColumn("j0.unnest", "\"arrayDoubleNulls\"", ColumnType.DOUBLE_ARRAY),
null
)
)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("j0.unnest")
.context(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.legacy(false)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{null},
new Object[]{999.0D},
new Object[]{5.5D},
new Object[]{null},
new Object[]{1.1D},
new Object[]{2.2D},
new Object[]{null},
new Object[]{null},
new Object[]{2.2D},
new Object[]{null},
new Object[]{999.0D},
new Object[]{null},
new Object[]{5.5D},
new Object[]{null},
new Object[]{1.1D},
new Object[]{999.0D},
new Object[]{5.5D},
new Object[]{null},
new Object[]{1.1D},
new Object[]{2.2D},
new Object[]{null},
new Object[]{null},
new Object[]{2.2D},
new Object[]{null},
new Object[]{999.0D},
new Object[]{null},
new Object[]{5.5D}
)
)
.expectedSignature(
RowSignature.builder()
.add("doubles", ColumnType.DOUBLE)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLong()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayLong, "
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayLong", "d0", ColumnType.LONG_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{null, 4L},
new Object[]{Arrays.asList(1L, 2L, 3L), 4L},
new Object[]{Arrays.asList(1L, 2L, 3L, 4L), 2L},
new Object[]{Arrays.asList(1L, 4L), 2L},
new Object[]{Arrays.asList(2L, 3L), 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayLong", ColumnType.LONG_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLongFilteredArrayEquality()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayLong, "
+ "SUM(cnt) "
+ "FROM druid.arrays WHERE arrayLong = ARRAY[1, 2, 3] GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY_USE_EQUALITY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimFilter(
// don't use static functions since context flag indicates to always use equality filter
new EqualityFilter(
"arrayLong",
ColumnType.LONG_ARRAY,
new Object[]{1L, 2L, 3L},
null
)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayLong", "d0", ColumnType.LONG_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY_USE_EQUALITY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{Arrays.asList(1L, 2L, 3L), 4L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayLong", ColumnType.LONG_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLongNulls()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayLongNulls, "
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayLongNulls", "d0", ColumnType.LONG_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{null, 3L},
new Object[]{Collections.emptyList(), 1L},
new Object[]{Collections.singletonList(null), 1L},
new Object[]{Arrays.asList(null, 2L, 9L), 2L},
new Object[]{Collections.singletonList(1L), 1L},
new Object[]{Arrays.asList(1L, null, 3L), 2L},
new Object[]{Arrays.asList(1L, 2L, 3L), 2L},
new Object[]{Arrays.asList(2L, 3L), 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayLongNulls", ColumnType.LONG_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeLongJsonValueFilter()
{
testQuery(
"SELECT "
+ "long, "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(long, '$.') = '1' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("long", "d0", ColumnType.LONG)
)
)
.setVirtualColumns(
new NestedFieldVirtualColumn(
"long",
"v0",
ColumnType.STRING,
Collections.emptyList(),
false,
null,
false
)
)
.setDimFilter(
equality("v0", "1", ColumnType.STRING)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{1L, 1L}
),
RowSignature.builder()
.add("long", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeArrayLongNullsFilteredArrayEquality()
{
if (NullHandling.replaceWithDefault()) {
// this fails in default value mode because it relies on equality filter and null filter to behave correctly
return;
}
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayLongNulls, "
+ "SUM(cnt) "
+ "FROM druid.arrays WHERE arrayLongNulls = ARRAY[null, 2, 9] OR arrayLongNulls IS NULL GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimFilter(
or(
isNull("arrayLongNulls"),
equality("arrayLongNulls", new Object[]{null, 2L, 9L}, ColumnType.LONG_ARRAY)
)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayLongNulls", "d0", ColumnType.LONG_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{null, 3L},
new Object[]{Arrays.asList(null, 2L, 9L), 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayLongNulls", ColumnType.LONG_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLongNullsUnnest()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "longs, "
+ "SUM(cnt) "
+ "FROM druid.arrays, UNNEST(arrayLongNulls) as u (longs) GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(
UnnestDataSource.create(
TableDataSource.create(DATA_SOURCE_ARRAYS),
expressionVirtualColumn("j0.unnest", "\"arrayLongNulls\"", ColumnType.LONG_ARRAY),
null
)
)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("j0.unnest", "d0", ColumnType.LONG)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{NullHandling.defaultLongValue(), 5L},
new Object[]{1L, 5L},
new Object[]{2L, 6L},
new Object[]{3L, 6L},
new Object[]{9L, 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("longs", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLongNullsFiltered()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayLongNulls, "
+ "SUM(cnt), "
+ "SUM(ARRAY_LENGTH(arrayLongNulls)) "
+ "FROM druid.arrays "
+ "WHERE ARRAY_CONTAINS(arrayLongNulls, 1) "
+ "GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayLongNulls", "d0", ColumnType.LONG_ARRAY)
)
)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"array_length(\"arrayLongNulls\")",
ColumnType.LONG,
queryFramework().macroTable()
)
)
.setDimFilter(
new ArrayContainsElementFilter("arrayLongNulls", ColumnType.LONG, 1, null)
)
.setAggregatorSpecs(
aggregators(
new LongSumAggregatorFactory("a0", "cnt"),
new LongSumAggregatorFactory("a1", "v0")
)
)
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{Collections.singletonList(1L), 1L, 1L},
new Object[]{Arrays.asList(1L, null, 3L), 2L, 6L},
new Object[]{Arrays.asList(1L, 2L, 3L), 2L, 6L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayLongNulls", ColumnType.LONG_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.add("EXPR$2", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLongNullsFilteredMore()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayLongNulls, "
+ "SUM(cnt) "
+ "FROM druid.arrays WHERE ARRAY_CONTAINS(arrayLongNulls, 1) OR ARRAY_OVERLAP(arrayLongNulls, ARRAY[2, 3]) GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayLongNulls", "d0", ColumnType.LONG_ARRAY)
)
)
.setDimFilter(
or(
new ArrayContainsElementFilter("arrayLongNulls", ColumnType.LONG, 1L, null),
new ArrayContainsElementFilter("arrayLongNulls", ColumnType.LONG, 2L, null),
new ArrayContainsElementFilter("arrayLongNulls", ColumnType.LONG, 3L, null)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{Arrays.asList(null, 2L, 9L), 2L},
new Object[]{Collections.singletonList(1L), 1L},
new Object[]{Arrays.asList(1L, null, 3L), 2L},
new Object[]{Arrays.asList(1L, 2L, 3L), 2L},
new Object[]{Arrays.asList(2L, 3L), 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayLongNulls", ColumnType.LONG_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayString()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayString, "
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayString", "d0", ColumnType.STRING_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{null, 4L},
new Object[]{Arrays.asList("a", "b"), 4L},
new Object[]{Arrays.asList("a", "b", "c"), 2L},
new Object[]{Arrays.asList("b", "c"), 2L},
new Object[]{Arrays.asList("d", "e"), 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayString", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayStringNulls()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayStringNulls, "
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayStringNulls", "d0", ColumnType.STRING_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{null, 3L},
new Object[]{Collections.emptyList(), 1L},
new Object[]{Collections.singletonList(null), 1L},
new Object[]{Arrays.asList(null, "b"), 2L},
new Object[]{Arrays.asList("a", "b"), 3L},
new Object[]{Arrays.asList("b", "b"), 2L},
new Object[]{Arrays.asList("d", null, "b"), 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayStringNulls", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayStringNullsUnnest()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "strings, "
+ "SUM(cnt) "
+ "FROM druid.arrays, unnest(arrayStringNulls) as u (strings) GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(
UnnestDataSource.create(
TableDataSource.create(DATA_SOURCE_ARRAYS),
expressionVirtualColumn(
"j0.unnest",
"\"arrayStringNulls\"",
ColumnType.STRING_ARRAY
),
null
)
)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("j0.unnest", "d0", ColumnType.STRING)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 5L},
new Object[]{"a", 3L},
new Object[]{"b", 11L},
new Object[]{"d", 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("strings", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayStringNullsFiltered()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayStringNulls, "
+ "SUM(cnt), "
+ "SUM(ARRAY_LENGTH(arrayStringNulls)) "
+ "FROM druid.arrays "
+ "WHERE ARRAY_CONTAINS(arrayStringNulls, 'b') "
+ "GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayStringNulls", "d0", ColumnType.STRING_ARRAY)
)
)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"array_length(\"arrayStringNulls\")",
ColumnType.LONG,
queryFramework().macroTable()
)
)
.setDimFilter(
new ArrayContainsElementFilter("arrayStringNulls", ColumnType.STRING, "b", null)
)
.setAggregatorSpecs(
aggregators(
new LongSumAggregatorFactory("a0", "cnt"),
new LongSumAggregatorFactory("a1", "v0")
)
)
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{Arrays.asList(null, "b"), 2L, 4L},
new Object[]{Arrays.asList("a", "b"), 3L, 6L},
new Object[]{Arrays.asList("b", "b"), 2L, 4L},
new Object[]{Arrays.asList("d", null, "b"), 2L, 6L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayStringNulls", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.add("EXPR$2", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayDouble()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayDouble, "
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayDouble", "d0", ColumnType.DOUBLE_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{null, 4L},
new Object[]{Arrays.asList(1.1, 2.2, 3.3), 4L},
new Object[]{Arrays.asList(1.1, 3.3), 2L},
new Object[]{Arrays.asList(2.2, 3.3, 4.0), 2L},
new Object[]{Arrays.asList(3.3, 4.4, 5.5), 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayDouble", ColumnType.DOUBLE_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayDoubleNulls()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayDoubleNulls, "
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayDoubleNulls", "d0", ColumnType.DOUBLE_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{null, 3L},
new Object[]{Collections.emptyList(), 1L},
new Object[]{Collections.singletonList(null), 1L},
new Object[]{Arrays.asList(null, 1.1), 1L},
new Object[]{Arrays.asList(null, 2.2, null), 2L},
new Object[]{Arrays.asList(1.1, 2.2, null), 2L},
new Object[]{Arrays.asList(999.0, null, 5.5), 2L},
new Object[]{Arrays.asList(999.0, 5.5, null), 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayDoubleNulls", ColumnType.DOUBLE_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayDoubleNullsUnnest()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "doubles, "
+ "SUM(cnt) "
+ "FROM druid.arrays, UNNEST(arrayDoubleNulls) as u (doubles) GROUP BY doubles"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(
UnnestDataSource.create(
TableDataSource.create(DATA_SOURCE_ARRAYS),
expressionVirtualColumn(
"j0.unnest",
"\"arrayDoubleNulls\"",
ColumnType.DOUBLE_ARRAY
),
null
)
)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("j0.unnest", "d0", ColumnType.DOUBLE)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{NullHandling.defaultDoubleValue(), 12L},
new Object[]{1.1D, 3L},
new Object[]{2.2D, 4L},
new Object[]{5.5D, 4L},
new Object[]{999.0D, 4L}
)
)
.expectedSignature(
RowSignature.builder()
.add("doubles", ColumnType.DOUBLE)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayDoubleNullsFiltered()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "arrayDoubleNulls, "
+ "SUM(cnt), "
+ "SUM(ARRAY_LENGTH(arrayDoubleNulls)) "
+ "FROM druid.arrays "
+ "WHERE ARRAY_CONTAINS(arrayDoubleNulls, 2.2)"
+ "GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("arrayDoubleNulls", "d0", ColumnType.DOUBLE_ARRAY)
)
)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"array_length(\"arrayDoubleNulls\")",
ColumnType.LONG,
queryFramework().macroTable()
)
)
.setDimFilter(
new ArrayContainsElementFilter("arrayDoubleNulls", ColumnType.DOUBLE, 2.2, null)
)
.setAggregatorSpecs(
aggregators(
new LongSumAggregatorFactory("a0", "cnt"),
new LongSumAggregatorFactory("a1", "v0")
)
)
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{Arrays.asList(null, 2.2, null), 2L, 6L},
new Object[]{Arrays.asList(1.1, 2.2, null), 2L, 6L}
)
)
.expectedSignature(
RowSignature.builder()
.add("arrayDoubleNulls", ColumnType.DOUBLE_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.add("EXPR$2", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLongElement()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "JSON_VALUE(arrayLong, '$[1]' RETURNING BIGINT),"
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.LONG)
)
)
.setVirtualColumns(
new NestedFieldVirtualColumn("arrayLong", "$[1]", "v0", ColumnType.LONG)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{NullHandling.defaultLongValue(), 4L},
new Object[]{2L, 6L},
new Object[]{3L, 2L},
new Object[]{4L, 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLongElementFiltered()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "JSON_VALUE(arrayLong, '$[1]' RETURNING BIGINT),"
+ "SUM(cnt) "
+ "FROM druid.arrays "
+ "WHERE JSON_VALUE(arrayLong, '$[1]' RETURNING BIGINT) = 2"
+ "GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.LONG)
)
)
.setVirtualColumns(
new NestedFieldVirtualColumn("arrayLong", "$[1]", "v0", ColumnType.LONG)
)
.setDimFilter(equality("v0", 2L, ColumnType.LONG))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{2L, 6L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLongElementDefault()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "JSON_VALUE(arrayLong, '$[1]'),"
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setVirtualColumns(
new NestedFieldVirtualColumn("arrayLong", "$[1]", "v0", ColumnType.STRING)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"2", 6L},
new Object[]{"3", 2L},
new Object[]{"4", 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayStringElement()
{
testBuilder()
.sql(
"SELECT "
+ "JSON_VALUE(arrayStringNulls, '$[1]'),"
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setVirtualColumns(
new NestedFieldVirtualColumn("arrayStringNulls", "$[1]", "v0", ColumnType.STRING)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 7L},
new Object[]{"b", 7L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayStringElementFiltered()
{
testBuilder()
.sql(
"SELECT "
+ "JSON_VALUE(arrayStringNulls, '$[1]'),"
+ "SUM(cnt) "
+ "FROM druid.arrays "
+ "WHERE JSON_VALUE(arrayStringNulls, '$[1]') = 'b'"
+ "GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setVirtualColumns(
new NestedFieldVirtualColumn("arrayStringNulls", "$[1]", "v0", ColumnType.STRING)
)
.setDimFilter(equality("v0", "b", ColumnType.STRING))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{"b", 7L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayDoubleElement()
{
testBuilder()
.sql(
"SELECT "
+ "JSON_VALUE(arrayDoubleNulls, '$[2]' RETURNING DOUBLE),"
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.DOUBLE)
)
)
.setVirtualColumns(
new NestedFieldVirtualColumn("arrayDoubleNulls", "$[2]", "v0", ColumnType.DOUBLE)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ResultMatchMode.RELAX_NULLS,
ImmutableList.of(
new Object[]{null, 12L},
new Object[]{5.5, 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayDoubleElementFiltered()
{
testBuilder()
.sql(
"SELECT "
+ "JSON_VALUE(arrayDoubleNulls, '$[2]' RETURNING DOUBLE),"
+ "SUM(cnt) "
+ "FROM druid.arrays "
+ "WHERE JSON_VALUE(arrayDoubleNulls, '$[2]' RETURNING DOUBLE) = 5.5"
+ "GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY_USE_EQUALITY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.DOUBLE)
)
)
.setDimFilter(
// dont use static function since context flag indicates to always use equality
new EqualityFilter("v0", ColumnType.DOUBLE, 5.5, null)
)
.setVirtualColumns(
new NestedFieldVirtualColumn("arrayDoubleNulls", "$[2]", "v0", ColumnType.DOUBLE)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY_USE_EQUALITY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{5.5, 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByJsonValues()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "JSON_VALUE(nest, '$[''x'']'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1, 2",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0"),
new DefaultDimensionSpec("v0", "d1")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), NullHandling.defaultStringValue(), 4L},
new Object[]{"100", "100", 2L},
new Object[]{"200", "200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.STRING)
.add("EXPR$2", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilter()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') = '100' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(equality("v0", "100", ColumnType.STRING))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{
"100",
2L
}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterCoalesce()
{
cannotVectorize();
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE COALESCE(JSON_VALUE(nest, '$.x'), '0') = '100' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(
expressionFilter(
"case_searched(notnull(json_value(\"nest\",'$.x', 'STRING')),(json_value(\"nest\",'$.x', 'STRING') == '100'),0)"
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{
"100",
2L
}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testJsonAndArrayAgg()
{
cannotVectorize();
testQuery(
"SELECT "
+ "string, "
+ "ARRAY_AGG(nest, 16384), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("string", "d0")
)
)
.setAggregatorSpecs(
aggregators(
new ExpressionLambdaAggregatorFactory(
"a0",
ImmutableSet.of("nest"),
"__acc",
"ARRAY<COMPLEX<json>>[]",
"ARRAY<COMPLEX<json>>[]",
true,
true,
false,
"array_append(\"__acc\", \"nest\")",
"array_concat(\"__acc\", \"a0\")",
null,
null,
HumanReadableBytes.valueOf(16384),
queryFramework().macroTable()
),
new LongSumAggregatorFactory("a1", "cnt")
)
)
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{
"aaa",
"[{\"x\":100,\"y\":2.02,\"z\":\"300\",\"mixed\":1,\"mixed2\":\"1\"},{\"x\":100,\"y\":2.02,\"z\":\"400\",\"mixed2\":1.1}]",
2L
},
new Object[]{
"bbb",
"[null]",
1L
},
new Object[]{
"ccc",
"[{\"x\":200,\"y\":3.03,\"z\":\"abcdef\",\"mixed\":1.1,\"mixed2\":1}]",
1L
},
new Object[]{
"ddd",
"[null,null]",
2L
},
new Object[]{
"eee",
"[null]",
1L
}
),
RowSignature.builder()
.add("string", ColumnType.STRING)
.add("EXPR$1", ColumnType.ofArray(ColumnType.NESTED_DATA))
.add("EXPR$2", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterLong()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') = 100 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(equality("v0", 100L, ColumnType.LONG))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{
"100",
2L
}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterDouble()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.y') = 2.02 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.y", "v0", ColumnType.DOUBLE),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(equality("v0", 2.02, ColumnType.DOUBLE))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{
"100",
2L
}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterString()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.z') = '400' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(equality("v0", "400", ColumnType.STRING))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{
"100",
1L
}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterVariant()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nester, '$.n.x') = 1 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nester", "$.n.x", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(equality("v0", 1L, ColumnType.LONG))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(new Object[]{"100", 1L}),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterVariant2()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.mixed2') = '1' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.mixed2", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(equality("v0", "1", ColumnType.STRING))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 1L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterVariant2Int()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.mixed2') = 1 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.mixed2", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(equality("v0", 1L, ColumnType.LONG))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
// this is a bit wonky, we get extra matches for numeric 1 matcher because the virtual column is defined
// as long typed, which makes a long processor which will convert the 1.1 to a 1L
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterVariant2Double()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.mixed2') = 1.1 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.mixed2", "v0", ColumnType.DOUBLE),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(equality("v0", 1.1, ColumnType.DOUBLE))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterVariant2BothTypesMatcher()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.mixed2') = '1' OR JSON_VALUE(nest, '$.mixed2') = 1 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.mixed2", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.mixed2", "v1", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v2", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v2", "d0")
)
)
.setDimFilter(
or(
equality("v0", "1", ColumnType.STRING),
equality("v1", 1L, ColumnType.LONG)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
// this is a bit wonky, we get 2 matches for numeric 1 matcher because the virtual column is defined as
// long typed, which makes a long processor which will convert the 1.1 to a 1L
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterVariant3()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.mixed2') in ('1', '1.1') GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.mixed2", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(in("v0", ImmutableList.of("1", "1.1")))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterNonExistent()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.missing') = 'no way' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.missing", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(equality("v0", "no way", ColumnType.STRING))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterNull()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.z') IS NOT NULL GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(notNull("v0"))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterLong()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') >= '100' AND JSON_VALUE(nest, '$.x') <= '300' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(range("v0", ColumnType.STRING, "100", "300", false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterLongNoUpper()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') >= '100' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(range("v0", ColumnType.STRING, "100", null, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterLongNoLower()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') <= '100' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(range("v0", ColumnType.STRING, null, "100", false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterLongNumeric()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') >= 100 AND JSON_VALUE(nest, '$.x') <= 300 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(range("v0", ColumnType.LONG, 100L, 300L, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterLongNoUpperNumeric()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') >= 100 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(range("v0", ColumnType.LONG, 100L, null, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathNumericBoundFilterLongNoUpperNumeric()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x' RETURNING BIGINT),"
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x' RETURNING BIGINT) >= 100 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.LONG)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.LONG)
)
)
.setDimFilter(range("v0", ColumnType.LONG, 100L, null, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{100L, 2L},
new Object[]{200L, 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterLongNoLowerNumeric()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') <= 100 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(range("v0", ColumnType.LONG, null, 100L, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
NullHandling.replaceWithDefault()
? ImmutableList.of(
new Object[]{"", 4L},
new Object[]{"100", 2L}
)
: ImmutableList.of(
new Object[]{"100", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterDouble()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.y'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.y') >= '1.01' AND JSON_VALUE(nest, '$.y') <= '3.03' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.y", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(range("v0", ColumnType.STRING, "1.01", "3.03", false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"2.02", 2L},
new Object[]{"3.03", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterDoubleNoUpper()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.y'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.y') >= '1.01' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.y", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(range("v0", ColumnType.STRING, "1.01", null, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"2.02", 2L},
new Object[]{"3.03", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterDoubleNoLower()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.y'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.y') <= '2.02' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.y", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(range("v0", ColumnType.STRING, null, "2.02", false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"2.02", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundDoubleFilterNumeric()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.y'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.y') >= 2.0 AND JSON_VALUE(nest, '$.y') <= 3.5 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.y", "v0", ColumnType.DOUBLE),
new NestedFieldVirtualColumn("nest", "$.y", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(range("v0", ColumnType.DOUBLE, 2.0, 3.5, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"2.02", 2L},
new Object[]{"3.03", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterDoubleNoUpperNumeric()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.y'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.y') >= 1.0 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.y", "v0", ColumnType.DOUBLE),
new NestedFieldVirtualColumn("nest", "$.y", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(range("v0", ColumnType.DOUBLE, 1.0, null, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"2.02", 2L},
new Object[]{"3.03", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterDoubleNoLowerNumeric()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.y'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.y') <= 2.02 GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.y", "v0", ColumnType.DOUBLE),
new NestedFieldVirtualColumn("nest", "$.y", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(range("v0", ColumnType.DOUBLE, null, 2.02, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
NullHandling.replaceWithDefault()
? ImmutableList.of(
new Object[]{"", 4L},
new Object[]{"2.02", 2L}
)
: ImmutableList.of(
new Object[]{"2.02", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterString()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') >= '100' AND JSON_VALUE(nest, '$.x') <= '300' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(range("v0", ColumnType.STRING, "100", "300", false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterStringNoUpper()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.z') >= '400' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(range("v0", ColumnType.STRING, "400", null, false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 1L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathBoundFilterStringNoLower()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.z') <= '400' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(range("v0", ColumnType.STRING, null, "400", false, false))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
NullHandling.replaceWithDefault()
? ImmutableList.of(
new Object[]{"", 4L},
new Object[]{"100", 2L}
)
: ImmutableList.of(
new Object[]{"100", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathLikeFilter()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') LIKE '10%' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setDimFilter(new LikeDimFilter("v0", "10%", null, null))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathLikeFilterStringPrefix()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.z') LIKE '30%' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(new LikeDimFilter("v0", "30%", null, null))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathLikeFilterString()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.z') LIKE '%00%' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(new LikeDimFilter("v0", "%00%", null, null))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathLikeFilterVariant()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nester, '$.n.x') LIKE '%ell%' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nester", "$.n.x", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(new LikeDimFilter("v0", "%ell%", null, null))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathInFilter()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.x') in (100, 200) GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(
in("v0", ColumnType.LONG, ImmutableList.of(100L, 200L))
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathInFilterDouble()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.y') in (2.02, 3.03) GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.y", "v0", ColumnType.DOUBLE),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(
in("v0", ColumnType.DOUBLE, ImmutableList.of(2.02, 3.03))
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathInFilterString()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nest, '$.z') in ('300', 'abcdef') GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(in("v0", ImmutableSet.of("300", "abcdef")))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 1L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathInFilterVariant()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nester, '$.n.x') in ('hello', 1) GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nester", "$.n.x", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0")
)
)
.setDimFilter(in("v0", ImmutableSet.of("hello", "1")))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testSumPath()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x')) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.DOUBLE))
.aggregators(aggregators(new DoubleSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{400.0}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test
public void testSumPathFilteredAggDouble()
{
// this one actually equals 2.1 because the filter is a long so double is cast and is 1 so both rows match
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x')) FILTER(WHERE((JSON_VALUE(nest, '$.y'))=2.02))"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(
new NestedFieldVirtualColumn("nest", "$.y", "v0", ColumnType.DOUBLE),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.DOUBLE)
)
.aggregators(
aggregators(
new FilteredAggregatorFactory(
new DoubleSumAggregatorFactory("a0", "v1"),
equality("v0", 2.02, ColumnType.DOUBLE)
)
)
)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{200.0}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test
public void testSumPathFilteredAggString()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x')) FILTER(WHERE((JSON_VALUE(nest, '$.z'))='300'))"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(
new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.STRING),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.DOUBLE)
)
.aggregators(
aggregators(
new FilteredAggregatorFactory(
new DoubleSumAggregatorFactory("a0", "v1"),
equality("v0", "300", ColumnType.STRING)
)
)
)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{100.0}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test
public void testSumPathMixed()
{
// throws a "Cannot make vector value selector for variant typed nested field [[LONG, DOUBLE]]"
skipVectorize();
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.mixed')) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.mixed", "v0", ColumnType.DOUBLE))
.aggregators(aggregators(new DoubleSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{2.1}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test
public void testSumPathMixedFilteredAggLong()
{
// throws a "Cannot make vector value selector for variant typed nested field [[LONG, DOUBLE]]"
skipVectorize();
// this one actually equals 2.1 because the filter is a long so double is cast and is 1 so both rows match
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.mixed')) FILTER(WHERE((JSON_VALUE(nest, '$.mixed'))=1))"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(
new NestedFieldVirtualColumn("nest", "$.mixed", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.mixed", "v1", ColumnType.DOUBLE)
)
.aggregators(
aggregators(
new FilteredAggregatorFactory(
new DoubleSumAggregatorFactory("a0", "v1"),
equality("v0", 1L, ColumnType.LONG)
)
)
)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{2.1}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test
public void testSumPathMixedFilteredAggDouble()
{
// throws a "Cannot make vector value selector for variant typed nested field [[LONG, DOUBLE]]"
skipVectorize();
// with double matcher, only the one row matches since the long value cast is not picked up
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.mixed')) FILTER(WHERE((JSON_VALUE(nest, '$.mixed'))=1.1))"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.mixed", "v0", ColumnType.DOUBLE))
.aggregators(
aggregators(
new FilteredAggregatorFactory(
new DoubleSumAggregatorFactory("a0", "v0"),
equality("v0", 1.1, ColumnType.DOUBLE)
)
)
)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{1.1}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test
public void testCastAndSumPath()
{
testQuery(
"SELECT "
+ "SUM(CAST(JSON_VALUE(nest, '$.x') as BIGINT)) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.LONG))
.aggregators(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{400L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.build()
);
}
@Test
public void testCastAndSumPathStrings()
{
testQuery(
"SELECT "
+ "SUM(CAST(JSON_VALUE(nest, '$.z') as BIGINT)) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.LONG))
.aggregators(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{700L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.build()
);
}
@Test
public void testReturningAndSumPath()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x' RETURNING BIGINT)) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.LONG))
.aggregators(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{400L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.build()
);
}
@Test
public void testReturningAndSumPathWithMaths()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x' RETURNING BIGINT) / 100) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(
expressionVirtualColumn("v0", "(\"v1\" / 100)", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.LONG)
)
.aggregators(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{4L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.build()
);
}
@Test
public void testReturningAndSumPathDouble()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x' RETURNING DOUBLE)) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.DOUBLE))
.aggregators(aggregators(new DoubleSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{400.0}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test
public void testReturningAndSumPathDecimal()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x' RETURNING DECIMAL)) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.x", "v0", ColumnType.DOUBLE))
.aggregators(aggregators(new DoubleSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{400.0}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test
public void testReturningAndSumPathDecimalWithMaths()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x' RETURNING DECIMAL) / 100.0) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(
expressionVirtualColumn("v0", "(\"v1\" / 100.0)", ColumnType.DOUBLE),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.DOUBLE)
)
.aggregators(aggregators(new DoubleSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{4.0}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test
public void testReturningAndSumPathStrings()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.z' RETURNING BIGINT)) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.LONG))
.aggregators(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{700L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootKeys()
{
cannotVectorize();
testQuery(
"SELECT "
+ "JSON_KEYS(nester, '$'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"json_keys(\"nester\",'$')",
ColumnType.STRING_ARRAY,
queryFramework().macroTable()
)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 5L},
new Object[]{"[\"array\",\"n\"]", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootKeysJsonPath()
{
cannotVectorize();
testQuery(
"SELECT "
+ "JSON_KEYS(nester, '$.'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"json_keys(\"nester\",'$.')",
ColumnType.STRING_ARRAY,
queryFramework().macroTable()
)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 5L},
new Object[]{"[\"array\",\"n\"]", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootKeys2()
{
cannotVectorize();
testQuery(
"SELECT "
+ "JSON_KEYS(nest, '$'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"json_keys(\"nest\",'$')",
ColumnType.STRING_ARRAY,
queryFramework().macroTable()
)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 4L},
new Object[]{"[\"x\",\"y\",\"z\",\"mixed\",\"mixed2\"]", 2L},
new Object[]{"[\"x\",\"y\",\"z\",\"mixed2\"]", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByCastedRootKeysJsonPath()
{
cannotVectorize();
testQuery(
"SELECT "
+ "JSON_KEYS(nester, CAST('$.' AS VARCHAR)), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"json_keys(\"nester\",'$.')",
ColumnType.STRING_ARRAY,
queryFramework().macroTable()
)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null, 5L},
new Object[]{"[\"array\",\"n\"]", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByAllPaths()
{
cannotVectorize();
testQuery(
"SELECT "
+ "JSON_PATHS(nester), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new ExpressionVirtualColumn(
"v0",
"json_paths(\"nester\")",
ColumnType.STRING_ARRAY,
queryFramework().macroTable()
)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING_ARRAY)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"[\"$\"]", 5L},
new Object[]{"[\"$.array\",\"$.n.x\"]", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByNestedArrayPath()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nester, '$.array[1]'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nester", "$.array[1]", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 5L},
new Object[]{"b", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByInvalidPath()
{
testQueryThrows(
"SELECT "
+ "JSON_VALUE(nester, '.array.[1]'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
DruidExceptionMatcher
.invalidInput()
.expectMessageIs("JSONPath [.array.[1]] is invalid, it must start with '$'")
);
}
@Test
public void testJsonQuery()
{
testQuery(
"SELECT JSON_QUERY(nester, '$.n'), JSON_QUERY(nester, '$')\n"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
new NestedFieldVirtualColumn(
"nester",
"v0",
ColumnType.NESTED_DATA,
null,
true,
"$.n",
false
),
new NestedFieldVirtualColumn(
"nester",
"v1",
ColumnType.NESTED_DATA,
null,
true,
"$.",
false
)
)
.columns("v0", "v1")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{"{\"x\":\"hello\"}", "{\"array\":[\"a\",\"b\"],\"n\":{\"x\":\"hello\"}}"},
new Object[]{null, "\"hello\""},
new Object[]{null, null},
new Object[]{null, null},
new Object[]{null, null},
new Object[]{"{\"x\":1}", "{\"array\":[\"a\",\"b\"],\"n\":{\"x\":1}}"},
new Object[]{null, "2"}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.NESTED_DATA)
.add("EXPR$1", ColumnType.NESTED_DATA)
.build()
);
}
@Test
public void testJsonQueryAndJsonObject()
{
testQuery(
"SELECT JSON_OBJECT(KEY 'n' VALUE JSON_QUERY(nester, '$.n'), KEY 'x' VALUE JSON_VALUE(nest, '$.x'))\n"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
new ExpressionVirtualColumn(
"v0",
"json_object('n',\"v1\",'x',\"v2\")",
ColumnType.NESTED_DATA,
queryFramework().macroTable()
),
new NestedFieldVirtualColumn(
"nester",
"v1",
ColumnType.NESTED_DATA,
null,
true,
"$.n",
false
),
new NestedFieldVirtualColumn("nest", "$.x", "v2", ColumnType.STRING)
)
.columns("v0")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{"{\"x\":\"100\",\"n\":{\"x\":\"hello\"}}"},
new Object[]{"{\"x\":null,\"n\":null}"},
new Object[]{"{\"x\":\"200\",\"n\":null}"},
new Object[]{"{\"x\":null,\"n\":null}"},
new Object[]{"{\"x\":null,\"n\":null}"},
new Object[]{"{\"x\":\"100\",\"n\":{\"x\":1}}"},
new Object[]{"{\"x\":null,\"n\":null}"}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.NESTED_DATA)
.build()
);
}
@Test
public void testCompositionTyping()
{
testQuery(
"SELECT "
+ "JSON_VALUE((JSON_OBJECT(KEY 'x' VALUE JSON_VALUE(nest, '$.x' RETURNING BIGINT))), '$.x' RETURNING BIGINT)\n"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
new ExpressionVirtualColumn(
"v0",
"json_value(json_object('x',\"v1\"),'$.x', 'LONG')",
ColumnType.LONG,
queryFramework().macroTable()
),
new NestedFieldVirtualColumn(
"nest",
"v1",
ColumnType.LONG,
null,
false,
"$.x",
false
)
)
.columns("v0")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{100L},
new Object[]{NullHandling.defaultLongValue()},
new Object[]{200L},
new Object[]{NullHandling.defaultLongValue()},
new Object[]{NullHandling.defaultLongValue()},
new Object[]{100L},
new Object[]{NullHandling.defaultLongValue()}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.build()
);
}
@Test
public void testToJsonAndParseJson()
{
ExprMacroTable macroTable = queryFramework().macroTable();
testQuery(
"SELECT string, TRY_PARSE_JSON(TO_JSON_STRING(string)), PARSE_JSON('{\"foo\":1}'), PARSE_JSON(TO_JSON_STRING(nester))\n"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
new ExpressionVirtualColumn(
"v0",
"try_parse_json(to_json_string(\"string\"))",
ColumnType.NESTED_DATA,
macroTable
),
new ExpressionVirtualColumn(
"v1",
"parse_json('{\\u0022foo\\u0022:1}')",
ColumnType.NESTED_DATA,
macroTable
),
new ExpressionVirtualColumn(
"v2",
"parse_json(to_json_string(\"nester\"))",
ColumnType.NESTED_DATA,
macroTable
)
)
.columns("string", "v0", "v1", "v2")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{
"aaa",
"\"aaa\"",
"{\"foo\":1}",
"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":\"hello\"}}"
},
new Object[]{"bbb", "\"bbb\"", "{\"foo\":1}", "\"hello\""},
new Object[]{"ccc", "\"ccc\"", "{\"foo\":1}", null},
new Object[]{"ddd", "\"ddd\"", "{\"foo\":1}", null},
new Object[]{"eee", "\"eee\"", "{\"foo\":1}", null},
new Object[]{"aaa", "\"aaa\"", "{\"foo\":1}", "{\"array\":[\"a\",\"b\"],\"n\":{\"x\":1}}"},
new Object[]{"ddd", "\"ddd\"", "{\"foo\":1}", "2"}
),
RowSignature.builder()
.add("string", ColumnType.STRING)
.add("EXPR$1", ColumnType.NESTED_DATA)
.add("EXPR$2", ColumnType.NESTED_DATA)
.add("EXPR$3", ColumnType.NESTED_DATA)
.build()
);
}
@Test
public void testGroupByNegativeJsonPathIndex()
{
// negative array index cannot vectorize
cannotVectorize();
testQuery(
"SELECT "
+ "JSON_VALUE(nester, '$.array[-1]'), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nester", "$.array[-1]", "v0", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 5L},
new Object[]{"b", 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testJsonPathNegativeIndex()
{
testQuery(
"SELECT JSON_VALUE(nester, '$.array[-1]'), JSON_QUERY(nester, '$.array[-1]'), JSON_KEYS(nester, '$.array[-1]') FROM druid.nested",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
new NestedFieldVirtualColumn(
"nester",
"v0",
ColumnType.STRING,
null,
false,
"$.array[-1]",
false
),
new NestedFieldVirtualColumn(
"nester",
"v1",
ColumnType.NESTED_DATA,
null,
true,
"$.array[-1]",
false
),
expressionVirtualColumn("v2", "json_keys(\"nester\",'$.array[-1]')", ColumnType.STRING_ARRAY)
)
.columns("v0", "v1", "v2")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{"b", "\"b\"", null},
new Object[]{NullHandling.defaultStringValue(), null, null},
new Object[]{NullHandling.defaultStringValue(), null, null},
new Object[]{NullHandling.defaultStringValue(), null, null},
new Object[]{NullHandling.defaultStringValue(), null, null},
new Object[]{"b", "\"b\"", null},
new Object[]{NullHandling.defaultStringValue(), null, null}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.NESTED_DATA)
.add("EXPR$2", ColumnType.STRING_ARRAY)
.build()
);
}
@Test
public void testJsonPathsNonJsonInput()
{
testQuery(
"SELECT JSON_PATHS(string), JSON_PATHS(1234), JSON_PATHS('1234'), JSON_PATHS(1.1), JSON_PATHS(null)\n"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
expressionVirtualColumn("v0", "json_paths(\"string\")", ColumnType.STRING_ARRAY),
expressionVirtualColumn("v1", "array('$')", ColumnType.STRING_ARRAY)
)
.columns("v0", "v1")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{"[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]"},
new Object[]{"[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]"},
new Object[]{"[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]"},
new Object[]{"[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]"},
new Object[]{"[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]"},
new Object[]{"[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]"},
new Object[]{"[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]", "[\"$\"]"}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.STRING_ARRAY)
.add("EXPR$2", ColumnType.STRING_ARRAY)
.add("EXPR$3", ColumnType.STRING_ARRAY)
.add("EXPR$4", ColumnType.STRING_ARRAY)
.build()
);
}
@Test
public void testJsonKeysNonJsonInput()
{
testQuery(
"SELECT JSON_KEYS(string, '$'), JSON_KEYS(1234, '$'), JSON_KEYS('1234', '$'), JSON_KEYS(1.1, '$'), JSON_KEYS(null, '$')\n"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
expressionVirtualColumn("v0", "json_keys(\"string\",'$')", ColumnType.STRING_ARRAY),
expressionVirtualColumn("v1", "null", ColumnType.STRING_ARRAY)
)
.columns("v0", "v1")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{null, null, null, null, null},
new Object[]{null, null, null, null, null},
new Object[]{null, null, null, null, null},
new Object[]{null, null, null, null, null},
new Object[]{null, null, null, null, null},
new Object[]{null, null, null, null, null},
new Object[]{null, null, null, null, null}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.STRING_ARRAY)
.add("EXPR$2", ColumnType.STRING_ARRAY)
.add("EXPR$3", ColumnType.STRING_ARRAY)
.add("EXPR$4", ColumnType.STRING_ARRAY)
.build()
);
}
@Test
public void testJsonValueUnDocumentedButSupportedOptions()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.z' RETURNING BIGINT NULL ON EMPTY NULL ON ERROR)) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(new NestedFieldVirtualColumn("nest", "$.z", "v0", ColumnType.LONG))
.aggregators(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{700L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.build()
);
}
@Test
public void testJsonValueUnsupportedOptions()
{
testQueryThrows(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.z' RETURNING BIGINT ERROR ON EMPTY ERROR ON ERROR)) "
+ "FROM druid.nested",
IllegalArgumentException.class,
ThrowableMessageMatcher.hasMessage(
CoreMatchers.containsString(
"Unsupported JSON_VALUE parameter 'ON EMPTY' defined - please re-issue this query without this argument"
)
)
);
}
@Test
public void testGroupByPathSelectorFilterVariantNull()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "JSON_VALUE(nester, '$.n.x' RETURNING BIGINT), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nester, '$.n.x' RETURNING BIGINT) IS NULL GROUP BY 1, 2",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nester", "$.n.x", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0"),
new DefaultDimensionSpec("v0", "d1", ColumnType.LONG)
)
)
.setDimFilter(isNull("v0"))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), NullHandling.defaultLongValue(), 4L},
new Object[]{"100", NullHandling.defaultLongValue(), 1L},
new Object[]{"200", NullHandling.defaultLongValue(), 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.add("EXPR$2", ColumnType.LONG)
.build()
);
}
@Test
public void testSelectPathSelectorFilterVariantNull()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "JSON_VALUE(nester, '$.n.x' RETURNING BIGINT) "
+ "FROM druid.nested WHERE JSON_VALUE(nester, '$.n.x' RETURNING BIGINT) IS NULL",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
new NestedFieldVirtualColumn("nester", "$.n.x", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.columns(
"v0", "v1"
)
.filters(isNull("v0"))
.context(QUERY_CONTEXT_DEFAULT)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{"100", null},
new Object[]{NullHandling.defaultStringValue(), null},
new Object[]{"200", null},
new Object[]{NullHandling.defaultStringValue(), null},
new Object[]{NullHandling.defaultStringValue(), null},
new Object[]{NullHandling.defaultStringValue(), null}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathSelectorFilterVariantNotNull()
{
testQuery(
"SELECT "
+ "JSON_VALUE(nest, '$.x'), "
+ "JSON_VALUE(nester, '$.n.x' RETURNING BIGINT), "
+ "SUM(cnt) "
+ "FROM druid.nested WHERE JSON_VALUE(nester, '$.n.x' RETURNING BIGINT) IS NOT NULL GROUP BY 1, 2",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("nester", "$.n.x", "v0", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.STRING)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v1", "d0"),
new DefaultDimensionSpec("v0", "d1", ColumnType.LONG)
)
)
.setDimFilter(notNull("v0"))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"100", 1L, 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.add("EXPR$2", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRegularLongLongMixed1FilterNotNull()
{
testQuery(
"SELECT "
+ "JSON_VALUE(long, '$' RETURNING BIGINT), "
+ "SUM(cnt) "
+ "FROM druid.nested_mix WHERE JSON_VALUE(long, '$' RETURNING BIGINT) IS NOT NULL GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.LONG)
)
)
.setVirtualColumns(new NestedFieldVirtualColumn("long", "$", "v0", ColumnType.LONG))
.setDimFilter(notNull("v0"))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{1L, 2L},
new Object[]{2L, 4L},
new Object[]{3L, 2L},
new Object[]{4L, 2L},
new Object[]{5L, 4L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeStringMixed1SparseNotNull()
{
testQuery(
"SELECT "
+ "JSON_VALUE(string_sparse, '$' RETURNING BIGINT), "
+ "SUM(cnt) "
+ "FROM druid.nested_mix_2 WHERE JSON_VALUE(string_sparse, '$' RETURNING BIGINT) IS NOT NULL GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED_2)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.LONG)
)
)
.setVirtualColumns(new NestedFieldVirtualColumn("string_sparse", "$", "v0", ColumnType.LONG))
.setDimFilter(notNull("v0"))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{10L, 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testScanStringNotNullCast()
{
skipVectorize();
testQuery(
"SELECT "
+ "CAST(string_sparse as BIGINT)"
+ "FROM druid.nested_mix WHERE CAST(string_sparse as BIGINT) IS NOT NULL",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE_MIXED)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
expressionVirtualColumn("v0", "CAST(\"string_sparse\", 'LONG')", ColumnType.LONG)
)
.filters(notNull("v0"))
.columns("v0")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
NullHandling.sqlCompatible() ?
ImmutableList.of(
new Object[]{10L},
new Object[]{10L}
) :
ImmutableList.of(
new Object[]{0L},
new Object[]{0L},
new Object[]{10L},
new Object[]{0L},
new Object[]{0L},
new Object[]{0L},
new Object[]{0L},
new Object[]{0L},
new Object[]{0L},
new Object[]{10L},
new Object[]{0L},
new Object[]{0L},
new Object[]{0L},
new Object[]{0L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByRootSingleTypeStringMixed1SparseNotNullCast2()
{
testQuery(
"SELECT "
+ "CAST(string_sparse as BIGINT), "
+ "SUM(cnt) "
+ "FROM druid.nested_mix WHERE CAST(string_sparse as BIGINT) IS NOT NULL GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_MIXED)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("string_sparse", "d0", ColumnType.LONG)
)
)
.setVirtualColumns(expressionVirtualColumn(
"v0",
"CAST(\"string_sparse\", 'LONG')",
ColumnType.LONG
))
.setDimFilter(notNull("v0"))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
NullHandling.sqlCompatible() ?
ImmutableList.of(
new Object[]{10L, 2L}
) :
ImmutableList.of(
new Object[]{0L, 12L},
new Object[]{10L, 2L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
/**
* MVD version of {@link #testGroupByRootSingleTypeArrayLongNullsUnnest()}
*/
@Test
public void testGroupByRootSingleTypeArrayLongNullsAsMvd()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "ARRAY_TO_MV(arrayLongNulls), "
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(TableDataSource.create(DATA_SOURCE_ARRAYS))
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setVirtualColumns(expressionVirtualColumn(
"v0",
"array_to_mv(\"arrayLongNulls\")",
ColumnType.STRING
))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
// implicit mvd unnest treats null and empty as [null] so we get extra null matches than unnest
// directly on the ARRAY
new Object[]{NullHandling.defaultStringValue(), 9L},
new Object[]{"1", 5L},
new Object[]{"2", 6L},
new Object[]{"3", 6L},
new Object[]{"9", 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByRootSingleTypeArrayLongNullsAsMvdWithExpression()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "ARRAY_TO_MV(ARRAY_CONCAT(arrayLongNulls, arrayLong)), "
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(TableDataSource.create(DATA_SOURCE_ARRAYS))
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setVirtualColumns(expressionVirtualColumn(
"v0",
"array_to_mv(array_concat(\"arrayLongNulls\",\"arrayLong\"))",
ColumnType.STRING
))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
// 9 isn't present in result because arrayLong rows are null in rows of arrayLongNulls that have value 9
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 10L},
new Object[]{"1", 12L},
new Object[]{"2", 7L},
new Object[]{"3", 9L},
new Object[]{"4", 4L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
/**
* MVD version of {@link #testGroupByRootSingleTypeArrayLongNullsFiltered()}
* - implicit unnest since it is an mvd instead of array grouping
* - filters are adjusted to match strings instead of numbers
*/
@Test
public void testGroupByRootSingleTypeArrayLongNullsAsMvdFiltered()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "ARRAY_TO_MV(arrayLongNulls), "
+ "SUM(cnt), "
+ "SUM(MV_LENGTH(ARRAY_TO_MV(arrayLongNulls))) "
+ "FROM druid.arrays "
+ "WHERE MV_CONTAINS(ARRAY_TO_MV(arrayLongNulls), '1') "
+ "GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setVirtualColumns(
expressionVirtualColumn("v0", "array_to_mv(\"arrayLongNulls\")", ColumnType.STRING),
expressionVirtualColumn(
"v1",
"array_length(array_to_mv(\"arrayLongNulls\"))",
ColumnType.LONG
)
)
.setDimFilter(
new ExpressionDimFilter(
"array_contains(array_to_mv(\"arrayLongNulls\"),'1')",
queryFramework().macroTable()
)
)
.setAggregatorSpecs(
aggregators(
new LongSumAggregatorFactory("a0", "cnt"),
new LongSumAggregatorFactory("a1", "v1")
)
)
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 2L, 6L},
new Object[]{"1", 5L, 13L},
new Object[]{"2", 2L, 6L},
new Object[]{"3", 4L, 12L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.add("EXPR$2", ColumnType.LONG)
.build()
)
.run();
}
/**
* MVD version of {@link #testGroupByRootSingleTypeArrayLongNullsFilteredMore()}
* - implicit unnest since it is an mvd instead of array grouping
* - filters are adjusted to match strings instead of numbers
*/
@Test
public void testGroupByRootSingleTypeArrayLongNullsAsMvdFilteredMore()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "ARRAY_TO_MV(arrayLongNulls), "
+ "SUM(cnt) "
+ "FROM druid.arrays WHERE MV_CONTAINS(ARRAY_TO_MV(arrayLongNulls), '1') OR MV_OVERLAP(ARRAY_TO_MV(arrayLongNulls), ARRAY['2', '3']) GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setVirtualColumns(
expressionVirtualColumn("v0", "array_to_mv(\"arrayLongNulls\")", ColumnType.STRING)
)
.setDimFilter(
or(
expressionFilter("array_contains(array_to_mv(\"arrayLongNulls\"),'1')"),
expressionFilter("array_overlap(array_to_mv(\"arrayLongNulls\"),array('2','3'))")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
// since array is converted to a MVD, implicit unnesting occurs
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"1", 5L},
new Object[]{"2", 6L},
new Object[]{"3", 6L},
new Object[]{"9", 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
/**
* MVD version of {@link #testGroupByRootSingleTypeArrayStringNullsUnnest()}
*/
@Test
public void testGroupByRootSingleTypeArrayStringNullsAsMvdUnnest()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "ARRAY_TO_MV(arrayStringNulls), "
+ "SUM(cnt) "
+ "FROM druid.arrays GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(
TableDataSource.create(DATA_SOURCE_ARRAYS)
)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setVirtualColumns(
expressionVirtualColumn("v0", "array_to_mv(\"arrayStringNulls\")", ColumnType.STRING)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
// count is 9 instead of 5 because implicit unnest treats null and empty as [null]
new Object[]{NullHandling.defaultStringValue(), 9L},
new Object[]{"a", 3L},
new Object[]{"b", 11L},
new Object[]{"d", 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
/**
* MVD version of {@link #testGroupByRootSingleTypeArrayStringNullsFiltered()}
* - implicit unnest since mvd instead of string array
*/
@Test
public void testGroupByRootSingleTypeArrayStringNullsFilteredAsMvd()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT "
+ "ARRAY_TO_MV(arrayStringNulls), "
+ "SUM(cnt), "
+ "SUM(MV_LENGTH(ARRAY_TO_MV(arrayStringNulls))) "
+ "FROM druid.arrays "
+ "WHERE MV_CONTAINS(ARRAY_TO_MV(arrayStringNulls), 'b') "
+ "GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ARRAYS)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.STRING)
)
)
.setVirtualColumns(
expressionVirtualColumn("v0", "array_to_mv(\"arrayStringNulls\")", ColumnType.STRING),
new ExpressionVirtualColumn(
"v1",
"array_length(array_to_mv(\"arrayStringNulls\"))",
ColumnType.LONG,
queryFramework().macroTable()
)
)
.setDimFilter(
new ExpressionDimFilter(
"array_contains(array_to_mv(\"arrayStringNulls\"),'b')",
queryFramework().macroTable()
)
)
.setAggregatorSpecs(
aggregators(
new LongSumAggregatorFactory("a0", "cnt"),
new LongSumAggregatorFactory("a1", "v1")
)
)
.setContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L, 10L},
new Object[]{"a", 3L, 6L},
new Object[]{"b", 11L, 24L},
new Object[]{"d", 2L, 6L}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.add("EXPR$2", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testGroupByAndFilterVariant()
{
testQuery(
"SELECT "
+ "variant, "
+ "SUM(cnt) "
+ "FROM druid.all_auto WHERE variant = '1' GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE_ALL)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(
dimensions(
new DefaultDimensionSpec("variant", "d0")
)
)
.setDimFilter(equality("variant", "1", ColumnType.STRING))
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"1", 2L}
),
RowSignature.builder()
.add("variant", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testScanAllTypesAuto()
{
skipVectorize();
testQuery(
"SELECT * FROM druid.all_auto",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE_ALL)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns(
"__time",
"arrayBool",
"arrayDouble",
"arrayDoubleNulls",
"arrayLong",
"arrayLongNulls",
"arrayNestedLong",
"arrayObject",
"arrayString",
"arrayStringNulls",
"arrayVariant",
"bool",
"cDoubleArray",
"cEmptyArray",
"cEmptyObj",
"cEmptyObjectArray",
"cLongArray",
"cNullArray",
"cObj",
"cObjectArray",
"cdouble",
"clong",
"cnt",
"complexObj",
"cstr",
"cstringArray",
"double",
"long",
"null",
"obj",
"str",
"variant",
"variantEmptyObj",
"variantEmtpyArray",
"variantNumeric",
"variantWithArrays"
)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
useDefault ?
ImmutableList.of(
new Object[]{
1672531200000L,
"",
0L,
0.0D,
1L,
"51",
-0.13D,
"1",
"[]",
"[51,-35]",
"{\"a\":700,\"b\":{\"x\":\"g\",\"y\":1.1,\"z\":[9,null,9,9]},\"v\":[]}",
"{\"x\":400,\"y\":[{\"l\":[null],\"m\":100,\"n\":5},{\"l\":[\"a\",\"b\",\"c\"],\"m\":\"a\",\"n\":1}],\"z\":{}}",
null,
"[\"a\",\"b\"]",
null,
"[2,3]",
null,
"[null]",
null,
"[1,0,1]",
null,
"[{\"x\":1},{\"x\":2}]",
"",
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"",
2L,
0.0D,
0L,
"b",
1.1D,
"\"b\"",
"2",
"b",
"{\"a\":200,\"b\":{\"x\":\"b\",\"y\":1.1,\"z\":[2,4,6]},\"v\":[]}",
"{\"x\":10,\"y\":[{\"l\":[\"b\",\"b\",\"c\"],\"m\":\"b\",\"n\":2},[1,2,3]],\"z\":{\"a\":[5.5],\"b\":false}}",
"[\"a\",\"b\",\"c\"]",
"[null,\"b\"]",
"[2,3]",
null,
"[3.3,4.4,5.5]",
"[999.0,null,5.5]",
"[null,null,2.2]",
"[1,1]",
"[null,[null],[]]",
"[{\"x\":3},{\"x\":4}]",
"",
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"a",
1L,
1.0D,
1L,
"1",
1.0D,
"1",
"1",
"1",
"{\"a\":100,\"b\":{\"x\":\"a\",\"y\":1.1,\"z\":[1,2,3,4]},\"v\":[]}",
"{\"x\":1234,\"y\":[{\"l\":[\"a\",\"b\",\"c\"],\"m\":\"a\",\"n\":1},{\"l\":[\"a\",\"b\",\"c\"],\"m\":\"a\",\"n\":1}],\"z\":{\"a\":[1.1,2.2,3.3],\"b\":true}}",
"[\"a\",\"b\"]",
"[\"a\",\"b\"]",
"[1,2,3]",
"[1,null,3]",
"[1.1,2.2,3.3]",
"[1.1,2.2,null]",
"[\"a\",\"1\",\"2.2\"]",
"[1,0,1]",
"[[1,2,null],[3,4]]",
"[{\"x\":1},{\"x\":2}]",
"",
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"b",
4L,
3.3D,
1L,
"1",
0.0D,
"{}",
"4",
"1",
"{\"a\":400,\"b\":{\"x\":\"d\",\"y\":1.1,\"z\":[3,4]},\"v\":[]}",
"{\"x\":1234,\"z\":{\"a\":[1.1,2.2,3.3],\"b\":true}}",
"[\"d\",\"e\"]",
"[\"b\",\"b\"]",
"[1,4]",
"[1]",
"[2.2,3.3,4.0]",
null,
"[\"a\",\"b\",\"c\"]",
"[null,0,1]",
"[[1,2],[3,4],[5,6,7]]",
"[{\"x\":null},{\"x\":2}]",
"",
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"c",
0L,
4.4D,
1L,
"hello",
-1000.0D,
"{}",
"[]",
"hello",
"{\"a\":500,\"b\":{\"x\":\"e\",\"z\":[1,2,3,4]},\"v\":\"a\"}",
"{\"x\":11,\"y\":[],\"z\":{\"a\":[null],\"b\":false}}",
null,
null,
"[1,2,3]",
"[]",
"[1.1,2.2,3.3]",
null,
null,
"[0]",
null,
"[{\"x\":1000},{\"y\":2000}]",
"",
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"d",
5L,
5.9D,
0L,
"",
3.33D,
"\"a\"",
"6",
null,
"{\"a\":600,\"b\":{\"x\":\"f\",\"y\":1.1,\"z\":[6,7,8,9]},\"v\":\"b\"}",
null,
"[\"a\",\"b\"]",
null,
null,
"[null,2,9]",
null,
"[999.0,5.5,null]",
"[\"a\",\"1\",\"2.2\"]",
"[]",
"[[1],[1,2,null]]",
"[{\"a\":1},{\"b\":2}]",
"",
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"null",
3L,
2.0D,
0L,
"3.0",
1.0D,
"3.3",
"3",
"3.0",
"{\"a\":300}",
"{\"x\":4.4,\"y\":[{\"l\":[],\"m\":100,\"n\":3},{\"l\":[\"a\"]},{\"l\":[\"b\"],\"n\":[]}],\"z\":{\"a\":[],\"b\":true}}",
"[\"b\",\"c\"]",
"[\"d\",null,\"b\"]",
"[1,2,3,4]",
"[1,2,3]",
"[1.1,3.3]",
"[null,2.2,null]",
"[1,null,1]",
"[1,null,1]",
"[[1],null,[1,2,3]]",
"[null,{\"x\":2}]",
"",
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
}
) :
ImmutableList.of(
new Object[]{
1672531200000L,
null,
null,
null,
1L,
"51",
-0.13D,
"1",
"[]",
"[51,-35]",
"{\"a\":700,\"b\":{\"x\":\"g\",\"y\":1.1,\"z\":[9,null,9,9]},\"v\":[]}",
"{\"x\":400,\"y\":[{\"l\":[null],\"m\":100,\"n\":5},{\"l\":[\"a\",\"b\",\"c\"],\"m\":\"a\",\"n\":1}],\"z\":{}}",
null,
"[\"a\",\"b\"]",
null,
"[2,3]",
null,
"[null]",
null,
"[1,0,1]",
null,
"[{\"x\":1},{\"x\":2}]",
null,
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"",
2L,
null,
0L,
"b",
1.1D,
"\"b\"",
"2",
"b",
"{\"a\":200,\"b\":{\"x\":\"b\",\"y\":1.1,\"z\":[2,4,6]},\"v\":[]}",
"{\"x\":10,\"y\":[{\"l\":[\"b\",\"b\",\"c\"],\"m\":\"b\",\"n\":2},[1,2,3]],\"z\":{\"a\":[5.5],\"b\":false}}",
"[\"a\",\"b\",\"c\"]",
"[null,\"b\"]",
"[2,3]",
null,
"[3.3,4.4,5.5]",
"[999.0,null,5.5]",
"[null,null,2.2]",
"[1,1]",
"[null,[null],[]]",
"[{\"x\":3},{\"x\":4}]",
null,
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"a",
1L,
1.0D,
1L,
"1",
1.0D,
"1",
"1",
"1",
"{\"a\":100,\"b\":{\"x\":\"a\",\"y\":1.1,\"z\":[1,2,3,4]},\"v\":[]}",
"{\"x\":1234,\"y\":[{\"l\":[\"a\",\"b\",\"c\"],\"m\":\"a\",\"n\":1},{\"l\":[\"a\",\"b\",\"c\"],\"m\":\"a\",\"n\":1}],\"z\":{\"a\":[1.1,2.2,3.3],\"b\":true}}",
"[\"a\",\"b\"]",
"[\"a\",\"b\"]",
"[1,2,3]",
"[1,null,3]",
"[1.1,2.2,3.3]",
"[1.1,2.2,null]",
"[\"a\",\"1\",\"2.2\"]",
"[1,0,1]",
"[[1,2,null],[3,4]]",
"[{\"x\":1},{\"x\":2}]",
null,
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"b",
4L,
3.3D,
1L,
"1",
null,
"{}",
"4",
"1",
"{\"a\":400,\"b\":{\"x\":\"d\",\"y\":1.1,\"z\":[3,4]},\"v\":[]}",
"{\"x\":1234,\"z\":{\"a\":[1.1,2.2,3.3],\"b\":true}}",
"[\"d\",\"e\"]",
"[\"b\",\"b\"]",
"[1,4]",
"[1]",
"[2.2,3.3,4.0]",
null,
"[\"a\",\"b\",\"c\"]",
"[null,0,1]",
"[[1,2],[3,4],[5,6,7]]",
"[{\"x\":null},{\"x\":2}]",
null,
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"c",
null,
4.4D,
1L,
"hello",
-1000.0D,
"{}",
"[]",
"hello",
"{\"a\":500,\"b\":{\"x\":\"e\",\"z\":[1,2,3,4]},\"v\":\"a\"}",
"{\"x\":11,\"y\":[],\"z\":{\"a\":[null],\"b\":false}}",
null,
null,
"[1,2,3]",
"[]",
"[1.1,2.2,3.3]",
null,
null,
"[0]",
null,
"[{\"x\":1000},{\"y\":2000}]",
null,
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"d",
5L,
5.9D,
0L,
null,
3.33D,
"\"a\"",
"6",
null,
"{\"a\":600,\"b\":{\"x\":\"f\",\"y\":1.1,\"z\":[6,7,8,9]},\"v\":\"b\"}",
null,
"[\"a\",\"b\"]",
null,
null,
"[null,2,9]",
null,
"[999.0,5.5,null]",
"[\"a\",\"1\",\"2.2\"]",
"[]",
"[[1],[1,2,null]]",
"[{\"a\":1},{\"b\":2}]",
null,
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
},
new Object[]{
1672531200000L,
"null",
3L,
2.0D,
null,
"3.0",
1.0D,
"3.3",
"3",
"3.0",
"{\"a\":300}",
"{\"x\":4.4,\"y\":[{\"l\":[],\"m\":100,\"n\":3},{\"l\":[\"a\"]},{\"l\":[\"b\"],\"n\":[]}],\"z\":{\"a\":[],\"b\":true}}",
"[\"b\",\"c\"]",
"[\"d\",null,\"b\"]",
"[1,2,3,4]",
"[1,2,3]",
"[1.1,3.3]",
"[null,2.2,null]",
"[1,null,1]",
"[1,null,1]",
"[[1],null,[1,2,3]]",
"[null,{\"x\":2}]",
null,
"hello",
1234L,
1.234D,
"{\"x\":1,\"y\":\"hello\",\"z\":{\"a\":1.1,\"b\":1234,\"c\":[\"a\",\"b\",\"c\"],\"d\":[]}}",
"[\"a\",\"b\",\"c\"]",
"[1,2,3]",
"[1.1,2.2,3.3]",
"[]",
"{}",
"[null,null]",
"[{},{},{}]",
"[{\"a\":\"b\",\"x\":1,\"y\":1.3}]",
1L
}
),
RowSignature.builder()
.add("__time", ColumnType.LONG)
.add("str", ColumnType.STRING)
.add("long", ColumnType.LONG)
.add("double", ColumnType.DOUBLE)
.add("bool", ColumnType.LONG)
.add("variant", ColumnType.STRING)
.add("variantNumeric", ColumnType.DOUBLE)
.add("variantEmptyObj", ColumnType.NESTED_DATA)
.add("variantEmtpyArray", ColumnType.LONG_ARRAY)
.add("variantWithArrays", ColumnType.STRING_ARRAY)
.add("obj", ColumnType.NESTED_DATA)
.add("complexObj", ColumnType.NESTED_DATA)
.add("arrayString", ColumnType.STRING_ARRAY)
.add("arrayStringNulls", ColumnType.STRING_ARRAY)
.add("arrayLong", ColumnType.LONG_ARRAY)
.add("arrayLongNulls", ColumnType.LONG_ARRAY)
.add("arrayDouble", ColumnType.DOUBLE_ARRAY)
.add("arrayDoubleNulls", ColumnType.DOUBLE_ARRAY)
.add("arrayVariant", ColumnType.STRING_ARRAY)
.add("arrayBool", ColumnType.LONG_ARRAY)
.add("arrayNestedLong", ColumnType.NESTED_DATA)
.add("arrayObject", ColumnType.NESTED_DATA)
.add("null", ColumnType.STRING)
.add("cstr", ColumnType.STRING)
.add("clong", ColumnType.LONG)
.add("cdouble", ColumnType.DOUBLE)
.add("cObj", ColumnType.NESTED_DATA)
.add("cstringArray", ColumnType.STRING_ARRAY)
.add("cLongArray", ColumnType.LONG_ARRAY)
.add("cDoubleArray", ColumnType.DOUBLE_ARRAY)
.add("cEmptyArray", ColumnType.LONG_ARRAY)
.add("cEmptyObj", ColumnType.NESTED_DATA)
.add("cNullArray", ColumnType.LONG_ARRAY)
.add("cEmptyObjectArray", ColumnType.NESTED_DATA)
.add("cObjectArray", ColumnType.NESTED_DATA)
.add("cnt", ColumnType.LONG)
.build()
);
}
@Test
public void testFilterJsonIsNotNull()
{
testQuery(
"SELECT nest\n"
+ "FROM druid.nested WHERE nest IS NOT NULL",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("nest")
.filters(notNull("nest"))
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
NullHandling.replaceWithDefault()
? ImmutableList.of()
: ImmutableList.of(
new Object[]{"{\"x\":100,\"y\":2.02,\"z\":\"300\",\"mixed\":1,\"mixed2\":\"1\"}"},
new Object[]{"{\"x\":200,\"y\":3.03,\"z\":\"abcdef\",\"mixed\":1.1,\"mixed2\":1}"},
new Object[]{"{\"x\":100,\"y\":2.02,\"z\":\"400\",\"mixed2\":1.1}"}
),
RowSignature.builder()
.add("nest", ColumnType.NESTED_DATA)
.build()
);
}
@Test
public void testFilterJsonIsNull()
{
testQuery(
"SELECT nest, nester\n"
+ "FROM druid.nested WHERE nest IS NULL",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("nest", "nester")
.filters(isNull("nest"))
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
// selector filter is wrong
NullHandling.replaceWithDefault()
? ImmutableList.of(
new Object[]{
"{\"x\":100,\"y\":2.02,\"z\":\"300\",\"mixed\":1,\"mixed2\":\"1\"}",
"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":\"hello\"}}"
},
new Object[]{null, "\"hello\""},
new Object[]{"{\"x\":200,\"y\":3.03,\"z\":\"abcdef\",\"mixed\":1.1,\"mixed2\":1}", null},
new Object[]{null, null},
new Object[]{null, null},
new Object[]{
"{\"x\":100,\"y\":2.02,\"z\":\"400\",\"mixed2\":1.1}",
"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":1}}"
},
new Object[]{null, "2"}
)
: ImmutableList.of(
new Object[]{null, "\"hello\""},
new Object[]{null, null},
new Object[]{null, null},
new Object[]{null, "2"}
),
RowSignature.builder()
.add("nest", ColumnType.NESTED_DATA)
.add("nester", ColumnType.NESTED_DATA)
.build()
);
}
@Test
public void testCoalesceOnNestedColumns()
{
// jo.unnest is first entry in coalesce
// so Calcite removes the coalesce to be used here
testQuery(
"select coalesce(c,long) as col "
+ " from druid.all_auto, unnest(json_value(arrayNestedLong, '$[1]' returning bigint array)) as u(c) ",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(UnnestDataSource.create(
new TableDataSource(DATA_SOURCE_ALL),
new NestedFieldVirtualColumn("arrayNestedLong", "$[1]", "j0.unnest", ColumnType.LONG_ARRAY),
null
))
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("j0.unnest")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{null},
new Object[]{3L},
new Object[]{4L},
new Object[]{3L},
new Object[]{4L},
new Object[]{1L},
new Object[]{2L},
new Object[]{null}
),
RowSignature.builder()
.add("col", ColumnType.LONG)
.build()
);
}
@Test
public void testCoalesceOnNestedColumnsLater()
{
// the first column in coalesce comes from the table
// so a virtual expression is present for the coalesce
testQuery(
"select coalesce(long,c) as col "
+ " from druid.all_auto, unnest(json_value(arrayNestedLong, '$[1]' returning bigint array)) as u(c) ",
useDefault ?
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(UnnestDataSource.create(
new TableDataSource(DATA_SOURCE_ALL),
new NestedFieldVirtualColumn("arrayNestedLong", "$[1]", "j0.unnest", ColumnType.LONG_ARRAY),
null
))
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("long")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.context(QUERY_CONTEXT_DEFAULT)
.build()
) :
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(UnnestDataSource.create(
new TableDataSource(DATA_SOURCE_ALL),
new NestedFieldVirtualColumn("arrayNestedLong", "$[1]", "j0.unnest", ColumnType.LONG_ARRAY),
null
))
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(expressionVirtualColumn("v0", "nvl(\"long\",\"j0.unnest\")", ColumnType.LONG))
.columns("v0")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{2L},
new Object[]{1L},
new Object[]{1L},
new Object[]{4L},
new Object[]{4L},
new Object[]{5L},
new Object[]{5L},
new Object[]{5L}
),
RowSignature.builder()
.add("col", ColumnType.LONG)
.build()
);
}
@Test
public void testGroupByPathDynamicArg()
{
cannotVectorize();
testQuery(
"SELECT "
+ "JSON_VALUE(nest, ARRAY_OFFSET(JSON_PATHS(nest), 0)), "
+ "SUM(cnt) "
+ "FROM druid.nested GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(DATA_SOURCE)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
expressionVirtualColumn(
"v0",
"json_value(\"nest\",array_offset(json_paths(\"nest\"),0),'STRING')",
ColumnType.STRING
)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0")
)
)
.setAggregatorSpecs(aggregators(new LongSumAggregatorFactory("a0", "cnt")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L},
new Object[]{"200", 1L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.add("EXPR$1", ColumnType.LONG)
.build()
);
}
@Test
public void testJsonQueryDynamicArg()
{
cannotVectorize();
testQuery(
"SELECT JSON_PATHS(nester), JSON_QUERY(nester, ARRAY_OFFSET(JSON_PATHS(nester), 0))\n"
+ "FROM druid.nested",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
expressionVirtualColumn(
"v0",
"json_paths(\"nester\")",
ColumnType.STRING_ARRAY
),
expressionVirtualColumn(
"v1",
"json_query(\"nester\",array_offset(json_paths(\"nester\"),0))",
ColumnType.NESTED_DATA
)
)
.columns("v0", "v1")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{"[\"$.array\",\"$.n.x\"]", "[\"a\",\"b\"]"},
new Object[]{"[\"$\"]", "\"hello\""},
new Object[]{"[\"$\"]", null},
new Object[]{"[\"$\"]", null},
new Object[]{"[\"$\"]", null},
new Object[]{"[\"$.array\",\"$.n.x\"]", "[\"a\",\"b\"]"},
new Object[]{"[\"$\"]", "2"}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING_ARRAY)
.add("EXPR$1", ColumnType.NESTED_DATA)
.build()
);
}
@Test
public void testJsonQueryArrays()
{
cannotVectorize();
testBuilder()
.sql("SELECT JSON_QUERY_ARRAY(arrayObject, '$') FROM druid.arrays")
.queryContext(QUERY_CONTEXT_DEFAULT)
.expectedQueries(
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE_ARRAYS)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
expressionVirtualColumn(
"v0",
"json_query_array(\"arrayObject\",'$')",
ColumnType.ofArray(ColumnType.NESTED_DATA)
)
)
.columns("v0")
.context(QUERY_CONTEXT_DEFAULT)
.legacy(false)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{"[{\"x\":1000},{\"y\":2000}]"},
new Object[]{"[{\"x\":1},{\"x\":2}]"},
new Object[]{"[{\"x\":null},{\"x\":2}]"},
new Object[]{"[{\"a\":1},{\"b\":2}]"},
new Object[]{"[{\"x\":1},{\"x\":2}]"},
new Object[]{"[null,{\"x\":2}]"},
new Object[]{"[{\"x\":3},{\"x\":4}]"},
new Object[]{"[{\"x\":1000},{\"y\":2000}]"},
new Object[]{"[{\"x\":1},{\"x\":2}]"},
new Object[]{"[{\"x\":null},{\"x\":2}]"},
new Object[]{"[{\"a\":1},{\"b\":2}]"},
new Object[]{"[{\"x\":1},{\"x\":2}]"},
new Object[]{"[null,{\"x\":2}]"},
new Object[]{"[{\"x\":3},{\"x\":4}]"}
)
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.ofArray(ColumnType.NESTED_DATA))
.build()
)
.run();
}
@Test
public void testJsonQueryArrayNullArray()
{
cannotVectorize();
testBuilder()
.sql("SELECT JSON_QUERY_ARRAY(arrayObject, '$.') FROM druid.arrays where arrayObject is null limit 1")
.queryContext(QUERY_CONTEXT_DEFAULT)
.expectedQueries(
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE_ARRAYS)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
expressionVirtualColumn(
"v0",
"null",
ColumnType.ofArray(ColumnType.NESTED_DATA)
)
)
.filters(isNull("arrayObject"))
.columns("v0")
.limit(1)
.context(QUERY_CONTEXT_DEFAULT)
.legacy(false)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.build()
)
)
.expectedResults(
NullHandling.replaceWithDefault() ?
ImmutableList.of(new Object[]{null}) : ImmutableList.of()
)
.expectedSignature(
RowSignature.builder()
.add("EXPR$0", ColumnType.ofArray(ColumnType.NESTED_DATA))
.build()
)
.run();
}
@Test
public void testUnnestJsonQueryArrays()
{
cannotVectorize();
testBuilder()
.sql("SELECT objects FROM druid.arrays, UNNEST(JSON_QUERY_ARRAY(arrayObject, '$')) as u(objects)")
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(
UnnestDataSource.create(
TableDataSource.create(DATA_SOURCE_ARRAYS),
expressionVirtualColumn(
"j0.unnest",
"json_query_array(\"arrayObject\",'$')",
ColumnType.ofArray(ColumnType.NESTED_DATA)
),
null
)
)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("j0.unnest")
.context(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.legacy(false)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{"{\"x\":1000}"},
new Object[]{"{\"y\":2000}"},
new Object[]{"{\"x\":1}"},
new Object[]{"{\"x\":2}"},
new Object[]{"{\"x\":null}"},
new Object[]{"{\"x\":2}"},
new Object[]{"{\"a\":1}"},
new Object[]{"{\"b\":2}"},
new Object[]{"{\"x\":1}"},
new Object[]{"{\"x\":2}"},
new Object[]{null},
new Object[]{"{\"x\":2}"},
new Object[]{"{\"x\":3}"},
new Object[]{"{\"x\":4}"},
new Object[]{"{\"x\":1000}"},
new Object[]{"{\"y\":2000}"},
new Object[]{"{\"x\":1}"},
new Object[]{"{\"x\":2}"},
new Object[]{"{\"x\":null}"},
new Object[]{"{\"x\":2}"},
new Object[]{"{\"a\":1}"},
new Object[]{"{\"b\":2}"},
new Object[]{"{\"x\":1}"},
new Object[]{"{\"x\":2}"},
new Object[]{null},
new Object[]{"{\"x\":2}"},
new Object[]{"{\"x\":3}"},
new Object[]{"{\"x\":4}"}
)
)
.expectedSignature(
RowSignature.builder()
.add("objects", ColumnType.NESTED_DATA)
.build()
)
.run();
}
@Test
public void testUnnestJsonQueryArraysJsonValue()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT"
+ " json_value(objects, '$.x' returning bigint) as x,"
+ " count(*)"
+ " FROM druid.arrays, UNNEST(JSON_QUERY_ARRAY(arrayObject, '$')) as u(objects)"
+ " GROUP BY 1"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(
UnnestDataSource.create(
TableDataSource.create(DATA_SOURCE_ARRAYS),
expressionVirtualColumn(
"j0.unnest",
"json_query_array(\"arrayObject\",'$')",
ColumnType.ofArray(ColumnType.NESTED_DATA)
),
null
)
)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
new NestedFieldVirtualColumn("j0.unnest", "$.x", "v0", ColumnType.LONG)
)
.setDimensions(
dimensions(
new DefaultDimensionSpec("v0", "d0", ColumnType.LONG)
)
)
.setAggregatorSpecs(new CountAggregatorFactory("a0"))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{NullHandling.defaultLongValue(), 10L},
new Object[]{1L, 4L},
new Object[]{2L, 8L},
new Object[]{3L, 2L},
new Object[]{4L, 2L},
new Object[]{1000L, 2L}
)
)
.expectedSignature(
RowSignature.builder()
.add("x", ColumnType.LONG)
.add("EXPR$1", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testUnnestJsonQueryArraysJsonValueSum()
{
cannotVectorize();
testBuilder()
.sql(
"SELECT"
+ " sum(json_value(objects, '$.x' returning bigint)) as xs"
+ " FROM druid.arrays, UNNEST(JSON_QUERY_ARRAY(arrayObject, '$')) as u(objects)"
)
.queryContext(QUERY_CONTEXT_NO_STRINGIFY_ARRAY)
.expectedQueries(
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.intervals(querySegmentSpec(Filtration.eternity()))
.dataSource(
UnnestDataSource.create(
TableDataSource.create(DATA_SOURCE_ARRAYS),
expressionVirtualColumn(
"j0.unnest",
"json_query_array(\"arrayObject\",'$')",
ColumnType.ofArray(ColumnType.NESTED_DATA)
),
null
)
)
.virtualColumns(
new NestedFieldVirtualColumn("j0.unnest", "$.x", "v0", ColumnType.LONG)
)
.aggregators(
new LongSumAggregatorFactory("a0", "v0")
)
.context(QUERY_CONTEXT_DEFAULT)
.build()
)
)
.expectedResults(
ImmutableList.of(
new Object[]{2034L}
)
)
.expectedSignature(
RowSignature.builder()
.add("xs", ColumnType.LONG)
.build()
)
.run();
}
@Test
public void testJsonValueNestedEmptyArray()
{
// test for regression
skipVectorize();
testQuery(
"SELECT json_value(cObj, '$.z.d') FROM druid.all_auto",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(DATA_SOURCE_ALL)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns(
"v0"
)
.virtualColumns(
new NestedFieldVirtualColumn(
"cObj",
"$.z.d",
"v0",
ColumnType.STRING
)
)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{"[]"},
new Object[]{"[]"},
new Object[]{"[]"},
new Object[]{"[]"},
new Object[]{"[]"},
new Object[]{"[]"},
new Object[]{"[]"}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.STRING)
.build()
);
}
}