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"