diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/rel/QueryMaker.java b/sql/src/main/java/org/apache/druid/sql/calcite/rel/QueryMaker.java index 7b7a4d03f6e0..a04280e30c9e 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/rel/QueryMaker.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/rel/QueryMaker.java @@ -61,13 +61,16 @@ import org.apache.druid.sql.calcite.table.RowSignature; import org.joda.time.DateTime; +import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; public class QueryMaker { @@ -424,6 +427,18 @@ private Object coerce(final Object value, final SqlTypeName sqlType) coercedValue = ((NlsString) value).getValue(); } else if (value instanceof Number) { coercedValue = String.valueOf(value); + } else if (value instanceof Collection) { + // Iterate through the collection, coercing each value. Useful for handling selects of multi-value dimensions. + final List valueStrings = ((Collection) value).stream() + .map(v -> (String) coerce(v, sqlType)) + .collect(Collectors.toList()); + + try { + coercedValue = jsonMapper.writeValueAsString(valueStrings); + } + catch (IOException e) { + throw new RuntimeException(e); + } } else { throw new ISE("Cannot coerce[%s] to %s", value.getClass().getName(), sqlType); } diff --git a/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java b/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java index 4831421cdf8a..dee3d2fc6e1e 100644 --- a/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java +++ b/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java @@ -461,6 +461,14 @@ public void testDatabaseMetaDataColumns() throws Exception Pair.of("TYPE_NAME", "VARCHAR"), Pair.of("IS_NULLABLE", "YES") ), + ROW( + Pair.of("TABLE_SCHEM", "druid"), + Pair.of("TABLE_NAME", "foo"), + Pair.of("COLUMN_NAME", "dim3"), + Pair.of("DATA_TYPE", Types.VARCHAR), + Pair.of("TYPE_NAME", "VARCHAR"), + Pair.of("IS_NULLABLE", "YES") + ), ROW( Pair.of("TABLE_SCHEM", "druid"), Pair.of("TABLE_NAME", "foo"), diff --git a/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java b/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java index 77a44dc05974..ce98b7f19873 100644 --- a/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java +++ b/sql/src/test/java/org/apache/druid/sql/avatica/DruidStatementTest.java @@ -127,6 +127,7 @@ public void testSignature() Lists.newArrayList("cnt", "BIGINT", "java.lang.Long"), Lists.newArrayList("dim1", "VARCHAR", "java.lang.String"), Lists.newArrayList("dim2", "VARCHAR", "java.lang.String"), + Lists.newArrayList("dim3", "VARCHAR", "java.lang.String"), Lists.newArrayList("m1", "FLOAT", "java.lang.Float"), Lists.newArrayList("m2", "DOUBLE", "java.lang.Double"), Lists.newArrayList("unique_dim1", "OTHER", "java.lang.Object") diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java index 81bb09129b43..4316ec056083 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java @@ -139,6 +139,8 @@ public class CalciteQueryTest extends CalciteTestBase { + private static final String NULL_VALUE = NullHandling.replaceWithDefault() ? "" : null; + private static final String HLLC_STRING = VersionOneHyperLogLogCollector.class.getName(); private static final Logger log = new Logger(CalciteQueryTest.class); @@ -535,6 +537,7 @@ public void testInformationSchemaColumnsOnTable() throws Exception new Object[]{"cnt", "BIGINT", "NO"}, new Object[]{"dim1", "VARCHAR", "YES"}, new Object[]{"dim2", "VARCHAR", "YES"}, + new Object[]{"dim3", "VARCHAR", "YES"}, new Object[]{"m1", "FLOAT", "NO"}, new Object[]{"m2", "DOUBLE", "NO"}, new Object[]{"unique_dim1", "OTHER", "YES"} @@ -623,26 +626,27 @@ public void testMinOnInformationSchemaColumns() throws Exception @Test public void testSelectStar() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; - String hyperLogLogCollectorClassName = VersionOneHyperLogLogCollector.class.getName(); + String hyperLogLogCollectorClassName = HLLC_STRING; testQuery( "SELECT * FROM druid.foo", ImmutableList.of( newScanQueryBuilder() .dataSource(CalciteTests.DATASOURCE1) .intervals(QSS(Filtration.eternity())) - .columns("__time", "cnt", "dim1", "dim2", "m1", "m2", "unique_dim1") + .columns("__time", "cnt", "dim1", "dim2", "dim3", "m1", "m2", "unique_dim1") .resultFormat(ScanQuery.RESULT_FORMAT_COMPACTED_LIST) .context(QUERY_CONTEXT_DEFAULT) .build() ), ImmutableList.of( - new Object[]{T("2000-01-01"), 1L, "", "a", 1f, 1.0, hyperLogLogCollectorClassName}, - new Object[]{T("2000-01-02"), 1L, "10.1", nullValue, 2f, 2.0, hyperLogLogCollectorClassName}, - new Object[]{T("2000-01-03"), 1L, "2", "", 3f, 3.0, hyperLogLogCollectorClassName}, - new Object[]{T("2001-01-01"), 1L, "1", "a", 4f, 4.0, hyperLogLogCollectorClassName}, - new Object[]{T("2001-01-02"), 1L, "def", "abc", 5f, 5.0, hyperLogLogCollectorClassName}, - new Object[]{T("2001-01-03"), 1L, "abc", nullValue, 6f, 6.0, hyperLogLogCollectorClassName} + new Object[]{T("2000-01-01"), 1L, "", "a", "[\"a\",\"b\"]", 1f, 1.0, hyperLogLogCollectorClassName}, + new Object[]{ + T("2000-01-02"), 1L, "10.1", NULL_VALUE, "[\"b\",\"c\"]", 2f, 2.0, hyperLogLogCollectorClassName + }, + new Object[]{T("2000-01-03"), 1L, "2", "", "d", 3f, 3.0, hyperLogLogCollectorClassName}, + new Object[]{T("2001-01-01"), 1L, "1", "a", "", 4f, 4.0, hyperLogLogCollectorClassName}, + new Object[]{T("2001-01-02"), 1L, "def", "abc", NULL_VALUE, 5f, 5.0, hyperLogLogCollectorClassName}, + new Object[]{T("2001-01-03"), 1L, "abc", NULL_VALUE, NULL_VALUE, 6f, 6.0, hyperLogLogCollectorClassName} ) ); } @@ -676,7 +680,7 @@ public void testSelectStarOnForbiddenTable() throws Exception "abcd", 9999.0f, NullHandling.defaultDoubleValue(), - VersionOneHyperLogLogCollector.class.getName() + HLLC_STRING } ) ); @@ -710,7 +714,7 @@ public void testExplainSelectStar() throws Exception ImmutableList.of(), ImmutableList.of( new Object[]{ - "DruidQueryRel(query=[{\"queryType\":\"scan\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"resultFormat\":\"compactedList\",\"batchSize\":20480,\"limit\":9223372036854775807,\"filter\":null,\"columns\":[\"__time\",\"cnt\",\"dim1\",\"dim2\",\"m1\",\"m2\",\"unique_dim1\"],\"legacy\":false,\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false,\"granularity\":{\"type\":\"all\"}}], signature=[{__time:LONG, cnt:LONG, dim1:STRING, dim2:STRING, m1:FLOAT, m2:DOUBLE, unique_dim1:COMPLEX}])\n" + "DruidQueryRel(query=[{\"queryType\":\"scan\",\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},\"intervals\":{\"type\":\"intervals\",\"intervals\":[\"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z\"]},\"virtualColumns\":[],\"resultFormat\":\"compactedList\",\"batchSize\":20480,\"limit\":9223372036854775807,\"filter\":null,\"columns\":[\"__time\",\"cnt\",\"dim1\",\"dim2\",\"dim3\",\"m1\",\"m2\",\"unique_dim1\"],\"legacy\":false,\"context\":{\"defaultTimeout\":300000,\"maxScatterGatherBytes\":9223372036854775807,\"sqlCurrentTimestamp\":\"2000-01-01T00:00:00Z\"},\"descending\":false,\"granularity\":{\"type\":\"all\"}}], signature=[{__time:LONG, cnt:LONG, dim1:STRING, dim2:STRING, dim3:STRING, m1:FLOAT, m2:DOUBLE, unique_dim1:COMPLEX}])\n" } ) ); @@ -719,23 +723,21 @@ public void testExplainSelectStar() throws Exception @Test public void testSelectStarWithLimit() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; - testQuery( "SELECT * FROM druid.foo LIMIT 2", ImmutableList.of( newScanQueryBuilder() .dataSource(CalciteTests.DATASOURCE1) .intervals(QSS(Filtration.eternity())) - .columns("__time", "cnt", "dim1", "dim2", "m1", "m2", "unique_dim1") + .columns("__time", "cnt", "dim1", "dim2", "dim3", "m1", "m2", "unique_dim1") .limit(2) .resultFormat(ScanQuery.RESULT_FORMAT_COMPACTED_LIST) .context(QUERY_CONTEXT_DEFAULT) .build() ), ImmutableList.of( - new Object[]{T("2000-01-01"), 1L, "", "a", 1.0f, 1.0, VersionOneHyperLogLogCollector.class.getName()}, - new Object[]{T("2000-01-02"), 1L, "10.1", nullValue, 2.0f, 2.0, VersionOneHyperLogLogCollector.class.getName()} + new Object[]{T("2000-01-01"), 1L, "", "a", "[\"a\",\"b\"]", 1.0f, 1.0, HLLC_STRING}, + new Object[]{T("2000-01-02"), 1L, "10.1", NULL_VALUE, "[\"b\",\"c\"]", 2.0f, 2.0, HLLC_STRING} ) ); } @@ -743,7 +745,6 @@ public void testSelectStarWithLimit() throws Exception @Test public void testSelectWithProjection() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; testQuery( "SELECT SUBSTRING(dim2, 1, 1) FROM druid.foo LIMIT 2", ImmutableList.of( @@ -761,7 +762,7 @@ public void testSelectWithProjection() throws Exception ), ImmutableList.of( new Object[]{"a"}, - new Object[]{nullValue} + new Object[]{NULL_VALUE} ) ); } @@ -769,8 +770,6 @@ public void testSelectWithProjection() throws Exception @Test public void testSelectStarWithLimitTimeDescending() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; - testQuery( "SELECT * FROM druid.foo ORDER BY __time DESC LIMIT 2", ImmutableList.of( @@ -779,15 +778,15 @@ public void testSelectStarWithLimitTimeDescending() throws Exception .intervals(QSS(Filtration.eternity())) .granularity(Granularities.ALL) .dimensions(ImmutableList.of("dummy")) - .metrics(ImmutableList.of("__time", "cnt", "dim1", "dim2", "m1", "m2", "unique_dim1")) + .metrics(ImmutableList.of("__time", "cnt", "dim1", "dim2", "dim3", "m1", "m2", "unique_dim1")) .descending(true) .pagingSpec(FIRST_PAGING_SPEC) .context(QUERY_CONTEXT_DEFAULT) .build() ), ImmutableList.of( - new Object[]{T("2001-01-03"), 1L, "abc", nullValue, 6f, 6d, VersionOneHyperLogLogCollector.class.getName()}, - new Object[]{T("2001-01-02"), 1L, "def", "abc", 5f, 5d, VersionOneHyperLogLogCollector.class.getName()} + new Object[]{T("2001-01-03"), 1L, "abc", NULL_VALUE, NULL_VALUE, 6f, 6d, HLLC_STRING}, + new Object[]{T("2001-01-02"), 1L, "def", "abc", NULL_VALUE, 5f, 5d, HLLC_STRING} ) ); } @@ -795,7 +794,6 @@ public void testSelectStarWithLimitTimeDescending() throws Exception @Test public void testSelectStarWithoutLimitTimeAscending() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; testQuery( "SELECT * FROM druid.foo ORDER BY __time", ImmutableList.of( @@ -804,7 +802,7 @@ public void testSelectStarWithoutLimitTimeAscending() throws Exception .intervals(QSS(Filtration.eternity())) .granularity(Granularities.ALL) .dimensions(ImmutableList.of("dummy")) - .metrics(ImmutableList.of("__time", "cnt", "dim1", "dim2", "m1", "m2", "unique_dim1")) + .metrics(ImmutableList.of("__time", "cnt", "dim1", "dim2", "dim3", "m1", "m2", "unique_dim1")) .descending(false) .pagingSpec(FIRST_PAGING_SPEC) .context(QUERY_CONTEXT_DEFAULT) @@ -814,7 +812,7 @@ public void testSelectStarWithoutLimitTimeAscending() throws Exception .intervals(QSS(Filtration.eternity())) .granularity(Granularities.ALL) .dimensions(ImmutableList.of("dummy")) - .metrics(ImmutableList.of("__time", "cnt", "dim1", "dim2", "m1", "m2", "unique_dim1")) + .metrics(ImmutableList.of("__time", "cnt", "dim1", "dim2", "dim3", "m1", "m2", "unique_dim1")) .descending(false) .pagingSpec( new PagingSpec( @@ -827,12 +825,12 @@ public void testSelectStarWithoutLimitTimeAscending() throws Exception .build() ), ImmutableList.of( - new Object[]{T("2000-01-01"), 1L, "", "a", 1f, 1.0, VersionOneHyperLogLogCollector.class.getName()}, - new Object[]{T("2000-01-02"), 1L, "10.1", nullValue, 2f, 2.0, VersionOneHyperLogLogCollector.class.getName()}, - new Object[]{T("2000-01-03"), 1L, "2", "", 3f, 3.0, VersionOneHyperLogLogCollector.class.getName()}, - new Object[]{T("2001-01-01"), 1L, "1", "a", 4f, 4.0, VersionOneHyperLogLogCollector.class.getName()}, - new Object[]{T("2001-01-02"), 1L, "def", "abc", 5f, 5.0, VersionOneHyperLogLogCollector.class.getName()}, - new Object[]{T("2001-01-03"), 1L, "abc", nullValue, 6f, 6.0, VersionOneHyperLogLogCollector.class.getName()} + new Object[]{T("2000-01-01"), 1L, "", "a", "[\"a\",\"b\"]", 1f, 1.0, HLLC_STRING}, + new Object[]{T("2000-01-02"), 1L, "10.1", NULL_VALUE, "[\"b\",\"c\"]", 2f, 2.0, HLLC_STRING}, + new Object[]{T("2000-01-03"), 1L, "2", "", "d", 3f, 3.0, HLLC_STRING}, + new Object[]{T("2001-01-01"), 1L, "1", "a", "", 4f, 4.0, HLLC_STRING}, + new Object[]{T("2001-01-02"), 1L, "def", "abc", NULL_VALUE, 5f, 5.0, HLLC_STRING}, + new Object[]{T("2001-01-03"), 1L, "abc", NULL_VALUE, NULL_VALUE, 6f, 6.0, HLLC_STRING} ) ); } @@ -840,7 +838,6 @@ public void testSelectStarWithoutLimitTimeAscending() throws Exception @Test public void testSelectSingleColumnTwice() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; testQuery( "SELECT dim2 x, dim2 y FROM druid.foo LIMIT 2", ImmutableList.of( @@ -855,7 +852,7 @@ public void testSelectSingleColumnTwice() throws Exception ), ImmutableList.of( new Object[]{"a", "a"}, - new Object[]{nullValue, nullValue} + new Object[]{NULL_VALUE, NULL_VALUE} ) ); } @@ -1497,7 +1494,6 @@ public void testHavingOnRatio() throws Exception @Test public void testGroupByWithSelectProjections() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; testQuery( "SELECT\n" + " dim1," @@ -1517,10 +1513,10 @@ public void testGroupByWithSelectProjections() throws Exception .build() ), ImmutableList.of( - new Object[]{"", nullValue}, - new Object[]{"1", nullValue}, + new Object[]{"", NULL_VALUE}, + new Object[]{"1", NULL_VALUE}, new Object[]{"10.1", "0.1"}, - new Object[]{"2", nullValue}, + new Object[]{"2", NULL_VALUE}, new Object[]{"abc", "bc"}, new Object[]{"def", "ef"} ) @@ -1530,7 +1526,6 @@ public void testGroupByWithSelectProjections() throws Exception @Test public void testGroupByWithSelectAndOrderByProjections() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; testQuery( "SELECT\n" + " dim1," @@ -1570,9 +1565,9 @@ public void testGroupByWithSelectAndOrderByProjections() throws Exception new Object[]{"10.1", "0.1"}, new Object[]{"abc", "bc"}, new Object[]{"def", "ef"}, - new Object[]{"1", nullValue}, - new Object[]{"2", nullValue}, - new Object[]{"", nullValue} + new Object[]{"1", NULL_VALUE}, + new Object[]{"2", NULL_VALUE}, + new Object[]{"", NULL_VALUE} ) ); } @@ -1580,8 +1575,6 @@ public void testGroupByWithSelectAndOrderByProjections() throws Exception @Test public void testTopNWithSelectProjections() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; - testQuery( "SELECT\n" + " dim1," @@ -1604,10 +1597,10 @@ public void testTopNWithSelectProjections() throws Exception .build() ), ImmutableList.of( - new Object[]{"", nullValue}, - new Object[]{"1", nullValue}, + new Object[]{"", NULL_VALUE}, + new Object[]{"1", NULL_VALUE}, new Object[]{"10.1", "0.1"}, - new Object[]{"2", nullValue}, + new Object[]{"2", NULL_VALUE}, new Object[]{"abc", "bc"}, new Object[]{"def", "ef"} ) @@ -1617,7 +1610,6 @@ public void testTopNWithSelectProjections() throws Exception @Test public void testTopNWithSelectAndOrderByProjections() throws Exception { - String nullValue = NullHandling.replaceWithDefault() ? "" : null; testQuery( "SELECT\n" @@ -1646,9 +1638,9 @@ public void testTopNWithSelectAndOrderByProjections() throws Exception new Object[]{"10.1", "0.1"}, new Object[]{"abc", "bc"}, new Object[]{"def", "ef"}, - new Object[]{"1", nullValue}, - new Object[]{"2", nullValue}, - new Object[]{"", nullValue} + new Object[]{"1", NULL_VALUE}, + new Object[]{"2", NULL_VALUE}, + new Object[]{"", NULL_VALUE} ) ); } @@ -2126,15 +2118,15 @@ public void testSelectStarWithDimFilter() throws Exception SELECTOR("dim2", "a", null) ) ) - .columns("__time", "cnt", "dim1", "dim2", "m1", "m2", "unique_dim1") + .columns("__time", "cnt", "dim1", "dim2", "dim3", "m1", "m2", "unique_dim1") .resultFormat(ScanQuery.RESULT_FORMAT_COMPACTED_LIST) .context(QUERY_CONTEXT_DEFAULT) .build() ), ImmutableList.of( - new Object[]{T("2000-01-01"), 1L, "", "a", 1.0f, 1.0d, VersionOneHyperLogLogCollector.class.getName()}, - new Object[]{T("2001-01-01"), 1L, "1", "a", 4.0f, 4.0d, VersionOneHyperLogLogCollector.class.getName()}, - new Object[]{T("2001-01-02"), 1L, "def", "abc", 5.0f, 5.0d, VersionOneHyperLogLogCollector.class.getName()} + new Object[]{T("2000-01-01"), 1L, "", "a", "[\"a\",\"b\"]", 1.0f, 1.0d, HLLC_STRING}, + new Object[]{T("2001-01-01"), 1L, "1", "a", "", 4.0f, 4.0d, HLLC_STRING}, + new Object[]{T("2001-01-02"), 1L, "def", "abc", NULL_VALUE, 5.0f, 5.0d, HLLC_STRING} ) ); } diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/http/SqlResourceTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/http/SqlResourceTest.java index 59374e323bae..ac0cc6e7ca1d 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/http/SqlResourceTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/http/SqlResourceTest.java @@ -262,6 +262,7 @@ public void testArrayResultFormat() throws Exception 1, "", "a", + "[\"a\",\"b\"]", 1.0, 1.0, "org.apache.druid.hll.VersionOneHyperLogLogCollector", @@ -272,6 +273,7 @@ public void testArrayResultFormat() throws Exception 1, "10.1", nullStr, + "[\"b\",\"c\"]", 2.0, 2.0, "org.apache.druid.hll.VersionOneHyperLogLogCollector", @@ -290,12 +292,13 @@ public void testArrayResultFormatWithHeader() throws Exception Assert.assertEquals( ImmutableList.of( - Arrays.asList("__time", "cnt", "dim1", "dim2", "m1", "m2", "unique_dim1", "EXPR$7"), + Arrays.asList("__time", "cnt", "dim1", "dim2", "dim3", "m1", "m2", "unique_dim1", "EXPR$8"), Arrays.asList( "2000-01-01T00:00:00.000Z", 1, "", "a", + "[\"a\",\"b\"]", 1.0, 1.0, "org.apache.druid.hll.VersionOneHyperLogLogCollector", @@ -306,6 +309,7 @@ public void testArrayResultFormatWithHeader() throws Exception 1, "10.1", nullStr, + "[\"b\",\"c\"]", 2.0, 2.0, "org.apache.druid.hll.VersionOneHyperLogLogCollector", @@ -331,6 +335,7 @@ public void testArrayLinesResultFormat() throws Exception 1, "", "a", + "[\"a\",\"b\"]", 1.0, 1.0, "org.apache.druid.hll.VersionOneHyperLogLogCollector", @@ -344,6 +349,7 @@ public void testArrayLinesResultFormat() throws Exception 1, "10.1", nullStr, + "[\"b\",\"c\"]", 2.0, 2.0, "org.apache.druid.hll.VersionOneHyperLogLogCollector", @@ -365,7 +371,7 @@ public void testArrayLinesResultFormatWithHeader() throws Exception Assert.assertEquals(5, lines.size()); Assert.assertEquals( - Arrays.asList("__time", "cnt", "dim1", "dim2", "m1", "m2", "unique_dim1", "EXPR$7"), + Arrays.asList("__time", "cnt", "dim1", "dim2", "dim3", "m1", "m2", "unique_dim1", "EXPR$8"), JSON_MAPPER.readValue(lines.get(0), List.class) ); Assert.assertEquals( @@ -374,6 +380,7 @@ public void testArrayLinesResultFormatWithHeader() throws Exception 1, "", "a", + "[\"a\",\"b\"]", 1.0, 1.0, "org.apache.druid.hll.VersionOneHyperLogLogCollector", @@ -387,6 +394,7 @@ public void testArrayLinesResultFormatWithHeader() throws Exception 1, "10.1", nullStr, + "[\"b\",\"c\"]", 2.0, 2.0, "org.apache.druid.hll.VersionOneHyperLogLogCollector", @@ -406,7 +414,7 @@ public void testObjectResultFormat() throws Exception final Function, Map> transformer = m -> { return Maps.transformEntries( m, - (k, v) -> "EXPR$7".equals(k) || ("dim2".equals(k) && v.toString().isEmpty()) ? nullStr : v + (k, v) -> "EXPR$8".equals(k) || ("dim2".equals(k) && v.toString().isEmpty()) ? nullStr : v ); }; @@ -418,10 +426,11 @@ public void testObjectResultFormat() throws Exception .put("cnt", 1) .put("dim1", "") .put("dim2", "a") + .put("dim3", "[\"a\",\"b\"]") .put("m1", 1.0) .put("m2", 1.0) .put("unique_dim1", "org.apache.druid.hll.VersionOneHyperLogLogCollector") - .put("EXPR$7", "") + .put("EXPR$8", "") .build(), ImmutableMap .builder() @@ -429,10 +438,11 @@ public void testObjectResultFormat() throws Exception .put("cnt", 1) .put("dim1", "10.1") .put("dim2", "") + .put("dim3", "[\"b\",\"c\"]") .put("m1", 2.0) .put("m2", 2.0) .put("unique_dim1", "org.apache.druid.hll.VersionOneHyperLogLogCollector") - .put("EXPR$7", "") + .put("EXPR$8", "") .build() ).stream().map(transformer).collect(Collectors.toList()), doPost( @@ -451,7 +461,7 @@ public void testObjectLinesResultFormat() throws Exception final Function, Map> transformer = m -> { return Maps.transformEntries( m, - (k, v) -> "EXPR$7".equals(k) || ("dim2".equals(k) && v.toString().isEmpty()) ? nullStr : v + (k, v) -> "EXPR$8".equals(k) || ("dim2".equals(k) && v.toString().isEmpty()) ? nullStr : v ); }; final List lines = Splitter.on('\n').splitToList(response); @@ -465,10 +475,11 @@ public void testObjectLinesResultFormat() throws Exception .put("cnt", 1) .put("dim1", "") .put("dim2", "a") + .put("dim3", "[\"a\",\"b\"]") .put("m1", 1.0) .put("m2", 1.0) .put("unique_dim1", "org.apache.druid.hll.VersionOneHyperLogLogCollector") - .put("EXPR$7", "") + .put("EXPR$8", "") .build() ), JSON_MAPPER.readValue(lines.get(0), Object.class) @@ -481,10 +492,11 @@ public void testObjectLinesResultFormat() throws Exception .put("cnt", 1) .put("dim1", "10.1") .put("dim2", "") + .put("dim3", "[\"b\",\"c\"]") .put("m1", 2.0) .put("m2", 2.0) .put("unique_dim1", "org.apache.druid.hll.VersionOneHyperLogLogCollector") - .put("EXPR$7", "") + .put("EXPR$8", "") .build() ), JSON_MAPPER.readValue(lines.get(1), Object.class) @@ -502,8 +514,8 @@ public void testCsvResultFormat() throws Exception Assert.assertEquals( ImmutableList.of( - "2000-01-01T00:00:00.000Z,1,,a,1.0,1.0,org.apache.druid.hll.VersionOneHyperLogLogCollector,", - "2000-01-02T00:00:00.000Z,1,10.1,,2.0,2.0,org.apache.druid.hll.VersionOneHyperLogLogCollector,", + "2000-01-01T00:00:00.000Z,1,,a,\"[\"\"a\"\",\"\"b\"\"]\",1.0,1.0,org.apache.druid.hll.VersionOneHyperLogLogCollector,", + "2000-01-02T00:00:00.000Z,1,10.1,,\"[\"\"b\"\",\"\"c\"\"]\",2.0,2.0,org.apache.druid.hll.VersionOneHyperLogLogCollector,", "", "" ), @@ -520,9 +532,9 @@ public void testCsvResultFormatWithHeaders() throws Exception Assert.assertEquals( ImmutableList.of( - "__time,cnt,dim1,dim2,m1,m2,unique_dim1,EXPR$7", - "2000-01-01T00:00:00.000Z,1,,a,1.0,1.0,org.apache.druid.hll.VersionOneHyperLogLogCollector,", - "2000-01-02T00:00:00.000Z,1,10.1,,2.0,2.0,org.apache.druid.hll.VersionOneHyperLogLogCollector,", + "__time,cnt,dim1,dim2,dim3,m1,m2,unique_dim1,EXPR$8", + "2000-01-01T00:00:00.000Z,1,,a,\"[\"\"a\"\",\"\"b\"\"]\",1.0,1.0,org.apache.druid.hll.VersionOneHyperLogLogCollector,", + "2000-01-02T00:00:00.000Z,1,10.1,,\"[\"\"b\"\",\"\"c\"\"]\",2.0,2.0,org.apache.druid.hll.VersionOneHyperLogLogCollector,", "", "" ), @@ -553,7 +565,7 @@ public void testCannotValidate() throws Exception { final QueryInterruptedException exception = doPost( new SqlQuery( - "SELECT dim3 FROM druid.foo", + "SELECT dim4 FROM druid.foo", ResultFormat.OBJECT, false, null @@ -563,7 +575,7 @@ public void testCannotValidate() throws Exception Assert.assertNotNull(exception); Assert.assertEquals(QueryInterruptedException.UNKNOWN_EXCEPTION, exception.getErrorCode()); Assert.assertEquals(ValidationException.class.getName(), exception.getErrorClass()); - Assert.assertTrue(exception.getMessage().contains("Column 'dim3' not found in any table")); + Assert.assertTrue(exception.getMessage().contains("Column 'dim4' not found in any table")); } @Test diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java b/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java index 68ca422d712b..8ba21cc8992c 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/util/CalciteTests.java @@ -249,7 +249,7 @@ public void configure(final Binder binder) new TimeAndDimsParseSpec( new TimestampSpec(TIMESTAMP_COLUMN, "iso", null), new DimensionsSpec( - DimensionsSpec.getDefaultSchemas(ImmutableList.of("dim1", "dim2")), + DimensionsSpec.getDefaultSchemas(ImmutableList.of("dim1", "dim2", "dim3")), null, null ) @@ -268,22 +268,62 @@ public void configure(final Binder binder) public static final List ROWS1 = ImmutableList.of( createRow( - ImmutableMap.of("t", "2000-01-01", "m1", "1.0", "m2", "1.0", "dim1", "", "dim2", ImmutableList.of("a")) + ImmutableMap.builder() + .put("t", "2000-01-01") + .put("m1", "1.0") + .put("m2", "1.0") + .put("dim1", "") + .put("dim2", ImmutableList.of("a")) + .put("dim3", ImmutableList.of("a", "b")) + .build() ), createRow( - ImmutableMap.of("t", "2000-01-02", "m1", "2.0", "m2", "2.0", "dim1", "10.1", "dim2", ImmutableList.of()) + ImmutableMap.builder() + .put("t", "2000-01-02") + .put("m1", "2.0") + .put("m2", "2.0") + .put("dim1", "10.1") + .put("dim2", ImmutableList.of()) + .put("dim3", ImmutableList.of("b", "c")) + .build() ), createRow( - ImmutableMap.of("t", "2000-01-03", "m1", "3.0", "m2", "3.0", "dim1", "2", "dim2", ImmutableList.of("")) + ImmutableMap.builder() + .put("t", "2000-01-03") + .put("m1", "3.0") + .put("m2", "3.0") + .put("dim1", "2") + .put("dim2", ImmutableList.of("")) + .put("dim3", ImmutableList.of("d")) + .build() ), createRow( - ImmutableMap.of("t", "2001-01-01", "m1", "4.0", "m2", "4.0", "dim1", "1", "dim2", ImmutableList.of("a")) + ImmutableMap.builder() + .put("t", "2001-01-01") + .put("m1", "4.0") + .put("m2", "4.0") + .put("dim1", "1") + .put("dim2", ImmutableList.of("a")) + .put("dim3", ImmutableList.of("")) + .build() ), createRow( - ImmutableMap.of("t", "2001-01-02", "m1", "5.0", "m2", "5.0", "dim1", "def", "dim2", ImmutableList.of("abc")) + ImmutableMap.builder() + .put("t", "2001-01-02") + .put("m1", "5.0") + .put("m2", "5.0") + .put("dim1", "def") + .put("dim2", ImmutableList.of("abc")) + .put("dim3", ImmutableList.of()) + .build() ), createRow( - ImmutableMap.of("t", "2001-01-03", "m1", "6.0", "m2", "6.0", "dim1", "abc") + ImmutableMap.builder() + .put("t", "2001-01-03") + .put("m1", "6.0") + .put("m2", "6.0") + .put("dim1", "abc") + .build() ) );