This is an automated email from the ASF dual-hosted git repository. xiangfu pushed a commit to branch support_alias_phase_1 in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
commit 5e0a8e3b5f4e69f767acd51d4a1f9707effff804 Author: Xiang Fu <fx19880...@gmail.com> AuthorDate: Sat Jan 25 01:52:06 2020 -0800 Support alias replacement in PinotQuery --- .../apache/pinot/sql/parsers/CalciteSqlParser.java | 47 +++++++++++++++- .../pinot/sql/parsers/CalciteSqlCompilerTest.java | 62 ++++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) 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 b0070b0..584a722 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 @@ -47,6 +47,7 @@ import org.apache.pinot.common.request.DataSource; import org.apache.pinot.common.request.Expression; import org.apache.pinot.common.request.ExpressionType; import org.apache.pinot.common.request.Function; +import org.apache.pinot.common.request.Identifier; import org.apache.pinot.common.request.PinotQuery; import org.apache.pinot.common.utils.request.RequestUtils; import org.apache.pinot.pql.parsers.Pql2Compiler; @@ -101,7 +102,7 @@ public class CalciteSqlParser { private static void validateGroupByClause(PinotQuery pinotQuery) throws SqlCompilationException { - if(pinotQuery.getGroupByList() == null) { + if (pinotQuery.getGroupByList() == null) { return; } // Sanity check group by query: All identifiers in selection list should be also included in group by list. @@ -234,10 +235,54 @@ public class CalciteSqlParser { throw new RuntimeException( "Unable to convert SqlNode: " + sqlNode + " to PinotQuery. Unknown node type: " + sqlNode.getKind()); } + Map<Identifier, Expression> aliasMap = extractAlias(pinotQuery.getSelectList()); + applyAlias(aliasMap, pinotQuery); validate(pinotQuery); return pinotQuery; } + private static void applyAlias(Map<Identifier, Expression> aliasMap, PinotQuery pinotQuery) { + applyAlias(aliasMap, pinotQuery.getFilterExpression()); + for (Expression groupByExpr : pinotQuery.getGroupByList()) { + applyAlias(aliasMap, groupByExpr); + } + for (Expression orderByExpr : pinotQuery.getOrderByList()) { + applyAlias(aliasMap, orderByExpr); + } + } + + private static void applyAlias(Map<Identifier, Expression> aliasMap, Expression expression) { + if (expression == null) { + return; + } + Identifier identifierKey = expression.getIdentifier(); + if ((identifierKey != null) && (aliasMap.containsKey(identifierKey))) { + Expression aliasExpression = aliasMap.get(identifierKey); + expression.setType(aliasExpression.getType()).setIdentifier(aliasExpression.getIdentifier()) + .setFunctionCall(aliasExpression.getFunctionCall()).setLiteral(aliasExpression.getLiteral()); + } + if (expression.getFunctionCall() != null) { + for (Expression operand : expression.getFunctionCall().getOperands()) { + applyAlias(aliasMap, operand); + } + } + } + + private static Map<Identifier, Expression> extractAlias(List<Expression> expressions) { + Map<Identifier, Expression> aliasMap = new HashMap<>(); + for (Expression expression : expressions) { + Function functionCall = expression.getFunctionCall(); + if (functionCall == null) { + continue; + } + if (functionCall.getOperator().equalsIgnoreCase("AS")) { + Expression identifierExpr = functionCall.getOperands().get(1); + aliasMap.put(identifierExpr.getIdentifier(), functionCall.getOperands().get(0)); + } + } + return aliasMap; + } + private static List<String> extractOptionsFromSql(String sql) { List<String> results = new ArrayList<>(); Matcher matcher = OPTIONS_REGEX_PATTEN.matcher(sql); 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 383863d..3b771ca 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 @@ -887,4 +887,66 @@ public class CalciteSqlCompilerTest { Assert.assertTrue(e.getMessage().contains("is not allowed in GROUP BY clause.")); } } + + @Test + public void testAliasQuery() { + String sql; + PinotQuery pinotQuery; + // Valid alias in query. + sql = + "select secondsSinceEpoch, sum(rsvp_count) as sum_rsvp_count, count(*) as cnt from meetupRsvp group by dateConvert(secondsSinceEpoch) order by cnt, sum_rsvp_count DESC limit 50"; + pinotQuery = CalciteSqlParser.compileToPinotQuery(sql); + Assert.assertEquals(pinotQuery.getSelectListSize(), 3); + Assert.assertEquals(pinotQuery.getGroupByListSize(), 1); + Assert.assertEquals(pinotQuery.getOrderByListSize(), 2); + Assert.assertEquals(pinotQuery.getOrderByList().get(0).getFunctionCall().getOperator(), "ASC"); + Assert.assertEquals( + pinotQuery.getOrderByList().get(0).getFunctionCall().getOperands().get(0).getFunctionCall().getOperator(), + "COUNT"); + Assert.assertEquals( + pinotQuery.getOrderByList().get(0).getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(0) + .getIdentifier().getName(), "*"); + Assert.assertEquals(pinotQuery.getOrderByList().get(1).getFunctionCall().getOperator(), "DESC"); + Assert.assertEquals( + pinotQuery.getOrderByList().get(1).getFunctionCall().getOperands().get(0).getFunctionCall().getOperator(), + "SUM"); + Assert.assertEquals( + pinotQuery.getOrderByList().get(1).getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(0) + .getIdentifier().getName(), "rsvp_count"); + + sql = + "select secondsSinceEpoch/86400 AS daysSinceEpoch, sum(rsvp_count) as sum_rsvp_count, count(*) as cnt from meetupRsvp where daysSinceEpoch = 18523 group by daysSinceEpoch order by cnt, sum_rsvp_count DESC limit 50"; + pinotQuery = CalciteSqlParser.compileToPinotQuery(sql); + Assert.assertEquals(pinotQuery.getSelectListSize(), 3); + Assert.assertEquals(pinotQuery.getFilterExpression().getFunctionCall().getOperator(), "EQUALS"); + Assert.assertEquals( + pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperator(), + "DIVIDE"); + Assert.assertEquals( + pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(0) + .getIdentifier().getName(), "secondsSinceEpoch"); + Assert.assertEquals( + pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(1) + .getLiteral().getLongValue(), 86400); + Assert.assertEquals( + pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getLiteral().getLongValue(), 18523); + Assert.assertEquals(pinotQuery.getGroupByListSize(), 1); + Assert.assertEquals(pinotQuery.getGroupByList().get(0).getFunctionCall().getOperator(), "DIVIDE"); + Assert.assertEquals( + pinotQuery.getGroupByList().get(0).getFunctionCall().getOperands().get(0).getIdentifier().getName(), + "secondsSinceEpoch"); + Assert.assertEquals( + pinotQuery.getGroupByList().get(0).getFunctionCall().getOperands().get(1).getLiteral().getLongValue(), 86400); + Assert.assertEquals(pinotQuery.getOrderByListSize(), 2); + + // Invalid groupBy clause shouldn't contain aggregate expression, like sum(rsvp_count), count(*). + try { + sql = "select sum(rsvp_count), count(*) as cnt from meetupRsvp group by group_country, cnt limit 50"; + CalciteSqlParser.compileToPinotQuery(sql); + Assert.fail("Query should have failed compilation"); + } catch (Exception e) { + Assert.assertTrue(e instanceof SqlCompilationException); + Assert.assertTrue(e.getMessage().contains("is not allowed in GROUP BY clause.")); + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org