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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to