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]
