This is an automated email from the ASF dual-hosted git repository. siddteotia pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
The following commit(s) were added to refs/heads/master by this push: new e0b2be8 Normalize LHS and RHS numerical types for >, >=, <, and <= operators. (#6927) e0b2be8 is described below commit e0b2be8c989aa35d966808989d62fb5def00e088 Author: Amrish Lal <amrish.k....@gmail.com> AuthorDate: Thu May 27 22:58:03 2021 -0700 Normalize LHS and RHS numerical types for >, >=, <, and <= operators. (#6927) * Normalize LHS and RHS numerical types for >, >=, <, and <= operators. * Rebuild. * Cleanup. * codereview changes. --- .../optimizer/filter/NumericalFilterOptimizer.java | 294 ++++++++++++--- .../filter/NumericalFilterOptimizerTest.java | 405 +++++++++++---------- 2 files changed, 443 insertions(+), 256 deletions(-) diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/filter/NumericalFilterOptimizer.java b/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/filter/NumericalFilterOptimizer.java index 88ff24c..f580897 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/filter/NumericalFilterOptimizer.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/filter/NumericalFilterOptimizer.java @@ -33,22 +33,25 @@ import org.apache.pinot.spi.data.Schema; /** - * Numerical expressions of form "column = literal" or "column != literal" can compare a column of one datatype - * (say INT) with a literal of different datatype (say DOUBLE). These expressions can not be evaluated on the Server. - * Hence, we rewrite such expressions into an equivalent expression whose LHS and RHS are of the same datatype. + * Numerical expressions of form "column <operator> literal", where operator can be '=', '!=', '>', '>=', '<', or '<=', + * can compare a column of one datatype (say INT) with a literal of different datatype (say DOUBLE). These expressions + * can not be evaluated on the Server. Hence, we rewrite such expressions into an equivalent expression whose LHS and + * RHS are of the same datatype. * * Simple predicate examples: * 1) WHERE "intColumn = 5.0" gets rewritten to "WHERE intColumn = 5" * 2) WHERE "intColumn != 5.0" gets rewritten to "WHERE intColumn != 5" * 3) WHERE "intColumn = 5.5" gets rewritten to "WHERE false" because INT values can not match 5.5. - * 4) WHERE "intColumn = 3000000000 gets rewritten to "WHERE false" because INT values can not match 3000000000. - * 5) WHERE "intColumn != 3000000000 gets rewritten to "WHERE true" becuase INT values always not equal to 3000000000. + * 4) WHERE "intColumn = 3000000000" gets rewritten to "WHERE false" because INT values can not match 3000000000. + * 5) WHERE "intColumn != 3000000000" gets rewritten to "WHERE true" because INT values always not equal to 3000000000. + * 6) WHERE "intColumn < 5.1" gets rewritten to "WHERE intColumn <= 5" + * 7) WHERE "intColumn > -3E9" gets rewritten to "WHERE true" because int values are always greater than -3E9. * * Compound predicate examples: - * 6) WHERE "intColumn1 = 5.5 AND intColumn2 = intColumn3" + * 8) WHERE "intColumn1 = 5.5 AND intColumn2 = intColumn3" * rewrite to "WHERE false AND intColumn2 = intColumn3" * rewrite to "WHERE intColumn2 = intColumn3" - * 7) WHERE "intColumn1 != 5.5 OR intColumn2 = 5000000000" (5000000000 is out of bounds for integer column) + * 9) WHERE "intColumn1 != 5.5 OR intColumn2 = 5000000000" (5000000000 is out of bounds for integer column) * rewrite to "WHERE true OR false" * rewrite to "WHERE true" * rewrite to query without any WHERE clause. @@ -56,6 +59,8 @@ import org.apache.pinot.spi.data.Schema; * When entire predicate gets rewritten to false (Example 3 above), the query will not return any data. Hence, it is * better for the Broker itself to return an empty response rather than sending the query to servers for further * evaluation. + * + * TODO: Add support for BETWEEN, IN, and NOT IN operators. */ public class NumericalFilterOptimizer implements FilterOptimizer { @@ -80,22 +85,29 @@ public class NumericalFilterOptimizer implements FilterOptimizer { List<Expression> operands = function.getOperands(); String operator = function.getOperator(); if (operator.equals(FilterKind.AND.name()) || operator.equals(FilterKind.OR.name())) { - // One of the operands may be an EQUALS or NOT_EQUALS function so recursively traverse the expression tree to see - // if we find an EQUALS or NOT_EQUALS function to rewrite. + // Recursively traverse the expression tree to find an operator node that can be rewritten. operands.forEach(operand -> optimize(operand, schema)); // We have rewritten the child operands, so rewrite the parent if needed. return optimizeCurrent(expression); - } else if (operator.equals(FilterKind.EQUALS.name()) || operator.equals(FilterKind.NOT_EQUALS.name())) { + } else { // Verify that LHS is a numeric column and RHS is a numeric literal before rewriting. Expression lhs = operands.get(0); Expression rhs = operands.get(1); if (isNumericColumn(lhs, schema) && isNumericLiteral(rhs)) { - // Rewrite the expression. - return rewrite(expression, lhs, rhs, schema); + FilterKind kind = FilterKind.valueOf(operator); + switch (kind) { + case EQUALS: + case NOT_EQUALS: + return rewriteEqualsExpression(expression, kind, lhs, rhs, schema); + case GREATER_THAN: + case GREATER_THAN_OR_EQUAL: + case LESS_THAN: + case LESS_THAN_OR_EQUAL: + return rewriteRangeExpression(expression, kind, lhs, rhs, schema); + } } } - return expression; } @@ -139,52 +151,13 @@ public class NumericalFilterOptimizer implements FilterOptimizer { return expression; } - private boolean isNumericColumn(Expression expression, Schema schema) { - if (expression.getType() != ExpressionType.IDENTIFIER) { - // Expression can not be a column. - return false; - } - - String column = expression.getIdentifier().getName(); - FieldSpec fieldSpec = schema.getFieldSpecFor(column); - if (fieldSpec == null || !fieldSpec.isSingleValueField()) { - // Expression can not be a column name. - return false; - } - - return schema.getFieldSpecFor(column).getDataType().isNumeric(); - } - - private boolean isNumericLiteral(Expression expression) { - if (expression.getType() == ExpressionType.LITERAL) { - Literal._Fields type = expression.getLiteral().getSetField(); - switch (type) { - case SHORT_VALUE: - case INT_VALUE: - case LONG_VALUE: - case DOUBLE_VALUE: - return true; - } - } - return false; - } - - /** Change the expression value to boolean literal with given value. */ - private static Expression setExpressionToBoolean(Expression expression, boolean value) { - expression.unsetFunctionCall(); - expression.setType(ExpressionType.LITERAL); - expression.setLiteral(Literal.boolValue(value)); - - return expression; - } - /** * Rewrite expressions of form "column = literal" or "column != literal" to ensure that RHS literal is the same * datatype as LHS column. */ - private Expression rewrite(Expression equals, Expression lhs, Expression rhs, Schema schema) { + private static Expression rewriteEqualsExpression(Expression equals, FilterKind kind, Expression lhs, Expression rhs, Schema schema) { // Get expression operator - boolean result = equals.getFunctionCall().getOperator().equals(FilterKind.NOT_EQUALS.name()); + boolean result = kind == FilterKind.NOT_EQUALS; // Get column data type. FieldSpec.DataType dataType = schema.getFieldSpecFor(lhs.getIdentifier().getName()).getDataType(); @@ -234,7 +207,7 @@ public class NumericalFilterOptimizer implements FilterOptimizer { } break; } - case DOUBLE_VALUE: + case DOUBLE_VALUE: { double actual = rhs.getLiteral().getDoubleValue(); switch (dataType) { case INT: { @@ -271,7 +244,218 @@ public class NumericalFilterOptimizer implements FilterOptimizer { break; } } + } } return equals; } + + /** + * Rewrite expressions of form "column > literal", "column >= literal", "column < literal", and "column <= literal" + * to ensure that RHS literal is the same datatype as LHS column. + */ + private static Expression rewriteRangeExpression(Expression range, FilterKind kind, Expression lhs, Expression rhs, Schema schema) { + // Get column data type. + FieldSpec.DataType dataType = schema.getFieldSpecFor(lhs.getIdentifier().getName()).getDataType(); + + switch (rhs.getLiteral().getSetField()) { + case SHORT_VALUE: + case INT_VALUE: + // No rewrites needed since SHORT and INT conversion to numeric column types (INT, LONG, FLOAT, and DOUBLE) is + // lossless and will be implicitly handled on the server side. + break; + case LONG_VALUE: { + long actual = rhs.getLiteral().getLongValue(); + switch (dataType) { + case INT: { + int converted = (int) actual; + int comparison = Long.compare(actual, converted); + if (comparison > 0) { + // Literal value is greater than the bounds of INT. > and >= expressions will always be false because an + // INT column can never have a value greater than Integer.MAX_VALUE. < and <= expressions will always be + // true, because an INT column will always have values greater than or equal to Integer.MIN_VALUE and less + // than or equal to Integer.MAX_VALUE. + setExpressionToBoolean(range, kind == FilterKind.LESS_THAN || kind == FilterKind.LESS_THAN_OR_EQUAL); + } else if (comparison < 0) { + // Literal value is less than the bounds of INT. > and >= expressions will always be true because an + // INT column will always have a value greater than or equal to Integer.MIN_VALUE. < and <= expressions + // will always be false, because an INT column will never have values less than Integer.MIN_VALUE. + setExpressionToBoolean(range, kind == FilterKind.GREATER_THAN || kind == FilterKind.GREATER_THAN_OR_EQUAL); + } else { + // Long literal value falls within the bounds of INT column, server will successfully convert the literal + // value when needed. + } + break; + } + case FLOAT: { + // Since we are converting a long value to float, float value will never be out of bounds (i.e -Infinity + // or +Infinity). + float converted = (float) actual; + int comparison = BigDecimal.valueOf(actual).compareTo(BigDecimal.valueOf(converted)); + + // Rewrite range operator + rewriteRangeOperator(range, kind, comparison); + + // Rewrite range literal + rhs.getLiteral().setDoubleValue(converted); + break; + } + case DOUBLE: { + // long to double conversion is always within bounds of double datatype, but the conversion can be lossy. + // Example: + // Original long value : 9223372036854775807 (Long.MAX_VALUE) + // Converted double value: 9.223372036854776E18 + // This conversion is lossy because the last four digits of the long value (5807) had to be rounded off + // to 6. After conversion we lost all information about the existence of last four digits. Converting the + // double value back to long will not result in original long value. + double converted = (double) actual; + int comparison = BigDecimal.valueOf(actual).compareTo(BigDecimal.valueOf(converted)); + + // Rewrite range operator + rewriteRangeOperator(range, kind, comparison); + + // Rewrite range literal + rhs.getLiteral().setDoubleValue(converted); + break; + } + } + break; + } + case DOUBLE_VALUE: { + double actual = rhs.getLiteral().getDoubleValue(); + switch (dataType) { + case INT: { + int converted = (int) actual; + int comparison = Double.compare(actual, converted); + if (comparison > 0 && converted == Integer.MAX_VALUE) { + // Literal value is greater than the bounds of INT. + setExpressionToBoolean(range, kind == FilterKind.LESS_THAN || kind == FilterKind.LESS_THAN_OR_EQUAL); + } else if (comparison < 0 && converted == Integer.MIN_VALUE) { + // Literal value is less than the bounds of INT. + setExpressionToBoolean(range, kind == FilterKind.GREATER_THAN || kind == FilterKind.GREATER_THAN_OR_EQUAL); + } else { + // Literal value falls within the bounds of INT. + rewriteRangeOperator(range, kind, comparison); + + // Rewrite range literal + rhs.getLiteral().setLongValue(converted); + } + break; + } + case LONG: { + long converted = (long) actual; + int comparison = BigDecimal.valueOf(actual).compareTo(BigDecimal.valueOf(converted)); + + if (comparison > 0 && converted == Long.MAX_VALUE) { + // Literal value is greater than the bounds of LONG. + setExpressionToBoolean(range, kind == FilterKind.LESS_THAN || kind == FilterKind.LESS_THAN_OR_EQUAL); + } else if (comparison < 0 && converted == Long.MIN_VALUE) { + // Literal value is less than the bounds of LONG. + setExpressionToBoolean(range, kind == FilterKind.GREATER_THAN || kind == FilterKind.GREATER_THAN_OR_EQUAL); + } else { + // Rewrite range operator + rewriteRangeOperator(range, kind, comparison); + + // Rewrite range literal + rhs.getLiteral().setLongValue(converted); + } + break; + } + case FLOAT: { + float converted = (float) actual; + if (converted == Float.POSITIVE_INFINITY) { + // Literal value is greater than the bounds of FLOAT + setExpressionToBoolean(range, kind == FilterKind.LESS_THAN || kind == FilterKind.LESS_THAN_OR_EQUAL); + } else if (converted == Float.NEGATIVE_INFINITY) { + // Literal value is less than the bounds of LONG. + setExpressionToBoolean(range, kind == FilterKind.GREATER_THAN || kind == FilterKind.GREATER_THAN_OR_EQUAL); + } else { + int comparison = Double.compare(actual, converted); + // Rewrite range operator + rewriteRangeOperator(range, kind, comparison); + + // Rewrite range literal + rhs.getLiteral().setDoubleValue(converted); + } + break; + } + } + } + } + return range; + } + + /** + * Helper function to rewrite range operator of a range expression. + * @param range Range expression. + * @param kind The kind of range filter being used in the range expression. + * @param comparison -1 (literal < converted value), 0 (literal == converted value), 1 (literal > converted value). + */ + private static void rewriteRangeOperator(Expression range, FilterKind kind, int comparison) { + if (comparison > 0) { + // Literal value is greater than the converted value, so rewrite: + // "column > literal" to "column > converted" + // "column >= literal" to "column >= converted" + // "column < literal" to "column <= converted" + // "column <= literal" to "column < converted" + if (kind == FilterKind.GREATER_THAN || kind == FilterKind.GREATER_THAN_OR_EQUAL) { + range.getFunctionCall().setOperator(FilterKind.GREATER_THAN.name()); + } else if (kind == FilterKind.LESS_THAN || kind == FilterKind.LESS_THAN_OR_EQUAL) { + range.getFunctionCall().setOperator(FilterKind.LESS_THAN_OR_EQUAL.name()); + } + } else if (comparison < 0) { + // Literal value is less than the converted value, so rewrite: + // "column > literal" to "column >= converted" + // "column >= literal" to "column >= converted" + // "column < literal" to "column < converted" + // "column <= literal" to "column < converted" + if (kind == FilterKind.GREATER_THAN || kind == FilterKind.GREATER_THAN_OR_EQUAL) { + range.getFunctionCall().setOperator(FilterKind.GREATER_THAN_OR_EQUAL.name()); + } else if (kind == FilterKind.LESS_THAN || kind == FilterKind.LESS_THAN_OR_EQUAL) { + range.getFunctionCall().setOperator(FilterKind.LESS_THAN.name()); + } + } else { + // No need to rewrite range expression since conversion of literal value was lossless. + } + } + + /** @return true if expression is a column of numeric type */ + private static boolean isNumericColumn(Expression expression, Schema schema) { + if (expression.getType() != ExpressionType.IDENTIFIER) { + // Expression can not be a column. + return false; + } + + String column = expression.getIdentifier().getName(); + FieldSpec fieldSpec = schema.getFieldSpecFor(column); + if (fieldSpec == null || !fieldSpec.isSingleValueField()) { + // Expression can not be a column name. + return false; + } + + return schema.getFieldSpecFor(column).getDataType().isNumeric(); + } + + /** @return true if expression is a numeric literal; otherwise, false. */ + private static boolean isNumericLiteral(Expression expression) { + if (expression.getType() == ExpressionType.LITERAL) { + Literal._Fields type = expression.getLiteral().getSetField(); + switch (type) { + case SHORT_VALUE: + case INT_VALUE: + case LONG_VALUE: + case DOUBLE_VALUE: + return true; + } + } + return false; + } + + /** Change the expression value to boolean literal with given value. */ + private static Expression setExpressionToBoolean(Expression expression, boolean value) { + expression.unsetFunctionCall(); + expression.setType(ExpressionType.LITERAL); + expression.setLiteral(Literal.boolValue(value)); + + return expression; + } } diff --git a/pinot-core/src/test/java/org/apache/pinot/core/query/optimizer/filter/NumericalFilterOptimizerTest.java b/pinot-core/src/test/java/org/apache/pinot/core/query/optimizer/filter/NumericalFilterOptimizerTest.java index 55af556..5e631fb 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/query/optimizer/filter/NumericalFilterOptimizerTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/query/optimizer/filter/NumericalFilterOptimizerTest.java @@ -41,274 +41,277 @@ public class NumericalFilterOptimizerTest { .addMultiValueDimension("mvIntColumn", FieldSpec.DataType.INT).build(); @Test - public void testEqualsIntColumnWithValidDecimalValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn = 5.0"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); - - // "intColumn = 5.0" should have been rewritten to "intColumn = 5" since 5.0 converts to integer value without any - // loss of information. - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + public void testEqualsRewrites() { + // Test int column equals valid decimal value. "intColumn = 5.0" should have been rewritten to "intColumn = 5" + // since 5.0 converts to integer value without any loss of information. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn = 5.0"), "Expression(type:FUNCTION, functionCall:Function(operator:EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:intColumn)), Expression(type:LITERAL, literal:<Literal longValue:5>)]))"); - } - - @Test - public void testEqualsIntColumnWithInvalidDecimalValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn = 5.5"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test int column equals invalid decimal value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn = 5.5"), "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - } - @Test - public void testNotEqualsIntColumnWithValidDecimalValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn != 5.0"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); - - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test int column not equals valid decimal value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn != 5.0"), "Expression(type:FUNCTION, functionCall:Function(operator:NOT_EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:intColumn)), Expression(type:LITERAL, literal:<Literal longValue:5>)]))"); - } - @Test - public void testNotEqualsIntColumnWithInvalidDecimalValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn != 5.5"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test int column not equals invalid decimal value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn != 5.5"), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test int column equals out of domain value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn = 5000000000"), + "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); + + // Test int column not equals out of domain value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn != 5000000000"), "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - } - @Test - public void testEqualsIntColumnWithOutOfDomainValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn = 5000000000"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test long column equals valid decimal value. "longColumn = 5.0" should be rewritten to "longColumn = 5" since 5.0 + // converts to long value without any loss of information. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn = 5.0"), + "Expression(type:FUNCTION, functionCall:Function(operator:EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:5>)]))"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test long column equals invalid decimal value. "longColumn = 5.5" should have been rewritten to "false" literal + // since an LONG column can never have a decimal value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn = 5.5"), "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - } - @Test - public void testNotEqualsIntColumnWithOutOfDomainValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn != 5000000000"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test long column with valid decimal value. "longColumn = 5.5" should have been rewritten to "false" literal since + // LONG column can never have a decimal value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn != 5.0"), + "Expression(type:FUNCTION, functionCall:Function(operator:NOT_EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:5>)]))"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test long column not equals invalid decimal value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn != 5.5"), "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - } - @Test - public void testEqualsLongColumnWithValidDecimalValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE longColumn = 5.0"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test float column equals valid long value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn = 5"), + "Expression(type:FUNCTION, functionCall:Function(operator:EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:5.0>)]))"); - // "intColumn = 5.0" should have been rewritten to "intColumn = 5" since 5.0 converts to integer value without any - // loss of information. - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), - "Expression(type:FUNCTION, functionCall:Function(operator:EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:5>)]))"); - } + // Test float column equals invalid long value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn = " + String.valueOf(Long.MAX_VALUE)), + "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - @Test - public void testEqualsLongColumnWithInvalidDecimalValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE longColumn = 5.5"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test float column not equals valid long value + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn != " + String.valueOf(Long.MAX_VALUE)), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); + + // Test float column not equals valid long value + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn != 5"), + "Expression(type:FUNCTION, functionCall:Function(operator:NOT_EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:5.0>)]))"); + + // test double column equals valid long value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE doubleColumn = 5"), + "Expression(type:FUNCTION, functionCall:Function(operator:EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:doubleColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:5.0>)]))"); - // "intColumn = 5.5" should have been rewritten to "false" literal since an INT column can never have a decimal - // value. - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test double column equals invalid long value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE doubleColumn = " + String.valueOf(Long.MAX_VALUE)), "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - } - @Test - public void testNotEqualsLongColumnWithValidDecimalValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE longColumn != 5.0"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test double column not equals valid long value + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE doubleColumn != " + String.valueOf(Long.MAX_VALUE)), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - // "intColumn = 5.5" should have been rewritten to "false" literal since an INT column can never have a decimal - // value. - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), - "Expression(type:FUNCTION, functionCall:Function(operator:NOT_EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:5>)]))"); + // Test double column not equals invalid long value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE doubleColumn != 5"), + "Expression(type:FUNCTION, functionCall:Function(operator:NOT_EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:doubleColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:5.0>)]))"); } @Test - public void testNotEqualsLongColumnWithInvalidDecimalValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE longColumn != 5.5"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + public void testRangeRewrites() { - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test INT column with DOUBLE value greater than Integer.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn > 3000000000.0"), + "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); + + // Test INT column with DOUBLE value greater than Integer.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn < 3000000000.0"), "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - } - @Test - public void testEqualsFloatColumnWithValidLongValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE floatColumn = 5"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test INT column with DOUBLE value greater than Integer.MIN_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn > -3000000000.0"), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), - "Expression(type:FUNCTION, functionCall:Function(operator:EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:5.0>)]))"); - } + // Test INT column with LONG value less than Integer.MIN_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn < -3000000000"), + "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - @Test - public void testEqualsFloatColumnWithInvalidLongValue() { - BrokerRequest sqlBrokerRequest = SQL_COMPILER - .compileToBrokerRequest("SELECT * FROM testTable WHERE floatColumn = " + String.valueOf(Long.MAX_VALUE)); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test INT column with LONG value greater than Integer.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn > 3000000000"), + "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); + + // Test INT column with LONG value greater than Integer.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn < 3000000000"), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); + + // Test INT column with LONG value greater than Integer.MIN_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn > -3000000000"), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test INT column with LONG value less than Integer.MIN_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn < -3000000000"), "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - } - @Test - public void testNotEqualsFloatColumnWithValidLongValue() { - BrokerRequest sqlBrokerRequest = SQL_COMPILER - .compileToBrokerRequest("SELECT * FROM testTable WHERE floatColumn != " + String.valueOf(Long.MAX_VALUE)); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test INT column with DOUBLE value that falls within INT bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn < -2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:intColumn)), Expression(type:LITERAL, literal:<Literal longValue:-2100000000>)]))"); + + // Test INT column with DOUBLE value that falls within INT bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn < 2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:intColumn)), Expression(type:LITERAL, literal:<Literal longValue:2100000000>)]))"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test FLOAT column greater than Double.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn > " + Double.MAX_VALUE), + "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); + + // Test FLOAT column less than Double.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn < " + Double.MAX_VALUE), "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - } - @Test - public void testNotEqualsFloatColumnWithInvalidLongValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE floatColumn != 5"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test FLOAT column greater than -Double.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn > " + -Double.MAX_VALUE), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), - "Expression(type:FUNCTION, functionCall:Function(operator:NOT_EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:5.0>)]))"); - } + // Test FLOAT column less than -Double.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn < " + -Double.MAX_VALUE), + "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - @Test - public void testEqualsDoubleColumnWithValidLongValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE doubleColumn = 5"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test FLOAT column greater than Long.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn > " + Long.MAX_VALUE), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:9.223372036854776E18>)]))"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), - "Expression(type:FUNCTION, functionCall:Function(operator:EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:doubleColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:5.0>)]))"); - } + // Test FLOAT column less than Long.MIN_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn < " + Long.MIN_VALUE), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:-9.223372036854776E18>)]))"); - @Test - public void testEqualsDoubleColumnWithInvalidLongValue() { - BrokerRequest sqlBrokerRequest = SQL_COMPILER - .compileToBrokerRequest("SELECT * FROM testTable WHERE doubleColumn = " + String.valueOf(Long.MAX_VALUE)); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test FLOAT column greater than Long.MIN_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn > " + Long.MIN_VALUE), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:-9.223372036854776E18>)]))"); + + // Test FLOAT column with DOUBLE value that is within bounds of FLOAT. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn > -2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:-2.1E9>)]))"); + + // Test FLOAT column with DOUBLE value that is within bounds of FLOAT. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn < -2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:-2.1E9>)]))"); + + // Test FLOAT column with DOUBLE value that is within bounds of FLOAT. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn <= 2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:2.1E9>)]))"); + + // Test FLOAT column with DOUBLE value that is within bounds of FLOAT. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE floatColumn >= 2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:floatColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:2.1E9>)]))"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test LONG column with DOUBLE value greater than Long.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn > 999999999999999999999999999999.9999"), "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - } - @Test - public void testNotEqualsDoubleColumnWithValidLongValue() { - BrokerRequest sqlBrokerRequest = SQL_COMPILER - .compileToBrokerRequest("SELECT * FROM testTable WHERE doubleColumn != " + String.valueOf(Long.MAX_VALUE)); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test LONG column with DOUBLE value greater than Long.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn < 999999999999999999999999999999.9999"), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test LONG column with DOUBLE value greater than Long.MIN_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn > -999999999999999999999999999999.9999"), "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - } - @Test - public void testNotEqualsDoubleColumnWithInvalidLongValue() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE doubleColumn != 5"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test LONG column with DOUBLE value that falls within LONG bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn < -2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:-2100000000>)]))"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), - "Expression(type:FUNCTION, functionCall:Function(operator:NOT_EQUALS, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:doubleColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:5.0>)]))"); - } + // Test LONG column with DOUBLE value that falls within LONG bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn > -2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:-2100000000>)]))"); + + // Test LONG column with DOUBLE value that falls within LONG bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn < 2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:2100000000>)]))"); + + // Test LONG column with DOUBLE value that falls within LONG bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn > 2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:2100000000>)]))"); + + // Test DOUBLE column greater than Long.MAX_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE doubleColumn > " + Long.MAX_VALUE), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:doubleColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:9.223372036854776E18>)]))"); + + // Test DOUBLE column less than Long.MIN_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE doubleColumn < " + Long.MIN_VALUE), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:doubleColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:-9.223372036854776E18>)]))"); + + // Test DOUBLE column greater than Long.MIN_VALUE. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE doubleColumn > " + Long.MIN_VALUE), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:doubleColumn)), Expression(type:LITERAL, literal:<Literal doubleValue:-9.223372036854776E18>)]))"); - @Test - public void testAndWithAllTrueOperands() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn != 5.5 AND longColumn != 6.4"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), - "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); } @Test - public void testAndWithAllFalseOperands() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn = 5.5 AND longColumn = 6.4"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + public void temp() { + + // Test LONG column with DOUBLE value that falls within LONG bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn < -2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:-2100000000>)]))"); + + // Test LONG column with DOUBLE value that falls within LONG bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn > -2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:-2100000000>)]))"); + + // Test LONG column with DOUBLE value that falls within LONG bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn < 2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:LESS_THAN_OR_EQUAL, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:2100000000>)]))"); + + // Test LONG column with DOUBLE value that falls within LONG bounds. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE longColumn > 2100000000.5"), + "Expression(type:FUNCTION, functionCall:Function(operator:GREATER_THAN, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:longColumn)), Expression(type:LITERAL, literal:<Literal longValue:2100000000>)]))"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), - "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); } @Test - public void testAndWithOneFalseOperands() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn = 5.5 AND longColumn != 6.4"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + public void testAndRewrites() { + // Test and with all true operands + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn != 5.5 AND longColumn != 6.4"), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test and with all false operands + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn = 5.5 AND longColumn = 6.4"), "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - } - @Test - public void testOrWithAllTrueOperands() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn != 5.5 OR longColumn != 6.4"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); + // Test and with one false operand + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn = 5.5 AND longColumn != 6.4"), + "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + // Test or with all true operands + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn != 5.5 OR longColumn != 6.4"), "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); + + // Test int column with exclusive valid double value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn > 5.0 AND intColumn < 10.0"), + "Expression(type:FUNCTION, functionCall:Function(operator:RANGE, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:intColumn)), Expression(type:LITERAL, literal:<Literal stringValue:(5\u000010)>)]))"); + + // Test int column with inclusive valid double value. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn >= 5.0 AND intColumn <= 10.0"), + "Expression(type:FUNCTION, functionCall:Function(operator:RANGE, operands:[Expression(type:IDENTIFIER, identifier:Identifier(name:intColumn)), Expression(type:LITERAL, literal:<Literal stringValue:[5\u000010]>)]))"); } @Test - public void testOrWithAllFalseOperands() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn = 5.5 OR longColumn = 6.4"); - PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); - OPTIMIZER.optimize(pinotQuery, SCHEMA); - - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), + public void testOrRewrites() { + // Test or with all false operands + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn = 5.5 OR longColumn = 6.4"), "Expression(type:LITERAL, literal:<Literal boolValue:false>)"); + + // Test or with one false operand. + Assert.assertEquals(rewrite("SELECT * FROM testTable WHERE intColumn != 5.5 OR longColumn = 6.4"), + "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); } - @Test - public void testOrWithOneFalseOperands() { - BrokerRequest sqlBrokerRequest = - SQL_COMPILER.compileToBrokerRequest("SELECT * FROM testTable WHERE intColumn != 5.5 OR longColumn = 6.4"); + private static String rewrite(String query) { + BrokerRequest sqlBrokerRequest = SQL_COMPILER.compileToBrokerRequest(query); PinotQuery pinotQuery = sqlBrokerRequest.getPinotQuery(); OPTIMIZER.optimize(pinotQuery, SCHEMA); - - Assert.assertEquals(pinotQuery.getFilterExpression().toString(), - "Expression(type:LITERAL, literal:<Literal boolValue:true>)"); + return pinotQuery.getFilterExpression().toString(); } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org