vvivekiyer commented on code in PR #8518: URL: https://github.com/apache/pinot/pull/8518#discussion_r849963166
########## pinot-common/src/main/java/org/apache/pinot/sql/parsers/rewriter/PredicateComparisonRewriter.java: ########## @@ -42,6 +44,73 @@ public PinotQuery rewrite(PinotQuery pinotQuery) { return pinotQuery; } + /** + * Updates boolean predicates that are missing an EQUALS filter. + * E.g. 1: 'WHERE a' will be updated to 'WHERE a = true' + * E.g. 2: "WHERE startsWith(col, 'str')" will be updated to "WHERE startsWith(col, 'str') = true" + * + * @param expression current expression in the expression tree + * @param parentFunction parent expression + * @return re-written expression. + */ + private static Expression updateBooleanPredicates(Expression expression, Function parentFunction) { + ExpressionType type = expression.getType(); + if (type == ExpressionType.FUNCTION) { + Function function = expression.getFunctionCall(); + + // If the function is not of FilterKind, we might have to rewrite the function if parentFunction is AND, OR or + // NOT. Example: 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;". + if (!EnumUtils.isValidEnum(FilterKind.class, function.getOperator())) { + + // Rewrite non FilterKind functions if one of the two conditions are satified: + // 1. parent function is empty. Example: "select * from table where startsWith(col, 'myStr'); + // 2. Separator is not a predicate (non predicates are AND, OR, NOT). + // Example: "select * from table where startsWith(col, 'myStr') AND col2 > 10"; + if (parentFunction == null || (EnumUtils.isValidEnum(FilterKind.class, parentFunction.getOperator()) + && !FilterKind.valueOf(parentFunction.getOperator()).isPredicate())) { + Expression currExpression = expression.deepCopy(); + expression = RequestUtils.getFunctionExpression(FilterKind.EQUALS.name()); + List<Expression> operands = new ArrayList<>(); + operands.add(currExpression); + operands.add(RequestUtils.getLiteralExpression(true)); + expression.getFunctionCall().setOperands(operands); + + return expression; + } + } + + List<Expression> operands = expression.getFunctionCall().getOperands(); + + if (operands.size() > 0) { + // unset operands only within the "if" condition because 'no argument' functions expect operand list to + // be initialized. + expression.getFunctionCall().unsetOperands(); + + for (Expression exp : operands) { + expression.getFunctionCall().addToOperands(updateBooleanPredicates(exp, expression.getFunctionCall())); + } + } + } else if (type == ExpressionType.IDENTIFIER) { + + // Rewrite identifiers if one of the two conditions are satified: + // 1. parent function is empty. Example: "select * from table where col1"; + // 2. Separator is not a predicate (non predicates are AND, OR, NOT). + // Example: "select * from table where col1 AND col2 > 10"; + if (parentFunction == null || (EnumUtils.isValidEnum(FilterKind.class, parentFunction.getOperator()) Review Comment: In both the above example, when we reach `WHERE col1` we have to rewrite the query. But consider the example query `WHERE concat(col1, "str")`. In this case we have to not rewrite the query. So the logic is that, literals will be re-written only if at least one of the conditions is satisfied: 1. Parent function is null. 2. Parent function is one of AND, OR, NOT. ########## pinot-common/src/test/java/org/apache/pinot/sql/parsers/CalciteSqlCompilerTest.java: ########## @@ -2246,6 +2246,19 @@ public void testFlattenAndOr() { } } + { + String query = "SELECT * FROM foo WHERE col1 > 0 AND (col2 AND col3 > 0) AND startsWith(col4, 'myStr')"; + PinotQuery pinotQuery = CalciteSqlParser.compileToPinotQuery(query); + Function functionCall = pinotQuery.getFilterExpression().getFunctionCall(); + Assert.assertEquals(functionCall.getOperator(), FilterKind.AND.name()); + List<Expression> operands = functionCall.getOperands(); + Assert.assertEquals(operands.size(), 4); + Assert.assertEquals(operands.get(0).getFunctionCall().getOperator(), FilterKind.GREATER_THAN.name()); + Assert.assertEquals(operands.get(1).getFunctionCall().getOperator(), FilterKind.EQUALS.name()); + Assert.assertEquals(operands.get(2).getFunctionCall().getOperator(), FilterKind.GREATER_THAN.name()); + Assert.assertEquals(operands.get(3).getFunctionCall().getOperator(), FilterKind.EQUALS.name()); Review Comment: Done. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org