You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by xi...@apache.org on 2020/10/17 21:20:32 UTC

[incubator-pinot] 01/01: Support using ordinals in GROUP BY and ORDER BY clause

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

xiangfu pushed a commit to branch support_ordinals_in_sql
in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git

commit 0dc43e473389d043bb2f5bb35f9df743310f2488
Author: Xiang Fu <fx...@gmail.com>
AuthorDate: Sat Oct 17 14:19:59 2020 -0700

    Support using ordinals in GROUP BY and ORDER BY clause
---
 .../apache/pinot/sql/parsers/CalciteSqlParser.java | 36 ++++++++++++++++++++++
 .../pinot/sql/parsers/CalciteSqlCompilerTest.java  | 26 ++++++++++++++++
 2 files changed, 62 insertions(+)

diff --git a/pinot-common/src/main/java/org/apache/pinot/sql/parsers/CalciteSqlParser.java b/pinot-common/src/main/java/org/apache/pinot/sql/parsers/CalciteSqlParser.java
index 5275a1a..29ab482 100644
--- a/pinot-common/src/main/java/org/apache/pinot/sql/parsers/CalciteSqlParser.java
+++ b/pinot-common/src/main/java/org/apache/pinot/sql/parsers/CalciteSqlParser.java
@@ -356,6 +356,9 @@ public class CalciteSqlParser {
     // Rewrite GroupBy to Distinct
     rewriteNonAggregationGroupByToDistinct(pinotQuery);
 
+    // Update Ordinals
+    applyOrdinals(pinotQuery);
+
     // Update alias
     Map<Identifier, Expression> aliasMap = extractAlias(pinotQuery.getSelectList());
     applyAlias(aliasMap, pinotQuery);
@@ -364,6 +367,39 @@ public class CalciteSqlParser {
     validate(aliasMap, pinotQuery);
   }
 
+  private static void applyOrdinals(PinotQuery pinotQuery) {
+    // handle GROUP BY clause
+    for (int i = 0; i < pinotQuery.getGroupByListSize(); i++) {
+      final Expression groupByExpr = pinotQuery.getGroupByList().get(i);
+      if (groupByExpr.isSetLiteral() && groupByExpr.getLiteral().isSetLongValue()) {
+        final int ordinal = (int) groupByExpr.getLiteral().getLongValue();
+        pinotQuery.getGroupByList().set(i, getExpressionFromOrdinal(pinotQuery.getSelectList(), ordinal));
+      }
+    }
+
+    // handle ORDER BY clause
+    for (int i = 0; i < pinotQuery.getOrderByListSize(); i++) {
+      final Expression orderByExpr = pinotQuery.getOrderByList().get(i).getFunctionCall().getOperands().get(0);
+      if (orderByExpr.isSetLiteral() && orderByExpr.getLiteral().isSetLongValue()) {
+        final int ordinal = (int) orderByExpr.getLiteral().getLongValue();
+        pinotQuery.getOrderByList().get(i).getFunctionCall().setOperands(Arrays.asList(getExpressionFromOrdinal(pinotQuery.getSelectList(), ordinal)));
+      }
+    }
+  }
+
+  private static Expression getExpressionFromOrdinal(List<Expression> selectList, int ordinal) {
+    if (ordinal > 0 && ordinal <= selectList.size()) {
+      final Expression expression = selectList.get(ordinal - 1);
+      // If the expression has AS, return the left operand.
+      if (expression.isSetFunctionCall() && expression.getFunctionCall().getOperator().equalsIgnoreCase(SqlKind.AS.name())) {
+        return expression.getFunctionCall().getOperands().get(0);
+      }
+      return expression;
+    } else {
+      throw new SqlCompilationException(String.format("Expected Ordinal value to be between 1 and %d.", selectList.size()));
+    }
+  }
+
   /**
    * Rewrite non-aggregate group by query to distinct query.
    * E.g.
diff --git a/pinot-common/src/test/java/org/apache/pinot/sql/parsers/CalciteSqlCompilerTest.java b/pinot-common/src/test/java/org/apache/pinot/sql/parsers/CalciteSqlCompilerTest.java
index c025d6b..42e0f20 100644
--- a/pinot-common/src/test/java/org/apache/pinot/sql/parsers/CalciteSqlCompilerTest.java
+++ b/pinot-common/src/test/java/org/apache/pinot/sql/parsers/CalciteSqlCompilerTest.java
@@ -1558,6 +1558,32 @@ public class CalciteSqlCompilerTest {
   }
 
   @Test
+  public void testOrdinalsQueryRewrite() {
+    String query = "SELECT foo, bar, count(*) FROM t GROUP BY 1, 2 ORDER BY 1, 2 DESC";
+    PinotQuery pinotQuery = CalciteSqlParser.compileToPinotQuery(query);
+    Assert.assertEquals(pinotQuery.getSelectList().get(0).getIdentifier().getName(), "foo");
+    Assert.assertEquals(pinotQuery.getSelectList().get(1).getIdentifier().getName(), "bar");
+    Assert.assertEquals(pinotQuery.getGroupByList().get(0).getIdentifier().getName(), "foo");
+    Assert.assertEquals(pinotQuery.getGroupByList().get(1).getIdentifier().getName(), "bar");
+    Assert.assertEquals(pinotQuery.getOrderByList().get(0).getFunctionCall().getOperands().get(0).getIdentifier().getName(), "foo");
+    Assert.assertEquals(pinotQuery.getOrderByList().get(1).getFunctionCall().getOperands().get(0).getIdentifier().getName(), "bar");
+
+    query = "SELECT foo, bar, count(*) FROM t GROUP BY 2, 1 ORDER BY 2, 1 DESC";
+    pinotQuery = CalciteSqlParser.compileToPinotQuery(query);
+    Assert.assertEquals(pinotQuery.getSelectList().get(0).getIdentifier().getName(), "foo");
+    Assert.assertEquals(pinotQuery.getSelectList().get(1).getIdentifier().getName(), "bar");
+    Assert.assertEquals(pinotQuery.getGroupByList().get(0).getIdentifier().getName(), "bar");
+    Assert.assertEquals(pinotQuery.getGroupByList().get(1).getIdentifier().getName(), "foo");
+    Assert.assertEquals(pinotQuery.getOrderByList().get(0).getFunctionCall().getOperands().get(0).getIdentifier().getName(), "bar");
+    Assert.assertEquals(pinotQuery.getOrderByList().get(1).getFunctionCall().getOperands().get(0).getIdentifier().getName(), "foo");
+
+    Assert.expectThrows(SqlCompilationException.class,
+        () -> CalciteSqlParser.compileToPinotQuery("SELECT foo, bar, count(*) FROM t GROUP BY 0"));
+    Assert.expectThrows(SqlCompilationException.class,
+        () -> CalciteSqlParser.compileToPinotQuery("SELECT foo, bar, count(*) FROM t GROUP BY 3"));
+  }
+
+  @Test
   public void testNoArgFunction() {
     String query = "SELECT noArgFunc() FROM foo ";
     PinotQuery pinotQuery = CalciteSqlParser.compileToPinotQuery(query);


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org