Skip to content

Commit 3233bce

Browse files
committed
SQL: Fix issue with negative literels and parentheses (#48113)
Previously when a numeric literal was enclosed in parentheses and then negated, the negation was lost and the number was considered positive, e.g.: `-(5)` was considered as `5` instead of `-5` `- ( (1.28) )` was considered as `1.28` instead of `-1.28` Fixes: #48009 (cherry picked from commit 4dee4bf)
1 parent 8f81524 commit 3233bce

File tree

4 files changed

+67
-19
lines changed

4 files changed

+67
-19
lines changed

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java

+21-4
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ public Literal visitInterval(IntervalContext interval) {
528528

529529
TimeUnit leading = visitIntervalField(interval.leading);
530530
TimeUnit trailing = visitIntervalField(interval.trailing);
531-
531+
532532
// only YEAR TO MONTH or DAY TO HOUR/MINUTE/SECOND are valid declaration
533533
if (trailing != null) {
534534
if (leading == TimeUnit.YEAR && trailing != TimeUnit.MONTH) {
@@ -869,11 +869,28 @@ private static Source minusAwareSource(SqlBaseParser.NumberContext ctx) {
869869
if (parentCtx != null) {
870870
if (parentCtx instanceof SqlBaseParser.NumericLiteralContext) {
871871
parentCtx = parentCtx.getParent();
872-
if (parentCtx != null && parentCtx instanceof SqlBaseParser.ConstantDefaultContext) {
872+
if (parentCtx instanceof ConstantDefaultContext) {
873873
parentCtx = parentCtx.getParent();
874-
if (parentCtx != null && parentCtx instanceof SqlBaseParser.ValueExpressionDefaultContext) {
874+
if (parentCtx instanceof ValueExpressionDefaultContext) {
875875
parentCtx = parentCtx.getParent();
876-
if (parentCtx != null && parentCtx instanceof SqlBaseParser.ArithmeticUnaryContext) {
876+
877+
// Skip parentheses, e.g.: - (( (2.15) ) )
878+
while (parentCtx instanceof PredicatedContext) {
879+
parentCtx = parentCtx.getParent();
880+
if (parentCtx instanceof SqlBaseParser.BooleanDefaultContext) {
881+
parentCtx = parentCtx.getParent();
882+
}
883+
if (parentCtx instanceof SqlBaseParser.ExpressionContext) {
884+
parentCtx = parentCtx.getParent();
885+
}
886+
if (parentCtx instanceof SqlBaseParser.ParenthesizedExpressionContext) {
887+
parentCtx = parentCtx.getParent();
888+
}
889+
if (parentCtx instanceof ValueExpressionDefaultContext) {
890+
parentCtx = parentCtx.getParent();
891+
}
892+
}
893+
if (parentCtx instanceof ArithmeticUnaryContext) {
877894
if (((ArithmeticUnaryContext) parentCtx).MINUS() != null) {
878895
return source(parentCtx);
879896
}

x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/TestUtils.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,18 @@
1616
import java.time.Duration;
1717
import java.time.ZonedDateTime;
1818
import java.time.ZoneId;
19+
import java.util.StringJoiner;
1920

2021
import static org.elasticsearch.test.ESTestCase.randomAlphaOfLength;
2122
import static org.elasticsearch.test.ESTestCase.randomBoolean;
2223
import static org.elasticsearch.test.ESTestCase.randomFrom;
24+
import static org.elasticsearch.test.ESTestCase.randomInt;
2325
import static org.elasticsearch.test.ESTestCase.randomIntBetween;
2426
import static org.elasticsearch.test.ESTestCase.randomNonNegativeLong;
2527
import static org.elasticsearch.test.ESTestCase.randomZone;
2628

2729

28-
public class TestUtils {
30+
public final class TestUtils {
2931

3032
private TestUtils() {}
3133

@@ -42,7 +44,7 @@ private TestUtils() {}
4244
*
4345
* @return {@link ZonedDateTime} instance for the current date-time with milliseconds precision in UTC
4446
*/
45-
public static final ZonedDateTime now() {
47+
public static ZonedDateTime now() {
4648
return ZonedDateTime.now(Clock.tick(Clock.system(DateUtils.UTC), Duration.ofMillis(1)));
4749
}
4850

@@ -74,5 +76,12 @@ public static Configuration randomConfiguration(ZoneId providedZoneId) {
7476
randomBoolean());
7577
}
7678

79+
public static String randomWhitespaces() {
80+
StringJoiner sj = new StringJoiner("");
81+
for (int i = 0; i < randomInt(10); i++) {
82+
sj.add(randomFrom(" ", "\t", "\r", "\n"));
83+
}
84+
return sj.toString();
85+
}
7786
}
7887

x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/EscapedFunctionsTests.java

+1-9
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@
2222

2323
import java.util.List;
2424
import java.util.Locale;
25-
import java.util.StringJoiner;
2625

2726
import static java.lang.String.format;
2827
import static java.util.Arrays.asList;
28+
import static org.elasticsearch.xpack.sql.TestUtils.randomWhitespaces;
2929
import static org.hamcrest.Matchers.endsWith;
3030
import static org.hamcrest.Matchers.instanceOf;
3131
import static org.hamcrest.Matchers.is;
@@ -35,14 +35,6 @@ public class EscapedFunctionsTests extends ESTestCase {
3535

3636
private final SqlParser parser = new SqlParser();
3737

38-
private String randomWhitespaces() {
39-
StringJoiner sj = new StringJoiner("");
40-
for (int i = 0; i < randomInt(10); i++) {
41-
sj.add(randomFrom(" ", "\t", "\r", "\n"));
42-
}
43-
return sj.toString();
44-
}
45-
4638
private String buildExpression(String escape, String pattern, Object value) {
4739
return format(Locale.ROOT, "{" + randomWhitespaces() + escape + " " + randomWhitespaces() +
4840
pattern + randomWhitespaces() + "}", value);

x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/ExpressionTests.java

+34-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.elasticsearch.xpack.sql.parser;
77

88
import org.elasticsearch.test.ESTestCase;
9+
import org.elasticsearch.xpack.sql.TestUtils;
910
import org.elasticsearch.xpack.sql.expression.Expression;
1011
import org.elasticsearch.xpack.sql.expression.Literal;
1112
import org.elasticsearch.xpack.sql.expression.function.UnresolvedFunction;
@@ -202,26 +203,55 @@ public void testNegativeLiteral() {
202203
Expression expr = parser.createExpression("- 6");
203204
assertEquals(Literal.class, expr.getClass());
204205
assertEquals("- 6", expr.sourceText());
206+
assertEquals(-6, expr.fold());
207+
208+
expr = parser.createExpression("- ( 6.134 )");
209+
assertEquals(Literal.class, expr.getClass());
210+
assertEquals("- ( 6.134 )", expr.sourceText());
211+
assertEquals(-6.134, expr.fold());
212+
213+
expr = parser.createExpression("- ( ( (1.25) ) )");
214+
assertEquals(Literal.class, expr.getClass());
215+
assertEquals("- ( ( (1.25) ) )", expr.sourceText());
216+
assertEquals(-1.25, expr.fold());
217+
218+
int numberOfParentheses = randomIntBetween(3, 10);
219+
double value = randomDouble();
220+
StringBuilder sb = new StringBuilder("-");
221+
for (int i = 0; i < numberOfParentheses; i++) {
222+
sb.append("(").append(TestUtils.randomWhitespaces());
223+
}
224+
sb.append(value);
225+
for (int i = 0; i < numberOfParentheses; i++) {
226+
sb.append(")");
227+
if (i < numberOfParentheses - 1) {
228+
sb.append(TestUtils.randomWhitespaces());
229+
}
230+
}
231+
expr = parser.createExpression(sb.toString());
232+
assertEquals(Literal.class, expr.getClass());
233+
assertEquals(sb.toString(), expr.sourceText());
234+
assertEquals(- value, expr.fold());
205235
}
206236

207237
public void testComplexArithmetic() {
208-
String sql = "-(((a-2)-(-3))+b)";
238+
String sql = "-(((a-2)- (( - ( ( 3) )) ) )+ b)";
209239
Expression expr = parser.createExpression(sql);
210240
assertEquals(Neg.class, expr.getClass());
211241
Neg neg = (Neg) expr;
212242
assertEquals(sql, neg.sourceText());
213243
assertEquals(1, neg.children().size());
214244
assertEquals(Add.class, neg.children().get(0).getClass());
215245
Add add = (Add) neg.children().get(0);
216-
assertEquals("((a-2)-(-3))+b", add.sourceText());
246+
assertEquals("((a-2)- (( - ( ( 3) )) ) )+ b", add.sourceText());
217247
assertEquals(2, add.children().size());
218248
assertEquals("?b", add.children().get(1).toString());
219249
assertEquals(Sub.class, add.children().get(0).getClass());
220250
Sub sub1 = (Sub) add.children().get(0);
221-
assertEquals("(a-2)-(-3)", sub1.sourceText());
251+
assertEquals("(a-2)- (( - ( ( 3) )) )", sub1.sourceText());
222252
assertEquals(2, sub1.children().size());
223253
assertEquals(Literal.class, sub1.children().get(1).getClass());
224-
assertEquals("-3", sub1.children().get(1).sourceText());
254+
assertEquals("- ( ( 3) )", sub1.children().get(1).sourceText());
225255
assertEquals(Sub.class, sub1.children().get(0).getClass());
226256
Sub sub2 = (Sub) sub1.children().get(0);
227257
assertEquals(2, sub2.children().size());

0 commit comments

Comments
 (0)