You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jc...@apache.org on 2017/02/07 19:42:04 UTC

calcite git commit: [CALCITE-1619] CAST is ignored by rules pushing operators into DruidQuery

Repository: calcite
Updated Branches:
  refs/heads/master 08b1dddd5 -> a07c7420b


[CALCITE-1619] CAST is ignored by rules pushing operators into DruidQuery

Close apache/calcite#370


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/a07c7420
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/a07c7420
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/a07c7420

Branch: refs/heads/master
Commit: a07c7420bcf6283441d042ad77dafc929a7e9efe
Parents: 08b1ddd
Author: Jesus Camacho Rodriguez <jc...@apache.org>
Authored: Tue Feb 7 16:31:27 2017 +0000
Committer: Jesus Camacho Rodriguez <jc...@apache.org>
Committed: Tue Feb 7 19:41:16 2017 +0000

----------------------------------------------------------------------
 .../calcite/adapter/druid/DruidQuery.java       | 46 +++++++++++++++---
 .../org/apache/calcite/test/DruidAdapterIT.java | 51 +++++++++++++++++++-
 2 files changed, 87 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/a07c7420/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java
----------------------------------------------------------------------
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 9ed4c8b..9539326 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
@@ -54,6 +54,8 @@ 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.SqlKind;
+import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Litmus;
@@ -190,6 +192,10 @@ public class DruidQuery extends AbstractRelNode implements BindableRel {
   }
 
   boolean isValidFilter(RexNode e) {
+    return isValidFilter(e, false);
+  }
+
+  boolean isValidFilter(RexNode e, boolean boundedComparator) {
     switch (e.getKind()) {
     case INPUT_REF:
     case LITERAL:
@@ -199,28 +205,52 @@ public class DruidQuery extends AbstractRelNode implements BindableRel {
     case NOT:
     case EQUALS:
     case NOT_EQUALS:
+    case IN:
+      return areValidFilters(((RexCall) e).getOperands(), false);
     case LESS_THAN:
     case LESS_THAN_OR_EQUAL:
     case GREATER_THAN:
     case GREATER_THAN_OR_EQUAL:
     case BETWEEN:
-    case IN:
+      return areValidFilters(((RexCall) e).getOperands(), true);
     case CAST:
-      return areValidFilters(((RexCall) e).getOperands());
+      return isValidCast((RexCall) e, boundedComparator);
     default:
       return false;
     }
   }
 
-  private boolean areValidFilters(List<RexNode> es) {
+  private boolean areValidFilters(List<RexNode> es, boolean boundedComparator) {
     for (RexNode e : es) {
-      if (!isValidFilter(e)) {
+      if (!isValidFilter(e, boundedComparator)) {
         return false;
       }
     }
     return true;
   }
 
+  private boolean isValidCast(RexCall e, boolean boundedComparator) {
+    assert e.isA(SqlKind.CAST);
+    if (e.getOperands().get(0).isA(SqlKind.INPUT_REF)
+        && e.getType().getFamily() == SqlTypeFamily.CHARACTER) {
+      // CAST of input to character type
+      return true;
+    }
+    if (e.getOperands().get(0).isA(SqlKind.INPUT_REF)
+        && e.getType().getFamily() == SqlTypeFamily.NUMERIC
+        && boundedComparator) {
+      // CAST of input to numeric type, it is part of a bounded comparison
+      return true;
+    }
+    if (e.getOperands().get(0).isA(SqlKind.LITERAL)
+        && e.getType().getFamily() == SqlTypeFamily.TIMESTAMP) {
+      // CAST of literal to timestamp type
+      return true;
+    }
+    // Currently other CAST operations cannot be pushed to Druid
+    return false;
+  }
+
   /** Returns whether a signature represents an sequence of relational operators
    * that can be translated into a valid Druid query. */
   static boolean isValidSignature(String signature) {
@@ -873,16 +903,16 @@ public class DruidQuery extends AbstractRelNode implements BindableRel {
               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);
+              call.getOperands().get(posRef).getType().getFamily() == SqlTypeFamily.NUMERIC);
         case GREATER_THAN_OR_EQUAL:
           return new JsonBound("bound", tr(e, posRef), tr(e, posConstant), false, null, false,
-              false);
+              call.getOperands().get(posRef).getType().getFamily() == SqlTypeFamily.NUMERIC);
         case LESS_THAN:
           return new JsonBound("bound", tr(e, posRef), null, false, tr(e, posConstant), true,
-              false);
+              call.getOperands().get(posRef).getType().getFamily() == SqlTypeFamily.NUMERIC);
         case LESS_THAN_OR_EQUAL:
           return new JsonBound("bound", tr(e, posRef), null, false, tr(e, posConstant), false,
-              false);
+              call.getOperands().get(posRef).getType().getFamily() == SqlTypeFamily.NUMERIC);
         }
         break;
       case AND:

