This is an automated email from the ASF dual-hosted git repository.

sereda pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new b727f3b  [CALCITE-3056] Elasticsearch adapter. Invalid result with 
cast function on raw queries
b727f3b is described below

commit b727f3b04286dd39fddb25a9905819449d27475b
Author: Andrei Sereda <[email protected]>
AuthorDate: Wed May 8 01:52:41 2019 -0400

    [CALCITE-3056] Elasticsearch adapter. Invalid result with cast function on 
raw queries
    
    Fix queries of type (with elastic adapter):
    
    ```sql
    select max(cast(_MAP['foo'] as integer)) from elastic
    ```
---
 .../adapter/elasticsearch/ElasticsearchRules.java  | 28 ++++++++++++++++++----
 .../adapter/elasticsearch/AggregationTest.java     | 18 ++++++++++++++
 2 files changed, 42 insertions(+), 4 deletions(-)

diff --git 
a/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchRules.java
 
b/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchRules.java
index b7c0e34..ed20aa7 100644
--- 
a/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchRules.java
+++ 
b/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchRules.java
@@ -66,7 +66,7 @@ class ElasticsearchRules {
    * @param call current relational expression
    * @return literal value
    */
-  static String isItem(RexCall call) {
+  private static String isItemCall(RexCall call) {
     if (call.getOperator() != SqlStdOperatorTable.ITEM) {
       return null;
     }
@@ -82,15 +82,33 @@ class ElasticsearchRules {
     return null;
   }
 
+  /**
+   * Checks if current node represents item access as in {@code _MAP['foo']} or
+   * {@code cast(_MAP['foo'] as integer)}
+   *
+   * @return true if expression is item, false otherwise
+   */
   static boolean isItem(RexNode node) {
     final Boolean result = node.accept(new RexVisitorImpl<Boolean>(false) {
       @Override public Boolean visitCall(final RexCall call) {
-        return isItem(call) != null;
+        return isItemCall(uncast(call)) != null;
       }
     });
     return Boolean.TRUE.equals(result);
   }
 
+  /**
+   * Unwraps cast expressions from current call. {@code cast(cast(expr))} 
becomes {@code expr}.
+   */
+  private static RexCall uncast(RexCall maybeCast) {
+    if (maybeCast.getKind() == SqlKind.CAST && maybeCast.getOperands().get(0) 
instanceof RexCall) {
+      return uncast((RexCall) maybeCast.getOperands().get(0));
+    }
+
+    // not a cast
+    return maybeCast;
+  }
+
   static List<String> elasticsearchFieldNames(final RelDataType rowType) {
     return SqlValidatorUtil.uniquify(
         new AbstractList<String>() {
@@ -144,15 +162,17 @@ class ElasticsearchRules {
     }
 
     @Override public String visitCall(RexCall call) {
-      final String name = isItem(call);
+      final String name = isItemCall(call);
       if (name != null) {
         return name;
       }
 
       final List<String> strings = visitList(call.operands);
+
       if (call.getKind() == SqlKind.CAST) {
-        return strings.get(0).startsWith("$") ? strings.get(0).substring(1) : 
strings.get(0);
+        return call.getOperands().get(0).accept(this);
       }
+
       if (call.getOperator() == SqlStdOperatorTable.ITEM) {
         final RexNode op1 = call.getOperands().get(1);
         if (op1 instanceof RexLiteral && op1.getType().getSqlTypeName() == 
SqlTypeName.INTEGER) {
diff --git 
a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/AggregationTest.java
 
b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/AggregationTest.java
index 5b29e71..25fcd17 100644
--- 
a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/AggregationTest.java
+++ 
b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/AggregationTest.java
@@ -352,6 +352,24 @@ public class AggregationTest {
                           "cat1=b; EXPR$1=1",
                           "cat1=null; EXPR$1=1");
   }
+
+  /**
+   * {@code select max(cast(_MAP['foo'] as integer)) from tbl}
+   */
+  @Test
+  public void aggregationWithCast() {
+    CalciteAssert.that()
+        .with(newConnectionFactory())
+        .query(
+            String.format(Locale.ROOT, "select max(cast(_MAP['val1'] as 
integer)) as v1, "
+                + "min(cast(_MAP['val2'] as integer)) as v2 from elastic.%s", 
NAME))
+        .queryContains(
+            ElasticsearchChecker.elasticsearchChecker("_source:false, size:0",
+            "aggregations:{'v1.max.field': 'val1'",
+            "'v2.min.field': 'val2'}"))
+        .returnsUnordered("v1=7; v2=5");
+
+  }
 }
 
 // End AggregationTest.java

Reply via email to