blob: f5512b5e8fb7f9fb23015e6e8bbc6dbe16daf5b5 [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 junitparams.JUnitParamsRunner;
import org.apache.calcite.avatica.SqlType;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.java.util.common.DateTimes;
import org.apache.druid.java.util.common.Intervals;
import org.apache.druid.java.util.common.granularity.Granularities;
import org.apache.druid.query.Druids;
import org.apache.druid.query.InlineDataSource;
import org.apache.druid.query.aggregation.CountAggregatorFactory;
import org.apache.druid.query.aggregation.DoubleSumAggregatorFactory;
import org.apache.druid.query.aggregation.FilteredAggregatorFactory;
import org.apache.druid.query.dimension.DefaultDimensionSpec;
import org.apache.druid.query.groupby.GroupByQuery;
import org.apache.druid.query.ordering.StringComparators;
import org.apache.druid.query.scan.ScanQuery;
import org.apache.druid.query.scan.ScanQuery.ResultFormat;
import org.apache.druid.segment.column.RowSignature;
import org.apache.druid.segment.column.ValueType;
import org.apache.druid.sql.calcite.filtration.Filtration;
import org.apache.druid.sql.calcite.util.CalciteTests;
import org.apache.druid.sql.http.SqlParameter;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* This class has copied a subset of the tests in {@link CalciteQueryTest} and replaced various parts of queries with
* dynamic parameters. It is NOT important that this file remains in sync with {@link CalciteQueryTest}, the tests
* were merely chosen to produce a selection of parameter types and positions within query expressions and have been
* renamed to reflect this
*/
@RunWith(JUnitParamsRunner.class)
public class CalciteParameterQueryTest extends BaseCalciteQueryTest
{
@Test
public void testSelectConstantParamGetsConstant() throws Exception
{
testQuery(
"SELECT 1 + ?",
ImmutableList.of(
Druids.newScanQueryBuilder()
.dataSource(
InlineDataSource.fromIterable(
ImmutableList.of(new Object[]{2L}),
RowSignature.builder().add("EXPR$0", ValueType.LONG).build()
)
)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("EXPR$0")
.resultFormat(ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.legacy(false)
.build()
),
ImmutableList.of(
new Object[]{2}
),
ImmutableList.of(new SqlParameter(SqlType.INTEGER, 1))
);
}
@Test
public void testParamsGetOptimizedIntoConstant() throws Exception
{
testQuery(
"SELECT 1 + ?, dim1 FROM foo LIMIT ?",
ImmutableList.of(
newScanQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(expressionVirtualColumn("v0", "2", ValueType.LONG))
.columns("dim1", "v0")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.limit(1)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{2, ""}
),
ImmutableList.of(
new SqlParameter(SqlType.INTEGER, 1),
new SqlParameter(SqlType.INTEGER, 1)
)
);
}
@Test
public void testParametersInSelectAndFilter() throws Exception
{
testQuery(
PLANNER_CONFIG_DEFAULT,
QUERY_CONTEXT_DEFAULT,
ImmutableList.of(
new SqlParameter(SqlType.INTEGER, 10),
new SqlParameter(SqlType.INTEGER, 0)
),
"SELECT exp(count(*)) + ?, sum(m2) FROM druid.foo WHERE dim2 = ?",
CalciteTests.REGULAR_USER_AUTH_RESULT,
ImmutableList.of(Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Filtration.eternity()))
.filters(numericSelector("dim2", "0", null))
.granularity(Granularities.ALL)
.aggregators(aggregators(
new CountAggregatorFactory("a0"),
new DoubleSumAggregatorFactory("a1", "m2")
))
.postAggregators(
expressionPostAgg("p0", "(exp(\"a0\") + 10)")
)
.context(QUERY_CONTEXT_DEFAULT)
.build()),
ImmutableList.of(
new Object[]{11.0, NullHandling.defaultDoubleValue()}
)
);
}
@Test
public void testSelectTrimFamilyWithParameters() throws Exception
{
// TRIM has some whacky parsing. Abuse this to test a bunch of parameters
testQuery(
"SELECT\n"
+ "TRIM(BOTH ? FROM ?),\n"
+ "TRIM(TRAILING ? FROM ?),\n"
+ "TRIM(? FROM ?),\n"
+ "TRIM(TRAILING FROM ?),\n"
+ "TRIM(?),\n"
+ "BTRIM(?),\n"
+ "BTRIM(?, ?),\n"
+ "LTRIM(?),\n"
+ "LTRIM(?, ?),\n"
+ "RTRIM(?),\n"
+ "RTRIM(?, ?),\n"
+ "COUNT(*)\n"
+ "FROM foo",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.aggregators(aggregators(new CountAggregatorFactory("a0")))
.postAggregators(
expressionPostAgg("p0", "'foo'"),
expressionPostAgg("p1", "'xfoo'"),
expressionPostAgg("p2", "'foo'"),
expressionPostAgg("p3", "' foo'"),
expressionPostAgg("p4", "'foo'"),
expressionPostAgg("p5", "'foo'"),
expressionPostAgg("p6", "'foo'"),
expressionPostAgg("p7", "'foo '"),
expressionPostAgg("p8", "'foox'"),
expressionPostAgg("p9", "' foo'"),
expressionPostAgg("p10", "'xfoo'")
)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"foo", "xfoo", "foo", " foo", "foo", "foo", "foo", "foo ", "foox", " foo", "xfoo", 6L}
),
ImmutableList.of(
new SqlParameter(SqlType.VARCHAR, "x"),
new SqlParameter(SqlType.VARCHAR, "xfoox"),
new SqlParameter(SqlType.VARCHAR, "x"),
new SqlParameter(SqlType.VARCHAR, "xfoox"),
new SqlParameter(SqlType.VARCHAR, " "),
new SqlParameter(SqlType.VARCHAR, " foo "),
new SqlParameter(SqlType.VARCHAR, " foo "),
new SqlParameter(SqlType.VARCHAR, " foo "),
new SqlParameter(SqlType.VARCHAR, " foo "),
new SqlParameter(SqlType.VARCHAR, "xfoox"),
new SqlParameter(SqlType.VARCHAR, "x"),
new SqlParameter(SqlType.VARCHAR, " foo "),
new SqlParameter(SqlType.VARCHAR, "xfoox"),
new SqlParameter(SqlType.VARCHAR, "x"),
new SqlParameter(SqlType.VARCHAR, " foo "),
new SqlParameter(SqlType.VARCHAR, "xfoox"),
new SqlParameter(SqlType.VARCHAR, "x")
)
);
}
@Test
public void testParamsInInformationSchema() throws Exception
{
// Not including COUNT DISTINCT, since it isn't supported by BindableAggregate, and so it can't work.
testQuery(
"SELECT\n"
+ " COUNT(JDBC_TYPE),\n"
+ " SUM(JDBC_TYPE),\n"
+ " AVG(JDBC_TYPE),\n"
+ " MIN(JDBC_TYPE),\n"
+ " MAX(JDBC_TYPE)\n"
+ "FROM INFORMATION_SCHEMA.COLUMNS\n"
+ "WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?",
ImmutableList.of(),
ImmutableList.of(
new Object[]{8L, 1249L, 156L, -5L, 1111L}
),
ImmutableList.of(
new SqlParameter(SqlType.VARCHAR, "druid"),
new SqlParameter(SqlType.VARCHAR, "foo")
)
);
}
@Test
public void testParamsInSelectExpressionAndLimit() throws Exception
{
testQuery(
"SELECT SUBSTRING(dim2, ?, ?) FROM druid.foo LIMIT ?",
ImmutableList.of(
newScanQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Filtration.eternity()))
.virtualColumns(
expressionVirtualColumn("v0", "substring(\"dim2\", 0, 1)", ValueType.STRING)
)
.columns("v0")
.limit(2)
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"a"},
new Object[]{NULL_STRING}
),
ImmutableList.of(
new SqlParameter(SqlType.INTEGER, 1),
new SqlParameter(SqlType.INTEGER, 1),
new SqlParameter(SqlType.INTEGER, 2)
)
);
}
@Test
public void testParamsTuckedInACast() throws Exception
{
testQuery(
"SELECT dim1, m1, COUNT(*) FROM druid.foo WHERE m1 - CAST(? as INT) = dim1 GROUP BY dim1, m1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(CalciteTests.DATASOURCE1)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimFilter(expressionFilter("((\"m1\" - 1) == CAST(\"dim1\", 'DOUBLE'))"))
.setDimensions(dimensions(
new DefaultDimensionSpec("dim1", "d0"),
new DefaultDimensionSpec("m1", "d1", ValueType.FLOAT)
))
.setAggregatorSpecs(aggregators(new CountAggregatorFactory("a0")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
NullHandling.replaceWithDefault() ?
ImmutableList.of(
new Object[]{"", 1.0f, 1L},
new Object[]{"2", 3.0f, 1L}
) :
ImmutableList.of(
new Object[]{"2", 3.0f, 1L}
),
ImmutableList.of(
new SqlParameter(SqlType.INTEGER, 1)
)
);
}
@Test
public void testParametersInStrangePlaces() throws Exception
{
testQuery(
"SELECT\n"
+ " dim1,\n"
+ " COUNT(*) FILTER(WHERE dim2 <> ?)/COUNT(*) as ratio\n"
+ "FROM druid.foo\n"
+ "GROUP BY dim1\n"
+ "HAVING COUNT(*) FILTER(WHERE dim2 <> ?)/COUNT(*) = ?",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(CalciteTests.DATASOURCE1)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setDimensions(dimensions(new DefaultDimensionSpec("dim1", "d0")))
.setAggregatorSpecs(aggregators(
new FilteredAggregatorFactory(
new CountAggregatorFactory("a0"),
not(selector("dim2", "a", null))
),
new CountAggregatorFactory("a1")
))
.setPostAggregatorSpecs(ImmutableList.of(
expressionPostAgg("p0", "(\"a0\" / \"a1\")")
))
.setHavingSpec(having(expressionFilter("((\"a0\" / \"a1\") == 1)")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"10.1", 1L},
new Object[]{"2", 1L},
new Object[]{"abc", 1L},
new Object[]{"def", 1L}
),
ImmutableList.of(
new SqlParameter(SqlType.VARCHAR, "a"),
new SqlParameter(SqlType.VARCHAR, "a"),
new SqlParameter(SqlType.INTEGER, 1)
)
);
}
@Test
public void testParametersInCases() throws Exception
{
testQuery(
"SELECT\n"
+ " CASE 'foo'\n"
+ " WHEN ? THEN SUM(cnt) / CAST(? as INT)\n"
+ " WHEN ? THEN SUM(m1) / CAST(? as INT)\n"
+ " WHEN ? THEN SUM(m2) / CAST(? as INT)\n"
+ " END\n"
+ "FROM foo",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.aggregators(aggregators(new DoubleSumAggregatorFactory("a0", "m1")))
.postAggregators(ImmutableList.of(expressionPostAgg("p0", "(\"a0\" / 10)")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(new Object[]{2.1}),
ImmutableList.of(
new SqlParameter(SqlType.VARCHAR, "bar"),
new SqlParameter(SqlType.INTEGER, 10),
new SqlParameter(SqlType.VARCHAR, "foo"),
new SqlParameter(SqlType.INTEGER, 10),
new SqlParameter(SqlType.VARCHAR, "baz"),
new SqlParameter(SqlType.INTEGER, 10)
)
);
}
@Test
public void testTimestamp() throws Exception
{
// with millis
testQuery(
PLANNER_CONFIG_DEFAULT,
QUERY_CONTEXT_DEFAULT,
ImmutableList.of(
new SqlParameter(SqlType.INTEGER, 10),
new SqlParameter(
SqlType.TIMESTAMP,
DateTimes.of("2999-01-01T00:00:00Z").getMillis()
)
),
"SELECT exp(count(*)) + ?, sum(m2) FROM druid.foo WHERE __time >= ?",
CalciteTests.REGULAR_USER_AUTH_RESULT,
ImmutableList.of(Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Intervals.of(
"2999-01-01T00:00:00.000Z/146140482-04-24T15:36:27.903Z")))
.granularity(Granularities.ALL)
.aggregators(aggregators(
new CountAggregatorFactory("a0"),
new DoubleSumAggregatorFactory("a1", "m2")
))
.postAggregators(
expressionPostAgg("p0", "(exp(\"a0\") + 10)")
)
.context(QUERY_CONTEXT_DEFAULT)
.build()),
ImmutableList.of(
new Object[]{11.0, NullHandling.defaultDoubleValue()}
)
);
}
@Test
public void testTimestampString() throws Exception
{
// with timestampstring
testQuery(
PLANNER_CONFIG_DEFAULT,
QUERY_CONTEXT_DEFAULT,
ImmutableList.of(
new SqlParameter(SqlType.INTEGER, 10),
new SqlParameter(
SqlType.TIMESTAMP,
"2999-01-01 00:00:00"
)
),
"SELECT exp(count(*)) + ?, sum(m2) FROM druid.foo WHERE __time >= ?",
CalciteTests.REGULAR_USER_AUTH_RESULT,
ImmutableList.of(Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Intervals.of(
"2999-01-01T00:00:00.000Z/146140482-04-24T15:36:27.903Z")))
.granularity(Granularities.ALL)
.aggregators(aggregators(
new CountAggregatorFactory("a0"),
new DoubleSumAggregatorFactory("a1", "m2")
))
.postAggregators(
expressionPostAgg("p0", "(exp(\"a0\") + 10)")
)
.context(QUERY_CONTEXT_DEFAULT)
.build()),
ImmutableList.of(
new Object[]{11.0, NullHandling.defaultDoubleValue()}
)
);
}
@Test
public void testDate() throws Exception
{
// with date from millis
testQuery(
PLANNER_CONFIG_DEFAULT,
QUERY_CONTEXT_DEFAULT,
ImmutableList.of(
new SqlParameter(SqlType.INTEGER, 10),
new SqlParameter(
SqlType.DATE,
"2999-01-01"
)
),
"SELECT exp(count(*)) + ?, sum(m2) FROM druid.foo WHERE __time >= ?",
CalciteTests.REGULAR_USER_AUTH_RESULT,
ImmutableList.of(Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Intervals.of(
"2999-01-01T00:00:00.000Z/146140482-04-24T15:36:27.903Z")))
.granularity(Granularities.ALL)
.aggregators(aggregators(
new CountAggregatorFactory("a0"),
new DoubleSumAggregatorFactory("a1", "m2")
))
.postAggregators(
expressionPostAgg("p0", "(exp(\"a0\") + 10)")
)
.context(QUERY_CONTEXT_DEFAULT)
.build()),
ImmutableList.of(
new Object[]{11.0, NullHandling.defaultDoubleValue()}
)
);
}
@Test
public void testDoubles() throws Exception
{
testQuery(
"SELECT COUNT(*) FROM druid.foo WHERE cnt > ? and cnt < ?",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.filters(
bound("cnt", "1.1", "100000001", true, true, null, StringComparators.NUMERIC)
)
.aggregators(aggregators(new CountAggregatorFactory("a0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(new Object[]{0L}),
ImmutableList.of(
new SqlParameter(SqlType.DOUBLE, 1.1),
new SqlParameter(SqlType.FLOAT, 100000001.0)
)
);
testQuery(
"SELECT COUNT(*) FROM druid.foo WHERE cnt = ? or cnt = ?",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.filters(
in("cnt", ImmutableList.of("1.0", "100000001"), null)
)
.aggregators(aggregators(new CountAggregatorFactory("a0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{6L}
),
ImmutableList.of(
new SqlParameter(SqlType.DOUBLE, 1.0),
new SqlParameter(SqlType.FLOAT, 100000001.0)
)
);
}
@Test
public void testFloats() throws Exception
{
testQuery(
"SELECT COUNT(*) FROM druid.foo WHERE cnt = ?",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.filters(
selector("cnt", "1.0", null)
)
.aggregators(aggregators(new CountAggregatorFactory("a0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(new Object[]{6L}),
ImmutableList.of(new SqlParameter(SqlType.REAL, 1.0f))
);
}
@Test
public void testLongs() throws Exception
{
testQuery(
"SELECT COUNT(*)\n"
+ "FROM druid.numfoo\n"
+ "WHERE l1 > ?",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE3)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.filters(bound("l1", "3", null, true, false, null, StringComparators.NUMERIC))
.aggregators(aggregators(new CountAggregatorFactory("a0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(new Object[]{2L}),
ImmutableList.of(new SqlParameter(SqlType.BIGINT, 3L))
);
}
@Test
public void testMissingParameter() throws Exception
{
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Parameter: [?0] is not bound");
testQuery(
"SELECT COUNT(*)\n"
+ "FROM druid.numfoo\n"
+ "WHERE l1 > ?",
ImmutableList.of(),
ImmutableList.of(new Object[]{3L}),
ImmutableList.of()
);
}
@Test
public void testPartiallyMissingParameter() throws Exception
{
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Parameter: [?1] is not bound");
testQuery(
"SELECT COUNT(*)\n"
+ "FROM druid.numfoo\n"
+ "WHERE l1 > ? AND f1 = ?",
ImmutableList.of(),
ImmutableList.of(new Object[]{3L}),
ImmutableList.of(new SqlParameter(SqlType.BIGINT, 3L))
);
}
@Test
public void testWrongTypeParameter() throws Exception
{
if (!useDefault) {
// cannot vectorize inline datasource
cannotVectorize();
}
testQuery(
"SELECT COUNT(*)\n"
+ "FROM druid.numfoo\n"
+ "WHERE l1 > ? AND f1 = ?",
useDefault
? ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE3)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.filters(
and(
bound("l1", "3", null, true, false, null, StringComparators.NUMERIC),
selector("f1", useDefault ? "0.0" : null, null)
)
)
.aggregators(aggregators(new CountAggregatorFactory("a0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
)
: ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(
InlineDataSource.fromIterable(
ImmutableList.of(),
RowSignature.builder().add("f1", ValueType.FLOAT).add("l1", ValueType.LONG).build()
)
)
.intervals(querySegmentSpec(Filtration.eternity()))
.aggregators(aggregators(new CountAggregatorFactory("a0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(new Object[]{0L}),
ImmutableList.of(new SqlParameter(SqlType.BIGINT, 3L), new SqlParameter(SqlType.VARCHAR, "wat"))
);
}
@Test
public void testNullParameter() throws Exception
{
cannotVectorize();
// contrived example of using null as an sql parameter to at least test the codepath because lots of things dont
// actually work as null and things like 'IS NULL' fail to parse in calcite if expressed as 'IS ?'
// this will optimize out the 3rd argument because 2nd argument will be constant and not null
testQuery(
"SELECT COALESCE(dim2, ?, ?), COUNT(*) FROM druid.foo GROUP BY 1\n",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(CalciteTests.DATASOURCE1)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
expressionVirtualColumn(
"v0",
"case_searched(notnull(\"dim2\"),\"dim2\",'parameter')",
ValueType.STRING
)
)
.setDimensions(dimensions(new DefaultDimensionSpec("v0", "d0", ValueType.STRING)))
.setAggregatorSpecs(aggregators(new CountAggregatorFactory("a0")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
NullHandling.replaceWithDefault() ?
ImmutableList.of(
new Object[]{"a", 2L},
new Object[]{"abc", 1L},
new Object[]{"parameter", 3L}
) :
ImmutableList.of(
new Object[]{"", 1L},
new Object[]{"a", 2L},
new Object[]{"abc", 1L},
new Object[]{"parameter", 2L}
),
ImmutableList.of(new SqlParameter(SqlType.VARCHAR, "parameter"), new SqlParameter(SqlType.VARCHAR, null))
);
// when converting to rel expression, this will optimize out 2nd argument to coalesce which is null
testQuery(
"SELECT COALESCE(dim2, ?, ?), COUNT(*) FROM druid.foo GROUP BY 1\n",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(CalciteTests.DATASOURCE1)
.setInterval(querySegmentSpec(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
expressionVirtualColumn(
"v0",
"case_searched(notnull(\"dim2\"),\"dim2\",'parameter')",
ValueType.STRING
)
)
.setDimensions(dimensions(new DefaultDimensionSpec("v0", "d0", ValueType.STRING)))
.setAggregatorSpecs(aggregators(new CountAggregatorFactory("a0")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
NullHandling.replaceWithDefault() ?
ImmutableList.of(
new Object[]{"a", 2L},
new Object[]{"abc", 1L},
new Object[]{"parameter", 3L}
) :
ImmutableList.of(
new Object[]{"", 1L},
new Object[]{"a", 2L},
new Object[]{"abc", 1L},
new Object[]{"parameter", 2L}
),
ImmutableList.of(new SqlParameter(SqlType.VARCHAR, null), new SqlParameter(SqlType.VARCHAR, "parameter"))
);
}
}