Browse Source

ESQL: Rename `isInteger` to `isWholeNumber` (#110425)

It's confusing that we have a type called `integer` and we have a method
called `isInteger` which returns `true` for `integer` *and* `long`. This
renames that method to `isWholeNumber`. It also renames `isRational` to
`isRationalNumber` to line up.
Nik Everett 1 year ago
parent
commit
1dfb721b22

+ 2 - 2
x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/TypeResolutions.java

@@ -50,8 +50,8 @@ public final class TypeResolutions {
         return isType(e, dt -> dt == BOOLEAN, operationName, paramOrd, "boolean");
     }
 
-    public static TypeResolution isInteger(Expression e, String operationName, ParamOrdinal paramOrd) {
-        return isType(e, DataType::isInteger, operationName, paramOrd, "integer");
+    public static TypeResolution isWholeNumber(Expression e, String operationName, ParamOrdinal paramOrd) {
+        return isType(e, DataType::isWholeNumber, operationName, paramOrd, "integer");
     }
 
     public static TypeResolution isNumeric(Expression e, String operationName, ParamOrdinal paramOrd) {

+ 30 - 31
x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java

@@ -42,15 +42,15 @@ public enum DataType {
     COUNTER_INTEGER(builder().esType("counter_integer").size(Integer.BYTES).docValues().counter()),
     COUNTER_DOUBLE(builder().esType("counter_double").size(Double.BYTES).docValues().counter()),
 
-    LONG(builder().esType("long").size(Long.BYTES).integer().docValues().counter(COUNTER_LONG)),
-    INTEGER(builder().esType("integer").size(Integer.BYTES).integer().docValues().counter(COUNTER_INTEGER)),
-    SHORT(builder().esType("short").size(Short.BYTES).integer().docValues().widenSmallNumeric(INTEGER)),
-    BYTE(builder().esType("byte").size(Byte.BYTES).integer().docValues().widenSmallNumeric(INTEGER)),
-    UNSIGNED_LONG(builder().esType("unsigned_long").size(Long.BYTES).integer().docValues()),
-    DOUBLE(builder().esType("double").size(Double.BYTES).rational().docValues().counter(COUNTER_DOUBLE)),
-    FLOAT(builder().esType("float").size(Float.BYTES).rational().docValues().widenSmallNumeric(DOUBLE)),
-    HALF_FLOAT(builder().esType("half_float").size(Float.BYTES).rational().docValues().widenSmallNumeric(DOUBLE)),
-    SCALED_FLOAT(builder().esType("scaled_float").size(Long.BYTES).rational().docValues().widenSmallNumeric(DOUBLE)),
+    LONG(builder().esType("long").size(Long.BYTES).wholeNumber().docValues().counter(COUNTER_LONG)),
+    INTEGER(builder().esType("integer").size(Integer.BYTES).wholeNumber().docValues().counter(COUNTER_INTEGER)),
+    SHORT(builder().esType("short").size(Short.BYTES).wholeNumber().docValues().widenSmallNumeric(INTEGER)),
+    BYTE(builder().esType("byte").size(Byte.BYTES).wholeNumber().docValues().widenSmallNumeric(INTEGER)),
+    UNSIGNED_LONG(builder().esType("unsigned_long").size(Long.BYTES).wholeNumber().docValues()),
+    DOUBLE(builder().esType("double").size(Double.BYTES).rationalNumber().docValues().counter(COUNTER_DOUBLE)),
+    FLOAT(builder().esType("float").size(Float.BYTES).rationalNumber().docValues().widenSmallNumeric(DOUBLE)),
+    HALF_FLOAT(builder().esType("half_float").size(Float.BYTES).rationalNumber().docValues().widenSmallNumeric(DOUBLE)),
+    SCALED_FLOAT(builder().esType("scaled_float").size(Long.BYTES).rationalNumber().docValues().widenSmallNumeric(DOUBLE)),
 
     KEYWORD(builder().esType("keyword").unknownSize().docValues()),
     TEXT(builder().esType("text").unknownSize()),
@@ -80,14 +80,14 @@ public enum DataType {
     private final int size;
 
     /**
-     * True if the type represents an integer number
+     * True if the type represents a "whole number", as in, does <strong>not</strong> have a decimal part.
      */
-    private final boolean isInteger;
+    private final boolean isWholeNumber;
 
     /**
-     * True if the type represents a rational number
+     * True if the type represents a "rational number", as in, <strong>does</strong> have a decimal part.
      */
-    private final boolean isRational;
+    private final boolean isRationalNumber;
 
     /**
      * True if the type supports doc values by default
@@ -117,8 +117,8 @@ public enum DataType {
         this.name = typeString.toUpperCase(Locale.ROOT);
         this.esType = builder.esType;
         this.size = builder.size;
-        this.isInteger = builder.isInteger;
-        this.isRational = builder.isRational;
+        this.isWholeNumber = builder.isWholeNumber;
+        this.isRationalNumber = builder.isRationalNumber;
         this.docValues = builder.docValues;
         this.isCounter = builder.isCounter;
         this.widenSmallNumeric = builder.widenSmallNumeric;
@@ -262,25 +262,24 @@ public enum DataType {
     }
 
     /**
-     * Does this data type represent whole numbers? As in, numbers without a decimal point.
-     * Like {@code int} or {@code long}. See {@link #isRational} for numbers with a decimal point.
+     * True if the type represents a "whole number", as in, does <strong>not</strong> have a decimal part.
      */
-    public boolean isInteger() {
-        return isInteger;
+    public boolean isWholeNumber() {
+        return isWholeNumber;
     }
 
     /**
-     * Does this data type represent rational numbers (like floating point)?
+     * True if the type represents a "rational number", as in, <strong>does</strong> have a decimal part.
      */
-    public boolean isRational() {
-        return isRational;
+    public boolean isRationalNumber() {
+        return isRationalNumber;
     }
 
     /**
      * Does this data type represent <strong>any</strong> number?
      */
     public boolean isNumeric() {
-        return isInteger || isRational;
+        return isWholeNumber || isRationalNumber;
     }
 
     public int size() {
@@ -356,14 +355,14 @@ public enum DataType {
         private int size;
 
         /**
-         * True if the type represents an integer number
+         * True if the type represents a "whole number", as in, does <strong>not</strong> have a decimal part.
          */
-        private boolean isInteger;
+        private boolean isWholeNumber;
 
         /**
-         * True if the type represents a rational number
+         * True if the type represents a "rational number", as in, <strong>does</strong> have a decimal part.
          */
-        private boolean isRational;
+        private boolean isRationalNumber;
 
         /**
          * True if the type supports doc values by default
@@ -409,13 +408,13 @@ public enum DataType {
             return this;
         }
 
-        Builder integer() {
-            this.isInteger = true;
+        Builder wholeNumber() {
+            this.isWholeNumber = true;
             return this;
         }
 
-        Builder rational() {
-            this.isRational = true;
+        Builder rationalNumber() {
+            this.isRationalNumber = true;
             return this;
         }
 

+ 20 - 20
x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypeConverter.java

@@ -78,9 +78,9 @@ public final class DataTypeConverter {
         }
         if (left.isNumeric() && right.isNumeric()) {
             // if one is int
-            if (left.isInteger()) {
+            if (left.isWholeNumber()) {
                 // promote the highest int
-                if (right.isInteger()) {
+                if (right.isWholeNumber()) {
                     if (left == UNSIGNED_LONG || right == UNSIGNED_LONG) {
                         return UNSIGNED_LONG;
                     }
@@ -90,7 +90,7 @@ public final class DataTypeConverter {
                 return right;
             }
             // try the other side
-            if (right.isInteger()) {
+            if (right.isWholeNumber()) {
                 return left;
             }
             // promote the highest rational
@@ -200,10 +200,10 @@ public final class DataTypeConverter {
     }
 
     private static Converter conversionToUnsignedLong(DataType from) {
-        if (from.isRational()) {
+        if (from.isRationalNumber()) {
             return DefaultConverter.RATIONAL_TO_UNSIGNED_LONG;
         }
-        if (from.isInteger()) {
+        if (from.isWholeNumber()) {
             return DefaultConverter.INTEGER_TO_UNSIGNED_LONG;
         }
         if (from == BOOLEAN) {
@@ -219,10 +219,10 @@ public final class DataTypeConverter {
     }
 
     private static Converter conversionToLong(DataType from) {
-        if (from.isRational()) {
+        if (from.isRationalNumber()) {
             return DefaultConverter.RATIONAL_TO_LONG;
         }
-        if (from.isInteger()) {
+        if (from.isWholeNumber()) {
             return DefaultConverter.INTEGER_TO_LONG;
         }
         if (from == BOOLEAN) {
@@ -238,10 +238,10 @@ public final class DataTypeConverter {
     }
 
     private static Converter conversionToInt(DataType from) {
-        if (from.isRational()) {
+        if (from.isRationalNumber()) {
             return DefaultConverter.RATIONAL_TO_INT;
         }
-        if (from.isInteger()) {
+        if (from.isWholeNumber()) {
             return DefaultConverter.INTEGER_TO_INT;
         }
         if (from == BOOLEAN) {
@@ -257,10 +257,10 @@ public final class DataTypeConverter {
     }
 
     private static Converter conversionToShort(DataType from) {
-        if (from.isRational()) {
+        if (from.isRationalNumber()) {
             return DefaultConverter.RATIONAL_TO_SHORT;
         }
-        if (from.isInteger()) {
+        if (from.isWholeNumber()) {
             return DefaultConverter.INTEGER_TO_SHORT;
         }
         if (from == BOOLEAN) {
@@ -276,10 +276,10 @@ public final class DataTypeConverter {
     }
 
     private static Converter conversionToByte(DataType from) {
-        if (from.isRational()) {
+        if (from.isRationalNumber()) {
             return DefaultConverter.RATIONAL_TO_BYTE;
         }
-        if (from.isInteger()) {
+        if (from.isWholeNumber()) {
             return DefaultConverter.INTEGER_TO_BYTE;
         }
         if (from == BOOLEAN) {
@@ -295,10 +295,10 @@ public final class DataTypeConverter {
     }
 
     private static DefaultConverter conversionToFloat(DataType from) {
-        if (from.isRational()) {
+        if (from.isRationalNumber()) {
             return DefaultConverter.RATIONAL_TO_FLOAT;
         }
-        if (from.isInteger()) {
+        if (from.isWholeNumber()) {
             return DefaultConverter.INTEGER_TO_FLOAT;
         }
         if (from == BOOLEAN) {
@@ -314,10 +314,10 @@ public final class DataTypeConverter {
     }
 
     private static DefaultConverter conversionToDouble(DataType from) {
-        if (from.isRational()) {
+        if (from.isRationalNumber()) {
             return DefaultConverter.RATIONAL_TO_DOUBLE;
         }
-        if (from.isInteger()) {
+        if (from.isWholeNumber()) {
             return DefaultConverter.INTEGER_TO_DOUBLE;
         }
         if (from == BOOLEAN) {
@@ -333,10 +333,10 @@ public final class DataTypeConverter {
     }
 
     private static DefaultConverter conversionToDateTime(DataType from) {
-        if (from.isRational()) {
+        if (from.isRationalNumber()) {
             return DefaultConverter.RATIONAL_TO_DATETIME;
         }
-        if (from.isInteger()) {
+        if (from.isWholeNumber()) {
             return DefaultConverter.INTEGER_TO_DATETIME;
         }
         if (from == BOOLEAN) {
@@ -628,6 +628,6 @@ public final class DataTypeConverter {
             return dataType;
         }
 
-        return dataType.isInteger() ? dataType : LONG;
+        return dataType.isWholeNumber() ? dataType : LONG;
     }
 }

+ 2 - 2
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java

@@ -40,8 +40,8 @@ import java.util.List;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isFoldable;
-import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isInteger;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType;
+import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isWholeNumber;
 
 public class CountDistinct extends AggregateFunction implements OptionalArgument, ToAggregator, SurrogateExpression {
     public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
@@ -124,7 +124,7 @@ public class CountDistinct extends AggregateFunction implements OptionalArgument
         if (resolution.unresolved() || precision == null) {
             return resolution;
         }
-        return isInteger(precision, sourceText(), SECOND).and(isFoldable(precision, sourceText(), SECOND));
+        return isWholeNumber(precision, sourceText(), SECOND).and(isFoldable(precision, sourceText(), SECOND));
     }
 
     @Override

+ 1 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Rate.java

@@ -125,7 +125,7 @@ public class Rate extends AggregateFunction implements OptionalArgument, ToAggre
         );
         if (unit != null) {
             resolution = resolution.and(
-                isType(unit, dt -> dt.isInteger() || EsqlDataTypes.isTemporalAmount(dt), sourceText(), SECOND, "time_duration")
+                isType(unit, dt -> dt.isWholeNumber() || EsqlDataTypes.isTemporalAmount(dt), sourceText(), SECOND, "time_duration")
             );
         }
         return resolution;

+ 1 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sum.java

@@ -64,7 +64,7 @@ public class Sum extends NumericAggregate implements SurrogateExpression {
     @Override
     public DataType dataType() {
         DataType dt = field().dataType();
-        return dt.isInteger() == false || dt == UNSIGNED_LONG ? DOUBLE : LONG;
+        return dt.isWholeNumber() == false || dt == UNSIGNED_LONG ? DOUBLE : LONG;
     }
 
     @Override

+ 5 - 5
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Bucket.java

@@ -233,7 +233,7 @@ public class Bucket extends GroupingFunction implements Validatable, TwoOptional
     public ExpressionEvaluator.Factory toEvaluator(Function<Expression, ExpressionEvaluator.Factory> toEvaluator) {
         if (field.dataType() == DataType.DATETIME) {
             Rounding.Prepared preparedRounding;
-            if (buckets.dataType().isInteger()) {
+            if (buckets.dataType().isWholeNumber()) {
                 int b = ((Number) buckets.fold()).intValue();
                 long f = foldToLong(from);
                 long t = foldToLong(to);
@@ -252,7 +252,7 @@ public class Bucket extends GroupingFunction implements Validatable, TwoOptional
                 double t = ((Number) to.fold()).doubleValue();
                 roundTo = pickRounding(b, f, t);
             } else {
-                assert buckets.dataType().isRational() : "Unexpected rounding data type [" + buckets.dataType() + "]";
+                assert buckets.dataType().isRationalNumber() : "Unexpected rounding data type [" + buckets.dataType() + "]";
                 roundTo = ((Number) buckets.fold()).doubleValue();
             }
             Literal rounding = new Literal(source(), roundTo, DataType.DOUBLE);
@@ -323,21 +323,21 @@ public class Bucket extends GroupingFunction implements Validatable, TwoOptional
         if (fieldType == DataType.DATETIME) {
             TypeResolution resolution = isType(
                 buckets,
-                dt -> dt.isInteger() || EsqlDataTypes.isTemporalAmount(dt),
+                dt -> dt.isWholeNumber() || EsqlDataTypes.isTemporalAmount(dt),
                 sourceText(),
                 SECOND,
                 "integral",
                 "date_period",
                 "time_duration"
             );
-            return bucketsType.isInteger()
+            return bucketsType.isWholeNumber()
                 ? resolution.and(checkArgsCount(4))
                     .and(() -> isStringOrDate(from, sourceText(), THIRD))
                     .and(() -> isStringOrDate(to, sourceText(), FOURTH))
                 : resolution.and(checkArgsCount(2)); // temporal amount
         }
         if (fieldType.isNumeric()) {
-            return bucketsType.isInteger()
+            return bucketsType.isWholeNumber()
                 ? checkArgsCount(4).and(() -> isNumeric(from, sourceText(), THIRD)).and(() -> isNumeric(to, sourceText(), FOURTH))
                 : isNumeric(buckets, sourceText(), SECOND).and(checkArgsCount(2));
         }

+ 1 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Ceil.java

@@ -65,7 +65,7 @@ public class Ceil extends UnaryScalarFunction {
 
     @Override
     public ExpressionEvaluator.Factory toEvaluator(Function<Expression, ExpressionEvaluator.Factory> toEvaluator) {
-        if (dataType().isInteger()) {
+        if (dataType().isWholeNumber()) {
             return toEvaluator.apply(field());
         }
         var fieldEval = toEvaluator.apply(field());

+ 1 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Floor.java

@@ -67,7 +67,7 @@ public class Floor extends UnaryScalarFunction {
 
     @Override
     public ExpressionEvaluator.Factory toEvaluator(Function<Expression, ExpressionEvaluator.Factory> toEvaluator) {
-        if (dataType().isInteger()) {
+        if (dataType().isWholeNumber()) {
             return toEvaluator.apply(field());
         }
         return new FloorDoubleEvaluator.Factory(source(), toEvaluator.apply(field()));

+ 2 - 2
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Round.java

@@ -35,8 +35,8 @@ import java.util.function.Function;
 
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND;
-import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isInteger;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric;
+import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isWholeNumber;
 import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber;
 import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.bigIntegerToUnsignedLong;
 import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.longToUnsignedLong;
@@ -104,7 +104,7 @@ public class Round extends EsqlScalarFunction implements OptionalArgument {
             return resolution;
         }
 
-        return decimals == null ? TypeResolution.TYPE_RESOLVED : isInteger(decimals, sourceText(), SECOND);
+        return decimals == null ? TypeResolution.TYPE_RESOLVED : isWholeNumber(decimals, sourceText(), SECOND);
     }
 
     @Override

+ 5 - 5
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/SimplifyComparisonsArithmetics.java

@@ -132,7 +132,7 @@ public final class SimplifyComparisonsArithmetics extends
             // x + 1e18 > 1e18::long will yield different results with a field value in [-2^6, 2^6], optimised vs original;
             // x * (1 + 1e-15d) > 1 : same with a field value of (1 - 1e-15d)
             // so consequently, int fields optimisation requiring FP arithmetic isn't possible either: (x - 1e-15) * (1 + 1e-15) > 1.
-            if (opLiteral.dataType().isRational() || bcLiteral.dataType().isRational()) {
+            if (opLiteral.dataType().isRationalNumber() || bcLiteral.dataType().isRationalNumber()) {
                 return true;
             }
 
@@ -146,7 +146,7 @@ public final class SimplifyComparisonsArithmetics extends
 
         final Expression apply() {
             // force float point folding for FlP field
-            Literal bcl = operation.dataType().isRational()
+            Literal bcl = operation.dataType().isRationalNumber()
                 ? new Literal(bcLiteral.source(), ((Number) bcLiteral.value()).doubleValue(), DataType.DOUBLE)
                 : bcLiteral;
 
@@ -177,7 +177,7 @@ public final class SimplifyComparisonsArithmetics extends
         @Override
         boolean isOpUnsafe() {
             // no ADD/SUB with floating fields
-            if (operation.dataType().isRational()) {
+            if (operation.dataType().isRationalNumber()) {
                 return true;
             }
 
@@ -204,12 +204,12 @@ public final class SimplifyComparisonsArithmetics extends
         @Override
         boolean isOpUnsafe() {
             // Integer divisions are not safe to optimise: x / 5 > 1 <=/=> x > 5 for x in [6, 9]; same for the `==` comp
-            if (operation.dataType().isInteger() && isDiv) {
+            if (operation.dataType().isWholeNumber() && isDiv) {
                 return true;
             }
 
             // If current operation is a multiplication, it's inverse will be a division: safe only if outcome is still integral.
-            if (isDiv == false && opLeft.dataType().isInteger()) {
+            if (isDiv == false && opLeft.dataType().isWholeNumber()) {
                 long opLiteralValue = ((Number) opLiteral.value()).longValue();
                 return opLiteralValue == 0 || ((Number) bcLiteral.value()).longValue() % opLiteralValue != 0;
             }

+ 1 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java

@@ -294,7 +294,7 @@ public final class EsqlExpressionTranslators {
                 // Unsigned longs may be represented as BigInteger.
                 decimalValue = new BigDecimal(bigIntValue);
             } else {
-                decimalValue = valueDataType.isRational() ? BigDecimal.valueOf(doubleValue) : BigDecimal.valueOf(value.longValue());
+                decimalValue = valueDataType.isRationalNumber() ? BigDecimal.valueOf(doubleValue) : BigDecimal.valueOf(value.longValue());
             }
 
             // Determine min/max for dataType. Use BigDecimals as doubles will have rounding errors for long/ulong.