Repository: calcite Updated Branches: refs/heads/master 93a3aaedd -> e07e8ad9f
[CALCITE-2019] Druid's time column is not Null all the time thus Push count(druid_time_column) as count(*) (Slim Bouguerra) Close apache/calcite#551 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/e07e8ad9 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/e07e8ad9 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/e07e8ad9 Branch: refs/heads/master Commit: e07e8ad9fa9357b954cf967b95c7130a15c17b20 Parents: 93a3aae Author: Slim <[email protected]> Authored: Fri Oct 20 14:29:39 2017 -0700 Committer: Michael Mior <[email protected]> Committed: Wed Nov 8 11:07:50 2017 -0500 ---------------------------------------------------------------------- .../calcite/adapter/druid/DruidTable.java | 23 ++++++++++++++++---- .../org/apache/calcite/test/DruidAdapterIT.java | 19 +++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/e07e8ad9/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java ---------------------------------------------------------------------- diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java index ff1f3e8..1993789 100644 --- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java +++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java @@ -136,9 +136,14 @@ public class DruidTable extends AbstractTable implements TranslatableTable { Map<String, List<ComplexMetric>> complexMetrics) { final ImmutableMap<String, SqlTypeName> fields = ImmutableMap.copyOf(fieldMap); - return new DruidTable(druidSchema, dataSourceName, - new MapRelProtoDataType(fields), ImmutableSet.copyOf(metricNameSet), - timestampColumnName, intervals, complexMetrics, fieldMap); + return new DruidTable(druidSchema, + dataSourceName, + new MapRelProtoDataType(fields, timestampColumnName), + ImmutableSet.copyOf(metricNameSet), + timestampColumnName, + intervals, + complexMetrics, + fieldMap); } /** @@ -244,15 +249,25 @@ public class DruidTable extends AbstractTable implements TranslatableTable { * field names and types. */ private static class MapRelProtoDataType implements RelProtoDataType { private final ImmutableMap<String, SqlTypeName> fields; + private final String timestampColumn; MapRelProtoDataType(ImmutableMap<String, SqlTypeName> fields) { this.fields = fields; + this.timestampColumn = DruidTable.DEFAULT_TIMESTAMP_COLUMN; + } + + MapRelProtoDataType(ImmutableMap<String, SqlTypeName> fields, String timestampColumn) { + this.fields = fields; + this.timestampColumn = timestampColumn; } public RelDataType apply(RelDataTypeFactory typeFactory) { final RelDataTypeFactory.Builder builder = typeFactory.builder(); for (Map.Entry<String, SqlTypeName> field : fields.entrySet()) { - builder.add(field.getKey(), field.getValue()).nullable(true); + final String key = field.getKey(); + builder.add(key, field.getValue()) + // Druid's time column is always not null and the only column called __time. + .nullable(!timestampColumn.equals(key)); } return builder.build(); } http://git-wip-us.apache.org/repos/asf/calcite/blob/e07e8ad9/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java ---------------------------------------------------------------------- diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java index a8d0203..36c866e 100644 --- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java +++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java @@ -280,7 +280,7 @@ public class DruidAdapterIT { + "group by \"page\", floor(\"__time\" to DAY)\n" + "order by \"s\" desc"; final String explain = "PLAN=EnumerableInterpreter\n" - + " BindableProject(s=[$2], page=[$0], day=[CAST($1):TIMESTAMP(0)])\n" + + " BindableProject(s=[$2], page=[$0], day=[CAST($1):TIMESTAMP(0) NOT NULL])\n" + " DruidQuery(table=[[wiki, wikiticker]], " + "intervals=[[1900-01-01T00:00:00.000/3000-01-01T00:00:00.000]], projects=[[$17, FLOOR" + "($0, FLAG(DAY)), $1]], groups=[{0, 1}], aggs=[[SUM($2)]], sort0=[2], dir0=[DESC])"; @@ -361,7 +361,7 @@ public class DruidAdapterIT { + "where \"__time\" < '2015-10-12 00:00:00 UTC')"; final String explain = "PLAN=" + "EnumerableInterpreter\n" - + " BindableProject(__time=[CAST($0):TIMESTAMP(0)])\n" + + " BindableProject(__time=[CAST($0):TIMESTAMP(0) NOT NULL)\n" + " DruidQuery(table=[[wiki, wikiticker]], " + "intervals=[[1900-01-01T00:00:00.000/2015-10-12T00:00:00.000]], " + "groups=[{0}], aggs=[[]])\n"; @@ -394,7 +394,7 @@ public class DruidAdapterIT { // 1 timestamp, 2 float measure, 1 int measure, 88 dimensions assertThat(map.keySet().size(), is(4)); assertThat(map.values().size(), is(92)); - assertThat(map.get("TIMESTAMP_WITH_LOCAL_TIME_ZONE(0)").size(), is(1)); + assertThat(map.get("TIMESTAMP_WITH_LOCAL_TIME_ZONE(0) NOT NULL").size(), is(1)); assertThat(map.get("DOUBLE").size(), is(2)); assertThat(map.get("BIGINT").size(), is(1)); assertThat(map.get(VARCHAR_TYPE).size(), is(88)); @@ -1434,7 +1434,7 @@ public class DruidAdapterIT { String plan = "BindableProject(countryName=[$0], EXPR$1=[$1], C=[CAST($2):INTEGER NOT NULL])\n" + " BindableSort(sort0=[$2], dir0=[ASC], fetch=[5])\n" + " BindableAggregate(group=[{0, 1}], agg#0=[COUNT()])\n" - + " BindableProject(countryName=[$1], EXPR$1=[FLOOR(CAST($0):TIMESTAMP(0), FLAG(DAY))])\n" + + " BindableProject(countryName=[$1], EXPR$1=[FLOOR(CAST($0):TIMESTAMP(0) NOT NULL, FLAG(DAY))])\n" + " BindableFilter(condition=[AND(>=(FLOOR($0, FLAG(DAY)), 1997-01-01 00:00:00), <(FLOOR($0, FLAG(DAY)), 1997-09-01 00:00:00))])\n" + " DruidQuery(table=[[wiki, wiki]], intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], projects=[[$0, $5]])"; // NOTE: Druid query only has countryName as the dimension @@ -1938,7 +1938,7 @@ public class DruidAdapterIT { sql(sqlQuery) .explainContains("PLAN=EnumerableInterpreter\n" + " BindableSort(sort0=[$1], dir0=[DESC])\n" - + " BindableProject(C=[$1], S=[$2], EXPR$2=[CAST($0):TIMESTAMP(0)])\n" + + " BindableProject(C=[$1], S=[$2], EXPR$2=[CAST($0):TIMESTAMP(0) NOT NULL])\n" + " DruidQuery(table=[[foodmart, foodmart]], " + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], projects=[[FLOOR($0, " + "FLAG(MONTH)), $89]], groups=[{0}], aggs=[[COUNT(), SUM($1)]])") @@ -2901,6 +2901,15 @@ public class DruidAdapterIT { .explainContains(plan3); } + @Test + public void testCountWithNonNull() { + final String sql = "select count(\"timestamp\") from \"foodmart\"\n"; + final String druidQuery = "{'queryType':'timeseries','dataSource':'foodmart'"; + sql(sql) + .returnsUnordered("EXPR$0=86829") + .queryContains(druidChecker(druidQuery)); + } + /** * Test to make sure the "not" filter has only 1 field, rather than an array of fields. */
