From 55ecc709cf1b133a36f68347730cbdcc408d3193 Mon Sep 17 00:00:00 2001 From: Jesus Camacho Rodriguez Date: Thu, 29 Sep 2016 15:20:20 +0100 Subject: [PATCH] [CALCITE-1402] Druid Filter translation incorrect if input reference is in RHS of comparison --- .../calcite/adapter/druid/DruidQuery.java | 49 +++++++++++++------ .../apache/calcite/test/DruidAdapterIT.java | 13 +++++ 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java index fb48557f6a26..b5d6e30a7c2d 100644 --- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java +++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java @@ -50,6 +50,7 @@ import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexUtil; import org.apache.calcite.runtime.Hook; import org.apache.calcite.schema.ScannableTable; import org.apache.calcite.sql.type.SqlTypeName; @@ -834,35 +835,55 @@ String translate(RexNode e, boolean set) { } } - private JsonFilter translateFilter(RexNode e) { + @SuppressWarnings("incomplete-switch") private JsonFilter translateFilter(RexNode e) { final RexCall call; switch (e.getKind()) { case EQUALS: - return new JsonSelector("selector", tr(e, 0), tr(e, 1)); case NOT_EQUALS: - return new JsonCompositeFilter("not", - ImmutableList.of(new JsonSelector("selector", tr(e, 0), tr(e, 1)))); case GREATER_THAN: - return new JsonBound("bound", tr(e, 0), tr(e, 1), true, null, false, - false); case GREATER_THAN_OR_EQUAL: - return new JsonBound("bound", tr(e, 0), tr(e, 1), false, null, false, - false); case LESS_THAN: - return new JsonBound("bound", tr(e, 0), null, false, tr(e, 1), true, - false); case LESS_THAN_OR_EQUAL: - return new JsonBound("bound", tr(e, 0), null, false, tr(e, 1), false, - false); + call = (RexCall) e; + int posRef; + int posConstant; + if (RexUtil.isConstant(call.getOperands().get(1))) { + posRef = 0; + posConstant = 1; + } else if (RexUtil.isConstant(call.getOperands().get(0))) { + posRef = 1; + posConstant = 0; + } else { + throw new AssertionError("it is not a valid comparison: " + e); + } + switch (e.getKind()) { + case EQUALS: + return new JsonSelector("selector", tr(e, posRef), tr(e, posConstant)); + case NOT_EQUALS: + return new JsonCompositeFilter("not", + ImmutableList.of(new JsonSelector("selector", tr(e, posRef), tr(e, posConstant)))); + case GREATER_THAN: + return new JsonBound("bound", tr(e, posRef), tr(e, posConstant), true, null, false, + false); + case GREATER_THAN_OR_EQUAL: + return new JsonBound("bound", tr(e, posRef), tr(e, posConstant), false, null, false, + false); + case LESS_THAN: + return new JsonBound("bound", tr(e, posRef), null, false, tr(e, posConstant), true, + false); + case LESS_THAN_OR_EQUAL: + return new JsonBound("bound", tr(e, posRef), null, false, tr(e, posConstant), false, + false); + } + break; case AND: case OR: case NOT: call = (RexCall) e; return new JsonCompositeFilter(e.getKind().toString().toLowerCase(), translateFilters(call.getOperands())); - default: - throw new AssertionError("cannot translate filter: " + e); } + throw new AssertionError("cannot translate filter: " + e); } private String tr(RexNode call, int index) { 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 617321165f89..f88d8fb33ecf 100644 --- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java +++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java @@ -928,6 +928,19 @@ public Void apply(ResultSet resultSet) { .returnsUnordered("C=6588"); } + @Test public void testFilterSwapped() { + String sql = "select \"state_province\"\n" + + "from \"foodmart\"\n" + + "where 'High Top Dried Mushrooms' = \"product_name\""; + final String explain = "EnumerableInterpreter\n" + + " DruidQuery(table=[[foodmart, foodmart]], intervals=[[1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z]], filter=[=('High Top Dried Mushrooms', CAST($3):VARCHAR(24) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\")], projects=[[$30]])"; + final String druidQuery = "'filter':{'type':'selector','dimension':'product_name'," + + "'value':'High Top Dried Mushrooms'}"; + sql(sql) + .explainContains(explain) + .queryContains(druidChecker(druidQuery)); + } + /** Tests a query that exposed several bugs in the interpreter. */ @Test public void testWhereGroupBy() { String sql = "select \"wikiticker\".\"countryName\" as \"c0\",\n"