http://git-wip-us.apache.org/repos/asf/calcite/blob/a07c7420/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 5c28178..3fc8394 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
@@ -678,9 +678,9 @@ public class DruidAdapterIT {
 
   /** Tests a query that contains no GROUP BY and is therefore executed as a
    * Druid "select" query. */
-  @Test public void testFilterSortDesc() {
+  @Test public void testFilterSortDesc1() {
     final String sql = "select * from \"foodmart\"\n"
-        + "where \"product_id\" BETWEEN 1500 AND 1502\n"
+        + "where \"product_id\" BETWEEN '1500' AND '1502'\n"
         + "order by \"state_province\" desc, \"product_id\"";
     final String druidQuery = "{'queryType':'select','dataSource':'foodmart',"
         + "'descending':false,'intervals':['1900-01-09T00:00:00.000/2992-01-10T00:00:00.000'],"
@@ -723,6 +723,53 @@ public class DruidAdapterIT {
         .queryContains(druidChecker(druidQuery));
   }
 
+  /** Tests a query that contains no GROUP BY and is therefore executed as a
+   * Druid "select" query. */
+  @Test public void testFilterSortDesc2() {
+    final String sql = "select * from \"foodmart\"\n"
+        + "where \"product_id\" BETWEEN 1500 AND 1502\n"
+        + "order by \"state_province\" desc, \"product_id\"";
+    final String druidQuery = "{'queryType':'select','dataSource':'foodmart',"
+        + "'descending':false,'intervals':['1900-01-09T00:00:00.000/2992-01-10T00:00:00.000'],"
+        + "'filter':{'type':'and','fields':["
+        + "{'type':'bound','dimension':'product_id','lower':'1500','lowerStrict':false,'alphaNumeric':true},"
+        + "{'type':'bound','dimension':'product_id','upper':'1502','upperStrict':false,'alphaNumeric':true}]},"
+        + "'dimensions':['product_id','brand_name','product_name','SKU','SRP','gross_weight','net_weight',"
+        + "'recyclable_package','low_fat','units_per_case','cases_per_pallet','shelf_width','shelf_height',"
+        + "'shelf_depth','product_class_id','product_subcategory','product_category','product_department',"
+        + "'product_family','customer_id','account_num','lname','fname','mi','address1','address2','address3',"
+        + "'address4','city','state_province','postal_code','country','customer_region_id','phone1','phone2',"
+        + "'birthdate','marital_status','yearly_income','gender','total_children','num_children_at_home',"
+        + "'education','date_accnt_opened','member_card','occupation','houseowner','num_cars_owned',"
+        + "'fullname','promotion_id','promotion_district_id','promotion_name','media_type','cost','start_date',"
+        + "'end_date','store_id','store_type','region_id','store_name','store_number','store_street_address',"
+        + "'store_city','store_state','store_postal_code','store_country','store_manager','store_phone',"
+        + "'store_fax','first_opened_date','last_remodel_date','store_sqft','grocery_sqft','frozen_sqft',"
+        + "'meat_sqft','coffee_bar','video_store','salad_bar','prepared_food','florist','time_id','the_day',"
+        + "'the_month','the_year','day_of_month','week_of_year','month_of_year','quarter','fiscal_period'],"
+        + "'metrics':['unit_sales','store_sales','store_cost'],'granularity':'all',"
+        + "'pagingSpec':{'threshold':16384,'fromNext':true},'context':{'druid.query.fetch':false}}";
+    sql(sql)
+        .limit(4)
+        .returns(
+            new Function<ResultSet, Void>() {
+              public Void apply(ResultSet resultSet) {
+                try {
+                  for (int i = 0; i < 4; i++) {
+                    assertTrue(resultSet.next());
+                    assertThat(resultSet.getString("product_name"),
+                        is("Fort West Dried Apricots"));
+                  }
+                  assertFalse(resultSet.next());
+                  return null;
+                } catch (SQLException e) {
+                  throw new RuntimeException(e);
+                }
+              }
+            })
+        .queryContains(druidChecker(druidQuery));
+  }
+
   /** Tests a query whose filter removes all rows. */
   @Test public void testFilterOutEverything() {
     final String sql = "select * from \"foodmart\"\n"