Skip to content

Commit ce72761

Browse files
authored
SQL: handle NULL arithmetic operations with INTERVALs (#49633)
1 parent 034f4cf commit ce72761

File tree

15 files changed

+86
-26
lines changed

15 files changed

+86
-26
lines changed

docs/reference/sql/functions/date-time.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ s|Description
5555

5656
==== Operators
5757

58-
Basic arithmetic operators (`+`, `-`, etc) support date/time parameters as indicated below:
58+
Basic arithmetic operators (`+`, `-`, `*`) support date/time parameters as indicated below:
5959

6060
[source, sql]
6161
--------------------------------------------------

x-pack/plugin/sql/qa/src/main/resources/arithmetic.csv-spec

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@ SELECT 5 - 2 x FROM test_emp LIMIT 5;
1818
3
1919
;
2020

21+
22+
nullArithmetics
23+
schema::a:i|b:d|c:s|d:s|e:l|f:i|g:i|h:i|i:i|j:i|k:d
24+
SELECT null + 2 AS a, null * 1.5 AS b, null + null AS c, null - null AS d, null - 1234567890123 AS e, 123 - null AS f, null / 5 AS g, 5 / null AS h, null % 5 AS i, 5 % null AS j, null + 5.5 - (null * (null * 3)) AS k;
25+
26+
a | b | c | d | e | f | g | h | i | j | k
27+
---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------
28+
null |null |null |null |null |null |null |null |null |null |null
29+
;

x-pack/plugin/sql/qa/src/main/resources/datetime-interval.csv-spec

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,15 @@ SELECT 4 * -INTERVAL '2' HOURS AS result1, -5 * -INTERVAL '3' HOURS AS result2;
191191
-0 08:00:00.0 | +0 15:00:00.0
192192
;
193193

194+
intervalNullMath
195+
schema::null_multiply:string|null_sub1:string|null_sub2:string|null_add:string
196+
SELECT null * INTERVAL '1 23:45' DAY TO MINUTES AS null_multiply, INTERVAL '1' DAY - null AS null_sub1, null - INTERVAL '1' DAY AS null_sub2, INTERVAL 1 DAY + null AS null_add;
197+
198+
null_multiply | null_sub1 | null_sub2 | null_add
199+
-----------------+-------------+-------------+-------------
200+
null |null |null |null
201+
;
202+
194203
intervalAndFieldMultiply
195204
schema::languages:byte|result:string
196205
SELECT languages, CAST (languages * INTERVAL '1 10:30' DAY TO MINUTES AS string) AS result FROM test_emp ORDER BY emp_no LIMIT 5;

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/TypeResolutions.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55
*/
66
package org.elasticsearch.xpack.sql.expression;
77

8+
import org.elasticsearch.xpack.sql.expression.Expression.TypeResolution;
9+
import org.elasticsearch.xpack.sql.expression.Expressions.ParamOrdinal;
810
import org.elasticsearch.xpack.sql.type.DataType;
9-
import org.elasticsearch.xpack.sql.type.DataTypes;
1011
import org.elasticsearch.xpack.sql.type.EsField;
1112

1213
import java.util.Locale;
1314
import java.util.StringJoiner;
1415
import java.util.function.Predicate;
1516

1617
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
17-
import static org.elasticsearch.xpack.sql.expression.Expression.TypeResolution;
18-
import static org.elasticsearch.xpack.sql.expression.Expressions.ParamOrdinal;
1918
import static org.elasticsearch.xpack.sql.expression.Expressions.name;
2019
import static org.elasticsearch.xpack.sql.type.DataType.BOOLEAN;
2120

@@ -119,7 +118,7 @@ public static TypeResolution isType(Expression e,
119118
String operationName,
120119
ParamOrdinal paramOrd,
121120
String... acceptedTypes) {
122-
return predicate.test(e.dataType()) || DataTypes.isNull(e.dataType())?
121+
return predicate.test(e.dataType()) || e.dataType().isNull() ?
123122
TypeResolution.TYPE_RESOLVED :
124123
new TypeResolution(format(null, "{}argument of [{}] must be [{}], found value [{}] type [{}]",
125124
paramOrd == null || paramOrd == ParamOrdinal.DEFAULT ? "" : paramOrd.name().toLowerCase(Locale.ROOT) + " ",

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Cast.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import org.elasticsearch.xpack.sql.tree.Source;
1414
import org.elasticsearch.xpack.sql.type.DataType;
1515
import org.elasticsearch.xpack.sql.type.DataTypeConversion;
16-
import org.elasticsearch.xpack.sql.type.DataTypes;
1716

1817
import java.util.Objects;
1918

@@ -64,7 +63,7 @@ public Object fold() {
6463

6564
@Override
6665
public Nullability nullable() {
67-
if (DataTypes.isNull(from())) {
66+
if (from().isNull()) {
6867
return Nullability.TRUE;
6968
}
7069
return field().nullable();

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/conditional/Case.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ protected NodeInfo<? extends Expression> info() {
7878
protected TypeResolution resolveType() {
7979
DataType expectedResultDataType = null;
8080
for (IfConditional ifConditional : conditions) {
81-
if (DataTypes.isNull(ifConditional.result().dataType()) == false) {
81+
if (ifConditional.result().dataType().isNull() == false) {
8282
expectedResultDataType = ifConditional.result().dataType();
8383
break;
8484
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/nulls/IsNotNull.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@
1212
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
1313
import org.elasticsearch.xpack.sql.expression.predicate.Negatable;
1414
import org.elasticsearch.xpack.sql.expression.predicate.nulls.CheckNullProcessor.CheckNullOperation;
15-
import org.elasticsearch.xpack.sql.tree.Source;
1615
import org.elasticsearch.xpack.sql.tree.NodeInfo;
16+
import org.elasticsearch.xpack.sql.tree.Source;
1717
import org.elasticsearch.xpack.sql.type.DataType;
18-
import org.elasticsearch.xpack.sql.type.DataTypes;
1918

2019
public class IsNotNull extends UnaryScalarFunction implements Negatable<UnaryScalarFunction> {
2120

@@ -35,7 +34,7 @@ protected IsNotNull replaceChild(Expression newChild) {
3534

3635
@Override
3736
public Object fold() {
38-
return field().fold() != null && !DataTypes.isNull(field().dataType());
37+
return field().fold() != null && !field().dataType().isNull();
3938
}
4039

4140
@Override

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/nulls/IsNull.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@
1212
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
1313
import org.elasticsearch.xpack.sql.expression.predicate.Negatable;
1414
import org.elasticsearch.xpack.sql.expression.predicate.nulls.CheckNullProcessor.CheckNullOperation;
15-
import org.elasticsearch.xpack.sql.tree.Source;
1615
import org.elasticsearch.xpack.sql.tree.NodeInfo;
16+
import org.elasticsearch.xpack.sql.tree.Source;
1717
import org.elasticsearch.xpack.sql.type.DataType;
18-
import org.elasticsearch.xpack.sql.type.DataTypes;
1918

2019
public class IsNull extends UnaryScalarFunction implements Negatable<UnaryScalarFunction> {
2120

@@ -35,7 +34,7 @@ protected IsNull replaceChild(Expression newChild) {
3534

3635
@Override
3736
public Object fold() {
38-
return field().fold() == null || DataTypes.isNull(field().dataType());
37+
return field().fold() == null || field().dataType().isNull();
3938
}
4039

4140
@Override

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/arithmetic/DateTimeArithmeticOperation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ protected TypeResolution resolveWithIntervals() {
5656
DataType l = left().dataType();
5757
DataType r = right().dataType();
5858

59-
if (!(r.isDateOrTimeBased() || r.isInterval())|| !(l.isDateOrTimeBased() || l.isInterval())) {
59+
if (!(r.isDateOrTimeBased() || r.isInterval() || r.isNull())|| !(l.isDateOrTimeBased() || l.isInterval() || l.isNull())) {
6060
return new TypeResolution(format(null, "[{}] has arguments with incompatible types [{}] and [{}]", symbol(), l, r));
6161
}
6262
return TypeResolution.TYPE_RESOLVED;

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/arithmetic/Mul.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ protected TypeResolution resolveType() {
3434
DataType r = right().dataType();
3535

3636
// 1. both are numbers
37-
if (l.isNumeric() && r.isNumeric()) {
37+
if (l.isNullOrNumeric() && r.isNullOrNumeric()) {
3838
return TypeResolution.TYPE_RESOLVED;
3939
}
4040

41-
if (l.isInterval() && r.isInteger()) {
41+
if (l.isNullOrInterval() && (r.isInteger() || r.isNull())) {
4242
dataType = l;
4343
return TypeResolution.TYPE_RESOLVED;
44-
} else if (r.isInterval() && l.isInteger()) {
44+
} else if (r.isNullOrInterval() && (l.isInteger() || l.isNull())) {
4545
dataType = r;
4646
return TypeResolution.TYPE_RESOLVED;
4747
}

0 commit comments

Comments
 (0)