This is an automated email from the ASF dual-hosted git repository.
jackie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new e9beb340ec Add tests for PredicateComparisonRewriter (#14166)
e9beb340ec is described below
commit e9beb340ec05ebe2937bcec4633c64f4424e3336
Author: Yash Mayya <[email protected]>
AuthorDate: Tue Oct 8 06:40:20 2024 +0530
Add tests for PredicateComparisonRewriter (#14166)
---
.../apache/pinot/sql/parsers/CalciteSqlParser.java | 14 +-
.../rewriter/PredicateComparisonRewriterTest.java | 182 +++++++++++++++++++++
2 files changed, 195 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 88eea1b027..7ef6151e6e 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
@@ -161,6 +161,13 @@ public class CalciteSqlParser {
return compileToPinotQuery(compileToSqlNodeAndOptions(sql));
}
+ /**
+ * Should only be used for testing query rewriters.
+ */
+ public static PinotQuery compileToPinotQueryWithoutRewrites(String sql) {
+ return compileWithoutRewrite(compileToSqlNodeAndOptions(sql).getSqlNode());
+ }
+
public static PinotQuery compileToPinotQuery(SqlNodeAndOptions
sqlNodeAndOptions) {
// Compile SqlNode into PinotQuery
PinotQuery pinotQuery =
compileSqlNodeToPinotQuery(sqlNodeAndOptions.getSqlNode());
@@ -416,6 +423,12 @@ public class CalciteSqlParser {
}
public static PinotQuery compileSqlNodeToPinotQuery(SqlNode sqlNode) {
+ PinotQuery pinotQuery = compileWithoutRewrite(sqlNode);
+ queryRewrite(pinotQuery);
+ return pinotQuery;
+ }
+
+ private static PinotQuery compileWithoutRewrite(SqlNode sqlNode) {
PinotQuery pinotQuery = new PinotQuery();
if (sqlNode instanceof SqlExplain) {
// Extract sql node for the query
@@ -482,7 +495,6 @@ public class CalciteSqlParser {
pinotQuery.setOffset(((SqlNumericLiteral) offsetNode).intValue(false));
}
- queryRewrite(pinotQuery);
return pinotQuery;
}
diff --git
a/pinot-common/src/test/java/org/apache/pinot/sql/parsers/rewriter/PredicateComparisonRewriterTest.java
b/pinot-common/src/test/java/org/apache/pinot/sql/parsers/rewriter/PredicateComparisonRewriterTest.java
new file mode 100644
index 0000000000..9503b9a336
--- /dev/null
+++
b/pinot-common/src/test/java/org/apache/pinot/sql/parsers/rewriter/PredicateComparisonRewriterTest.java
@@ -0,0 +1,182 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.sql.parsers.rewriter;
+
+import org.apache.pinot.common.request.PinotQuery;
+import org.apache.pinot.sql.parsers.CalciteSqlParser;
+import org.apache.pinot.sql.parsers.SqlCompilationException;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertThrows;
+import static org.testng.AssertJUnit.assertTrue;
+
+
+public class PredicateComparisonRewriterTest {
+ PredicateComparisonRewriter _predicateComparisonRewriter = new
PredicateComparisonRewriter();
+
+ @Test
+ public void testIdentifierPredicateRewrite() {
+ // A query like "select * from table where col1" should be rewritten to
"select * from table where col1 = true"
+
+ PinotQuery pinotQuery =
CalciteSqlParser.compileToPinotQueryWithoutRewrites("SELECT * FROM mytable
WHERE col1");
+ assertTrue(pinotQuery.getFilterExpression().isSetIdentifier());
+
+ PinotQuery rewrittenQuery =
_predicateComparisonRewriter.rewrite(pinotQuery);
+
assertEquals(rewrittenQuery.getFilterExpression().getFunctionCall().getOperator(),
"EQUALS");
+
assertEquals(rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().size(),
2);
+
assertEquals(rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getIdentifier().getName(),
+ "col1");
+ Assert.assertTrue(
+
rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getLiteral().getBoolValue());
+
assertTrue(rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getLiteral().getBoolValue());
+ }
+
+ @Test
+ public void testFunctionPredicateRewrite() {
+ // A query like "select col1 from table where startsWith(col1, 'myStr')
AND col2 > 10" should be rewritten to
+ // "select col1 from table where startsWith(col1, 'myStr') = true AND col2
> 10"
+
+ PinotQuery pinotQuery =
CalciteSqlParser.compileToPinotQueryWithoutRewrites(
+ "SELECT col1 FROM mytable WHERE startsWith(col1, 'myStr') AND col2 >
10;");
+
assertEquals(pinotQuery.getFilterExpression().getFunctionCall().getOperator(),
"AND");
+
assertEquals(pinotQuery.getFilterExpression().getFunctionCall().getOperands().size(),
2);
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperator(),
+ "startswith");
+
+ PinotQuery rewrittenQuery =
_predicateComparisonRewriter.rewrite(pinotQuery);
+
assertEquals(rewrittenQuery.getFilterExpression().getFunctionCall().getOperator(),
"AND");
+
assertEquals(rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().size(),
2);
+ assertEquals(
+
rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperator(),
+ "EQUALS");
+ assertEquals(
+
rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands()
+ .size(), 2);
+ assertEquals(
+
rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands()
+ .get(0).getFunctionCall().getOperator(), "startswith");
+ assertTrue(
+
rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands()
+ .get(1).getLiteral().getBoolValue());
+ }
+
+ @Test
+ public void testFilterPredicateLiteralIdentifierSwap() {
+ // Filters like '10 = col1' should be rewritten to 'col1 = 10'
+
+ PinotQuery pinotQuery =
+ CalciteSqlParser.compileToPinotQueryWithoutRewrites("SELECT * FROM
mytable WHERE 10 = col1 OR 10 < col2;");
+
assertEquals(pinotQuery.getFilterExpression().getFunctionCall().getOperator(),
"OR");
+
assertEquals(pinotQuery.getFilterExpression().getFunctionCall().getOperands().size(),
2);
+
assertTrue(pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).isSetFunctionCall());
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperator(),
+ "EQUALS");
+ assertTrue(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(0)
+ .isSetLiteral());
+ assertTrue(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(1)
+ .isSetIdentifier());
+
+ PinotQuery rewrittenQuery =
_predicateComparisonRewriter.rewrite(pinotQuery);
+
assertEquals(rewrittenQuery.getFilterExpression().getFunctionCall().getOperator(),
"OR");
+
assertEquals(rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().size(),
2);
+
+ assertTrue(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(0)
+ .isSetIdentifier());
+ assertTrue(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(1)
+ .isSetLiteral());
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperator(),
+ "EQUALS");
+ assertTrue(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getFunctionCall().getOperands().get(0)
+ .isSetIdentifier());
+ assertTrue(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getFunctionCall().getOperands().get(1)
+ .isSetLiteral());
+ // Operator should be flipped
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getFunctionCall().getOperator(),
+ "GREATER_THAN");
+ }
+
+ @Test
+ public void testFilterPredicateColumnComparisonRewrite() {
+ // Filters like 'col1 = col2' should be rewritten to 'col1 - col2 = 0'
+
+ PinotQuery pinotQuery =
+ CalciteSqlParser.compileToPinotQueryWithoutRewrites("SELECT * FROM
mytable WHERE col1 = col2 AND col3 < col4;");
+
assertEquals(pinotQuery.getFilterExpression().getFunctionCall().getOperator(),
"AND");
+
assertEquals(pinotQuery.getFilterExpression().getFunctionCall().getOperands().size(),
2);
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperator(),
+ "EQUALS");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(0)
+ .getIdentifier().getName(), "col1");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(1)
+ .getIdentifier().getName(), "col2");
+
+ PinotQuery rewrittenQuery =
_predicateComparisonRewriter.rewrite(pinotQuery);
+
assertEquals(rewrittenQuery.getFilterExpression().getFunctionCall().getOperator(),
"AND");
+
assertEquals(rewrittenQuery.getFilterExpression().getFunctionCall().getOperands().size(),
2);
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperator(),
+ "EQUALS");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(0)
+ .getFunctionCall().getOperator(), "minus");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(0)
+ .getFunctionCall().getOperands().get(0).getIdentifier().getName(),
"col1");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(0).getFunctionCall().getOperands().get(0)
+ .getFunctionCall().getOperands().get(1).getIdentifier().getName(),
"col2");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getFunctionCall().getOperands().get(1)
+ .getLiteral().getIntValue(), 0);
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getFunctionCall().getOperator(),
+ "LESS_THAN");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getFunctionCall().getOperands().get(0)
+ .getFunctionCall().getOperator(), "minus");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getFunctionCall().getOperands().get(0)
+ .getFunctionCall().getOperands().get(0).getIdentifier().getName(),
"col3");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getFunctionCall().getOperands().get(0)
+ .getFunctionCall().getOperands().get(1).getIdentifier().getName(),
"col4");
+ assertEquals(
+
pinotQuery.getFilterExpression().getFunctionCall().getOperands().get(1).getFunctionCall().getOperands().get(1)
+ .getLiteral().getIntValue(), 0);
+
+ PinotQuery betweenQuery =
+ CalciteSqlParser.compileToPinotQueryWithoutRewrites("SELECT * FROM
mytable WHERE col1 BETWEEN col2 AND col3");
+ assertThrows(SqlCompilationException.class, () ->
_predicateComparisonRewriter.rewrite(betweenQuery));
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]