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