Browse Source

QL: add unsigned_long type support (#65145)

This introduces the UNSIGNED_LONG type to QL following its availability in ES (#60050).

The type is mapped to a BigInteger whose value is checked against the UL bounds.

The SQL will now support the type as literal and in the arithmetic functions; the non-arithmetic functions however are unchanged (i.e. they still require a long / int parameter where that is the case).

The type is version-gated: for the driver SQL clients (only) the server checks their version and in case this is lower than the one introducing the UL support, it fails the request, for queries, or simply hidden in catalog functions (similar to how UNSUPPORTED is currently treated in the similar case)

The JDBC tests are adjusted to read the (bwc) version of the driver they are run against and selectively disable part of the tests accordingly.

Closes #63312
Bogdan Pintea 3 years ago
parent
commit
67c98e9f3d
82 changed files with 3488 additions and 868 deletions
  1. 6 0
      docs/changelog/65145.yaml
  2. 2 14
      x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/ExpressionBuilder.java
  3. 1 0
      x-pack/plugin/eql/src/main/resources/org/elasticsearch/xpack/eql/plugin/eql_whitelist.txt
  4. 1 0
      x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java
  5. 3 0
      x-pack/plugin/eql/src/test/resources/mapping-numeric.json
  6. 0 1
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/execution/search/QlSourceBuilder.java
  7. 12 1
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/function/scalar/ScalarFunction.java
  8. 5 0
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/function/scalar/whitelist/InternalQlScriptUtils.java
  9. 36 0
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/predicate/operator/arithmetic/Arithmetics.java
  10. 6 0
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/predicate/operator/comparison/Comparisons.java
  11. 49 0
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/index/IndexCompatibility.java
  12. 44 0
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/index/VersionCompatibilityChecks.java
  13. 98 18
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypeConverter.java
  14. 7 1
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypes.java
  15. 1 1
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/Types.java
  16. 37 0
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/util/NumericUtils.java
  17. 22 0
      x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/util/StringUtils.java
  18. 90 0
      x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/expression/predicate/operator/arithmetic/BinaryArithmeticProcessorTests.java
  19. 13 0
      x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/expression/predicate/operator/comparison/BinaryComparisonProcessorTests.java
  20. 143 0
      x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/DataTypeConversionTests.java
  21. 1 1
      x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java
  22. 1 0
      x-pack/plugin/ql/src/test/resources/mapping-multi-field-variation.json
  23. 1 0
      x-pack/plugin/ql/src/test/resources/mapping-multi-field-with-nested.json
  24. 3 0
      x-pack/plugin/ql/src/test/resources/mapping-numeric.json
  25. 2 1
      x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/EsType.java
  26. 5 2
      x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcPreparedStatement.java
  27. 1 2
      x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcResultSetMetaData.java
  28. 89 8
      x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeConverter.java
  29. 21 1
      x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeUtils.java
  30. 60 0
      x-pack/plugin/sql/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/JdbcPreparedStatementTests.java
  31. 41 3
      x-pack/plugin/sql/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/TypeConverterTests.java
  32. 48 0
      x-pack/plugin/sql/qa/jdbc/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/JdbcTestUtils.java
  33. 24 0
      x-pack/plugin/sql/qa/jdbc/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/PreparedStatementTestCase.java
  34. 56 13
      x-pack/plugin/sql/qa/jdbc/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/ResultSetMetaDataTestCase.java
  35. 378 120
      x-pack/plugin/sql/qa/jdbc/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/ResultSetTestCase.java
  36. 14 0
      x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/FieldExtractorTestCase.java
  37. 2 0
      x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/SqlProtocolTestCase.java
  38. 1 0
      x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/CsvTestUtils.java
  39. 53 67
      x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DataLoader.java
  40. 13 0
      x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/JdbcAssert.java
  41. 29 0
      x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlTestCase.java
  42. 54 52
      x-pack/plugin/sql/qa/server/src/main/resources/alias.csv-spec
  43. 157 153
      x-pack/plugin/sql/qa/server/src/main/resources/command.csv-spec
  44. 102 0
      x-pack/plugin/sql/qa/server/src/main/resources/logs_unsigned_long.csv
  45. 69 58
      x-pack/plugin/sql/qa/server/src/main/resources/multi-cluster-with-security/multi-cluster-command-sys.csv-spec
  46. 37 29
      x-pack/plugin/sql/qa/server/src/main/resources/multi-cluster-with-security/multi-cluster-command.csv-spec
  47. 142 131
      x-pack/plugin/sql/qa/server/src/main/resources/single-node-only/command-sys.csv-spec
  48. 1 0
      x-pack/plugin/sql/qa/server/src/main/resources/slow/frozen.csv-spec
  49. 693 0
      x-pack/plugin/sql/qa/server/src/main/resources/unsigned-long.csv-spec
  50. 73 0
      x-pack/plugin/sql/qa/server/src/main/resources/unsigned-long.sql-spec
  51. 2 1
      x-pack/plugin/sql/sql-proto/src/main/java/org/elasticsearch/xpack/sql/proto/SqlVersion.java
  52. 6 7
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Analyzer.java
  53. 35 5
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Verifier.java
  54. 3 3
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/execution/search/Querier.java
  55. 43 16
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/execution/search/extractor/CompositeKeyExtractor.java
  56. 7 0
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/execution/search/extractor/FieldHitExtractor.java
  57. 12 0
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/execution/search/extractor/TopHitsAggExtractor.java
  58. 3 1
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/aggregate/Sum.java
  59. 7 0
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/math/MathProcessor.java
  60. 7 2
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/optimizer/Optimizer.java
  61. 2 12
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java
  62. 1 1
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/Explain.java
  63. 5 2
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/ShowColumns.java
  64. 13 2
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysColumns.java
  65. 6 2
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTypes.java
  66. 10 25
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/planner/QueryFolder.java
  67. 6 5
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/container/GroupByRef.java
  68. 9 2
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/session/SqlSession.java
  69. 19 20
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverter.java
  70. 9 1
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypes.java
  71. 165 9
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/FieldAttributeTests.java
  72. 14 0
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/VerifierErrorMessagesTests.java
  73. 30 7
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/CompositeKeyExtractorTests.java
  74. 14 0
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/FieldHitExtractorTests.java
  75. 11 0
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/TopHitsAggExtractorTests.java
  76. 17 0
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/math/MathFunctionProcessorTests.java
  77. 55 49
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java
  78. 97 0
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/ShowColumnsTests.java
  79. 57 17
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysColumnsTests.java
  80. 27 0
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTypesTests.java
  81. 3 2
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorSpecTests.java
  82. 46 0
      x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverterTests.java

+ 6 - 0
docs/changelog/65145.yaml

@@ -0,0 +1,6 @@
+pr: 65145
+summary: Add `unsigned_long` type support
+area: Query Languages
+type: enhancement
+issues:
+ - 63312

+ 2 - 14
x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/ExpressionBuilder.java

@@ -49,7 +49,6 @@ import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.LessT
 import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.LessThanOrEqual;
 import org.elasticsearch.xpack.ql.expression.predicate.regex.Like;
 import org.elasticsearch.xpack.ql.tree.Source;
-import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypes;
 import org.elasticsearch.xpack.ql.util.StringUtils;
 
@@ -240,10 +239,9 @@ public class ExpressionBuilder extends IdentifierBuilder {
         Source source = source(ctx);
         String text = ctx.getText();
 
-        long value;
-
         try {
-            value = Long.valueOf(StringUtils.parseLong(text));
+            Number value = StringUtils.parseIntegral(text);
+            return new Literal(source, value, DataTypes.fromJava(value));
         } catch (QlIllegalArgumentException siae) {
             // if it's too large, then quietly try to parse as a float instead
             try {
@@ -252,16 +250,6 @@ public class ExpressionBuilder extends IdentifierBuilder {
 
             throw new ParsingException(source, siae.getMessage());
         }
-
-        Object val = Long.valueOf(value);
-        DataType type = DataTypes.LONG;
-
-        // try to downsize to int if possible (since that's the most common type)
-        if ((int) value == value) {
-            type = DataTypes.INTEGER;
-            val = Integer.valueOf((int) value);
-        }
-        return new Literal(source, val, type);
     }
 
     @Override

+ 1 - 0
x-pack/plugin/eql/src/main/resources/org/elasticsearch/xpack/eql/plugin/eql_whitelist.txt

@@ -19,6 +19,7 @@ class org.elasticsearch.xpack.ql.expression.function.scalar.whitelist.InternalQl
   double nullSafeSortNumeric(Number)
   String nullSafeSortString(Object)
   Number nullSafeCastNumeric(Number, String)
+  Number nullSafeCastToUnsignedLong(Number)
 
 #
 # ASCII Functions

+ 1 - 0
x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java

@@ -237,6 +237,7 @@ public class VerifierTests extends ESTestCase {
         accept(idxr, "foo where float_field == 0");
         accept(idxr, "foo where half_float_field == 0");
         accept(idxr, "foo where scaled_float_field == 0");
+        accept(idxr, "foo where unsigned_long_field == 0");
 
         // Test query against unsupported field type int
         assertEquals(

+ 3 - 0
x-pack/plugin/eql/src/test/resources/mapping-numeric.json

@@ -34,6 +34,9 @@
         "scaled_float_field": {
             "type" : "scaled_float"
         },
+        "unsigned_long_field" : {
+          "type": "unsigned_long"
+        },
         "wrong_int_type_field": {
             "type" : "int"
         }

+ 0 - 1
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/execution/search/QlSourceBuilder.java

@@ -22,7 +22,6 @@ import java.util.Set;
  * the resulting ES document as a field.
  */
 public class QlSourceBuilder {
-    public static final Version SWITCH_TO_FIELDS_API_VERSION = Version.V_7_10_0;
     public static final Version INTRODUCING_MISSING_ORDER_IN_COMPOSITE_AGGS_VERSION = Version.V_7_16_0;
     // The LinkedHashMaps preserve the order of the fields in the response
     private final Set<FieldAndFormat> fetchFields = new LinkedHashSet<>();

+ 12 - 1
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/function/scalar/ScalarFunction.java

@@ -12,6 +12,7 @@ import org.elasticsearch.xpack.ql.expression.FieldAttribute;
 import org.elasticsearch.xpack.ql.expression.function.Function;
 import org.elasticsearch.xpack.ql.expression.function.aggregate.AggregateFunction;
 import org.elasticsearch.xpack.ql.expression.function.grouping.GroupingFunction;
+import org.elasticsearch.xpack.ql.expression.gen.script.Params;
 import org.elasticsearch.xpack.ql.expression.gen.script.ParamsBuilder;
 import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate;
 import org.elasticsearch.xpack.ql.expression.gen.script.Scripts;
@@ -24,10 +25,12 @@ import java.time.ZonedDateTime;
 import java.util.List;
 
 import static java.util.Collections.emptyList;
+import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
 import static org.elasticsearch.xpack.ql.expression.gen.script.ParamsBuilder.paramsBuilder;
 import static org.elasticsearch.xpack.ql.expression.gen.script.Scripts.PARAM;
 import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
 import static org.elasticsearch.xpack.ql.type.DataTypes.LONG;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 
 /**
  * A {@code ScalarFunction} is a {@code Function} that takes values from some
@@ -150,7 +153,15 @@ public abstract class ScalarFunction extends Function {
     }
 
     protected ScriptTemplate scriptWithField(FieldAttribute field) {
-        return new ScriptTemplate(processScript(Scripts.DOC_VALUE), paramsBuilder().variable(field.name()).build(), dataType());
+        Params params = paramsBuilder().variable(field.name()).build();
+        // unsigned_long fields get returned in scripts as plain longs, so a conversion is required
+        return field.dataType() != UNSIGNED_LONG
+            ? new ScriptTemplate(processScript(Scripts.DOC_VALUE), params, dataType())
+            : new ScriptTemplate(
+                processScript(format("{ql}.", "nullSafeCastToUnsignedLong({})", Scripts.DOC_VALUE)),
+                params,
+                UNSIGNED_LONG
+            );
     }
 
     protected String processScript(String script) {

+ 5 - 0
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/function/scalar/whitelist/InternalQlScriptUtils.java

@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Map;
 
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.convert;
+import static org.elasticsearch.xpack.ql.type.DataTypeConverter.toUnsignedLong;
 import static org.elasticsearch.xpack.ql.type.DataTypes.fromTypeName;
 
 public class InternalQlScriptUtils {
@@ -58,6 +59,10 @@ public class InternalQlScriptUtils {
         return number == null || Double.isNaN(number.doubleValue()) ? null : (Number) convert(number, fromTypeName(typeName));
     }
 
+    public static Number nullSafeCastToUnsignedLong(Number number) {
+        return number == null || Double.isNaN(number.doubleValue()) ? null : toUnsignedLong(number);
+    }
+
     //
     // Operators
     //

+ 36 - 0
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/predicate/operator/arithmetic/Arithmetics.java

@@ -8,8 +8,11 @@ package org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic;
 
 import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
 
+import java.math.BigInteger;
 import java.util.function.BiFunction;
 
+import static org.elasticsearch.xpack.ql.util.NumericUtils.asUnsignedLong;
+
 /**
  * Arithmetic operation using the type widening rules of the JLS 5.6.2 namely
  * widen to double or float or long or int in this order.
@@ -43,6 +46,10 @@ public final class Arithmetics {
         if (l instanceof Float || r instanceof Float) {
             return Float.valueOf(l.floatValue() + r.floatValue());
         }
+        if (l instanceof BigInteger || r instanceof BigInteger) {
+            BigInteger bi = asBigInteger(l).add(asBigInteger(r));
+            return asUnsignedLong(bi);
+        }
         if (l instanceof Long || r instanceof Long) {
             return Long.valueOf(Math.addExact(l.longValue(), r.longValue()));
         }
@@ -61,6 +68,10 @@ public final class Arithmetics {
         if (l instanceof Float || r instanceof Float) {
             return Float.valueOf(l.floatValue() - r.floatValue());
         }
+        if (l instanceof BigInteger || r instanceof BigInteger) {
+            BigInteger bi = asBigInteger(l).subtract(asBigInteger(r));
+            return asUnsignedLong(bi);
+        }
         if (l instanceof Long || r instanceof Long) {
             return Long.valueOf(Math.subtractExact(l.longValue(), r.longValue()));
         }
@@ -79,6 +90,13 @@ public final class Arithmetics {
         if (l instanceof Float || r instanceof Float) {
             return Float.valueOf(l.floatValue() * r.floatValue());
         }
+        if (l instanceof BigInteger || r instanceof BigInteger) {
+            BigInteger bi = asBigInteger(l).multiply(asBigInteger(r));
+            // Note: in case of unsigned_long overflow (or underflow, with negative fixed point numbers), the exception is thrown.
+            // This is unlike the way some other traditional RDBMS that support unsigned types work, which simply promote the result to a
+            // floating point type, but in line with how our implementation treats other fixed point type operations (i.e. Math#xxExact()).
+            return asUnsignedLong(bi);
+        }
         if (l instanceof Long || r instanceof Long) {
             return Long.valueOf(Math.multiplyExact(l.longValue(), r.longValue()));
         }
@@ -97,6 +115,10 @@ public final class Arithmetics {
         if (l instanceof Float || r instanceof Float) {
             return l.floatValue() / r.floatValue();
         }
+        if (l instanceof BigInteger || r instanceof BigInteger) {
+            BigInteger bi = asBigInteger(l).divide(asBigInteger(r));
+            return asUnsignedLong(bi);
+        }
         if (l instanceof Long || r instanceof Long) {
             return l.longValue() / r.longValue();
         }
@@ -115,6 +137,10 @@ public final class Arithmetics {
         if (l instanceof Float || r instanceof Float) {
             return Float.valueOf(l.floatValue() % r.floatValue());
         }
+        if (l instanceof BigInteger || r instanceof BigInteger) {
+            BigInteger bi = asBigInteger(l).remainder(asBigInteger(r));
+            return asUnsignedLong(bi);
+        }
         if (l instanceof Long || r instanceof Long) {
             return Long.valueOf(l.longValue() % r.longValue());
         }
@@ -141,10 +167,20 @@ public final class Arithmetics {
             }
             return Float.valueOf(-n.floatValue());
         }
+        if (n instanceof BigInteger) {
+            if (((BigInteger) n).signum() != 0) {
+                throw new ArithmeticException("unsigned_long overflow"); // in the scope of the unsigned_long type
+            }
+            return n;
+        }
         if (n instanceof Long) {
             return Long.valueOf(Math.negateExact(n.longValue()));
         }
 
         return Integer.valueOf(Math.negateExact(n.intValue()));
     }
+
+    public static BigInteger asBigInteger(Number n) {
+        return n instanceof BigInteger ? (BigInteger) n : BigInteger.valueOf(n.longValue());
+    }
 }

+ 6 - 0
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/predicate/operator/comparison/Comparisons.java

@@ -6,8 +6,11 @@
  */
 package org.elasticsearch.xpack.ql.expression.predicate.operator.comparison;
 
+import java.math.BigInteger;
 import java.util.Set;
 
+import static org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.Arithmetics.asBigInteger;
+
 /**
  * Comparison utilities.
  */
@@ -92,6 +95,9 @@ public final class Comparisons {
         if (l instanceof Float || r instanceof Float) {
             return Float.compare(l.floatValue(), r.floatValue());
         }
+        if (l instanceof BigInteger || r instanceof BigInteger) {
+            return asBigInteger(l).compareTo(asBigInteger(r));
+        }
         if (l instanceof Long || r instanceof Long) {
             return Long.compare(l.longValue(), r.longValue());
         }

+ 49 - 0
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/index/IndexCompatibility.java

@@ -0,0 +1,49 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.ql.index;
+
+import org.elasticsearch.Version;
+import org.elasticsearch.xpack.ql.type.DataType;
+import org.elasticsearch.xpack.ql.type.EsField;
+import org.elasticsearch.xpack.ql.type.UnsupportedEsField;
+
+import java.util.Map;
+
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.isTypeSupportedInVersion;
+import static org.elasticsearch.xpack.ql.type.DataTypes.isPrimitive;
+import static org.elasticsearch.xpack.ql.type.Types.propagateUnsupportedType;
+
+public final class IndexCompatibility {
+
+    public static Map<String, EsField> compatible(Map<String, EsField> mapping, Version version) {
+        for (Map.Entry<String, EsField> entry : mapping.entrySet()) {
+            EsField esField = entry.getValue();
+            DataType dataType = esField.getDataType();
+            if (isPrimitive(dataType) == false) {
+                compatible(esField.getProperties(), version);
+            } else if (isTypeSupportedInVersion(dataType, version) == false) {
+                EsField field = new UnsupportedEsField(entry.getKey(), dataType.name(), null, esField.getProperties());
+                entry.setValue(field);
+                propagateUnsupportedType(entry.getKey(), dataType.name(), esField.getProperties());
+            }
+        }
+        return mapping;
+    }
+
+    public static EsIndex compatible(EsIndex esIndex, Version version) {
+        compatible(esIndex.mapping(), version);
+        return esIndex;
+    }
+
+    public static IndexResolution compatible(IndexResolution indexResolution, Version version) {
+        if (indexResolution.isValid()) {
+            compatible(indexResolution.get(), version);
+        }
+        return indexResolution;
+    }
+}

+ 44 - 0
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/index/VersionCompatibilityChecks.java

@@ -0,0 +1,44 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.ql.index;
+
+import org.elasticsearch.Version;
+import org.elasticsearch.core.Nullable;
+import org.elasticsearch.xpack.ql.type.DataType;
+
+import static org.elasticsearch.Version.V_8_2_0;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
+
+public final class VersionCompatibilityChecks {
+
+    public static final Version INTRODUCING_UNSIGNED_LONG = V_8_2_0;
+
+    private VersionCompatibilityChecks() {}
+
+    public static boolean isTypeSupportedInVersion(DataType dataType, Version version) {
+        if (dataType == UNSIGNED_LONG) {
+            return supportsUnsignedLong(version);
+        }
+        return true;
+    }
+
+    /**
+     * Does the provided {@code version} support the unsigned_long type (PR#60050)?
+     */
+    public static boolean supportsUnsignedLong(Version version) {
+        return INTRODUCING_UNSIGNED_LONG.compareTo(version) <= 0;
+    }
+
+    public static @Nullable Version versionIntroducingType(DataType dataType) {
+        if (dataType == UNSIGNED_LONG) {
+            return INTRODUCING_UNSIGNED_LONG;
+        }
+
+        return null;
+    }
+}

+ 98 - 18
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypeConverter.java

@@ -13,12 +13,13 @@ import org.elasticsearch.core.Booleans;
 import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
 
 import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeParseException;
 import java.util.Locale;
 import java.util.function.DoubleFunction;
 import java.util.function.Function;
-import java.util.function.LongFunction;
 
 import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN;
 import static org.elasticsearch.xpack.ql.type.DataTypes.BYTE;
@@ -32,9 +33,13 @@ import static org.elasticsearch.xpack.ql.type.DataTypes.LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypes.NULL;
 import static org.elasticsearch.xpack.ql.type.DataTypes.SHORT;
 import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypes.isDateTime;
 import static org.elasticsearch.xpack.ql.type.DataTypes.isPrimitive;
 import static org.elasticsearch.xpack.ql.type.DataTypes.isString;
+import static org.elasticsearch.xpack.ql.util.NumericUtils.UNSIGNED_LONG_MAX;
+import static org.elasticsearch.xpack.ql.util.NumericUtils.inUnsignedLongRange;
+import static org.elasticsearch.xpack.ql.util.NumericUtils.isUnsignedLong;
 
 /**
  * Conversion utility from one Elasticsearch data type to another Elasticsearch data types.
@@ -74,6 +79,9 @@ public final class DataTypeConverter {
             if (left.isInteger()) {
                 // promote the highest int
                 if (right.isInteger()) {
+                    if (left == UNSIGNED_LONG || right == UNSIGNED_LONG) {
+                        return UNSIGNED_LONG;
+                    }
                     return left.size() > right.size() ? left : right;
                 }
                 // promote the rational
@@ -135,6 +143,9 @@ public final class DataTypeConverter {
         if (to == LONG) {
             return conversionToLong(from);
         }
+        if (to == UNSIGNED_LONG) {
+            return conversionToUnsignedLong(from);
+        }
         if (to == INTEGER) {
             return conversionToInt(from);
         }
@@ -176,6 +187,25 @@ public final class DataTypeConverter {
         return null;
     }
 
+    private static Converter conversionToUnsignedLong(DataType from) {
+        if (from.isRational()) {
+            return DefaultConverter.RATIONAL_TO_UNSIGNED_LONG;
+        }
+        if (from.isInteger()) {
+            return DefaultConverter.INTEGER_TO_UNSIGNED_LONG;
+        }
+        if (from == BOOLEAN) {
+            return DefaultConverter.BOOL_TO_UNSIGNED_LONG;
+        }
+        if (isString(from)) {
+            return DefaultConverter.STRING_TO_UNSIGNED_LONG;
+        }
+        if (from == DATETIME) {
+            return DefaultConverter.DATETIME_TO_UNSIGNED_LONG;
+        }
+        return null;
+    }
+
     private static Converter conversionToLong(DataType from) {
         if (from.isRational()) {
             return DefaultConverter.RATIONAL_TO_LONG;
@@ -340,15 +370,59 @@ public final class DataTypeConverter {
         return (int) x;
     }
 
-    public static long safeToLong(double x) {
+    public static long safeDoubleToLong(double x) {
         if (x > Long.MAX_VALUE || x < Long.MIN_VALUE) {
             throw new QlIllegalArgumentException("[" + x + "] out of [long] range");
         }
         return Math.round(x);
     }
 
+    public static Long safeToLong(Number x) {
+        try {
+            if (x instanceof BigInteger) {
+                return ((BigInteger) x).longValueExact();
+            }
+            // integer converters are also provided double values (aggs generated on integer fields)
+            if (x instanceof Double || x instanceof Float) {
+                return safeDoubleToLong(x.doubleValue());
+            }
+            return x.longValue();
+        } catch (ArithmeticException ae) {
+            throw new QlIllegalArgumentException("[" + x + "] out of [long] range", ae);
+        }
+    }
+
+    public static BigInteger safeToUnsignedLong(Double x) {
+        if (inUnsignedLongRange(x) == false) {
+            throw new QlIllegalArgumentException("[" + x + "] out of [unsigned_long] range");
+        }
+        return BigDecimal.valueOf(x).toBigInteger();
+    }
+
+    public static BigInteger safeToUnsignedLong(Long x) {
+        if (x < 0) {
+            throw new QlIllegalArgumentException("[" + x + "] out of [unsigned_long] range");
+        }
+        return BigInteger.valueOf(x);
+    }
+
+    public static BigInteger safeToUnsignedLong(String x) {
+        BigInteger bi = new BigDecimal(x).toBigInteger();
+        if (isUnsignedLong(bi) == false) {
+            throw new QlIllegalArgumentException("[" + x + "] out of [unsigned_long] range");
+        }
+        return bi;
+    }
+
+    // "unsafe" value conversion to unsigned long (vs. "safe", type-only conversion of safeToUnsignedLong());
+    // -1L -> 18446744073709551615 (=UNSIGNED_LONG_MAX)
+    public static BigInteger toUnsignedLong(Number number) {
+        BigInteger bi = BigInteger.valueOf(number.longValue());
+        return bi.signum() < 0 ? bi.and(UNSIGNED_LONG_MAX) : bi;
+    }
+
     public static Number toInteger(double x, DataType dataType) {
-        long l = safeToLong(x);
+        long l = safeDoubleToLong(x);
 
         if (dataType == BYTE) {
             return safeToByte(l);
@@ -405,38 +479,43 @@ public final class DataTypeConverter {
         DATETIME_TO_STRING(o -> DateUtils.toString((ZonedDateTime) o)),
         OTHER_TO_STRING(String::valueOf),
 
-        RATIONAL_TO_LONG(fromDouble(DataTypeConverter::safeToLong)),
-        INTEGER_TO_LONG(fromLong(value -> value)),
+        RATIONAL_TO_UNSIGNED_LONG(fromDouble(DataTypeConverter::safeToUnsignedLong)),
+        INTEGER_TO_UNSIGNED_LONG(fromNumber(value -> DataTypeConverter.safeToUnsignedLong(value.longValue()))),
+        STRING_TO_UNSIGNED_LONG(fromString(DataTypeConverter::safeToUnsignedLong, "unsigned_long")),
+        DATETIME_TO_UNSIGNED_LONG(fromDateTime(DataTypeConverter::safeToUnsignedLong)),
+
+        RATIONAL_TO_LONG(fromDouble(DataTypeConverter::safeDoubleToLong)),
+        INTEGER_TO_LONG(fromNumber(DataTypeConverter::safeToLong)),
         STRING_TO_LONG(fromString(Long::valueOf, "long")),
         DATETIME_TO_LONG(fromDateTime(value -> value)),
 
-        RATIONAL_TO_INT(fromDouble(value -> safeToInt(safeToLong(value)))),
-        INTEGER_TO_INT(fromLong(DataTypeConverter::safeToInt)),
+        RATIONAL_TO_INT(fromDouble(value -> safeToInt(safeDoubleToLong(value)))),
+        INTEGER_TO_INT(fromNumber(value -> safeToInt(safeToLong(value)))),
         BOOL_TO_INT(fromBool(value -> value ? 1 : 0)),
         STRING_TO_INT(fromString(Integer::valueOf, "integer")),
         DATETIME_TO_INT(fromDateTime(DataTypeConverter::safeToInt)),
 
-        RATIONAL_TO_SHORT(fromDouble(value -> safeToShort(safeToLong(value)))),
-        INTEGER_TO_SHORT(fromLong(DataTypeConverter::safeToShort)),
+        RATIONAL_TO_SHORT(fromDouble(value -> safeToShort(safeDoubleToLong(value)))),
+        INTEGER_TO_SHORT(fromNumber(value -> safeToShort(safeToLong(value)))),
         BOOL_TO_SHORT(fromBool(value -> value ? (short) 1 : (short) 0)),
         STRING_TO_SHORT(fromString(Short::valueOf, "short")),
         DATETIME_TO_SHORT(fromDateTime(DataTypeConverter::safeToShort)),
 
-        RATIONAL_TO_BYTE(fromDouble(value -> safeToByte(safeToLong(value)))),
-        INTEGER_TO_BYTE(fromLong(DataTypeConverter::safeToByte)),
+        RATIONAL_TO_BYTE(fromDouble(value -> safeToByte(safeDoubleToLong(value)))),
+        INTEGER_TO_BYTE(fromNumber(value -> safeToByte(safeToLong(value)))),
         BOOL_TO_BYTE(fromBool(value -> value ? (byte) 1 : (byte) 0)),
         STRING_TO_BYTE(fromString(Byte::valueOf, "byte")),
         DATETIME_TO_BYTE(fromDateTime(DataTypeConverter::safeToByte)),
 
-        // TODO floating point conversions are lossy but conversions to integer conversions are not. Are we ok with that?
+        // TODO floating point conversions are lossy but conversions to integer are not. Are we ok with that?
         RATIONAL_TO_FLOAT(fromDouble(value -> (float) value)),
-        INTEGER_TO_FLOAT(fromLong(value -> (float) value)),
+        INTEGER_TO_FLOAT(fromNumber(Number::floatValue)),
         BOOL_TO_FLOAT(fromBool(value -> value ? 1f : 0f)),
         STRING_TO_FLOAT(fromString(Float::valueOf, "float")),
         DATETIME_TO_FLOAT(fromDateTime(value -> (float) value)),
 
         RATIONAL_TO_DOUBLE(fromDouble(Double::valueOf)),
-        INTEGER_TO_DOUBLE(fromLong(Double::valueOf)),
+        INTEGER_TO_DOUBLE(fromNumber(Number::doubleValue)),
         BOOL_TO_DOUBLE(fromBool(value -> value ? 1d : 0d)),
         STRING_TO_DOUBLE(fromString(Double::valueOf, "double")),
         DATETIME_TO_DOUBLE(fromDateTime(Double::valueOf)),
@@ -446,10 +525,11 @@ public final class DataTypeConverter {
         BOOL_TO_DATETIME(toDateTime(BOOL_TO_INT)),
         STRING_TO_DATETIME(fromString(DateUtils::asDateTime, "datetime")),
 
-        NUMERIC_TO_BOOLEAN(fromLong(value -> value != 0)),
+        NUMERIC_TO_BOOLEAN(fromDouble(value -> value != 0)),
         STRING_TO_BOOLEAN(fromString(DataTypeConverter::convertToBoolean, "boolean")),
         DATETIME_TO_BOOLEAN(fromDateTime(value -> value != 0)),
 
+        BOOL_TO_UNSIGNED_LONG(fromBool(value -> value ? BigInteger.ONE : BigInteger.ZERO)),
         BOOL_TO_LONG(fromBool(value -> value ? 1L : 0L)),
 
         STRING_TO_IP(o -> {
@@ -471,11 +551,11 @@ public final class DataTypeConverter {
             return (Object l) -> converter.apply(((Number) l).doubleValue());
         }
 
-        private static Function<Object, Object> fromLong(LongFunction<Object> converter) {
-            return (Object l) -> converter.apply(((Number) l).longValue());
+        private static Function<Object, Object> fromNumber(Function<Number, Object> converter) {
+            return l -> converter.apply((Number) l);
         }
 
-        private static Function<Object, Object> fromString(Function<String, Object> converter, String to) {
+        public static Function<Object, Object> fromString(Function<String, Object> converter, String to) {
             return (Object value) -> {
                 try {
                     return converter.apply(value.toString());

+ 7 - 1
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypes.java

@@ -6,6 +6,7 @@
  */
 package org.elasticsearch.xpack.ql.type;
 
+import java.math.BigInteger;
 import java.time.ZonedDateTime;
 import java.util.Arrays;
 import java.util.Collection;
@@ -31,6 +32,7 @@ public final class DataTypes {
     public static final DataType SHORT            = new DataType("short",             Short.BYTES,       true, false, true);
     public static final DataType INTEGER          = new DataType("integer",           Integer.BYTES,     true, false, true);
     public static final DataType LONG             = new DataType("long",              Long.BYTES,        true, false, true);
+    public static final DataType UNSIGNED_LONG    = new DataType("unsigned_long",     Long.BYTES,        true, false, true);
     // decimal numeric
     public static final DataType DOUBLE           = new DataType("double",            Double.BYTES,      false, true, true);
     public static final DataType FLOAT            = new DataType("float",             Float.BYTES,       false, true, true);
@@ -58,6 +60,7 @@ public final class DataTypes {
         SHORT,
         INTEGER,
         LONG,
+        UNSIGNED_LONG,
         DOUBLE,
         FLOAT,
         HALF_FLOAT,
@@ -106,6 +109,9 @@ public final class DataTypes {
         if (value instanceof Long) {
             return LONG;
         }
+        if (value instanceof BigInteger) {
+            return UNSIGNED_LONG;
+        }
         if (value instanceof Boolean) {
             return BOOLEAN;
         }
@@ -152,7 +158,7 @@ public final class DataTypes {
     }
 
     public static boolean isSigned(DataType t) {
-        return t.isNumeric();
+        return t.isNumeric() && t.equals(UNSIGNED_LONG) == false;
     }
 
     public static boolean isDateTime(DataType type) {

+ 1 - 1
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/Types.java

@@ -121,7 +121,7 @@ public abstract class Types {
         return value == null ? defaultValue : Integer.parseInt(value.toString());
     }
 
-    private static void propagateUnsupportedType(String inherited, String originalType, Map<String, EsField> properties) {
+    public static void propagateUnsupportedType(String inherited, String originalType, Map<String, EsField> properties) {
         if (properties != null && properties.isEmpty() == false) {
             for (Entry<String, EsField> entry : properties.entrySet()) {
                 EsField field = entry.getValue();

+ 37 - 0
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/util/NumericUtils.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.ql.util;
+
+import java.math.BigInteger;
+
+public abstract class NumericUtils {
+    // 18446744073709551615
+    public static final BigInteger UNSIGNED_LONG_MAX = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE);
+
+    // 18446744073709551615.0
+    public static final double UNSIGNED_LONG_MAX_AS_DOUBLE = UNSIGNED_LONG_MAX.doubleValue();
+
+    public static boolean isUnsignedLong(BigInteger bi) {
+        return bi.signum() >= 0 && bi.compareTo(UNSIGNED_LONG_MAX) <= 0;
+    }
+
+    public static boolean inUnsignedLongRange(double d) {
+        // UNSIGNED_LONG_MAX can't be represented precisely enough on a double, being converted as a rounded up value.
+        // Converting it to a double and back will yield a larger unsigned long, so the double comparison is still preferred, but
+        // it'll require the equality check. (BigDecimal comparisons only make sense for string-recovered floating point numbers.)
+        // This also means that 18446744073709551615.0 is actually a double too high to be converted as an unsigned long.
+        return d >= 0 && d < UNSIGNED_LONG_MAX_AS_DOUBLE;
+    }
+
+    public static BigInteger asUnsignedLong(BigInteger bi) {
+        if (isUnsignedLong(bi) == false) {
+            throw new ArithmeticException("unsigned_long overflow");
+        }
+        return bi;
+    }
+}

+ 22 - 0
x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/util/StringUtils.java

@@ -26,6 +26,7 @@ import java.util.StringJoiner;
 import static java.util.stream.Collectors.toList;
 import static org.elasticsearch.transport.RemoteClusterAware.REMOTE_CLUSTER_INDEX_SEPARATOR;
 import static org.elasticsearch.transport.RemoteClusterAware.buildRemoteIndexName;
+import static org.elasticsearch.xpack.ql.util.NumericUtils.isUnsignedLong;
 
 public final class StringUtils {
 
@@ -300,6 +301,27 @@ public final class StringUtils {
         }
     }
 
+    public static Number parseIntegral(String string) throws QlIllegalArgumentException {
+        BigInteger bi;
+        try {
+            bi = new BigInteger(string);
+        } catch (NumberFormatException ex) {
+            throw new QlIllegalArgumentException("Cannot parse number [{}]", string);
+        }
+        if (bi.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
+            if (isUnsignedLong(bi) == false) {
+                throw new QlIllegalArgumentException("Number [{}] is too large", string);
+            }
+            return bi;
+        }
+        // try to downsize to int if possible (since that's the most common type)
+        if (bi.intValue() == bi.longValue()) { // ternary operator would always promote to Long
+            return bi.intValueExact();
+        } else {
+            return bi.longValueExact();
+        }
+    }
+
     public static String ordinal(int i) {
         return switch (i % 100) {
             case 11, 12, 13 -> i + "th";

+ 90 - 0
x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/expression/predicate/operator/arithmetic/BinaryArithmeticProcessorTests.java

@@ -15,6 +15,9 @@ import org.elasticsearch.xpack.ql.expression.Literal;
 import org.elasticsearch.xpack.ql.expression.gen.processor.ConstantProcessor;
 import org.elasticsearch.xpack.ql.expression.gen.processor.Processor;
 import org.elasticsearch.xpack.ql.expression.processor.Processors;
+import org.elasticsearch.xpack.ql.util.NumericUtils;
+
+import java.math.BigInteger;
 
 import static org.elasticsearch.xpack.ql.tree.Source.EMPTY;
 
@@ -47,16 +50,61 @@ public class BinaryArithmeticProcessorTests extends AbstractWireSerializingTestC
         assertEquals(10, ba.process(null));
     }
 
+    public void testAddUnsignedLong() {
+        Processor ba = new Add(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor();
+        assertEquals(BigInteger.valueOf(10), ba.process(null));
+
+        ba = new Add(EMPTY, l(BigInteger.ONE), l(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE))).makePipe().asProcessor();
+        assertEquals(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.TWO), ba.process(null));
+
+        ba = new Add(EMPTY, l(BigInteger.valueOf(7)), l((short) -3)).makePipe().asProcessor();
+        assertEquals(BigInteger.valueOf(4), ba.process(null));
+
+        ba = new Add(EMPTY, l(BigInteger.valueOf(7)), l(-3f)).makePipe().asProcessor();
+        assertEquals(4f, ba.process(null));
+
+        Processor pn = new Add(EMPTY, l(BigInteger.valueOf(7)), l(-8)).makePipe().asProcessor();
+        expectThrows(ArithmeticException.class, () -> pn.process(null));
+
+        Processor pm = new Add(EMPTY, l(NumericUtils.UNSIGNED_LONG_MAX), l(1)).makePipe().asProcessor();
+        expectThrows(ArithmeticException.class, () -> pm.process(null));
+    }
+
     public void testSub() {
         Processor ba = new Sub(EMPTY, l(7), l(3)).makePipe().asProcessor();
         assertEquals(4, ba.process(null));
     }
 
+    public void testSubUnsignedLong() {
+        Processor bs = new Sub(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor();
+        assertEquals(BigInteger.valueOf(4), bs.process(null));
+
+        bs = new Sub(EMPTY, l(BigInteger.valueOf(7)), l((short) -3)).makePipe().asProcessor();
+        assertEquals(BigInteger.valueOf(10), bs.process(null));
+
+        bs = new Sub(EMPTY, l(BigInteger.valueOf(7)), l(3f)).makePipe().asProcessor();
+        assertEquals(4f, bs.process(null));
+
+        Processor proc = new Sub(EMPTY, l(BigInteger.valueOf(7)), l(8)).makePipe().asProcessor();
+        expectThrows(ArithmeticException.class, () -> proc.process(null));
+    }
+
     public void testMul() {
         Processor ba = new Mul(EMPTY, l(7), l(3)).makePipe().asProcessor();
         assertEquals(21, ba.process(null));
     }
 
+    public void testMulUnsignedLong() {
+        Processor bm = new Mul(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor();
+        assertEquals(BigInteger.valueOf(21), bm.process(null));
+
+        bm = new Mul(EMPTY, l(BigInteger.valueOf(7)), l(3f)).makePipe().asProcessor();
+        assertEquals(21f, bm.process(null));
+
+        Processor proc = new Mul(EMPTY, l(BigInteger.valueOf(7)), l(-8)).makePipe().asProcessor();
+        expectThrows(ArithmeticException.class, () -> proc.process(null));
+    }
+
     public void testDiv() {
         Processor ba = new Div(EMPTY, l(7), l(3)).makePipe().asProcessor();
         assertEquals(2, ((Number) ba.process(null)).longValue());
@@ -64,16 +112,46 @@ public class BinaryArithmeticProcessorTests extends AbstractWireSerializingTestC
         assertEquals(2.33, ((Number) ba.process(null)).doubleValue(), 0.01d);
     }
 
+    public void testDivUnsignedLong() {
+        Processor bd = new Div(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor();
+        assertEquals(BigInteger.TWO, bd.process(null));
+
+        bd = new Div(EMPTY, l(7), l(BigInteger.valueOf(8))).makePipe().asProcessor();
+        assertEquals(BigInteger.ZERO, bd.process(null));
+
+        bd = new Div(EMPTY, l(BigInteger.valueOf(7)), l(3f)).makePipe().asProcessor();
+        assertEquals(7 / 3f, bd.process(null));
+
+        Processor proc = new Div(EMPTY, l(BigInteger.valueOf(7)), l(-2)).makePipe().asProcessor();
+        expectThrows(ArithmeticException.class, () -> proc.process(null));
+    }
+
     public void testMod() {
         Processor ba = new Mod(EMPTY, l(7), l(3)).makePipe().asProcessor();
         assertEquals(1, ba.process(null));
     }
 
+    public void testModUnsignedLong() {
+        Processor bm = new Mod(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor();
+        assertEquals(BigInteger.valueOf(1), bm.process(null));
+
+        Processor proc = new Mod(EMPTY, l(-7), l(BigInteger.valueOf(3))).makePipe().asProcessor();
+        expectThrows(ArithmeticException.class, () -> proc.process(null));
+    }
+
     public void testNegate() {
         Processor ba = new Neg(EMPTY, l(7)).asPipe().asProcessor();
         assertEquals(-7, ba.process(null));
     }
 
+    public void testNegateUnsignedLong() {
+        Processor nm = new Neg(EMPTY, l(BigInteger.valueOf(0))).makePipe().asProcessor();
+        assertEquals(BigInteger.ZERO, nm.process(null));
+
+        Processor proc = new Neg(EMPTY, l(BigInteger.valueOf(3))).makePipe().asProcessor();
+        expectThrows(ArithmeticException.class, () -> proc.process(null));
+    }
+
     // ((3*2+4)/2-2)%2
     public void testTree() {
         Expression mul = new Mul(EMPTY, l(3), l(2));
@@ -86,6 +164,18 @@ public class BinaryArithmeticProcessorTests extends AbstractWireSerializingTestC
         assertEquals(1, proc.process(null));
     }
 
+    // ((3*2+4)/2-2)%2
+    public void testTreeUnsignedLong() {
+        Expression mul = new Mul(EMPTY, l(3), l(BigInteger.TWO));
+        Expression add = new Add(EMPTY, mul, l(4));
+        Expression div = new Div(EMPTY, add, l(2));
+        Expression sub = new Sub(EMPTY, div, l(2));
+        Mod mod = new Mod(EMPTY, sub, l(2));
+
+        Processor proc = mod.makePipe().asProcessor();
+        assertEquals(BigInteger.ONE, proc.process(null));
+    }
+
     public void testHandleNull() {
         assertNull(new Add(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null));
         assertNull(new Sub(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null));

+ 13 - 0
x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/expression/predicate/operator/comparison/BinaryComparisonProcessorTests.java

@@ -14,6 +14,8 @@ import org.elasticsearch.xpack.ql.expression.Literal;
 import org.elasticsearch.xpack.ql.expression.gen.processor.ConstantProcessor;
 import org.elasticsearch.xpack.ql.expression.processor.Processors;
 
+import java.math.BigInteger;
+
 import static org.elasticsearch.xpack.ql.TestUtils.equalsOf;
 import static org.elasticsearch.xpack.ql.TestUtils.greaterThanOf;
 import static org.elasticsearch.xpack.ql.TestUtils.greaterThanOrEqualOf;
@@ -51,6 +53,8 @@ public class BinaryComparisonProcessorTests extends AbstractWireSerializingTestC
     public void testEq() {
         assertEquals(true, equalsOf(l(4), l(4)).makePipe().asProcessor().process(null));
         assertEquals(false, equalsOf(l(3), l(4)).makePipe().asProcessor().process(null));
+        assertEquals(true, equalsOf(l(BigInteger.valueOf(4)), l(4L)).makePipe().asProcessor().process(null));
+        assertEquals(false, equalsOf(l(BigInteger.valueOf(3)), l(4L)).makePipe().asProcessor().process(null));
     }
 
     public void testNullEq() {
@@ -64,30 +68,39 @@ public class BinaryComparisonProcessorTests extends AbstractWireSerializingTestC
     public void testNEq() {
         assertEquals(false, notEqualsOf(l(4), l(4)).makePipe().asProcessor().process(null));
         assertEquals(true, notEqualsOf(l(3), l(4)).makePipe().asProcessor().process(null));
+        assertEquals(true, notEqualsOf(l(BigInteger.valueOf(3)), l(4)).makePipe().asProcessor().process(null));
     }
 
     public void testGt() {
         assertEquals(true, greaterThanOf(l(4), l(3)).makePipe().asProcessor().process(null));
         assertEquals(false, greaterThanOf(l(3), l(4)).makePipe().asProcessor().process(null));
         assertEquals(false, greaterThanOf(l(3), l(3)).makePipe().asProcessor().process(null));
+        assertEquals(true, greaterThanOf(l(4), l(BigInteger.valueOf(3))).makePipe().asProcessor().process(null));
     }
 
     public void testGte() {
         assertEquals(true, greaterThanOrEqualOf(l(4), l(3)).makePipe().asProcessor().process(null));
         assertEquals(false, greaterThanOrEqualOf(l(3), l(4)).makePipe().asProcessor().process(null));
         assertEquals(true, greaterThanOrEqualOf(l(3), l(3)).makePipe().asProcessor().process(null));
+        assertEquals(true, greaterThanOrEqualOf(l(BigInteger.valueOf(3)), l(3L)).makePipe().asProcessor().process(null));
+        assertEquals(true, greaterThanOrEqualOf(l(BigInteger.valueOf(4)), l(3L)).makePipe().asProcessor().process(null));
+        assertEquals(false, greaterThanOrEqualOf(l(BigInteger.valueOf(3)), l(4L)).makePipe().asProcessor().process(null));
     }
 
     public void testLt() {
         assertEquals(false, lessThanOf(l(4), l(3)).makePipe().asProcessor().process(null));
         assertEquals(true, lessThanOf(l(3), l(4)).makePipe().asProcessor().process(null));
         assertEquals(false, lessThanOf(l(3), l(3)).makePipe().asProcessor().process(null));
+        assertEquals(false, lessThanOf(l(3), l(BigInteger.valueOf(3))).makePipe().asProcessor().process(null));
     }
 
     public void testLte() {
         assertEquals(false, lessThanOrEqualOf(l(4), l(3)).makePipe().asProcessor().process(null));
         assertEquals(true, lessThanOrEqualOf(l(3), l(4)).makePipe().asProcessor().process(null));
         assertEquals(true, lessThanOrEqualOf(l(3), l(3)).makePipe().asProcessor().process(null));
+        assertEquals(false, lessThanOrEqualOf(l(4), l(BigInteger.valueOf(3))).makePipe().asProcessor().process(null));
+        assertEquals(true, lessThanOrEqualOf(l(3), l(BigInteger.valueOf(4))).makePipe().asProcessor().process(null));
+        assertEquals(true, lessThanOrEqualOf(l(3), l(BigInteger.valueOf(3))).makePipe().asProcessor().process(null));
     }
 
     public void testHandleNull() {

+ 143 - 0
x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/DataTypeConversionTests.java

@@ -12,6 +12,8 @@ import org.elasticsearch.xpack.ql.expression.Literal;
 import org.elasticsearch.xpack.ql.tree.Location;
 import org.elasticsearch.xpack.ql.tree.Source;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.time.ZonedDateTime;
 
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.commonType;
@@ -28,8 +30,10 @@ import static org.elasticsearch.xpack.ql.type.DataTypes.LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypes.NULL;
 import static org.elasticsearch.xpack.ql.type.DataTypes.SHORT;
 import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypes.UNSUPPORTED;
 import static org.elasticsearch.xpack.ql.type.DateUtils.asDateTime;
+import static org.elasticsearch.xpack.ql.util.NumericUtils.UNSIGNED_LONG_MAX;
 
 public class DataTypeConversionTests extends ESTestCase {
 
@@ -40,6 +44,12 @@ public class DataTypeConversionTests extends ESTestCase {
             assertNull(conversion.convert(null));
             assertEquals("10.0", conversion.convert(10.0));
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+            BigInteger bi = randomBigInteger();
+            assertEquals(bi.toString(), conversion.convert(bi));
+        }
         {
             Converter conversion = converterFor(DATETIME, to);
             assertNull(conversion.convert(null));
@@ -63,6 +73,16 @@ public class DataTypeConversionTests extends ESTestCase {
             Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(Double.MAX_VALUE));
             assertEquals("[" + Double.MAX_VALUE + "] out of [long] range", e.getMessage());
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+            BigInteger bi = BigInteger.valueOf(randomNonNegativeLong());
+            assertEquals(bi.longValue(), conversion.convert(bi));
+
+            BigInteger longPlus = bi.add(BigInteger.valueOf(Long.MAX_VALUE));
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(longPlus));
+            assertEquals("[" + longPlus + "] out of [long] range", e.getMessage());
+        }
         {
             Converter conversion = converterFor(INTEGER, to);
             assertNull(conversion.convert(null));
@@ -104,6 +124,16 @@ public class DataTypeConversionTests extends ESTestCase {
             Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(Double.MAX_VALUE));
             assertEquals("[" + Double.MAX_VALUE + "] out of [long] range", e.getMessage());
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+            BigInteger bi = BigInteger.valueOf(randomNonNegativeLong());
+            assertEquals(asDateTime(bi.longValue()), conversion.convert(bi));
+
+            BigInteger longPlus = bi.add(BigInteger.valueOf(Long.MAX_VALUE));
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(longPlus));
+            assertEquals("[" + longPlus + "] out of [long] range", e.getMessage());
+        }
         {
             Converter conversion = converterFor(INTEGER, to);
             assertNull(conversion.convert(null));
@@ -157,6 +187,13 @@ public class DataTypeConversionTests extends ESTestCase {
             assertEquals(10.1f, (float) conversion.convert(10.1d), 0.00001);
             assertEquals(10.6f, (float) conversion.convert(10.6d), 0.00001);
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+
+            BigInteger bi = randomBigInteger();
+            assertEquals(bi.floatValue(), (float) conversion.convert(bi), 0);
+        }
         {
             Converter conversion = converterFor(INTEGER, to);
             assertNull(conversion.convert(null));
@@ -197,6 +234,13 @@ public class DataTypeConversionTests extends ESTestCase {
             assertEquals(10.1, (double) conversion.convert(10.1f), 0.00001);
             assertEquals(10.6, (double) conversion.convert(10.6f), 0.00001);
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+
+            BigInteger bi = randomBigInteger();
+            assertEquals(bi.doubleValue(), (double) conversion.convert(bi), 0);
+        }
         {
             Converter conversion = converterFor(INTEGER, to);
             assertNull(conversion.convert(null));
@@ -237,6 +281,12 @@ public class DataTypeConversionTests extends ESTestCase {
             assertEquals(true, conversion.convert(-10.0f));
             assertEquals(false, conversion.convert(0.0f));
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+            assertEquals(true, conversion.convert(BigInteger.valueOf(randomNonNegativeLong())));
+            assertEquals(false, conversion.convert(BigInteger.ZERO));
+        }
         {
             Converter conversion = converterFor(INTEGER, to);
             assertNull(conversion.convert(null));
@@ -289,6 +339,67 @@ public class DataTypeConversionTests extends ESTestCase {
         }
     }
 
+    public void testConversionToUnsignedLong() {
+        DataType to = UNSIGNED_LONG;
+        {
+            Converter conversion = converterFor(DOUBLE, to);
+            assertNull(conversion.convert(null));
+            double d = Math.abs(randomDouble());
+            assertEquals(BigDecimal.valueOf(d).toBigInteger(), conversion.convert(d));
+
+            Double ulmAsDouble = UNSIGNED_LONG_MAX.doubleValue();
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(ulmAsDouble));
+            assertEquals("[" + ulmAsDouble + "] out of [unsigned_long] range", e.getMessage());
+
+            Double nd = -Math.abs(randomDouble());
+            e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(nd));
+            assertEquals("[" + nd + "] out of [unsigned_long] range", e.getMessage());
+        }
+        {
+            Converter conversion = converterFor(LONG, to);
+            assertNull(conversion.convert(null));
+
+            BigInteger bi = BigInteger.valueOf(randomNonNegativeLong());
+            assertEquals(bi, conversion.convert(bi.longValue()));
+
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(bi.negate()));
+            assertEquals("[" + bi.negate() + "] out of [unsigned_long] range", e.getMessage());
+        }
+        {
+            Converter conversion = converterFor(DATETIME, to);
+            assertNull(conversion.convert(null));
+
+            long l = randomNonNegativeLong();
+            assertEquals(BigInteger.valueOf(l), conversion.convert(asDateTime(l)));
+
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(asDateTime(-l)));
+            assertEquals("[" + -l + "] out of [unsigned_long] range", e.getMessage());
+        }
+        {
+            Converter conversion = converterFor(BOOLEAN, to);
+            assertNull(conversion.convert(null));
+
+            assertEquals(BigInteger.ONE, conversion.convert(true));
+            assertEquals(BigInteger.ZERO, conversion.convert(false));
+        }
+        {
+            Converter conversion = converterFor(KEYWORD, to);
+            assertNull(conversion.convert(null));
+            BigInteger bi = randomBigInteger();
+            assertEquals(bi, conversion.convert(bi.toString()));
+
+            assertEquals(UNSIGNED_LONG_MAX, conversion.convert(UNSIGNED_LONG_MAX.toString()));
+            assertEquals(UNSIGNED_LONG_MAX, conversion.convert(UNSIGNED_LONG_MAX.toString() + ".0"));
+
+            assertEquals(bi, conversion.convert(bi.toString() + "." + randomNonNegativeLong()));
+
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(BigInteger.ONE.negate().toString()));
+            assertEquals("[-1] out of [unsigned_long] range", e.getMessage());
+            e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(UNSIGNED_LONG_MAX.add(BigInteger.ONE).toString()));
+            assertEquals("[" + UNSIGNED_LONG_MAX.add(BigInteger.ONE).toString() + "] out of [unsigned_long] range", e.getMessage());
+        }
+    }
+
     public void testConversionToInt() {
         DataType to = INTEGER;
         {
@@ -300,6 +411,16 @@ public class DataTypeConversionTests extends ESTestCase {
             Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(Long.MAX_VALUE));
             assertEquals("[" + Long.MAX_VALUE + "] out of [integer] range", e.getMessage());
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+            BigInteger bi = BigInteger.valueOf(randomIntBetween(0, Integer.MAX_VALUE));
+            assertEquals(bi.intValueExact(), conversion.convert(bi));
+
+            BigInteger bip = BigInteger.valueOf(randomLongBetween(Integer.MAX_VALUE, Long.MAX_VALUE));
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(bip));
+            assertEquals("[" + bip + "] out of [integer] range", e.getMessage());
+        }
         {
             Converter conversion = converterFor(DATETIME, to);
             assertNull(conversion.convert(null));
@@ -324,6 +445,16 @@ public class DataTypeConversionTests extends ESTestCase {
             Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(Integer.MAX_VALUE));
             assertEquals("[" + Integer.MAX_VALUE + "] out of [short] range", e.getMessage());
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+            BigInteger bi = BigInteger.valueOf(randomIntBetween(0, Short.MAX_VALUE));
+            assertEquals(bi.shortValueExact(), conversion.convert(bi));
+
+            BigInteger bip = BigInteger.valueOf(randomLongBetween(Short.MAX_VALUE, Long.MAX_VALUE));
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(bip));
+            assertEquals("[" + bip + "] out of [short] range", e.getMessage());
+        }
         {
             Converter conversion = converterFor(DATETIME, to);
             assertNull(conversion.convert(null));
@@ -347,6 +478,16 @@ public class DataTypeConversionTests extends ESTestCase {
             Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(Short.MAX_VALUE));
             assertEquals("[" + Short.MAX_VALUE + "] out of [byte] range", e.getMessage());
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+            BigInteger bi = BigInteger.valueOf(randomIntBetween(0, Byte.MAX_VALUE));
+            assertEquals(bi.byteValueExact(), conversion.convert(bi));
+
+            BigInteger bip = BigInteger.valueOf(randomLongBetween(Byte.MAX_VALUE, Long.MAX_VALUE));
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(bip));
+            assertEquals("[" + bip + "] out of [byte] range", e.getMessage());
+        }
         {
             Converter conversion = converterFor(DATETIME, to);
             assertNull(conversion.convert(null));
@@ -387,7 +528,9 @@ public class DataTypeConversionTests extends ESTestCase {
         assertEquals(SHORT, commonType(SHORT, BYTE));
         assertEquals(FLOAT, commonType(BYTE, FLOAT));
         assertEquals(FLOAT, commonType(FLOAT, INTEGER));
+        assertEquals(UNSIGNED_LONG, commonType(UNSIGNED_LONG, LONG));
         assertEquals(DOUBLE, commonType(DOUBLE, FLOAT));
+        assertEquals(FLOAT, commonType(FLOAT, UNSIGNED_LONG));
 
         // strings
         assertEquals(TEXT, commonType(TEXT, KEYWORD));

+ 1 - 1
x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java

@@ -228,7 +228,7 @@ public class TypesTests extends ESTestCase {
         return loadMapping(registry, stream, ordered);
     }
 
-    public static Map<String, EsField> loadMapping(DataTypeRegistry registry, InputStream stream, Boolean ordered) {
+    private static Map<String, EsField> loadMapping(DataTypeRegistry registry, InputStream stream, Boolean ordered) {
         boolean order = ordered != null ? ordered.booleanValue() : randomBoolean();
         try (InputStream in = stream) {
             return Types.fromEs(registry, XContentHelper.convertToMap(JsonXContent.jsonXContent, in, order));

+ 1 - 0
x-pack/plugin/ql/src/test/resources/mapping-multi-field-variation.json

@@ -2,6 +2,7 @@
     "properties" : {
         "bool" : { "type" : "boolean" },
         "int" : { "type" : "integer" },
+        "unsigned_long" : { "type" : "unsigned_long" },
         "float" : { "type" : "float" },
         "text" : { "type" : "text" },
         "keyword" : { "type" : "keyword" },

+ 1 - 0
x-pack/plugin/ql/src/test/resources/mapping-multi-field-with-nested.json

@@ -2,6 +2,7 @@
     "properties" : {
         "bool" : { "type" : "boolean" },
         "int" : { "type" : "integer" },
+        "unsigned_long" : { "type" : "unsigned_long" },
         "text" : { "type" : "text" },
         "keyword" : { "type" : "keyword" },
         "unsupported" : { "type" : "ip_range" },

+ 3 - 0
x-pack/plugin/ql/src/test/resources/mapping-numeric.json

@@ -12,6 +12,9 @@
         "long" : {
             "type" : "long"
         },
+        "unsigned_long" : {
+          "type" : "unsigned_long"
+        },
         "meta_subfield" : {
             "type" : "text",
             "fields" : {

+ 2 - 1
x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/EsType.java

@@ -47,7 +47,8 @@ public enum EsType implements SQLType {
     INTERVAL_MINUTE_TO_SECOND(ExtraTypes.INTERVAL_MINUTE_SECOND),
     GEO_POINT(ExtraTypes.GEOMETRY),
     GEO_SHAPE(ExtraTypes.GEOMETRY),
-    SHAPE(ExtraTypes.GEOMETRY);
+    SHAPE(ExtraTypes.GEOMETRY),
+    UNSIGNED_LONG(Types.NUMERIC);
 
     private final Integer type;
 

+ 5 - 2
x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcPreparedStatement.java

@@ -9,6 +9,7 @@ package org.elasticsearch.xpack.sql.jdbc;
 import java.io.InputStream;
 import java.io.Reader;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.net.URL;
 import java.sql.Array;
 import java.sql.Blob;
@@ -44,6 +45,7 @@ import java.util.List;
 import java.util.Locale;
 
 import static java.time.ZoneOffset.UTC;
+import static org.elasticsearch.xpack.sql.jdbc.TypeUtils.scaleOrLength;
 
 class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
 
@@ -209,7 +211,7 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
         // {@code java.sql.Array} etc) will generate the correct exception message. Otherwise, the method call
         // {@code TypeConverter.fromJavaToJDBC(x.getClass())} will report the implementing class as not being supported.
         checkKnownUnsupportedTypes(x);
-        setObject(parameterIndex, x, TypeUtils.of(x.getClass()).getVendorTypeNumber(), 0);
+        setObject(parameterIndex, x, TypeUtils.of(x.getClass()).getVendorTypeNumber(), scaleOrLength(x));
     }
 
     @Override
@@ -353,7 +355,7 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
 
     @Override
     public void setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLException {
-        setObject(parameterIndex, x, TypeUtils.of(targetSqlType), targetSqlType.getName());
+        setObject(parameterIndex, x, TypeUtils.of(targetSqlType, scaleOrLength), targetSqlType.getName());
     }
 
     private void setObject(int parameterIndex, Object x, EsType dataType, String typeString) throws SQLException {
@@ -418,6 +420,7 @@ class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
             || x instanceof Short
             || x instanceof Integer
             || x instanceof Long
+            || x instanceof BigInteger
             || x instanceof Float
             || x instanceof Double
             || x instanceof String) {

+ 1 - 2
x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcResultSetMetaData.java

@@ -94,8 +94,7 @@ class JdbcResultSetMetaData implements ResultSetMetaData, JdbcWrapper {
 
     @Override
     public int getScale(int column) throws SQLException {
-        column(column);
-        return 0;
+        return column(column).displaySize();
     }
 
     @Override

+ 89 - 8
x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeConverter.java

@@ -9,6 +9,7 @@ package org.elasticsearch.xpack.sql.jdbc;
 import org.elasticsearch.xpack.sql.proto.StringUtils;
 
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.sql.Date;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
@@ -157,6 +158,9 @@ final class TypeConverter {
         if (type == Long.class) {
             return (T) asLong(val, columnType, typeString);
         }
+        if (type == BigInteger.class) {
+            return (T) asBigInteger(val, columnType, typeString);
+        }
         if (type == Float.class) {
             return (T) asFloat(val, columnType, typeString);
         }
@@ -219,6 +223,8 @@ final class TypeConverter {
                 return ((Number) v).intValue();
             case LONG:
                 return ((Number) v).longValue();
+            case UNSIGNED_LONG:
+                return asBigInteger(v, columnType, typeString);
             case HALF_FLOAT:
             case SCALED_FLOAT:
             case DOUBLE:
@@ -311,11 +317,12 @@ final class TypeConverter {
             case SHORT:
             case INTEGER:
             case LONG:
+            case UNSIGNED_LONG:
             case FLOAT:
             case HALF_FLOAT:
             case SCALED_FLOAT:
             case DOUBLE:
-                return Boolean.valueOf(Integer.signum(((Number) val).intValue()) != 0);
+                return Boolean.valueOf(((Number) val).doubleValue() != 0);
             case KEYWORD:
             case TEXT:
                 return Boolean.valueOf((String) val);
@@ -333,6 +340,8 @@ final class TypeConverter {
             case INTEGER:
             case LONG:
                 return safeToByte(((Number) val).longValue());
+            case UNSIGNED_LONG:
+                return safeToByte(asBigInteger(val, columnType, typeString));
             case FLOAT:
             case HALF_FLOAT:
             case SCALED_FLOAT:
@@ -360,6 +369,8 @@ final class TypeConverter {
             case INTEGER:
             case LONG:
                 return safeToShort(((Number) val).longValue());
+            case UNSIGNED_LONG:
+                return safeToShort(asBigInteger(val, columnType, typeString));
             case FLOAT:
             case HALF_FLOAT:
             case SCALED_FLOAT:
@@ -386,6 +397,8 @@ final class TypeConverter {
             case INTEGER:
             case LONG:
                 return safeToInt(((Number) val).longValue());
+            case UNSIGNED_LONG:
+                return safeToInt(asBigInteger(val, columnType, typeString));
             case FLOAT:
             case HALF_FLOAT:
             case SCALED_FLOAT:
@@ -412,6 +425,8 @@ final class TypeConverter {
             case INTEGER:
             case LONG:
                 return Long.valueOf(((Number) val).longValue());
+            case UNSIGNED_LONG:
+                return safeToLong(asBigInteger(val, columnType, typeString));
             case FLOAT:
             case HALF_FLOAT:
             case SCALED_FLOAT:
@@ -444,6 +459,8 @@ final class TypeConverter {
             case INTEGER:
             case LONG:
                 return Float.valueOf(((Number) val).longValue());
+            case UNSIGNED_LONG:
+                return asBigInteger(val, columnType, typeString).floatValue();
             case FLOAT:
             case HALF_FLOAT:
             case SCALED_FLOAT:
@@ -470,6 +487,8 @@ final class TypeConverter {
             case INTEGER:
             case LONG:
                 return Double.valueOf(((Number) val).longValue());
+            case UNSIGNED_LONG:
+                return asBigInteger(val, columnType, typeString).doubleValue();
             case FLOAT:
             case HALF_FLOAT:
             case SCALED_FLOAT:
@@ -524,6 +543,34 @@ final class TypeConverter {
         throw new SQLFeatureNotSupportedException();
     }
 
+    private static BigInteger asBigInteger(Object val, EsType columnType, String typeString) throws SQLException {
+        switch (columnType) {
+            case BOOLEAN:
+                return ((Boolean) val).booleanValue() ? BigInteger.ONE : BigInteger.ZERO;
+            case BYTE:
+            case SHORT:
+            case INTEGER:
+            case LONG:
+                return BigInteger.valueOf(((Number) val).longValue());
+            case FLOAT:
+            case HALF_FLOAT:
+            case SCALED_FLOAT:
+            case DOUBLE:
+                return BigDecimal.valueOf(((Number) val).doubleValue()).toBigInteger();
+            // Aggs can return floats dressed as UL types (bugUrl="https://github.com/elastic/elasticsearch/issues/65413")
+            case UNSIGNED_LONG:
+            case KEYWORD:
+            case TEXT:
+                try {
+                    return new BigDecimal(val.toString()).toBigInteger();
+                } catch (NumberFormatException e) {
+                    return failConversion(val, columnType, typeString, BigInteger.class, e);
+                }
+            default:
+        }
+        return failConversion(val, columnType, typeString, BigInteger.class);
+    }
+
     private static BigDecimal asBigDecimal(Object val, EsType columnType, String typeString) throws SQLException {
         switch (columnType) {
             case BOOLEAN:
@@ -533,6 +580,8 @@ final class TypeConverter {
             case INTEGER:
             case LONG:
                 return BigDecimal.valueOf(((Number) val).longValue());
+            case UNSIGNED_LONG:
+                return new BigDecimal(asBigInteger(val, columnType, typeString));
             case FLOAT:
             case HALF_FLOAT:
                 // floats are passed in as doubles here, so we need to dip into string to keep original float's (reduced) precision.
@@ -573,28 +622,60 @@ final class TypeConverter {
         throw new SQLFeatureNotSupportedException();
     }
 
-    private static byte safeToByte(long x) throws SQLException {
+    private static byte safeToByte(Number n) throws SQLException {
+        if (n instanceof BigInteger) {
+            try {
+                return ((BigInteger) n).byteValueExact();
+            } catch (ArithmeticException ae) {
+                throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", n));
+            }
+        }
+        long x = n.longValue();
         if (x > Byte.MAX_VALUE || x < Byte.MIN_VALUE) {
-            throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", Long.toString(x)));
+            throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", n));
         }
         return (byte) x;
     }
 
-    private static short safeToShort(long x) throws SQLException {
+    private static short safeToShort(Number n) throws SQLException {
+        if (n instanceof BigInteger) {
+            try {
+                return ((BigInteger) n).shortValueExact();
+            } catch (ArithmeticException ae) {
+                throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", n));
+            }
+        }
+        long x = n.longValue();
         if (x > Short.MAX_VALUE || x < Short.MIN_VALUE) {
-            throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", Long.toString(x)));
+            throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", n));
         }
         return (short) x;
     }
 
-    private static int safeToInt(long x) throws SQLException {
+    private static int safeToInt(Number n) throws SQLException {
+        if (n instanceof BigInteger) {
+            try {
+                return ((BigInteger) n).intValueExact();
+            } catch (ArithmeticException ae) {
+                throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", n));
+            }
+        }
+        long x = n.longValue();
         if (x > Integer.MAX_VALUE || x < Integer.MIN_VALUE) {
-            throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", Long.toString(x)));
+            throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", n));
         }
         return (int) x;
     }
 
-    private static long safeToLong(double x) throws SQLException {
+    private static long safeToLong(Number n) throws SQLException {
+        if (n instanceof BigInteger) {
+            try {
+                return ((BigInteger) n).longValueExact();
+            } catch (ArithmeticException ae) {
+                throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", n));
+            }
+        }
+        double x = n.doubleValue();
         if (x > Long.MAX_VALUE || x < Long.MIN_VALUE) {
             throw new SQLException(format(Locale.ROOT, "Numeric %s out of range", Double.toString(x)));
         }

+ 21 - 1
x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeUtils.java

@@ -7,6 +7,7 @@
 
 package org.elasticsearch.xpack.sql.jdbc;
 
+import java.math.BigInteger;
 import java.sql.JDBCType;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
@@ -25,6 +26,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import static java.sql.Types.BIGINT;
 import static java.util.Collections.unmodifiableMap;
 
 final class TypeUtils {
@@ -48,18 +50,21 @@ final class TypeUtils {
         EsType.DATETIME
     );
 
+    public static final int LONG_MAX_LENGTH = String.valueOf(Long.MAX_VALUE).length(); // type length value as defined in ES
+
     static {
+        // Note: keep in sync with org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils#CLASS_TO_ES_TYPE
         Map<Class<?>, EsType> aMap = new LinkedHashMap<>();
         aMap.put(Boolean.class, EsType.BOOLEAN);
         aMap.put(Byte.class, EsType.BYTE);
         aMap.put(Short.class, EsType.SHORT);
         aMap.put(Integer.class, EsType.INTEGER);
         aMap.put(Long.class, EsType.LONG);
+        aMap.put(BigInteger.class, EsType.UNSIGNED_LONG);
         aMap.put(Float.class, EsType.FLOAT);
         aMap.put(Double.class, EsType.DOUBLE);
         aMap.put(String.class, EsType.KEYWORD);
         aMap.put(byte[].class, EsType.BINARY);
-        aMap.put(String.class, EsType.KEYWORD);
         aMap.put(Timestamp.class, EsType.DATETIME);
 
         // apart from the mappings in {@code DataType} three more Java classes can be mapped to a {@code JDBCType.TIMESTAMP}
@@ -78,6 +83,7 @@ final class TypeUtils {
         types.put(EsType.SHORT, Short.class);
         types.put(EsType.INTEGER, Integer.class);
         types.put(EsType.LONG, Long.class);
+        types.put(EsType.UNSIGNED_LONG, BigInteger.class);
         types.put(EsType.DOUBLE, Double.class);
         types.put(EsType.FLOAT, Float.class);
         types.put(EsType.HALF_FLOAT, Double.class);
@@ -155,6 +161,16 @@ final class TypeUtils {
         return dataType;
     }
 
+    static EsType of(SQLType sqlType, int scaleOrLength) throws SQLException {
+        EsType esType;
+        if (sqlType.getVendorTypeNumber() == BIGINT) {
+            esType = scaleOrLength > LONG_MAX_LENGTH ? EsType.UNSIGNED_LONG : EsType.LONG;
+        } else {
+            esType = TypeUtils.of(sqlType);
+        }
+        return esType;
+    }
+
     static EsType of(String name) throws SQLException {
         EsType dataType = ENUM_NAME_TO_TYPE.get(name);
         if (dataType == null) {
@@ -182,4 +198,8 @@ final class TypeUtils {
         }
         return dataType;
     }
+
+    static int scaleOrLength(Object val) {
+        return val instanceof BigInteger ? LONG_MAX_LENGTH + 1 : 0;
+    }
 }

+ 60 - 0
x-pack/plugin/sql/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/JdbcPreparedStatementTests.java

@@ -9,8 +9,10 @@ package org.elasticsearch.xpack.sql.jdbc;
 import org.elasticsearch.common.logging.LoggerMessageFormat;
 import org.elasticsearch.test.ESTestCase;
 
+import java.math.BigInteger;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
+import java.sql.JDBCType;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.sql.Struct;
@@ -39,6 +41,7 @@ import static org.elasticsearch.xpack.sql.jdbc.EsType.KEYWORD;
 import static org.elasticsearch.xpack.sql.jdbc.EsType.LONG;
 import static org.elasticsearch.xpack.sql.jdbc.EsType.SHORT;
 import static org.elasticsearch.xpack.sql.jdbc.EsType.TIME;
+import static org.elasticsearch.xpack.sql.jdbc.EsType.UNSIGNED_LONG;
 
 public class JdbcPreparedStatementTests extends ESTestCase {
 
@@ -122,6 +125,14 @@ public class JdbcPreparedStatementTests extends ESTestCase {
         assertEquals(123, value(jps));
         assertEquals(INTEGER, jdbcType(jps));
 
+        jps.setObject(1, (byte) 123, Types.BIGINT);
+        assertEquals(123L, value(jps));
+        assertEquals(LONG, jdbcType(jps));
+
+        jps.setObject(1, (byte) 123, Types.BIGINT, 20);
+        assertEquals(BigInteger.valueOf(123), value(jps));
+        assertEquals(UNSIGNED_LONG, jdbcType(jps));
+
         jps.setObject(1, (byte) -128, Types.DOUBLE);
         assertEquals(-128.0, value(jps));
         assertEquals(DOUBLE, jdbcType(jps));
@@ -234,6 +245,55 @@ public class JdbcPreparedStatementTests extends ESTestCase {
         assertEquals(HALF_FLOAT, jdbcType(jps));
     }
 
+    public void testSettingBigIntegerValues() throws SQLException {
+        JdbcPreparedStatement jps = createJdbcPreparedStatement();
+
+        BigInteger bi = BigInteger.valueOf(randomLong()).abs();
+
+        jps.setObject(1, bi);
+        assertEquals(bi, value(jps));
+        assertEquals(UNSIGNED_LONG, jdbcType(jps));
+        assertTrue(value(jps) instanceof BigInteger);
+
+        jps.setObject(1, bi, Types.VARCHAR);
+        assertEquals(String.valueOf(bi), value(jps));
+        assertEquals(KEYWORD, jdbcType(jps));
+
+        jps.setObject(1, bi, Types.BIGINT);
+        assertEquals(bi.longValueExact(), value(jps));
+        assertEquals(LONG, jdbcType(jps));
+
+        jps.setObject(1, bi, Types.DOUBLE);
+        assertEquals(bi.doubleValue(), value(jps));
+        assertEquals(DOUBLE, jdbcType(jps));
+
+        jps.setObject(1, bi, Types.FLOAT);
+        assertEquals(bi.doubleValue(), value(jps));
+        assertEquals(HALF_FLOAT, jdbcType(jps));
+
+        jps.setObject(1, bi, Types.REAL);
+        assertEquals(bi.floatValue(), value(jps));
+        assertEquals(FLOAT, jdbcType(jps));
+
+        jps.setObject(1, BigInteger.ZERO, Types.BOOLEAN);
+        assertEquals(false, value(jps));
+        assertEquals(BOOLEAN, jdbcType(jps));
+
+        jps.setObject(1, BigInteger.TEN, Types.BOOLEAN);
+        assertEquals(true, value(jps));
+        assertEquals(BOOLEAN, jdbcType(jps));
+
+        jps.setObject(1, bi.longValueExact(), JDBCType.BIGINT, 19);
+        assertTrue(value(jps) instanceof Long);
+        assertEquals(bi.longValueExact(), value(jps));
+        assertEquals(LONG, jdbcType(jps));
+
+        jps.setObject(1, bi.longValueExact(), JDBCType.BIGINT, 20);
+        assertTrue(value(jps) instanceof BigInteger);
+        assertEquals(bi, value(jps));
+        assertEquals(UNSIGNED_LONG, jdbcType(jps));
+    }
+
     public void testThrownExceptionsWhenSettingLongValues() throws SQLException {
         JdbcPreparedStatement jps = createJdbcPreparedStatement();
         long someLong = randomLong();

+ 41 - 3
x-pack/plugin/sql/jdbc/src/test/java/org/elasticsearch/xpack/sql/jdbc/TypeConverterTests.java

@@ -12,6 +12,8 @@ import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.json.JsonXContent;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.sql.Date;
 import java.sql.Timestamp;
 import java.time.ZoneId;
@@ -24,6 +26,32 @@ public class TypeConverterTests extends ESTestCase {
 
     private static final ZoneId UTC = ZoneId.of("Z");
 
+    public void testConvertToBigInteger() throws Exception {
+        {
+            assertEquals(BigInteger.ZERO, convertAsNative(false, BigInteger.class));
+            assertEquals(BigInteger.ONE, convertAsNative(true, BigInteger.class));
+        }
+        {
+            BigInteger bi = randomBigInteger();
+            assertEquals(bi, convertAsNative(bi, BigInteger.class));
+        }
+        // 18446744073709551615
+        BigInteger UNSIGNED_LONG_MAX = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE);
+        BigDecimal bd = BigDecimal.valueOf(randomDouble()).abs().remainder(new BigDecimal(UNSIGNED_LONG_MAX));
+        {
+            float f = bd.floatValue();
+            assertEquals(BigDecimal.valueOf(f).toBigInteger(), convertAsNative(f, BigInteger.class));
+        }
+        {
+            double d = bd.doubleValue();
+            assertEquals(BigDecimal.valueOf(d).toBigInteger(), convertAsNative(d, BigInteger.class));
+        }
+        {
+            String s = bd.toString();
+            assertEquals(new BigDecimal(s).toBigInteger(), convertAsNative(s, BigInteger.class));
+        }
+    }
+
     public void testFloatAsNative() throws Exception {
         assertThat(convertAsNative(42.0f, EsType.FLOAT), instanceOf(Float.class));
         assertThat(convertAsNative(42.0, EsType.FLOAT), instanceOf(Float.class));
@@ -61,15 +89,25 @@ public class TypeConverterTests extends ESTestCase {
         assertEquals(now.toLocalDate().atStartOfDay(ZoneId.of("Etc/GMT-10")).toInstant().toEpochMilli(), ((Date) nativeObject).getTime());
     }
 
-    private Object convertAsNative(Object value, EsType type) throws Exception {
-        // Simulate sending over XContent
+    // Simulate sending over XContent
+    private static Object throughXContent(Object value) throws Exception {
         XContentBuilder builder = JsonXContent.contentBuilder();
         builder.startObject();
         builder.field("value");
         builder.value(value);
         builder.endObject();
         builder.close();
-        Object copy = XContentHelper.convertToMap(BytesReference.bytes(builder), false, builder.contentType()).v2().get("value");
+        return XContentHelper.convertToMap(BytesReference.bytes(builder), false, builder.contentType()).v2().get("value");
+
+    }
+
+    private Object convertAsNative(Object value, EsType type) throws Exception {
+        Object copy = throughXContent(value);
         return TypeConverter.convert(copy, type, type.toString());
     }
+
+    private <T> Object convertAsNative(Object value, Class<T> nativeType) throws Exception {
+        EsType esType = TypeUtils.of(value.getClass());
+        return TypeConverter.convert(value, esType, nativeType, esType.toString());
+    }
 }

+ 48 - 0
x-pack/plugin/sql/qa/jdbc/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/JdbcTestUtils.java

@@ -7,17 +7,26 @@
 package org.elasticsearch.xpack.sql.qa.jdbc;
 
 import org.elasticsearch.Version;
+import org.elasticsearch.xpack.sql.jdbc.EsType;
 import org.elasticsearch.xpack.sql.proto.StringUtils;
 
+import java.math.BigInteger;
 import java.sql.Date;
 import java.sql.Time;
+import java.sql.Timestamp;
 import java.time.Instant;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.util.Calendar;
+import java.util.Collections;
+import java.util.GregorianCalendar;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
+import static org.elasticsearch.Version.V_8_2_0;
 import static org.elasticsearch.common.time.DateUtils.toMilliSeconds;
 import static org.elasticsearch.test.ESTestCase.randomLongBetween;
 
@@ -25,11 +34,16 @@ final class JdbcTestUtils {
 
     private JdbcTestUtils() {}
 
+    private static final Map<Class<?>, EsType> CLASS_TO_ES_TYPE;
+
     static final ZoneId UTC = ZoneId.of("Z");
     static final String JDBC_TIMEZONE = "timezone";
     private static final String DRIVER_VERSION_PROPERTY_NAME = "jdbc.driver.version";
     static final LocalDate EPOCH = LocalDate.of(1970, 1, 1);
 
+    static final String UNSIGNED_LONG_TYPE_NAME = "UNSIGNED_LONG";
+    static final BigInteger UNSIGNED_LONG_MAX = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE);
+
     /*
      * The version of the driver that the QA (bwc-)tests run against.
      * Note: when adding a version-gated feature (i.e. new feature that would not be supported by old drivers) and adding code in these QA
@@ -50,6 +64,36 @@ final class JdbcTestUtils {
         // master's version is x.0.0-SNAPSHOT, tho Version#fromString() won't accept that back for recent versions
         String jdbcDriverVersion = System.getProperty(DRIVER_VERSION_PROPERTY_NAME, "").replace("-SNAPSHOT", "");
         JDBC_DRIVER_VERSION = Version.fromString(jdbcDriverVersion); // takes empty and null strings, resolves them to CURRENT
+
+        // Note: keep in sync with org.elasticsearch.xpack.sql.jdbc.TypeUtils#CLASS_TO_TYPE
+        Map<Class<?>, EsType> aMap = new LinkedHashMap<>();
+        aMap.put(Boolean.class, EsType.BOOLEAN);
+        aMap.put(Byte.class, EsType.BYTE);
+        aMap.put(Short.class, EsType.SHORT);
+        aMap.put(Integer.class, EsType.INTEGER);
+        aMap.put(Long.class, EsType.LONG);
+        if (isUnsignedLongSupported()) {
+            aMap.put(BigInteger.class, EsType.UNSIGNED_LONG);
+        }
+        aMap.put(Float.class, EsType.FLOAT);
+        aMap.put(Double.class, EsType.DOUBLE);
+        aMap.put(String.class, EsType.KEYWORD);
+        aMap.put(byte[].class, EsType.BINARY);
+        aMap.put(Timestamp.class, EsType.DATETIME);
+
+        // apart from the mappings in {@code DataType} three more Java classes can be mapped to a {@code JDBCType.TIMESTAMP}
+        // according to B-4 table from the jdbc4.2 spec
+        aMap.put(Calendar.class, EsType.DATETIME);
+        aMap.put(GregorianCalendar.class, EsType.DATETIME);
+        aMap.put(java.util.Date.class, EsType.DATETIME);
+        aMap.put(java.sql.Date.class, EsType.DATETIME);
+        aMap.put(java.sql.Time.class, EsType.TIME);
+        aMap.put(LocalDateTime.class, EsType.DATETIME);
+        CLASS_TO_ES_TYPE = Collections.unmodifiableMap(aMap);
+    }
+
+    static EsType of(Class<?> clazz) {
+        return CLASS_TO_ES_TYPE.get(clazz);
     }
 
     static String of(long millis, String zoneId) {
@@ -107,4 +151,8 @@ final class JdbcTestUtils {
     static boolean versionSupportsDateNanos() {
         return JDBC_DRIVER_VERSION.onOrAfter(Version.V_7_12_0);
     }
+
+    public static boolean isUnsignedLongSupported() {
+        return JDBC_DRIVER_VERSION.onOrAfter(V_8_2_0);
+    }
 }

+ 24 - 0
x-pack/plugin/sql/qa/jdbc/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/PreparedStatementTestCase.java

@@ -12,6 +12,7 @@ import org.elasticsearch.core.Tuple;
 
 import java.io.IOException;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.sql.Connection;
 import java.sql.Date;
 import java.sql.JDBCType;
@@ -39,7 +40,9 @@ import static org.elasticsearch.xpack.sql.jdbc.EsType.KEYWORD;
 import static org.elasticsearch.xpack.sql.jdbc.EsType.LONG;
 import static org.elasticsearch.xpack.sql.jdbc.EsType.SHORT;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.JDBC_DRIVER_VERSION;
+import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.UNSIGNED_LONG_TYPE_NAME;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.extractNanosOnly;
+import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.isUnsignedLongSupported;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.randomTimeInNanos;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.versionSupportsDateNanos;
 import static org.hamcrest.Matchers.equalTo;
@@ -411,6 +414,7 @@ public abstract class PreparedStatementTestCase extends JdbcIntegrationTestCase
         String stringVal = randomAlphaOfLength(randomIntBetween(0, 1000));
         int intVal = randomInt();
         long longVal = randomLong();
+        BigInteger bigIntegerVal = randomBigInteger();
         double doubleVal = randomDouble();
         float floatVal = randomFloat();
         boolean booleanVal = randomBoolean();
@@ -442,6 +446,26 @@ public abstract class PreparedStatementTestCase extends JdbcIntegrationTestCase
         }
     }
 
+    public void testSingleParameterUnsignedLong() throws SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        BigInteger bigIntegerVal = randomBigInteger();
+        long longVal = randomLong();
+
+        try (Connection connection = esJdbc()) {
+            try (PreparedStatement statement = connection.prepareStatement("SELECT ?")) {
+
+                statement.setObject(1, bigIntegerVal);
+                assertEquals(new Tuple<>(UNSIGNED_LONG_TYPE_NAME, bigIntegerVal), execute(statement));
+
+                statement.setObject(1, longVal, JDBCType.BIGINT, 19);
+                assertEquals(new Tuple<>(LONG.getName(), longVal), execute(statement));
+                statement.setObject(1, Math.abs(longVal), JDBCType.BIGINT, 20);
+                assertEquals(new Tuple<>(UNSIGNED_LONG_TYPE_NAME, BigInteger.valueOf(Math.abs(longVal))), execute(statement));
+            }
+        }
+    }
+
     private Tuple<String, Object> execute(PreparedStatement statement) throws SQLException {
         try (ResultSet results = statement.executeQuery()) {
             ResultSetMetaData resultSetMetaData = results.getMetaData();

+ 56 - 13
x-pack/plugin/sql/qa/jdbc/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/ResultSetMetaDataTestCase.java

@@ -15,10 +15,19 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+import static java.util.Collections.singletonList;
+import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.JDBC_DRIVER_VERSION;
+import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.UNSIGNED_LONG_TYPE_NAME;
+import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.isUnsignedLongSupported;
 
 public abstract class ResultSetMetaDataTestCase extends JdbcIntegrationTestCase {
 
-    private final String[] fieldsNames = new String[] {
+    private static final List<String> FIELDS_NAMES = List.of(
         "test_byte",
         "test_integer",
         "test_long",
@@ -27,40 +36,74 @@ public abstract class ResultSetMetaDataTestCase extends JdbcIntegrationTestCase
         "test_float",
         "test_keyword",
         "test_boolean",
-        "test_date" };
+        "test_date"
+    );
+    private static final String UNSIGNED_LONG_FIELD = "test_" + UNSIGNED_LONG_TYPE_NAME.toLowerCase(Locale.ROOT);
 
-    public void testValidGetObjectCalls() throws IOException, SQLException {
+    private static void createMappedIndex(List<String> fieldsNames) throws IOException {
         ResultSetTestCase.createIndex("test");
         ResultSetTestCase.updateMapping("test", builder -> {
             for (String field : fieldsNames) {
                 builder.startObject(field).field("type", field.substring(5)).endObject();
             }
         });
+    }
+
+    public void testValidGetObjectCalls() throws IOException, SQLException {
+        doTestValidGetObjectCalls(FIELDS_NAMES);
+    }
 
-        String q = "SELECT test_byte, test_integer, test_long, test_short, test_double, test_float, test_keyword, "
-            + "test_boolean, test_date FROM test";
+    public void testValidGetObjectCallsWithUnsignedLong() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        doTestValidGetObjectCalls(singletonList(UNSIGNED_LONG_FIELD));
+    }
+
+    private void doTestValidGetObjectCalls(List<String> fieldsNames) throws IOException, SQLException {
+        createMappedIndex(fieldsNames);
+
+        String q = "SELECT " + String.join(", ", fieldsNames) + " FROM test";
         doWithQuery(q, r -> assertColumnNamesAndLabels(r.getMetaData(), fieldsNames));
 
-        q = "SELECT test_byte AS b, test_integer AS i, test_long AS l, test_short AS s, test_double AS d, test_float AS f, "
-            + "test_keyword AS k, test_boolean AS bool, test_date AS dt FROM test";
-        doWithQuery(q, r -> assertColumnNamesAndLabels(r.getMetaData(), new String[] { "b", "i", "l", "s", "d", "f", "k", "bool", "dt" }));
+        String selectedFields = fieldsNames.stream().map(x -> x + " AS " + x.replace("_", "")).collect(Collectors.joining(", "));
+        q = "SELECT " + selectedFields + " FROM test";
+        doWithQuery(
+            q,
+            r -> assertColumnNamesAndLabels(r.getMetaData(), fieldsNames.stream().map(x -> x.replace("_", "")).collect(Collectors.toList()))
+        );
+    }
+
+    public void testUnsignedLongConditionallyReturnedOnStarExpansion() throws IOException, SQLException {
+        List<String> fieldsNames = new ArrayList<>(FIELDS_NAMES);
+        fieldsNames.add(UNSIGNED_LONG_FIELD);
+        createMappedIndex(fieldsNames);
+
+        String query = "SELECT * FROM test";
+        doWithQuery(query, r -> {
+            List<String> columnTypeNames = new ArrayList<>(fieldsNames.size());
+            for (int i = 0; i < r.getMetaData().getColumnCount(); i++) {
+                columnTypeNames.add(r.getMetaData().getColumnTypeName(i + 1).toLowerCase(Locale.ROOT));
+            }
+            // the assert executes only if UL is supported; the failing case would be triggered earlier in the driver already
+            assertEquals(isUnsignedLongSupported(), columnTypeNames.contains(UNSIGNED_LONG_TYPE_NAME.toLowerCase(Locale.ROOT)));
+        });
     }
 
     private void doWithQuery(String query, CheckedConsumer<ResultSet, SQLException> consumer) throws SQLException {
         try (Connection connection = esJdbc()) {
             try (PreparedStatement statement = connection.prepareStatement(query)) {
                 try (ResultSet results = statement.executeQuery()) {
-                    assertEquals(fieldsNames.length, results.getMetaData().getColumnCount());
                     consumer.accept(results);
                 }
             }
         }
     }
 
-    private void assertColumnNamesAndLabels(ResultSetMetaData metaData, String[] names) throws SQLException {
-        for (int i = 0; i < fieldsNames.length; i++) {
-            assertEquals(names[i], metaData.getColumnName(i + 1));
-            assertEquals(names[i], metaData.getColumnLabel(i + 1));
+    private void assertColumnNamesAndLabels(ResultSetMetaData metaData, List<String> names) throws SQLException {
+        assertEquals(names.size(), metaData.getColumnCount());
+        for (int i = 0; i < names.size(); i++) {
+            assertEquals(names.get(i), metaData.getColumnName(i + 1));
+            assertEquals(names.get(i), metaData.getColumnLabel(i + 1));
         }
     }
 }

+ 378 - 120
x-pack/plugin/sql/qa/jdbc/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/ResultSetTestCase.java

@@ -24,6 +24,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.sql.Blob;
 import java.sql.Clob;
 import java.sql.Connection;
@@ -46,19 +47,16 @@ import java.util.Arrays;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
-import java.util.Set;
 import java.util.TimeZone;
 import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 import static java.lang.String.format;
 import static java.util.Calendar.DAY_OF_MONTH;
@@ -69,14 +67,18 @@ import static java.util.Calendar.MINUTE;
 import static java.util.Calendar.MONTH;
 import static java.util.Calendar.SECOND;
 import static java.util.Calendar.YEAR;
+import static java.util.Collections.singletonList;
 import static java.util.regex.Pattern.compile;
 import static java.util.regex.Pattern.quote;
 import static org.elasticsearch.common.time.DateUtils.toMilliSeconds;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.JDBC_DRIVER_VERSION;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.JDBC_TIMEZONE;
+import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.UNSIGNED_LONG_MAX;
+import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.UNSIGNED_LONG_TYPE_NAME;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.asDate;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.asTime;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.extractNanosOnly;
+import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.isUnsignedLongSupported;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.of;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.randomTimeInNanos;
 import static org.elasticsearch.xpack.sql.qa.jdbc.JdbcTestUtils.versionSupportsDateNanos;
@@ -84,7 +86,7 @@ import static org.hamcrest.Matchers.matchesPattern;
 
 public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
 
-    static final Set<String> fieldsNames = Stream.of(
+    static final List<String> FIELDS_NAMES = List.of(
         "test_byte",
         "test_integer",
         "test_long",
@@ -92,12 +94,16 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         "test_double",
         "test_float",
         "test_keyword"
-    ).collect(Collectors.toCollection(HashSet::new));
+    );
+    static final String UNSIGNED_LONG_FIELD = "test_" + UNSIGNED_LONG_TYPE_NAME.toLowerCase(Locale.ROOT);
+
     static final Map<Tuple<String, Object>, SQLType> dateTimeTestingFields = new HashMap<>();
-    static final String SELECT_ALL_FIELDS = "SELECT test_boolean, test_byte, test_integer,"
-        + "test_long, test_short, test_double, test_float, test_keyword, test_date, test_date_nanos FROM test";
+    static final String SELECT_ALL_FIELDS;
     static final String SELECT_WILDCARD = "SELECT * FROM test";
+
     static {
+        SELECT_ALL_FIELDS = "SELECT test_boolean, " + String.join(", ", FIELDS_NAMES) + ", test_date, test_date_nanos FROM test";
+
         dateTimeTestingFields.put(new Tuple<>("test_boolean", true), EsType.BOOLEAN);
         dateTimeTestingFields.put(new Tuple<>("test_byte", 1), EsType.BYTE);
         dateTimeTestingFields.put(new Tuple<>("test_integer", 1), EsType.INTEGER);
@@ -259,15 +265,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
             ? Double.toString(doubleNotByte)
             : Long.toString(Math.round(doubleNotByte));
 
-        index("test", "1", builder -> {
-            builder.field("test_integer", intNotByte);
-            builder.field("test_long", longNotByte);
-            builder.field("test_short", shortNotByte);
-            builder.field("test_double", doubleNotByte);
-            builder.field("test_float", floatNotByte);
-            builder.field("test_keyword", randomString);
-            builder.field("test_date", randomDate);
-        });
+        indexTestFieldsDoc("1", intNotByte, longNotByte, shortNotByte, doubleNotByte, floatNotByte, randomString, new Date(randomDate));
 
         doWithQuery(SELECT_WILDCARD, results -> {
             results.next();
@@ -315,6 +313,25 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         });
     }
 
+    public void testGettingInvalidByteFromUnsignedLong() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        createIndex("test");
+        updateMappingForNumericValuesTests("test", singletonList(UNSIGNED_LONG_FIELD));
+
+        BigInteger bigIntegerNotByte = BigInteger.valueOf(randomLongBetween(Byte.MAX_VALUE + 1, Long.MAX_VALUE));
+        indexTestFieldsDoc("1", bigIntegerNotByte);
+
+        doWithQuery(SELECT_WILDCARD, results -> {
+            results.next();
+
+            SQLException sqle = expectThrows(SQLException.class, () -> results.getByte(UNSIGNED_LONG_FIELD));
+            assertEquals(format(Locale.ROOT, "Numeric %s out of range", bigIntegerNotByte), sqle.getMessage());
+            sqle = expectThrows(SQLException.class, () -> results.getObject(UNSIGNED_LONG_FIELD, Byte.class));
+            assertEquals(format(Locale.ROOT, "Numeric %s out of range", bigIntegerNotByte), sqle.getMessage());
+        });
+    }
+
     // Short values testing
     public void testGettingValidShortWithoutCasting() throws IOException, SQLException {
         List<Short> shortTestValues = createTestDataForNumericValueTests(ESTestCase::randomShort);
@@ -373,10 +390,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
     public void testGettingInvalidShort() throws IOException, SQLException {
         createIndex("test");
         updateMappingForNumericValuesTests("test");
-        updateMapping("test", builder -> {
-            builder.startObject("test_keyword").field("type", "keyword").endObject();
-            builder.startObject("test_date").field("type", "date").endObject();
-        });
+        updateMapping("test", builder -> { builder.startObject("test_date").field("type", "date").endObject(); });
 
         int intNotShort = randomIntBetween(Short.MAX_VALUE + 1, Integer.MAX_VALUE);
         long longNotShort = randomLongBetween(Short.MAX_VALUE + 1, Long.MAX_VALUE);
@@ -389,14 +403,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
             ? Double.toString(doubleNotShort)
             : Long.toString(Math.round(doubleNotShort));
 
-        index("test", "1", builder -> {
-            builder.field("test_integer", intNotShort);
-            builder.field("test_long", longNotShort);
-            builder.field("test_double", doubleNotShort);
-            builder.field("test_float", floatNotShort);
-            builder.field("test_keyword", randomString);
-            builder.field("test_date", randomDate);
-        });
+        indexTestFieldsDoc("1", intNotShort, longNotShort, doubleNotShort, floatNotShort, randomString, new Date(randomDate));
 
         doWithQuery(SELECT_WILDCARD, results -> {
             results.next();
@@ -439,6 +446,25 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         });
     }
 
+    public void testGettingInvalidShortFromUnsignedLong() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        createIndex("test");
+        updateMappingForNumericValuesTests("test", singletonList(UNSIGNED_LONG_FIELD));
+
+        BigInteger bigIntegerNotShort = BigInteger.valueOf(randomLongBetween(Short.MAX_VALUE + 1, Long.MAX_VALUE));
+        indexTestFieldsDoc("1", bigIntegerNotShort);
+
+        doWithQuery(SELECT_WILDCARD, results -> {
+            results.next();
+
+            SQLException sqle = expectThrows(SQLException.class, () -> results.getShort(UNSIGNED_LONG_FIELD));
+            assertEquals(format(Locale.ROOT, "Numeric %s out of range", bigIntegerNotShort), sqle.getMessage());
+            sqle = expectThrows(SQLException.class, () -> results.getObject(UNSIGNED_LONG_FIELD, Short.class));
+            assertEquals(format(Locale.ROOT, "Numeric %s out of range", bigIntegerNotShort), sqle.getMessage());
+        });
+    }
+
     // Integer values testing
     public void testGettingValidIntegerWithoutCasting() throws IOException, SQLException {
         List<Integer> integerTestValues = createTestDataForNumericValueTests(ESTestCase::randomInt);
@@ -497,10 +523,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
     public void testGettingInvalidInteger() throws IOException, SQLException {
         createIndex("test");
         updateMappingForNumericValuesTests("test");
-        updateMapping("test", builder -> {
-            builder.startObject("test_keyword").field("type", "keyword").endObject();
-            builder.startObject("test_date").field("type", "date").endObject();
-        });
+        updateMapping("test", builder -> { builder.startObject("test_date").field("type", "date").endObject(); });
 
         long longNotInt = randomLongBetween(getMaxIntPlusOne(), Long.MAX_VALUE);
         double doubleNotInt = randomDoubleBetween(getMaxIntPlusOne().doubleValue(), Double.MAX_VALUE, true);
@@ -512,13 +535,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
             ? Double.toString(doubleNotInt)
             : Long.toString(Math.round(doubleNotInt));
 
-        index("test", "1", builder -> {
-            builder.field("test_long", longNotInt);
-            builder.field("test_double", doubleNotInt);
-            builder.field("test_float", floatNotInt);
-            builder.field("test_keyword", randomString);
-            builder.field("test_date", randomDate);
-        });
+        indexTestFieldsDoc("1", longNotInt, doubleNotInt, floatNotInt, randomString, new Date(randomDate));
 
         doWithQuery(SELECT_WILDCARD, results -> {
             results.next();
@@ -556,6 +573,25 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         });
     }
 
+    public void testGettingInvalidIntegerFromUnsignedLong() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        createIndex("test");
+        updateMappingForNumericValuesTests("test", singletonList(UNSIGNED_LONG_FIELD));
+
+        BigInteger bigIntegerNotInt = BigInteger.valueOf(randomLongBetween(getMaxIntPlusOne(), Long.MAX_VALUE));
+        indexTestFieldsDoc("1", bigIntegerNotInt);
+
+        doWithQuery(SELECT_WILDCARD, results -> {
+            results.next();
+
+            SQLException sqle = expectThrows(SQLException.class, () -> results.getInt(UNSIGNED_LONG_FIELD));
+            assertEquals(format(Locale.ROOT, "Numeric %s out of range", bigIntegerNotInt), sqle.getMessage());
+            sqle = expectThrows(SQLException.class, () -> results.getObject(UNSIGNED_LONG_FIELD, Integer.class));
+            assertEquals(format(Locale.ROOT, "Numeric %s out of range", bigIntegerNotInt), sqle.getMessage());
+        });
+    }
+
     // Long values testing
     public void testGettingValidLongWithoutCasting() throws IOException, SQLException {
         List<Long> longTestValues = createTestDataForNumericValueTests(ESTestCase::randomLong);
@@ -611,22 +647,14 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
     public void testGettingInvalidLong() throws IOException, SQLException {
         createIndex("test");
         updateMappingForNumericValuesTests("test");
-        updateMapping("test", builder -> {
-            builder.startObject("test_keyword").field("type", "keyword").endObject();
-            builder.startObject("test_date").field("type", "date").endObject();
-        });
+        updateMapping("test", builder -> { builder.startObject("test_date").field("type", "date").endObject(); });
 
         double doubleNotLong = randomDoubleBetween(getMaxLongPlusOne(), Double.MAX_VALUE, true);
         float floatNotLong = randomFloatBetween(getMaxLongPlusOne().floatValue(), Float.MAX_VALUE);
         String randomString = randomUnicodeOfCodepointLengthBetween(128, 256);
         long randomDate = randomMillisUpToYear9999();
 
-        index("test", "1", builder -> {
-            builder.field("test_double", doubleNotLong);
-            builder.field("test_float", floatNotLong);
-            builder.field("test_keyword", randomString);
-            builder.field("test_date", randomDate);
-        });
+        indexTestFieldsDoc("1", doubleNotLong, floatNotLong, randomString, new Date(randomDate));
 
         doWithQuery(SELECT_WILDCARD, results -> {
             results.next();
@@ -659,6 +687,163 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         });
     }
 
+    public void testGettingInvalidLongFromUnsignedLong() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        createIndex("test");
+        updateMappingForNumericValuesTests("test", singletonList(UNSIGNED_LONG_FIELD));
+
+        BigInteger bigIntegerNotLong = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(randomNonNegativeLong()));
+        indexTestFieldsDoc("1", bigIntegerNotLong);
+
+        doWithQuery(SELECT_WILDCARD, results -> {
+            results.next();
+
+            SQLException sqle = expectThrows(SQLException.class, () -> results.getLong(UNSIGNED_LONG_FIELD));
+            assertEquals(format(Locale.ROOT, "Numeric %s out of range", bigIntegerNotLong), sqle.getMessage());
+            sqle = expectThrows(SQLException.class, () -> results.getObject(UNSIGNED_LONG_FIELD, Long.class));
+            assertEquals(format(Locale.ROOT, "Numeric %s out of range", bigIntegerNotLong), sqle.getMessage());
+        });
+    }
+
+    // BigInteger/unsigned_long values testing
+    public void testGettingValidBigIntegerWithoutCasting() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        List<BigInteger> bigIntegerTestValues = createTestDataForNumericValueTests(ESTestCase::randomBigInteger);
+        BigInteger random1 = bigIntegerTestValues.get(0);
+        BigInteger random2 = bigIntegerTestValues.get(1);
+        BigInteger random3 = bigIntegerTestValues.get(2);
+
+        doWithQuery("SELECT test_unsigned_long, test_null_unsigned_long, test_keyword FROM test", results -> {
+            ResultSetMetaData resultSetMetaData = results.getMetaData();
+
+            results.next();
+            assertEquals(3, resultSetMetaData.getColumnCount());
+            assertEquals(UNSIGNED_LONG_TYPE_NAME, resultSetMetaData.getColumnTypeName(1));
+            assertEquals(random1, results.getObject(1));
+            assertEquals(random1, results.getObject(UNSIGNED_LONG_FIELD));
+            assertEquals(random1, results.getObject(UNSIGNED_LONG_FIELD, BigInteger.class));
+            assertTrue(results.getObject(1) instanceof BigInteger);
+
+            assertEquals(UNSIGNED_LONG_TYPE_NAME, resultSetMetaData.getColumnTypeName(2));
+            assertNull(results.getObject(2));
+            assertTrue(results.wasNull());
+            assertNull(results.getObject("test_null_unsigned_long"));
+            assertTrue(results.wasNull());
+
+            assertTrue(results.next());
+            assertEquals(random2, results.getObject(1));
+            assertEquals(random2, results.getObject(UNSIGNED_LONG_FIELD));
+            assertTrue(results.getObject(1) instanceof BigInteger);
+            assertEquals(random3.toString(), results.getObject("test_keyword"));
+
+            assertFalse(results.next());
+        });
+    }
+
+    public void testGettingValidBigIntegerWithCasting() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        Map<String, Number> map = createTestDataForNumericValueTypes(ESTestCase::randomBigInteger);
+        updateMappingForNumericValuesTests("test", singletonList(UNSIGNED_LONG_FIELD));
+
+        BigInteger randomBigInteger = randomBigInteger();
+        indexTestFieldsDoc("2", randomBigInteger);
+
+        doWithQuery(SELECT_WILDCARD, results -> {
+            results.next();
+            for (Entry<String, Number> e : map.entrySet()) {
+                BigInteger actual = results.getObject(e.getKey(), BigInteger.class);
+                if (e.getValue() instanceof Float) {
+                    assertEquals("For field " + e.getKey(), e.getValue(), actual.floatValue());
+                } else if (e.getValue() instanceof Double) {
+                    assertEquals("For field " + e.getKey(), e.getValue(), actual.doubleValue());
+                } else {
+                    assertEquals("For field " + e.getKey(), e.getValue().longValue(), results.getLong(e.getKey()));
+                    assertEquals("For field " + e.getKey(), e.getValue().longValue(), actual.longValue());
+                }
+            }
+
+            results.next();
+            BigInteger actual = results.getObject(UNSIGNED_LONG_FIELD, BigInteger.class);
+            assertEquals("For field " + UNSIGNED_LONG_FIELD, randomBigInteger, actual);
+        });
+    }
+
+    public void testGettingInvalidBigInteger() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        createIndex("test");
+        updateMappingForNumericValuesTests("test");
+        updateMapping("test", builder -> {
+            builder.startObject("test_keyword").field("type", "keyword").endObject();
+            builder.startObject("test_date").field("type", "date").endObject();
+        });
+
+        String randomString = randomUnicodeOfCodepointLengthBetween(128, 256);
+        long randomDate = randomMillisUpToYear9999();
+
+        index("test", "1", builder -> {
+            builder.field("test_keyword", randomString);
+            builder.field("test_date", randomDate);
+        });
+
+        doWithQuery(SELECT_WILDCARD, results -> {
+            results.next();
+
+            SQLException sqle = expectThrows(SQLException.class, () -> results.getObject("test_keyword", BigInteger.class));
+            assertEquals(
+                format(Locale.ROOT, "Unable to convert value [%.128s] of type [KEYWORD] to [BigInteger]", randomString),
+                sqle.getMessage()
+            );
+
+            sqle = expectThrows(SQLException.class, () -> results.getObject("test_date", BigInteger.class));
+            assertEquals(
+                format(Locale.ROOT, "Unable to convert value [%.128s] of type [DATETIME] to [BigInteger]", asDateString(randomDate)),
+                sqle.getMessage()
+            );
+        });
+    }
+
+    public void testGettingValidNumbersWithCastingFromUnsignedLong() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        createIndex("test");
+        updateMappingForNumericValuesTests("test", singletonList(UNSIGNED_LONG_FIELD));
+
+        byte randomNonNegativeByte = randomNonNegativeByte();
+        short randomNonNegativeShort = (short) (Math.abs(randomShort()) - 1);
+        int randomNonNegativeInt = Math.abs(randomInt()) - 1;
+        long randomNonNegativeLong = randomNonNegativeLong();
+        double randomNonNegativeFloat = (float) randomDoubleBetween(0, UNSIGNED_LONG_MAX.doubleValue(), true);
+        double randomNonNegativeDouble = randomDoubleBetween(0, UNSIGNED_LONG_MAX.doubleValue(), true);
+
+        int docId = 1;
+        indexTestFieldsDoc(String.valueOf(docId++), BigInteger.valueOf(randomNonNegativeByte));
+        indexTestFieldsDoc(String.valueOf(docId++), BigInteger.valueOf(randomNonNegativeShort));
+        indexTestFieldsDoc(String.valueOf(docId++), BigInteger.valueOf(randomNonNegativeInt));
+        indexTestFieldsDoc(String.valueOf(docId++), BigInteger.valueOf(randomNonNegativeLong));
+        indexTestFieldsDoc(String.valueOf(docId++), BigDecimal.valueOf(randomNonNegativeFloat).toBigInteger());
+        indexTestFieldsDoc(String.valueOf(docId++), BigDecimal.valueOf(randomNonNegativeDouble).toBigInteger());
+
+        doWithQuery(SELECT_WILDCARD, results -> {
+            results.next();
+            assertEquals(randomNonNegativeByte, results.getByte(1));
+            results.next();
+            assertEquals(randomNonNegativeShort, results.getShort(1));
+            results.next();
+            assertEquals(randomNonNegativeInt, results.getInt(1));
+            results.next();
+            assertEquals(randomNonNegativeLong, results.getLong(1));
+            results.next();
+            assertEquals(randomNonNegativeFloat, results.getFloat(1), 0f);
+            results.next();
+            assertEquals(randomNonNegativeDouble, results.getDouble(1), 0d);
+        });
+
+    }
+
     // Double values testing
     public void testGettingValidDoubleWithoutCasting() throws IOException, SQLException {
         List<Double> doubleTestValues = createTestDataForNumericValueTests(ESTestCase::randomDouble);
@@ -1052,52 +1237,35 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         long randomDateNanos2 = randomTimeInNanos();
 
         // true values
-        indexSimpleDocumentWithTrueValues(randomDate1, randomDateNanos1);
-
+        indexSimpleDocumentWithBooleanValues("1", true, randomDate1, randomDateNanos1);
         // false values
-        index("test", "2", builder -> {
-            builder.field("test_boolean", false);
-            builder.field("test_byte", 0);
-            builder.field("test_integer", 0);
-            builder.field("test_long", 0L);
-            builder.field("test_short", 0);
-            builder.field("test_double", 0d);
-            builder.field("test_float", 0f);
-            builder.field("test_keyword", "false");
-            builder.field("test_date", randomDate2);
-            builder.field("test_date_nanos", asTimestampWithNanos(randomDateNanos2));
-        });
+        indexSimpleDocumentWithBooleanValues("2", false, randomDate2, randomDateNanos2);
 
         // other (non 0 = true) values
-        index("test", "3", builder -> {
-            builder.field("test_byte", randomValueOtherThan((byte) 0, ESTestCase::randomByte));
-            builder.field("test_integer", randomValueOtherThan(0, ESTestCase::randomInt));
-            builder.field("test_long", randomValueOtherThan(0L, ESTestCase::randomLong));
-            builder.field("test_short", randomValueOtherThan((short) 0, ESTestCase::randomShort));
-            builder.field(
-                "test_double",
-                randomValueOtherThanMany(
-                    i -> i < 1.0d && i > -1.0d && i < Double.MAX_VALUE && i > Double.MIN_VALUE,
-                    () -> randomDouble() * randomInt()
-                )
-            );
-            builder.field(
-                "test_float",
-                randomValueOtherThanMany(
-                    i -> i < 1.0f && i > -1.0f && i < Float.MAX_VALUE && i > Float.MIN_VALUE,
-                    () -> randomFloat() * randomInt()
-                )
-            );
-            builder.field("test_keyword", "1");
-        });
+        indexTestFieldsDoc(
+            "3",
+            randomValueOtherThan((byte) 0, ESTestCase::randomByte),
+            randomValueOtherThan(0, ESTestCase::randomInt),
+            randomValueOtherThan(0L, ESTestCase::randomLong),
+            randomValueOtherThan((short) 0, ESTestCase::randomShort),
+            randomValueOtherThanMany(
+                i -> i < 1.0d && i > -1.0d && i < Double.MAX_VALUE && i > Double.MIN_VALUE,
+                () -> randomDouble() * randomInt()
+            ),
+            randomValueOtherThanMany(
+                i -> i < 1.0f && i > -1.0f && i < Float.MAX_VALUE && i > Float.MIN_VALUE,
+                () -> randomFloat() * randomInt()
+            ),
+            "1"
+        );
 
         // other false values
         index("test", "4", builder -> builder.field("test_keyword", "0"));
 
         doWithQuery(SELECT_WILDCARD, results -> {
-            results.next();
+            results.next(); // docId: 1
             assertTrue(results.getBoolean("test_boolean"));
-            for (String fld : fieldsNames) {
+            for (String fld : FIELDS_NAMES) {
                 assertTrue("Expected: <true> but was: <false> for field " + fld, results.getBoolean(fld));
                 assertEquals("Expected: <true> but was: <false> for field " + fld, true, results.getObject(fld, Boolean.class));
             }
@@ -1106,9 +1274,9 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
             sqle = expectThrows(SQLException.class, () -> results.getBoolean("test_date_nanos"));
             assertErrorMessageForDateTimeValues(sqle, Boolean.class, toMilliSeconds(randomDateNanos1), extractNanosOnly(randomDateNanos1));
 
-            results.next();
+            results.next(); // docId: 2
             assertFalse(results.getBoolean("test_boolean"));
-            for (String fld : fieldsNames) {
+            for (String fld : FIELDS_NAMES) {
                 assertFalse("Expected: <false> but was: <true> for field " + fld, results.getBoolean(fld));
                 assertEquals("Expected: <false> but was: <true> for field " + fld, false, results.getObject(fld, Boolean.class));
             }
@@ -1124,18 +1292,43 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
             sqle = expectThrows(SQLException.class, () -> results.getObject("test_date_nanos", Boolean.class));
             assertErrorMessageForDateTimeValues(sqle, Boolean.class, toMilliSeconds(randomDateNanos2), extractNanosOnly(randomDateNanos2));
 
-            results.next();
-            for (String fld : fieldsNames.stream().filter(f -> f.equals("test_keyword") == false).collect(Collectors.toSet())) {
+            results.next(); // docId: 3
+            for (String fld : FIELDS_NAMES.stream().filter(f -> f.equals("test_keyword") == false).collect(Collectors.toSet())) {
                 assertTrue("Expected: <true> but was: <false> for field " + fld, results.getBoolean(fld));
                 assertEquals("Expected: <true> but was: <false> for field " + fld, true, results.getObject(fld, Boolean.class));
             }
 
-            results.next();
+            results.next(); // docId: 4
             assertFalse(results.getBoolean("test_keyword"));
             assertEquals(false, results.getObject("test_keyword", Boolean.class));
         });
     }
 
+    public void testGettingBooleanValuesFromUnsignedLong() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        createIndex("test");
+        updateMappingForNumericValuesTests("test", singletonList(UNSIGNED_LONG_FIELD));
+
+        indexTestFieldsDoc("1", BigInteger.ONE);
+        indexTestFieldsDoc("2", BigInteger.ZERO);
+        indexTestFieldsDoc("3", randomValueOtherThan(BigInteger.ZERO, ESTestCase::randomBigInteger));
+
+        doWithQuery(SELECT_WILDCARD, results -> {
+            results.next(); // docId: 1
+            assertTrue(results.getBoolean(UNSIGNED_LONG_FIELD));
+            assertTrue(results.getObject(UNSIGNED_LONG_FIELD, Boolean.class));
+
+            results.next(); // docId: 2
+            assertFalse(results.getBoolean(UNSIGNED_LONG_FIELD));
+            assertFalse(results.getObject(UNSIGNED_LONG_FIELD, Boolean.class));
+
+            results.next(); // docId: 3
+            assertTrue(results.getBoolean(UNSIGNED_LONG_FIELD));
+            assertTrue(results.getObject(UNSIGNED_LONG_FIELD, Boolean.class));
+        });
+    }
+
     private void setupDataForDateTimeTests(long randomLongDate) throws IOException {
         setupDataForDateTimeTests(randomLongDate, null);
     }
@@ -1149,7 +1342,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
             builder.startObject("test_date_nanos").field("type", "date_nanos").endObject();
         });
 
-        indexSimpleDocumentWithTrueValues(randomLongDate, randomLongDateNanos);
+        indexSimpleDocumentWithBooleanValues("1", true, randomLongDate, randomLongDateNanos);
         index("test", "2", builder -> {
             builder.timeField("test_date", null);
             builder.timeField("test_date_nanos", null);
@@ -1165,9 +1358,9 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
 
             Date expectedDate = asDate(randomLongDate, getZoneFromOffset(randomLongDate));
             assertEquals(expectedDate, results.getDate("test_date"));
-            assertEquals(expectedDate, results.getDate(9));
+            assertEquals(expectedDate, results.getDate(FIELDS_NAMES.size() + 2));
             assertEquals(expectedDate, results.getObject("test_date", Date.class));
-            assertEquals(expectedDate, results.getObject(9, Date.class));
+            assertEquals(expectedDate, results.getObject(FIELDS_NAMES.size() + 2, Date.class));
 
             // bulk validation for all fields which are not of type date
             validateErrorsForDateTimeTestsWithoutCalendar(results::getDate, "Date");
@@ -1224,7 +1417,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
 
             Date expectedDate = new Date(c.getTimeInMillis());
             assertEquals(expectedDate, results.getDate("test_date", c));
-            assertEquals(expectedDate, results.getDate(9, c));
+            assertEquals(expectedDate, results.getDate(FIELDS_NAMES.size() + 2, c));
 
             // bulk validation for all fields which are not of type date
             validateErrorsForDateTimeTestsWithCalendar(c, results::getDate);
@@ -1278,9 +1471,9 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
 
             Time expectedTime = asTime(randomLongDate, getZoneFromOffset(randomLongDate));
             assertEquals(expectedTime, results.getTime("test_date"));
-            assertEquals(expectedTime, results.getTime(9));
+            assertEquals(expectedTime, results.getTime(FIELDS_NAMES.size() + 2));
             assertEquals(expectedTime, results.getObject("test_date", Time.class));
-            assertEquals(expectedTime, results.getObject(9, Time.class));
+            assertEquals(expectedTime, results.getObject(FIELDS_NAMES.size() + 2, Time.class));
 
             validateErrorsForDateTimeTestsWithoutCalendar(results::getTime, "Time");
 
@@ -1335,7 +1528,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
 
             Time expectedTime = new Time(c.getTimeInMillis());
             assertEquals(expectedTime, results.getTime("test_date", c));
-            assertEquals(expectedTime, results.getTime(9, c));
+            assertEquals(expectedTime, results.getTime(FIELDS_NAMES.size() + 2, c));
 
             validateErrorsForDateTimeTestsWithCalendar(c, results::getTime);
 
@@ -1455,7 +1648,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
             c.setTimeInMillis(randomLongDate);
 
             assertEquals(new Timestamp(c.getTimeInMillis()), results.getTimestamp("test_date", c));
-            assertEquals(new Timestamp(c.getTimeInMillis()), results.getTimestamp(9, c));
+            assertEquals(new Timestamp(c.getTimeInMillis()), results.getTimestamp(FIELDS_NAMES.size() + 2, c));
 
             results.next();
             assertNull(results.getTimestamp("test_date"));
@@ -1491,6 +1684,32 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         });
     }
 
+    public void testErrorsValidationForDateTimeTypesConvertingToUnsignedLong() throws IOException, SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        createIndex("test");
+        updateMappingForNumericValuesTests("test", singletonList(UNSIGNED_LONG_FIELD));
+
+        indexTestFieldsDoc("1", BigInteger.ONE);
+
+        doWithQuery(SELECT_WILDCARD, results -> {
+            results.next();
+
+            SQLException sqle = expectThrows(SQLException.class, () -> results.getDate(UNSIGNED_LONG_FIELD));
+            assertEquals(
+                format(Locale.ROOT, "Unable to convert value [%.127s] of type [%s] to a Date", BigInteger.ONE, UNSIGNED_LONG_TYPE_NAME),
+                sqle.getMessage()
+            );
+
+            sqle = expectThrows(SQLException.class, () -> results.getTime(UNSIGNED_LONG_FIELD));
+            assertEquals(
+                format(Locale.ROOT, "Unable to convert value [%.127s] of type [%s] to a Time", BigInteger.ONE, UNSIGNED_LONG_TYPE_NAME),
+                sqle.getMessage()
+            );
+        });
+
+    }
+
     public void testScalarOnDates() throws IOException, SQLException {
         createIndex("test");
         updateMapping("test", builder -> builder.startObject("test_date").field("type", "date").endObject());
@@ -1815,6 +2034,18 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         });
     }
 
+    public void testGettingNullUnsignedLong() throws SQLException {
+        assumeTrue("Driver version [" + JDBC_DRIVER_VERSION + "] doesn't support UNSIGNED_LONGs", isUnsignedLongSupported());
+
+        String query = "SELECT CAST(NULL AS UNSIGNED_LONG) as ul";
+        doWithQuery(query, results -> {
+            results.next();
+
+            assertNull(results.getObject("ul"));
+            assertEquals(0.0f, results.getFloat("ul"), 0f);
+        });
+    }
+
     /*
      * Checks StackOverflowError fix for https://github.com/elastic/elasticsearch/pull/31735
      */
@@ -1845,7 +2076,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         index("test", "1", builder -> builder.field("test", "test"));
         try (
             Connection conn = esJdbc();
-            PreparedStatement statement = conn.prepareStatement("SELECT * FROM test");
+            PreparedStatement statement = conn.prepareStatement(SELECT_WILDCARD);
             ResultSet r = statement.executeQuery()
         ) {
 
@@ -1883,7 +2114,7 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         index("test", "1", builder -> builder.field("test", "test"));
         try (
             Connection conn = esJdbc();
-            PreparedStatement statement = conn.prepareStatement("SELECT * FROM test");
+            PreparedStatement statement = conn.prepareStatement(SELECT_WILDCARD);
             ResultSet r = statement.executeQuery()
         ) {
             r.next();
@@ -2157,22 +2388,23 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         T random2 = randomValueOtherThan(random1, numberGenerator);
         T random3 = randomValueOtherThanMany(Arrays.asList(random1, random2)::contains, numberGenerator);
 
-        Class<? extends Number> clazz = random1.getClass();
-        String primitiveName = clazz.getSimpleName().toLowerCase(Locale.ROOT);
+        EsType esType = of(random1.getClass());
+        assertNotNull(esType);
+        String esTypeName = esType.getName().toLowerCase(Locale.ROOT);
 
         createIndex("test");
         updateMapping("test", builder -> {
-            builder.startObject("test_" + primitiveName).field("type", primitiveName).endObject();
-            builder.startObject("test_null_" + primitiveName).field("type", primitiveName).endObject();
+            builder.startObject("test_" + esTypeName).field("type", esTypeName).endObject();
+            builder.startObject("test_null_" + esTypeName).field("type", esTypeName).endObject();
             builder.startObject("test_keyword").field("type", "keyword").endObject();
         });
 
         index("test", "1", builder -> {
-            builder.field("test_" + primitiveName, random1);
-            builder.field("test_null_" + primitiveName, (Byte) null);
+            builder.field("test_" + esTypeName, random1);
+            builder.field("test_null_" + esTypeName, (Byte) null);
         });
         index("test", "2", builder -> {
-            builder.field("test_" + primitiveName, random2);
+            builder.field("test_" + esTypeName, random2);
             builder.field("test_keyword", random3);
         });
 
@@ -2199,16 +2431,17 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         });
     }
 
-    private void indexSimpleDocumentWithTrueValues(long randomLongDate, Long randomLongNanos) throws IOException {
-        index("test", "1", builder -> {
-            builder.field("test_boolean", true);
-            builder.field("test_byte", 1);
-            builder.field("test_integer", 1);
-            builder.field("test_long", 1L);
-            builder.field("test_short", 1);
-            builder.field("test_double", 1d);
-            builder.field("test_float", 1f);
-            builder.field("test_keyword", "true");
+    private void indexSimpleDocumentWithBooleanValues(String docId, boolean bool, Long randomLongDate, Long randomLongNanos)
+        throws IOException {
+        index("test", docId, builder -> {
+            builder.field("test_boolean", bool);
+            builder.field("test_byte", bool ? 1 : 0);
+            builder.field("test_integer", bool ? 1 : 0);
+            builder.field("test_long", bool ? 1L : 0L);
+            builder.field("test_short", bool ? 1 : 0);
+            builder.field("test_double", bool ? 1d : 0d);
+            builder.field("test_float", bool ? 1f : 0f);
+            builder.field("test_keyword", bool ? "true" : "false");
             builder.field("test_date", randomLongDate);
             if (randomLongNanos != null) {
                 builder.field("test_date_nanos", asTimestampWithNanos(randomLongNanos));
@@ -2216,6 +2449,27 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         });
     }
 
+    private static void indexTestFieldsDoc(String docId, Object... values) throws IOException {
+        index("test", docId, builder -> {
+            for (Object value : values) {
+                String classSimpleName = value.getClass().getSimpleName().toLowerCase(Locale.ROOT);
+                switch (classSimpleName) {
+                    case "biginteger":
+                        builder.field(UNSIGNED_LONG_FIELD, value);
+                        break;
+                    case "date":
+                        builder.field("test_" + classSimpleName, ((Date) value).getTime());
+                        break;
+                    case "string":
+                        builder.field("test_keyword", value);
+                        break;
+                    default:
+                        builder.field("test_" + classSimpleName, value);
+                }
+            }
+        });
+    }
+
     /**
      * Creates test data for all numeric get* methods. All values random and different from the other numeric fields already generated.
      * It returns a map containing the field name and its randomly generated value to be later used in checking the returned values.
@@ -2259,14 +2513,18 @@ public abstract class ResultSetTestCase extends JdbcIntegrationTestCase {
         return map;
     }
 
-    private static void updateMappingForNumericValuesTests(String indexName) throws IOException {
+    private static void updateMappingForNumericValuesTests(String indexName, List<String> fieldsNames) throws IOException {
         updateMapping(indexName, builder -> {
             for (String field : fieldsNames) {
-                builder.startObject(field).field("type", field.substring(5)).endObject();
+                builder.startObject(field).field("type", field.substring("test_".length())).endObject();
             }
         });
     }
 
+    private static void updateMappingForNumericValuesTests(String indexName) throws IOException {
+        updateMappingForNumericValuesTests(indexName, FIELDS_NAMES);
+    }
+
     private void assertThrowsUnsupportedAndExpectErrorMessage(ThrowingRunnable runnable, String message) {
         SQLException sqle = expectThrows(SQLFeatureNotSupportedException.class, runnable);
         assertEquals(message, sqle.getMessage());

+ 14 - 0
x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/FieldExtractorTestCase.java

@@ -23,6 +23,7 @@ import org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.math.BigInteger;
 import java.sql.JDBCType;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -187,6 +188,7 @@ public abstract class FieldExtractorTestCase extends BaseRestSqlTestCase {
      *    "long/integer/short/byte_field": {
      *       "type": "long/integer/short/byte"
      *    }
+     *    Note: no unsigned_long tested -- the mapper for it won't accept float formats.
      */
     public void testFractionsForNonFloatingPointTypes() throws IOException {
         String floatingPointNumber = "123.456";
@@ -281,6 +283,17 @@ public abstract class FieldExtractorTestCase extends BaseRestSqlTestCase {
         testField("byte", ((Number) randomByte()).intValue());
     }
 
+    /*
+     *    "unsigned_long_field": {
+     *       "type": "unsigned_long",
+     *       "ignore_malformed": true/false
+     *    }
+     */
+    public void testUnsignedLongFieldType() throws IOException {
+        // randomBigInteger() can produce a value that fits into a Long, which is what testField() will then recover
+        testField("unsigned_long", BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(randomNonNegativeLong())));
+    }
+
     private void testField(String fieldType, Object value) throws IOException {
         String fieldName = fieldType + "_field";
         String query = "SELECT " + fieldName + " FROM test";
@@ -1602,6 +1615,7 @@ public abstract class FieldExtractorTestCase extends BaseRestSqlTestCase {
             case "half_float" -> JDBCType.FLOAT;
             case "scaled_float" -> JDBCType.DOUBLE;
             case "ip" -> JDBCType.VARCHAR;
+            case "unsigned_long" -> JDBCType.BIGINT;
             default -> throw new AssertionError("Illegal value [" + esType + "] for data type");
         };
     }

+ 2 - 0
x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/SqlProtocolTestCase.java

@@ -29,6 +29,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
+import static org.elasticsearch.xpack.ql.util.NumericUtils.UNSIGNED_LONG_MAX;
 import static org.elasticsearch.xpack.sql.proto.CoreProtocol.SQL_QUERY_REST_ENDPOINT;
 import static org.elasticsearch.xpack.sql.proto.Mode.CLI;
 import static org.elasticsearch.xpack.sql.proto.RequestInfo.CLIENT_IDS;
@@ -54,6 +55,7 @@ public abstract class SqlProtocolTestCase extends ESRestTestCase {
         assertQuery("SELECT -2123", "-2123", "integer", -2123, 11);
         assertQuery("SELECT 1234567890123", "1234567890123", "long", 1234567890123L, 20);
         assertQuery("SELECT -1234567890123", "-1234567890123", "long", -1234567890123L, 20);
+        assertQuery("SELECT 18446744073709551615", "18446744073709551615", "unsigned_long", UNSIGNED_LONG_MAX, 20);
         assertQuery("SELECT 1234567890123.34", "1234567890123.34", "double", 1234567890123.34, 25);
         assertQuery("SELECT -1234567890123.34", "-1234567890123.34", "double", -1234567890123.34, 25);
         assertQuery("SELECT CAST(1234.34 AS REAL)", "CAST(1234.34 AS REAL)", "float", 1234.34f, 15);

+ 1 - 0
x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/CsvTestUtils.java

@@ -153,6 +153,7 @@ public final class CsvTestUtils {
             case "ts" -> "timestamp";
             case "bt" -> "byte";
             case "sh" -> "short";
+            case "ul" -> "bigdecimal"; // CSV JDBC driver lacks biginteger support
             default -> type;
         };
     }

+ 53 - 67
x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DataLoader.java

@@ -67,6 +67,7 @@ public class DataLoader {
         loadEmpDatasetWithExtraIntoEs(client, "test_emp_copy", "employees");
         loadLogsDatasetIntoEs(client, "logs", "logs");
         loadLogNanosDatasetIntoEs(client, "logs_nanos", "logs_nanos");
+        loadLogUnsignedLongIntoEs(client, "logs_unsigned_long", "logs_unsigned_long");
         makeAlias(client, "test_alias", "test_emp", "test_emp_copy");
         makeAlias(client, "test_alias_emp", "test_emp", "test_emp_copy");
         // frozen index
@@ -151,6 +152,9 @@ public class DataLoader {
                 createIndex.startObject("birth_date").field("type", "date").endObject();
                 createIndex.startObject("hire_date").field("type", "date").endObject();
                 createIndex.startObject("salary").field("type", "integer").endObject();
+                if (extraFields) {
+                    createIndex.startObject("salary_ul").field("type", "unsigned_long").endObject();
+                }
                 createIndex.startObject("languages").field("type", "byte").endObject();
                 {
                     createIndex.startObject("dep").field("type", "nested");
@@ -226,8 +230,12 @@ public class DataLoader {
                     }
                     hadLastItem = true;
                     bulk.append('"').append(titles.get(f)).append("\":\"").append(fields.get(f)).append('"');
-                    if (titles.get(f).equals("gender") && extraFields) {
-                        bulk.append(",\"extra_gender\":\"Female\"");
+                    if (extraFields) {
+                        if (titles.get(f).equals("gender")) {
+                            bulk.append(",\"extra_gender\":\"Female\"");
+                        } else if (titles.get(f).equals("salary")) {
+                            bulk.append(",\"salary_ul\":" + fields.get(f));
+                        }
                     }
                 }
                 if ((titles.get(f).equals("first_name") || titles.get(f).equals("last_name")) && extraFields && setWildcardName) {
@@ -267,14 +275,7 @@ public class DataLoader {
     }
 
     protected static void loadLogsDatasetIntoEs(RestClient client, String index, String filename) throws Exception {
-        Request request = new Request("PUT", "/" + index);
         XContentBuilder createIndex = JsonXContent.contentBuilder().startObject();
-        createIndex.startObject("settings");
-        {
-            createIndex.field("number_of_shards", 1);
-            createIndex.field("number_of_replicas", 1);
-        }
-        createIndex.endObject();
         createIndex.startObject("mappings");
         {
             createIndex.startObject("properties");
@@ -290,82 +291,49 @@ public class DataLoader {
             }
             createIndex.endObject();
         }
-        createIndex.endObject().endObject();
-        request.setJsonEntity(Strings.toString(createIndex));
-        client.performRequest(request);
+        createIndex.endObject();
 
-        request = new Request("POST", "/" + index + "/_bulk?refresh=wait_for");
-        request.addParameter("refresh", "true");
-        StringBuilder bulk = new StringBuilder();
-        csvToLines(filename, (titles, fields) -> {
-            bulk.append("{\"index\":{\"_id\":\"" + fields.get(0) + "\"}}\n");
-            bulk.append("{");
-            for (int f = 0; f < titles.size(); f++) {
-                if (Strings.hasText(fields.get(f))) {
-                    if (f > 0) {
-                        bulk.append(",");
-                    }
-                    bulk.append('"').append(titles.get(f)).append("\":\"").append(fields.get(f)).append('"');
-                }
-            }
-            bulk.append("}\n");
-        });
-        request.setJsonEntity(bulk.toString());
-        client.performRequest(request);
+        loadDatasetIntoEs(client, index, filename, createIndex);
     }
 
     protected static void loadLogNanosDatasetIntoEs(RestClient client, String index, String filename) throws Exception {
-        Request request = new Request("PUT", "/" + index);
         XContentBuilder createIndex = JsonXContent.contentBuilder().startObject();
-        createIndex.startObject("settings");
+        createIndex.startObject("mappings");
         {
-            createIndex.field("number_of_shards", 1);
-            createIndex.field("number_of_replicas", 1);
+            createIndex.startObject("properties");
+            {
+                createIndex.startObject("id").field("type", "integer").endObject();
+                createIndex.startObject("@timestamp").field("type", "date_nanos").endObject();
+                createIndex.startObject("status").field("type", "keyword").endObject();
+            }
+            createIndex.endObject();
         }
         createIndex.endObject();
+
+        loadDatasetIntoEs(client, index, filename, createIndex);
+    }
+
+    protected static void loadLogUnsignedLongIntoEs(RestClient client, String index, String filename) throws Exception {
+        XContentBuilder createIndex = JsonXContent.contentBuilder().startObject();
         createIndex.startObject("mappings");
         {
             createIndex.startObject("properties");
             {
                 createIndex.startObject("id").field("type", "integer").endObject();
                 createIndex.startObject("@timestamp").field("type", "date_nanos").endObject();
+                createIndex.startObject("bytes_in").field("type", "unsigned_long").endObject();
+                createIndex.startObject("bytes_out").field("type", "unsigned_long").endObject();
                 createIndex.startObject("status").field("type", "keyword").endObject();
             }
             createIndex.endObject();
         }
-        createIndex.endObject().endObject();
-        request.setJsonEntity(Strings.toString(createIndex));
-        client.performRequest(request);
+        createIndex.endObject();
 
-        request = new Request("POST", "/" + index + "/_bulk?refresh=wait_for");
-        request.addParameter("refresh", "true");
-        StringBuilder bulk = new StringBuilder();
-        csvToLines(filename, (titles, fields) -> {
-            bulk.append("{\"index\":{\"_id\":\"" + fields.get(0) + "\"}}\n");
-            bulk.append("{");
-            for (int f = 0; f < titles.size(); f++) {
-                if (Strings.hasText(fields.get(f))) {
-                    if (f > 0) {
-                        bulk.append(",");
-                    }
-                    bulk.append('"').append(titles.get(f)).append("\":\"").append(fields.get(f)).append('"');
-                }
-            }
-            bulk.append("}\n");
-        });
-        request.setJsonEntity(bulk.toString());
-        client.performRequest(request);
+        loadDatasetIntoEs(client, index, filename, createIndex);
     }
 
     protected static void loadLibDatasetIntoEs(RestClient client, String index) throws Exception {
-        Request request = new Request("PUT", "/" + index);
         XContentBuilder createIndex = JsonXContent.contentBuilder().startObject();
-        createIndex.startObject("settings");
-        {
-            createIndex.field("number_of_shards", 1);
-            createIndex.field("number_of_replicas", 1);
-        }
-        createIndex.endObject();
         createIndex.startObject("mappings");
         {
             createIndex.startObject("properties");
@@ -377,21 +345,39 @@ public class DataLoader {
             }
             createIndex.endObject();
         }
-        createIndex.endObject().endObject();
+        createIndex.endObject();
+
+        loadDatasetIntoEs(client, index, "library", createIndex);
+    }
+
+    // createIndex must be startObject()'d, but not endObject()'d: the index settings are added at the end
+    protected static void loadDatasetIntoEs(RestClient client, String index, String filename, XContentBuilder createIndex)
+        throws Exception {
+        createIndex.startObject("settings");
+        {
+            createIndex.field("number_of_shards", 1);
+            createIndex.field("number_of_replicas", 1);
+        }
+        createIndex.endObject();
+        createIndex.endObject();
+
+        Request request = new Request("PUT", "/" + index);
         request.setJsonEntity(Strings.toString(createIndex));
         client.performRequest(request);
 
         request = new Request("POST", "/" + index + "/_bulk?refresh=wait_for");
         request.addParameter("refresh", "true");
         StringBuilder bulk = new StringBuilder();
-        csvToLines("library", (titles, fields) -> {
+        csvToLines(filename, (titles, fields) -> {
             bulk.append("{\"index\":{\"_id\":\"" + fields.get(0) + "\"}}\n");
             bulk.append("{");
             for (int f = 0; f < titles.size(); f++) {
-                if (f > 0) {
-                    bulk.append(",");
+                if (fields.size() > f && Strings.hasText(fields.get(f))) {
+                    if (f > 0) {
+                        bulk.append(",");
+                    }
+                    bulk.append('"').append(titles.get(f)).append("\":\"").append(fields.get(f)).append('"');
                 }
-                bulk.append('"').append(titles.get(f)).append("\":\"").append(fields.get(f)).append('"');
             }
             bulk.append("}\n");
         });

+ 13 - 0
x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/JdbcAssert.java

@@ -17,6 +17,8 @@ import org.elasticsearch.xpack.sql.proto.StringUtils;
 import org.relique.jdbc.csv.CsvResultSet;
 
 import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.sql.Date;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
@@ -160,6 +162,7 @@ public class JdbcAssert {
             // use the type not the name (timestamp with timezone returns spaces for example)
             int expectedType = typeOf(expectedMeta.getColumnType(column), lenientDataType);
             int actualType = typeOf(actualMeta.getColumnType(column), lenientDataType);
+            String actualTypeName = actualMeta.getColumnTypeName(column);
 
             // since H2 cannot use a fixed timezone, the data is stored in UTC (and thus with timezone)
             if (expectedType == Types.TIMESTAMP_WITH_TIMEZONE) {
@@ -185,6 +188,11 @@ public class JdbcAssert {
                 expectedType = Types.NULL;
             }
 
+            // csv and h2 both map values larger than Long.MAX_VALUE to Decimal types
+            if (expectedType == Types.DECIMAL && actualTypeName.compareTo(EsType.UNSIGNED_LONG.getName()) == 0) {
+                expectedType = EsType.UNSIGNED_LONG.getVendorTypeNumber();
+            }
+
             // when lenient is used, an int is equivalent to a short, etc...
             assertEquals(
                 "Different column type for column [" + expectedName + "] (" + nameOf(expectedType) + " != " + nameOf(actualType) + ")",
@@ -252,6 +260,7 @@ public class JdbcAssert {
                                 case "Time" -> "java.sql.Time";
                                 case "Timestamp" -> "java.sql.Timestamp";
                                 case "Int" -> "java.lang.Integer";
+                                case "BigDecimal" -> "java.math.BigDecimal";
                                 default -> "java.lang." + columnClassName;
                             };
                         }
@@ -319,6 +328,10 @@ public class JdbcAssert {
                     else if (type == Types.VARCHAR && actualObject instanceof TemporalAmount) {
                         assertEquals(msg, expectedObject, StringUtils.toString(actualObject));
                     }
+                    // unsigned_long
+                    else if (expectedObject instanceof BigDecimal && actualObject instanceof BigInteger) {
+                        assertEquals(expectedObject, new BigDecimal((BigInteger) actualObject));
+                    }
                     // finally the actual comparison
                     else {
                         assertEquals(msg, expectedObject, actualObject);

+ 29 - 0
x-pack/plugin/sql/qa/server/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlTestCase.java

@@ -11,6 +11,7 @@ import com.fasterxml.jackson.core.io.JsonStringEncoder;
 import org.apache.http.HttpEntity;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
+import org.elasticsearch.Version;
 import org.elasticsearch.client.Request;
 import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.Response;
@@ -22,6 +23,7 @@ import org.elasticsearch.common.io.Streams;
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.test.NotEqualMessageBuilder;
+import org.elasticsearch.test.VersionUtils;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.json.JsonXContent;
 import org.elasticsearch.xpack.sql.proto.CoreProtocol;
@@ -55,6 +57,7 @@ import static java.util.Collections.singletonMap;
 import static java.util.Collections.unmodifiableMap;
 import static org.elasticsearch.common.Strings.hasText;
 import static org.elasticsearch.xpack.ql.TestUtils.getNumberOfSearchContexts;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.INTRODUCING_UNSIGNED_LONG;
 import static org.elasticsearch.xpack.sql.proto.CoreProtocol.COLUMNS_NAME;
 import static org.elasticsearch.xpack.sql.proto.CoreProtocol.HEADER_NAME_ASYNC_ID;
 import static org.elasticsearch.xpack.sql.proto.CoreProtocol.HEADER_NAME_ASYNC_PARTIAL;
@@ -1152,6 +1155,16 @@ public abstract class RestSqlTestCase extends BaseRestSqlTestCase implements Err
         deleteIndex("test_binary");
     }
 
+    public void testPreventedUnsignedLongMaskedAccess() throws IOException {
+        loadUnsignedLongTestData();
+        Version version = VersionUtils.randomVersionBetween(random(), null, VersionUtils.getPreviousVersion(INTRODUCING_UNSIGNED_LONG));
+        String query = query("SELECT unsigned_long::STRING FROM " + indexPattern("test")).version(version.toString()).toString();
+        expectBadRequest(
+            () -> runSql(new StringEntity(query, ContentType.APPLICATION_JSON), "", randomMode()),
+            containsString("Cannot use field [unsigned_long] with unsupported type [UNSIGNED_LONG]")
+        );
+    }
+
     private void executeQueryWithNextPage(String format, String expectedHeader, String expectedLineFormat) throws IOException {
         int size = 20;
         String[] docs = new String[size];
@@ -1222,6 +1235,22 @@ public abstract class RestSqlTestCase extends BaseRestSqlTestCase implements Err
         provisioningClient().performRequest(request);
     }
 
+    private void loadUnsignedLongTestData() throws IOException {
+        Request request = new Request("PUT", "/test");
+        request.setJsonEntity("""
+            {
+              "mappings": {
+                "properties": {
+                  "unsigned_long": {
+                    "type": "unsigned_long"
+                  }
+                }
+              }
+            }""");
+        provisioningClient().performRequest(request);
+        index("{\"unsigned_long\": 18446744073709551615}");
+    }
+
     protected static Tuple<String, String> runSqlAsText(String sql, String accept) throws IOException {
         return runSqlAsText(StringUtils.EMPTY, new StringEntity(query(sql).toString(), ContentType.APPLICATION_JSON), accept);
     }

+ 54 - 52
x-pack/plugin/sql/qa/server/src/main/resources/alias.csv-spec

@@ -28,63 +28,65 @@ emp_no:i             | first_name:s
 describeAlias
 DESCRIBE test_alias;
 
-        column        |     type      |    mapping    
-----------------------+---------------+---------------
-birth_date            |TIMESTAMP      |datetime       
-dep                   |STRUCT         |nested         
-dep.dep_id            |VARCHAR        |keyword        
-dep.dep_name          |VARCHAR        |text           
-dep.dep_name.keyword  |VARCHAR        |keyword        
-dep.from_date         |TIMESTAMP      |datetime       
-dep.to_date           |TIMESTAMP      |datetime       
-emp_no                |INTEGER        |integer        
-extra                 |STRUCT         |object         
-extra.info            |STRUCT         |object         
-extra.info.gender     |VARCHAR        |keyword        
-extra_gender          |VARCHAR        |keyword        
-extra_no              |INTEGER        |integer        
-first_name            |VARCHAR        |text           
-first_name.keyword    |VARCHAR        |keyword        
-gender                |VARCHAR        |keyword        
-hire_date             |TIMESTAMP      |datetime       
-languages             |TINYINT        |byte           
-last_name             |VARCHAR        |text           
-last_name.keyword     |VARCHAR        |keyword        
-name                  |VARCHAR        |keyword
-null_constant         |VARCHAR        |keyword        
-salary                |INTEGER        |integer        
-wildcard_name         |VARCHAR        |keyword        
+       column       |     type      |    mapping
+--------------------+---------------+---------------
+birth_date          |TIMESTAMP      |datetime
+dep                 |STRUCT         |nested
+dep.dep_id          |VARCHAR        |keyword
+dep.dep_name        |VARCHAR        |text
+dep.dep_name.keyword|VARCHAR        |keyword
+dep.from_date       |TIMESTAMP      |datetime
+dep.to_date         |TIMESTAMP      |datetime
+emp_no              |INTEGER        |integer
+extra               |STRUCT         |object
+extra.info          |STRUCT         |object
+extra.info.gender   |VARCHAR        |keyword
+extra_gender        |VARCHAR        |keyword
+extra_no            |INTEGER        |integer
+first_name          |VARCHAR        |text
+first_name.keyword  |VARCHAR        |keyword
+gender              |VARCHAR        |keyword
+hire_date           |TIMESTAMP      |datetime
+languages           |TINYINT        |byte
+last_name           |VARCHAR        |text
+last_name.keyword   |VARCHAR        |keyword
+name                |VARCHAR        |keyword
+null_constant       |VARCHAR        |keyword
+salary              |INTEGER        |integer
+salary_ul           |NUMERIC        |unsigned_long
+wildcard_name       |VARCHAR        |keyword
 ;
 
 describePattern
 DESCRIBE "test_*";
 
-        column        |     type      |    mapping    
-----------------------+---------------+---------------
-birth_date            |TIMESTAMP      |datetime       
-dep                   |STRUCT         |nested         
-dep.dep_id            |VARCHAR        |keyword        
-dep.dep_name          |VARCHAR        |text           
-dep.dep_name.keyword  |VARCHAR        |keyword        
-dep.from_date         |TIMESTAMP      |datetime       
-dep.to_date           |TIMESTAMP      |datetime       
-emp_no                |INTEGER        |integer        
-extra                 |STRUCT         |object         
-extra.info            |STRUCT         |object         
-extra.info.gender     |VARCHAR        |keyword        
-extra_gender          |VARCHAR        |keyword        
-extra_no              |INTEGER        |integer        
-first_name            |VARCHAR        |text           
-first_name.keyword    |VARCHAR        |keyword        
-gender                |VARCHAR        |keyword        
-hire_date             |TIMESTAMP      |datetime       
-languages             |TINYINT        |byte           
-last_name             |VARCHAR        |text           
-last_name.keyword     |VARCHAR        |keyword        
-name                  |VARCHAR        |keyword
-null_constant         |VARCHAR        |keyword        
-salary                |INTEGER        |integer        
-wildcard_name         |VARCHAR        |keyword        
+       column       |     type      |    mapping
+--------------------+---------------+---------------
+birth_date          |TIMESTAMP      |datetime
+dep                 |STRUCT         |nested
+dep.dep_id          |VARCHAR        |keyword
+dep.dep_name        |VARCHAR        |text
+dep.dep_name.keyword|VARCHAR        |keyword
+dep.from_date       |TIMESTAMP      |datetime
+dep.to_date         |TIMESTAMP      |datetime
+emp_no              |INTEGER        |integer
+extra               |STRUCT         |object
+extra.info          |STRUCT         |object
+extra.info.gender   |VARCHAR        |keyword
+extra_gender        |VARCHAR        |keyword
+extra_no            |INTEGER        |integer
+first_name          |VARCHAR        |text
+first_name.keyword  |VARCHAR        |keyword
+gender              |VARCHAR        |keyword
+hire_date           |TIMESTAMP      |datetime
+languages           |TINYINT        |byte
+last_name           |VARCHAR        |text
+last_name.keyword   |VARCHAR        |keyword
+name                |VARCHAR        |keyword
+null_constant       |VARCHAR        |keyword
+salary              |INTEGER        |integer
+salary_ul           |NUMERIC        |unsigned_long
+wildcard_name       |VARCHAR        |keyword
 ;
 
 showAlias

+ 157 - 153
x-pack/plugin/sql/qa/server/src/main/resources/command.csv-spec

@@ -9,15 +9,15 @@ showFunctions
 SHOW FUNCTIONS;
 
     name:s       |    type:s
-AVG              |AGGREGATE      
+AVG              |AGGREGATE
 COUNT            |AGGREGATE
 FIRST            |AGGREGATE
 FIRST_VALUE      |AGGREGATE
 LAST             |AGGREGATE
 LAST_VALUE       |AGGREGATE
 MAX              |AGGREGATE
-MIN              |AGGREGATE      
-SUM              |AGGREGATE      
+MIN              |AGGREGATE
+SUM              |AGGREGATE
 KURTOSIS         |AGGREGATE
 MAD              |AGGREGATE
 PERCENTILE       |AGGREGATE
@@ -64,11 +64,11 @@ DAY_OF_MONTH     |SCALAR
 DAY_OF_WEEK      |SCALAR
 DAY_OF_YEAR      |SCALAR
 DOM              |SCALAR
-DOW              |SCALAR         
+DOW              |SCALAR
 DOY              |SCALAR
 FORMAT           |SCALAR
 HOUR             |SCALAR
-HOUR_OF_DAY      |SCALAR         
+HOUR_OF_DAY      |SCALAR
 IDOW             |SCALAR
 ISODAYOFWEEK     |SCALAR
 ISODOW           |SCALAR
@@ -78,16 +78,16 @@ ISO_DAY_OF_WEEK  |SCALAR
 ISO_WEEK_OF_YEAR |SCALAR
 IW               |SCALAR
 IWOY             |SCALAR
-MINUTE           |SCALAR         
-MINUTE_OF_DAY    |SCALAR         
-MINUTE_OF_HOUR   |SCALAR         
-MONTH            |SCALAR         
-MONTHNAME        |SCALAR         
-MONTH_NAME       |SCALAR         
-MONTH_OF_YEAR    |SCALAR         
+MINUTE           |SCALAR
+MINUTE_OF_DAY    |SCALAR
+MINUTE_OF_HOUR   |SCALAR
+MONTH            |SCALAR
+MONTHNAME        |SCALAR
+MONTH_NAME       |SCALAR
+MONTH_OF_YEAR    |SCALAR
 NOW              |SCALAR
-QUARTER          |SCALAR         
-SECOND           |SCALAR         
+QUARTER          |SCALAR
+SECOND           |SCALAR
 SECOND_OF_MINUTE |SCALAR
 TIMESTAMPADD     |SCALAR
 TIMESTAMPDIFF    |SCALAR
@@ -97,60 +97,60 @@ TIME_PARSE       |SCALAR
 TODAY            |SCALAR
 TO_CHAR          |SCALAR
 WEEK             |SCALAR
-WEEK_OF_YEAR     |SCALAR         
-YEAR             |SCALAR         
-ABS              |SCALAR         
-ACOS             |SCALAR         
-ASIN             |SCALAR         
-ATAN             |SCALAR         
-ATAN2            |SCALAR         
-CBRT             |SCALAR         
-CEIL             |SCALAR         
-CEILING          |SCALAR         
-COS              |SCALAR         
-COSH             |SCALAR         
-COT              |SCALAR         
-DEGREES          |SCALAR         
-E                |SCALAR         
-EXP              |SCALAR         
-EXPM1            |SCALAR         
-FLOOR            |SCALAR         
-LOG              |SCALAR         
-LOG10            |SCALAR         
-MOD              |SCALAR         
-PI               |SCALAR         
-POWER            |SCALAR         
-RADIANS          |SCALAR         
-RAND             |SCALAR         
-RANDOM           |SCALAR         
-ROUND            |SCALAR         
-SIGN             |SCALAR         
-SIGNUM           |SCALAR         
-SIN              |SCALAR         
-SINH             |SCALAR         
-SQRT             |SCALAR         
-TAN              |SCALAR         
+WEEK_OF_YEAR     |SCALAR
+YEAR             |SCALAR
+ABS              |SCALAR
+ACOS             |SCALAR
+ASIN             |SCALAR
+ATAN             |SCALAR
+ATAN2            |SCALAR
+CBRT             |SCALAR
+CEIL             |SCALAR
+CEILING          |SCALAR
+COS              |SCALAR
+COSH             |SCALAR
+COT              |SCALAR
+DEGREES          |SCALAR
+E                |SCALAR
+EXP              |SCALAR
+EXPM1            |SCALAR
+FLOOR            |SCALAR
+LOG              |SCALAR
+LOG10            |SCALAR
+MOD              |SCALAR
+PI               |SCALAR
+POWER            |SCALAR
+RADIANS          |SCALAR
+RAND             |SCALAR
+RANDOM           |SCALAR
+ROUND            |SCALAR
+SIGN             |SCALAR
+SIGNUM           |SCALAR
+SIN              |SCALAR
+SINH             |SCALAR
+SQRT             |SCALAR
+TAN              |SCALAR
 TRUNC            |SCALAR
 TRUNCATE         |SCALAR
 ASCII            |SCALAR
-BIT_LENGTH       |SCALAR         
-CHAR             |SCALAR         
-CHARACTER_LENGTH |SCALAR         
-CHAR_LENGTH      |SCALAR         
-CONCAT           |SCALAR         
-INSERT           |SCALAR         
-LCASE            |SCALAR         
-LEFT             |SCALAR         
-LENGTH           |SCALAR         
-LOCATE           |SCALAR         
-LTRIM            |SCALAR         
-OCTET_LENGTH     |SCALAR         
-POSITION         |SCALAR         
-REPEAT           |SCALAR         
-REPLACE          |SCALAR         
-RIGHT            |SCALAR         
-RTRIM            |SCALAR         
-SPACE            |SCALAR         
+BIT_LENGTH       |SCALAR
+CHAR             |SCALAR
+CHARACTER_LENGTH |SCALAR
+CHAR_LENGTH      |SCALAR
+CONCAT           |SCALAR
+INSERT           |SCALAR
+LCASE            |SCALAR
+LEFT             |SCALAR
+LENGTH           |SCALAR
+LOCATE           |SCALAR
+LTRIM            |SCALAR
+OCTET_LENGTH     |SCALAR
+POSITION         |SCALAR
+REPEAT           |SCALAR
+REPLACE          |SCALAR
+RIGHT            |SCALAR
+RTRIM            |SCALAR
+SPACE            |SCALAR
 STARTS_WITH      |SCALAR
 SUBSTRING        |SCALAR
 TRIM             |SCALAR
@@ -213,10 +213,10 @@ DAY_NAME       |SCALAR
 DAY_OF_MONTH   |SCALAR
 DAY_OF_WEEK    |SCALAR
 DAY_OF_YEAR    |SCALAR
-HOUR_OF_DAY    |SCALAR         
+HOUR_OF_DAY    |SCALAR
 ISODAYOFWEEK   |SCALAR
 ISO_DAY_OF_WEEK|SCALAR
-MINUTE_OF_DAY  |SCALAR         
+MINUTE_OF_DAY  |SCALAR
 TODAY          |SCALAR
 ;
 
@@ -231,14 +231,15 @@ integTest      |local
 showTables
 SHOW TABLES;
 
-catalog    |       name    |  type |  kind
-integTest  |empty_mapping  |TABLE  |INDEX
-integTest  |logs           |TABLE  |INDEX
-integTest  |logs_nanos     |TABLE  |INDEX
-integTest  |test_alias     |VIEW   |ALIAS
-integTest  |test_alias_emp |VIEW   |ALIAS
-integTest  |test_emp       |TABLE  |INDEX
-integTest  |test_emp_copy  |TABLE  |INDEX
+catalog    |       name        |  type |  kind
+integTest  |empty_mapping      |TABLE  |INDEX
+integTest  |logs               |TABLE  |INDEX
+integTest  |logs_nanos         |TABLE  |INDEX
+integTest  |logs_unsigned_long |TABLE  |INDEX
+integTest  |test_alias         |VIEW   |ALIAS
+integTest  |test_alias_emp     |VIEW   |ALIAS
+integTest  |test_emp           |TABLE  |INDEX
+integTest  |test_emp_copy      |TABLE  |INDEX
 ;
 
 showTablesSimpleLike
@@ -281,14 +282,15 @@ integTest  |test_alias_emp |VIEW    |ALIAS
 showTablesLocalCatalog
 SHOW TABLES CATALOG 'integTest';
 
-catalog    |       name    |  type |  kind
-integTest  |empty_mapping  |TABLE  |INDEX
-integTest  |logs           |TABLE  |INDEX
-integTest  |logs_nanos     |TABLE  |INDEX
-integTest  |test_alias     |VIEW   |ALIAS
-integTest  |test_alias_emp |VIEW   |ALIAS
-integTest  |test_emp       |TABLE  |INDEX
-integTest  |test_emp_copy  |TABLE  |INDEX
+catalog    |       name        |  type |  kind
+integTest  |empty_mapping      |TABLE  |INDEX
+integTest  |logs               |TABLE  |INDEX
+integTest  |logs_nanos         |TABLE  |INDEX
+integTest  |logs_unsigned_long |TABLE  |INDEX
+integTest  |test_alias         |VIEW   |ALIAS
+integTest  |test_alias_emp     |VIEW   |ALIAS
+integTest  |test_emp           |TABLE  |INDEX
+integTest  |test_emp_copy      |TABLE  |INDEX
 ;
 
 // DESCRIBE
@@ -296,63 +298,65 @@ integTest  |test_emp_copy  |TABLE  |INDEX
 describeSimpleLike
 DESCRIBE LIKE 'test_emp';
 
-        column        |     type      |    mapping    
-----------------------+---------------+---------------
-birth_date            |TIMESTAMP      |datetime       
-dep                   |STRUCT         |nested         
-dep.dep_id            |VARCHAR        |keyword        
-dep.dep_name          |VARCHAR        |text           
-dep.dep_name.keyword  |VARCHAR        |keyword        
-dep.from_date         |TIMESTAMP      |datetime       
-dep.to_date           |TIMESTAMP      |datetime       
-emp_no                |INTEGER        |integer        
-extra                 |STRUCT         |object         
-extra.info            |STRUCT         |object         
-extra.info.gender     |VARCHAR        |keyword        
-extra_gender          |VARCHAR        |keyword        
-extra_no              |INTEGER        |integer        
-first_name            |VARCHAR        |text           
-first_name.keyword    |VARCHAR        |keyword        
-gender                |VARCHAR        |keyword        
-hire_date             |TIMESTAMP      |datetime       
-languages             |TINYINT        |byte           
-last_name             |VARCHAR        |text           
-last_name.keyword     |VARCHAR        |keyword        
-name                  |VARCHAR        |keyword        
-null_constant         |VARCHAR        |keyword        
-salary                |INTEGER        |integer        
-wildcard_name         |VARCHAR        |keyword        
+       column       |     type      |    mapping
+--------------------+---------------+---------------
+birth_date          |TIMESTAMP      |datetime
+dep                 |STRUCT         |nested
+dep.dep_id          |VARCHAR        |keyword
+dep.dep_name        |VARCHAR        |text
+dep.dep_name.keyword|VARCHAR        |keyword
+dep.from_date       |TIMESTAMP      |datetime
+dep.to_date         |TIMESTAMP      |datetime
+emp_no              |INTEGER        |integer
+extra               |STRUCT         |object
+extra.info          |STRUCT         |object
+extra.info.gender   |VARCHAR        |keyword
+extra_gender        |VARCHAR        |keyword
+extra_no            |INTEGER        |integer
+first_name          |VARCHAR        |text
+first_name.keyword  |VARCHAR        |keyword
+gender              |VARCHAR        |keyword
+hire_date           |TIMESTAMP      |datetime
+languages           |TINYINT        |byte
+last_name           |VARCHAR        |text
+last_name.keyword   |VARCHAR        |keyword
+name                |VARCHAR        |keyword
+null_constant       |VARCHAR        |keyword
+salary              |INTEGER        |integer
+salary_ul           |NUMERIC        |unsigned_long
+wildcard_name       |VARCHAR        |keyword
 ;
 
 describeMultiLike
 DESCRIBE LIKE 'test_emp%';
 
-        column        |     type      |    mapping    
-----------------------+---------------+---------------
-birth_date            |TIMESTAMP      |datetime       
-dep                   |STRUCT         |nested         
-dep.dep_id            |VARCHAR        |keyword        
-dep.dep_name          |VARCHAR        |text           
-dep.dep_name.keyword  |VARCHAR        |keyword        
-dep.from_date         |TIMESTAMP      |datetime       
-dep.to_date           |TIMESTAMP      |datetime       
-emp_no                |INTEGER        |integer        
-extra                 |STRUCT         |object         
-extra.info            |STRUCT         |object         
-extra.info.gender     |VARCHAR        |keyword        
-extra_gender          |VARCHAR        |keyword        
-extra_no              |INTEGER        |integer        
-first_name            |VARCHAR        |text           
-first_name.keyword    |VARCHAR        |keyword        
-gender                |VARCHAR        |keyword        
-hire_date             |TIMESTAMP      |datetime       
-languages             |TINYINT        |byte           
-last_name             |VARCHAR        |text           
-last_name.keyword     |VARCHAR        |keyword        
-name                  |VARCHAR        |keyword        
-null_constant         |VARCHAR        |keyword        
-salary                |INTEGER        |integer        
-wildcard_name         |VARCHAR        |keyword        
+       column       |     type      |    mapping
+--------------------+---------------+---------------
+birth_date          |TIMESTAMP      |datetime
+dep                 |STRUCT         |nested
+dep.dep_id          |VARCHAR        |keyword
+dep.dep_name        |VARCHAR        |text
+dep.dep_name.keyword|VARCHAR        |keyword
+dep.from_date       |TIMESTAMP      |datetime
+dep.to_date         |TIMESTAMP      |datetime
+emp_no              |INTEGER        |integer
+extra               |STRUCT         |object
+extra.info          |STRUCT         |object
+extra.info.gender   |VARCHAR        |keyword
+extra_gender        |VARCHAR        |keyword
+extra_no            |INTEGER        |integer
+first_name          |VARCHAR        |text
+first_name.keyword  |VARCHAR        |keyword
+gender              |VARCHAR        |keyword
+hire_date           |TIMESTAMP      |datetime
+languages           |TINYINT        |byte
+last_name           |VARCHAR        |text
+last_name.keyword   |VARCHAR        |keyword
+name                |VARCHAR        |keyword
+null_constant       |VARCHAR        |keyword
+salary              |INTEGER        |integer
+salary_ul           |NUMERIC        |unsigned_long
+wildcard_name       |VARCHAR        |keyword
 ;
 
 describeSimpleIdentifier
@@ -384,23 +388,23 @@ DESCRIBE CATALOG 'integTest' "test_emp";
 
         column        |     type      |    mapping
 ----------------------+---------------+---------------
-birth_date            |TIMESTAMP      |datetime       
-dep                   |STRUCT         |nested         
-dep.dep_id            |VARCHAR        |keyword        
-dep.dep_name          |VARCHAR        |text           
-dep.dep_name.keyword  |VARCHAR        |keyword        
-dep.from_date         |TIMESTAMP      |datetime       
-dep.to_date           |TIMESTAMP      |datetime       
-emp_no                |INTEGER        |integer        
-first_name            |VARCHAR        |text           
-first_name.keyword    |VARCHAR        |keyword        
-gender                |VARCHAR        |keyword        
-hire_date             |TIMESTAMP      |datetime       
-languages             |TINYINT        |byte           
-last_name             |VARCHAR        |text           
-last_name.keyword     |VARCHAR        |keyword        
-name                  |VARCHAR        |keyword        
-salary                |INTEGER        |integer        
+birth_date            |TIMESTAMP      |datetime
+dep                   |STRUCT         |nested
+dep.dep_id            |VARCHAR        |keyword
+dep.dep_name          |VARCHAR        |text
+dep.dep_name.keyword  |VARCHAR        |keyword
+dep.from_date         |TIMESTAMP      |datetime
+dep.to_date           |TIMESTAMP      |datetime
+emp_no                |INTEGER        |integer
+first_name            |VARCHAR        |text
+first_name.keyword    |VARCHAR        |keyword
+gender                |VARCHAR        |keyword
+hire_date             |TIMESTAMP      |datetime
+languages             |TINYINT        |byte
+last_name             |VARCHAR        |text
+last_name.keyword     |VARCHAR        |keyword
+name                  |VARCHAR        |keyword
+salary                |INTEGER        |integer
 ;
 
 
@@ -409,7 +413,7 @@ salary                |INTEGER        |integer
 describeIncludeExcludeIdentifier-Ignore
 DESCRIBE "test_*,-test_alias*";
 
-       column       |     type      |    mapping    
+       column       |     type      |    mapping
 --------------------+---------------+---------------
 birth_date          |TIMESTAMP      |datetime
 dep                 |STRUCT         |nested

+ 102 - 0
x-pack/plugin/sql/qa/server/src/main/resources/logs_unsigned_long.csv

@@ -0,0 +1,102 @@
+id,@timestamp,bytes_in,bytes_out,status
+1,2017-11-10T21:15:54Z,4348801185987554667,12749081495402663265,OK
+2,2017-11-10T21:15:39Z,11054572642507476486,2215793005711196537,OK
+3,2017-11-10T21:15:39Z,7239423344688551324,4747671420480199905,OK
+4,2017-11-10T21:15:39Z,12880875341157998416,10347160802894727455,OK
+5,2017-11-10T21:15:40Z,6480569113728286781,4628689249901172357,OK
+6,2017-11-10T21:15:40Z,8847365258155648277,18107197698386620672,OK
+7,2017-11-10T21:15:40Z,18081123477485622121,6254036056888007861,OK
+8,2017-11-10T21:15:41Z,17159009460398071592,6041947699951197416,OK
+9,2017-11-10T21:15:41Z,18317075104972913640,3738987414350619907,OK
+10,2017-11-10T20:36:07Z,9223372036854775807,13014552081688587417,OK
+11,2017-11-10T20:36:08Z,10618481193158417699,7645257133789254601,OK
+12,2017-11-10T20:36:07Z,14243423136348863449,1851693232606252132,OK
+13,2017-11-10T20:36:07Z,8014838889043461601,12855878692699288887,OK
+14,2017-11-10T20:36:15Z,9704166250476073712,9243820354371174974,OK
+15,2017-11-10T20:36:15Z,16673466483681919036,17281501450843634251,OK
+16,2017-11-10T20:35:54Z,11414099303186823563,4552407785188434877,OK
+17,2017-11-10T20:35:54Z,9614024902524991937,583785103161450865,OK
+18,2017-11-10T20:35:55Z,2703254959364209157,15688732125935676003,OK
+19,2017-11-10T17:54:43Z,16907772202142018796,1978055896356244912,OK
+20,2017-11-10T23:23:24Z,18446744073709551614,9891957732954625161,OK
+21,2017-11-10T17:54:59Z,18098466156271475039,10560599221675458546,OK
+22,2017-11-10T21:13:27Z,12113814789427553914,17695317925249333633,OK
+23,2017-11-10T22:37:41Z,369412756671598363,4454824974559554214,OK
+24,2017-11-10T20:34:43Z,17764691215469285192,751496841062464739,OK
+25,2017-11-10T23:30:46Z,316080452389500167,13471731928228498458,OK
+26,2017-11-10T21:13:16Z,3987249898147090269,857017108209908030,OK
+27,2017-11-10T23:36:32Z,9343007301895818617,13652755194722568502,OK
+28,2017-11-10T23:36:33Z,12951716972543168268,9336652471323200906,OK
+29,2017-11-10T20:35:26Z,16002960716282089759,6754707638562449159,OK
+30,2017-11-10T23:36:41Z,18446744073709550591,14393839423240122480,OK
+31,2017-11-10T23:56:36Z,5495907774457032585,8384790841458113028,OK
+32,2017-11-10T20:29:25Z,905851433235877972,11682551086136399874,Error
+33,2017-11-10T21:35:01Z,4368413537705409055,10386906319745215430,OK
+34,2017-11-10T21:12:17Z,7953313938735885073,14008282674840239286,OK
+35,2017-11-10T23:17:14Z,9188929021194043442,991636820083925493,OK
+36,2017-11-10T23:28:11Z,13875498092704386047,17953153966527637143,OK
+37,2017-11-10T22:36:27Z,8156660980420095219,901610289258538340,OK
+38,2017-11-10T20:35:55Z,2408213296071189837,419872666232023984,OK
+39,2017-11-10T20:35:55Z,17460378829280278708,10724795375261191248,OK
+40,2017-11-10T20:35:55Z,18446744073709551614,14524142879756567901,OK
+41,2017-11-10T20:35:55Z,,,Error
+42,2017-11-10T21:34:49Z,154551962150890561,4317649615355527138,Error
+43,2017-11-10T20:35:55Z,6713823401157015713,768392740554438381,OK
+44,2017-11-10T20:14:04Z,13007085541148329579,1262767764958640849,OK
+45,2017-11-10T19:38:06Z,4008445367955620676,2444837981761911481,OK
+46,2017-11-10T21:14:18Z,9056948257586320738,3660006000364826492,OK
+47,2017-11-10T20:35:56Z,10640542847470647209,3071012467454913482,OK
+48,2017-11-10T20:53:05Z,14463699407888333801,16193000254773667372,OK
+49,2017-11-10T21:25:42Z,4691003749418709874,16735032755695343779,OK
+50,2017-11-10T21:14:44Z,18446744073709551615,8359170160363687272,OK
+51,2017-11-10T21:28:34Z,10414368669933920698,17857609920324506371,OK
+52,2017-11-10T20:35:55Z,14591698995327831783,837800054257171070,OK
+53,2017-11-10T20:15:24Z,9149768745019330607,9934783425401329847,OK
+54,2017-11-10T20:35:57Z,5826090293715995525,13263580863583654980,OK
+55,2017-11-10T17:14:10Z,15352019942832250739,1498178946494790227,OK
+56,2017-11-10T20:35:57Z,9732690250707058359,2520919358333960813,OK
+57,2017-11-10T23:22:13Z,8914368988247035466,16187631537609304549,OK
+58,2017-11-10T20:32:57Z,8420006392678593250,14938622925960605968,OK
+59,2017-11-10T21:24:00Z,17056885385468285787,9973198429366930442,OK
+60,2017-11-10T20:35:56Z,9223372036854775808,6620615504579533702,OK
+61,2017-11-10T23:43:10Z,2390976293435536689,16020561580624977312,OK
+62,2017-11-10T20:35:57Z,10993546521190430203,18184253384683076090,OK
+63,2017-11-10T20:21:58Z,5246566629176459718,9382204513185396493,OK
+64,2017-11-10T20:35:57Z,9983398877364735609,10626289664367265415,OK
+65,2017-11-10T20:33:06Z,5480608687137202404,6895880056122579688,Error
+66,2017-11-10T20:35:57Z,7538807943450220608,11745980216826561015,OK
+67,2017-11-10T20:26:21Z,17067060651018256448,1722789377000665830,OK
+68,2017-11-10T21:23:25Z,16873365461162643186,10056378788277261033,OK
+69,2017-11-10T21:23:54Z,9991932520184465636,16110121334900810541,OK
+70,2017-11-10T20:35:57Z,0,2507200025082562692,OK
+71,2017-11-10T00:27:03Z,0,18223615477147360166,OK
+72,2017-11-10T00:27:46Z,0,11206857258468587792,OK
+73,2017-11-10T20:35:58Z,13986802678251316321,1330575423003442317,OK
+74,2017-11-10T20:35:57Z,13922094693483143156,14343149449348005776,OK
+75,2017-11-10T22:27:09Z,13999070515664268533,8422074124513216267,OK
+76,2017-11-10T20:35:58Z,15968566213936682639,3784845108080773823,OK
+77,2017-11-10T22:26:44Z,1729864283282545225,11105009496753939058,OK
+78,2017-11-10T22:27:31Z,14241624006161076477,11563896463355414928,OK
+79,2017-11-10T20:35:52Z,2294690022638798960,14564159158999105001,OK
+80,2017-11-10T00:00:22Z,0,11060623717086222747,OK
+81,2017-11-10T20:35:52Z,7470203340634956368,7490193999241578548,OK
+82,2017-11-10T00:01:20Z,74330435873664882,4875216609683497742,OK
+83,2017-11-10T00:01:04Z,9636626466125797351,14208813483941526550,OK
+84,2017-11-10T00:32:48Z,11949176856304796477,8190769023162854115,OK
+85,2017-11-10T00:01:45Z,754822992931077409,12647826153259487490,OK
+86,2017-11-10T20:36:08Z,16424089095262982944,12394320926003300611,OK
+87,2017-11-10T21:17:37Z,10580536762493152413,13605535835272740587,OK
+88,2017-11-10T20:06:49Z,195161570976258241,15395084776572180858,Error
+89,2017-11-10T21:17:37Z,15084788733189711518,6353233118260828721,OK
+90,2017-11-10T19:51:38Z,,,Error
+91,2017-11-10T19:51:38Z,11628588779507401305,8500236459902170712,Error
+92,2017-11-10T20:06:50Z,2706408999083639864,594246218266628121,OK
+93,2017-11-10T21:17:46Z,9007528787465012783,15931740851225178582,OK
+94,2017-11-10T19:51:38Z,18345360876889252152,16119381686035586648,Error
+95,2017-11-10T21:17:46Z,2788944430410706777,11087293691148056886,OK
+96,2017-11-10T00:04:50Z,9932469097722733505,14925592145374204307,OK
+97,2017-11-10T21:17:48Z,11620953158540412267,3809712277266935082,OK
+98,2017-11-10T21:12:24Z,3448205404634246112,5409549730889481641,OK
+99,2017-11-10T21:17:37Z,1957665857956635540,352442273299370793,OK
+100,2017-11-10T03:21:36Z,16462768484251021236,15616395223975497926,OK
+101,2017-11-10T23:22:36Z,,,Error

+ 69 - 58
x-pack/plugin/sql/qa/server/src/main/resources/multi-cluster-with-security/multi-cluster-command-sys.csv-spec

@@ -64,7 +64,8 @@ my_remote_cluster|null           |test_emp       |last_name.keyword |12
 my_remote_cluster|null           |test_emp       |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
 my_remote_cluster|null           |test_emp       |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
 my_remote_cluster|null           |test_emp       |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp       |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp       |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
 ;
 
 sysColumnsWithCatalogAndLike
@@ -87,7 +88,8 @@ my_remote_cluster|null           |test_emp_copy  |last_name.keyword |12
 my_remote_cluster|null           |test_emp_copy  |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
 my_remote_cluster|null           |test_emp_copy  |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
 my_remote_cluster|null           |test_emp_copy  |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy  |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy  |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
 ;
 
 sysColumnsOnAliasWithTableLike
@@ -110,64 +112,72 @@ my_remote_cluster|null           |test_alias     |last_name.keyword |12
 my_remote_cluster|null           |test_alias     |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
 my_remote_cluster|null           |test_alias     |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
 my_remote_cluster|null           |test_alias     |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_alias     |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_alias     |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_alias     |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
 ;
 
 sysColumnsAllTables
 SYS COLUMNS CATALOG 'my_remote_cluster' TABLE LIKE '%';
 
-   TABLE_CAT:s    |  TABLE_SCHEM:s|  TABLE_NAME:s |    COLUMN_NAME:s |   DATA_TYPE:i |   TYPE_NAME:s |  COLUMN_SIZE:i| BUFFER_LENGTH:i|DECIMAL_DIGITS:i|NUM_PREC_RADIX:i | NULLABLE:i|    REMARKS:s  |  COLUMN_DEF:s |SQL_DATA_TYPE:i|SQL_DATETIME_SUB:i|CHAR_OCTET_LENGTH:i|ORDINAL_POSITION:i|IS_NULLABLE:s|SCOPE_CATALOG:s|SCOPE_SCHEMA:s|SCOPE_TABLE:s|SOURCE_DATA_TYPE:sh|IS_AUTOINCREMENT:s|IS_GENERATEDCOLUMN:s
------------------+---------------+---------------+------------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+----------------+-----------------+----------------+---------------+---------------+---------------+---------------+----------------+----------------+------------------
-my_remote_cluster|null           |logs           |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs           |bytes_in          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs           |bytes_out         |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs           |client_ip         |12             |IP             |45             |45             |null           |null           |1              |null           |null           |12             |0               |null             |4               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs           |client_port       |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |5               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs           |dest_ip           |12             |IP             |45             |45             |null           |null           |1              |null           |null           |12             |0               |null             |6               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs           |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs           |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |8               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs_nanos     |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs_nanos     |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |logs_nanos     |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |3               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |4               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |5               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp       |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
-my_remote_cluster|null           |test_emp_copy  |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO
+   TABLE_CAT:s    |  TABLE_SCHEM:s|  TABLE_NAME:s    |    COLUMN_NAME:s |   DATA_TYPE:i |   TYPE_NAME:s |  COLUMN_SIZE:i| BUFFER_LENGTH:i|DECIMAL_DIGITS:i|NUM_PREC_RADIX:i | NULLABLE:i|    REMARKS:s  |  COLUMN_DEF:s |SQL_DATA_TYPE:i|SQL_DATETIME_SUB:i|CHAR_OCTET_LENGTH:i|ORDINAL_POSITION:i|IS_NULLABLE:s|SCOPE_CATALOG:s|SCOPE_SCHEMA:s|SCOPE_TABLE:s|SOURCE_DATA_TYPE:sh|IS_AUTOINCREMENT:s|IS_GENERATEDCOLUMN:s
+-----------------+---------------+-------------------+------------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+----------------+-----------------+----------------+---------------+---------------+---------------+---------------+----------------+----------------+------------------
+my_remote_cluster|null           |logs               |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs               |bytes_in          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs               |bytes_out         |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs               |client_ip         |12             |IP             |45             |45             |null           |null           |1              |null           |null           |12             |0               |null             |4               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs               |client_port       |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |5               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs               |dest_ip           |12             |IP             |45             |45             |null           |null           |1              |null           |null           |12             |0               |null             |6               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs               |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs               |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |8               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs_nanos         |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs_nanos         |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs_nanos         |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |3               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs_unsigned_long |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs_unsigned_long |bytes_in          |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs_unsigned_long |bytes_out         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs_unsigned_long |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |4               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |logs_unsigned_long |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |5               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |4               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |5               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp           |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+my_remote_cluster|null           |test_emp_copy      |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
 ;
 
 sysTablesSimple
 SYS TABLES CATALOG LIKE 'my_remote_cluster';
 
-    TABLE_CAT:s  |  TABLE_SCHEM:s|  TABLE_NAME:s |  TABLE_TYPE:s |    REMARKS:s  |   TYPE_CAT:s  |  TYPE_SCHEM:S |   TYPE_NAME:s |SELF_REFERENCING_COL_NAME:s|REF_GENERATION:s
------------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+-------------------------+---------------
-my_remote_cluster|null           |empty_mapping  |TABLE          |               |null           |null           |null           |null                     |null
-my_remote_cluster|null           |logs           |TABLE          |               |null           |null           |null           |null                     |null
-my_remote_cluster|null           |logs_nanos     |TABLE          |               |null           |null           |null           |null                     |null
-my_remote_cluster|null           |test_emp       |TABLE          |               |null           |null           |null           |null                     |null
-my_remote_cluster|null           |test_emp_copy  |TABLE          |               |null           |null           |null           |null                     |null
+    TABLE_CAT:s  |  TABLE_SCHEM:s|  TABLE_NAME:s     |  TABLE_TYPE:s |    REMARKS:s  |   TYPE_CAT:s  |  TYPE_SCHEM:S |   TYPE_NAME:s |SELF_REFERENCING_COL_NAME:s|REF_GENERATION:s
+-----------------+---------------+-------------------+---------------+---------------+---------------+---------------+---------------+-------------------------+---------------
+my_remote_cluster|null           |empty_mapping      |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |logs               |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |logs_nanos         |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |logs_unsigned_long |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |test_emp           |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |test_emp_copy      |TABLE          |               |null           |null           |null           |null                     |null
 ;
 
 sysTablesIndexLikeFilter
@@ -186,16 +196,17 @@ SYS TABLES CATALOG LIKE 'my_remote_cluster' "empty*";
 my_remote_cluster|null           |empty_mapping  |TABLE          |               |null           |null           |null           |null                     |null
 ;
 
-sysTablesEmptyFilters
+sysTablesEmptyFiltersExceptCatalog
 SYS TABLES CATALOG LIKE 'my_remote_cluster' "" TYPE '';
 
-    TABLE_CAT:s  |  TABLE_SCHEM:s|  TABLE_NAME:s |  TABLE_TYPE:s |    REMARKS:s  |   TYPE_CAT:s  |  TYPE_SCHEM:S |   TYPE_NAME:s |SELF_REFERENCING_COL_NAME:s|REF_GENERATION:s
------------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+-------------------------+---------------
-my_remote_cluster|null           |empty_mapping  |TABLE          |               |null           |null           |null           |null                     |null
-my_remote_cluster|null           |logs           |TABLE          |               |null           |null           |null           |null                     |null
-my_remote_cluster|null           |logs_nanos     |TABLE          |               |null           |null           |null           |null                     |null
-my_remote_cluster|null           |test_emp       |TABLE          |               |null           |null           |null           |null                     |null
-my_remote_cluster|null           |test_emp_copy  |TABLE          |               |null           |null           |null           |null                     |null
+    TABLE_CAT:s  |  TABLE_SCHEM:s|  TABLE_NAME:s     |  TABLE_TYPE:s |    REMARKS:s  |   TYPE_CAT:s  |  TYPE_SCHEM:S |   TYPE_NAME:s |SELF_REFERENCING_COL_NAME:s|REF_GENERATION:s
+-----------------+---------------+-------------------+---------------+---------------+---------------+---------------+---------------+-------------------------+---------------
+my_remote_cluster|null           |empty_mapping      |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |logs               |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |logs_nanos         |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |logs_unsigned_long |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |test_emp           |TABLE          |               |null           |null           |null           |null                     |null
+my_remote_cluster|null           |test_emp_copy      |TABLE          |               |null           |null           |null           |null                     |null
 ;
 
 sysTablesCatalogEnumeration

+ 37 - 29
x-pack/plugin/sql/qa/server/src/main/resources/multi-cluster-with-security/multi-cluster-command.csv-spec

@@ -21,38 +21,41 @@ my_remote_cluster |remote
 showTables
 SHOW TABLES CATALOG 'my_remote_cluster';
 
-     catalog     |     name      |     type      |     kind
------------------+---------------+---------------+---------------
-my_remote_cluster|empty_mapping  |TABLE          |INDEX
-my_remote_cluster|logs           |TABLE          |INDEX
-my_remote_cluster|logs_nanos     |TABLE          |INDEX
-my_remote_cluster|test_emp       |TABLE          |INDEX
-my_remote_cluster|test_emp_copy  |TABLE          |INDEX
+     catalog     |     name          |     type      |     kind
+-----------------+-------------------+---------------+---------------
+my_remote_cluster|empty_mapping      |TABLE          |INDEX
+my_remote_cluster|logs               |TABLE          |INDEX
+my_remote_cluster|logs_nanos         |TABLE          |INDEX
+my_remote_cluster|logs_unsigned_long |TABLE          |INDEX
+my_remote_cluster|test_emp           |TABLE          |INDEX
+my_remote_cluster|test_emp_copy      |TABLE          |INDEX
 ;
 
 showTablesWithLike
 SHOW TABLES CATALOG LIKE 'my_remote_%';
 
-     catalog     |     name      |     type      |     kind
------------------+---------------+---------------+---------------
-my_remote_cluster|empty_mapping  |TABLE          |INDEX
-my_remote_cluster|logs           |TABLE          |INDEX
-my_remote_cluster|logs_nanos     |TABLE          |INDEX
-my_remote_cluster|test_emp       |TABLE          |INDEX
-my_remote_cluster|test_emp_copy  |TABLE          |INDEX
+     catalog     |     name          |     type      |     kind
+-----------------+-------------------+---------------+---------------
+my_remote_cluster|empty_mapping      |TABLE          |INDEX
+my_remote_cluster|logs               |TABLE          |INDEX
+my_remote_cluster|logs_nanos         |TABLE          |INDEX
+my_remote_cluster|logs_unsigned_long |TABLE          |INDEX
+my_remote_cluster|test_emp           |TABLE          |INDEX
+my_remote_cluster|test_emp_copy      |TABLE          |INDEX
 ;
 
 showTablesWithFrozen
 SHOW TABLES CATALOG 'my_remote_cluster' INCLUDE FROZEN;
 
-     catalog     |     name      |     type      |     kind
------------------+---------------+---------------+---------------
-my_remote_cluster|empty_mapping  |TABLE          |INDEX
-my_remote_cluster|frozen_emp     |TABLE          |INDEX
-my_remote_cluster|logs           |TABLE          |INDEX
-my_remote_cluster|logs_nanos     |TABLE          |INDEX
-my_remote_cluster|test_emp       |TABLE          |INDEX
-my_remote_cluster|test_emp_copy  |TABLE          |INDEX
+     catalog     |     name          |     type      |     kind
+-----------------+-------------------+---------------+---------------
+my_remote_cluster|empty_mapping      |TABLE          |INDEX
+my_remote_cluster|frozen_emp         |TABLE          |INDEX
+my_remote_cluster|logs               |TABLE          |INDEX
+my_remote_cluster|logs_nanos         |TABLE          |INDEX
+my_remote_cluster|logs_unsigned_long |TABLE          |INDEX
+my_remote_cluster|test_emp           |TABLE          |INDEX
+my_remote_cluster|test_emp_copy      |TABLE          |INDEX
 ;
 
 showTablesSimpleLike
@@ -114,13 +117,14 @@ test_alias_emp |VIEW    |ALIAS
 showTablesAllCatalogs
 SHOW TABLES CATALOG '*';
 
-     catalog     |     name      |     type      |     kind
------------------+---------------+---------------+---------------
-my_remote_cluster|empty_mapping  |TABLE          |INDEX
-my_remote_cluster|logs           |TABLE          |INDEX
-my_remote_cluster|logs_nanos     |TABLE          |INDEX
-my_remote_cluster|test_emp       |TABLE          |INDEX
-my_remote_cluster|test_emp_copy  |TABLE          |INDEX
+     catalog     |     name          |     type      |     kind
+-----------------+-------------------+---------------+---------------
+my_remote_cluster|empty_mapping      |TABLE          |INDEX
+my_remote_cluster|logs               |TABLE          |INDEX
+my_remote_cluster|logs_nanos         |TABLE          |INDEX
+my_remote_cluster|logs_unsigned_long |TABLE          |INDEX
+my_remote_cluster|test_emp           |TABLE          |INDEX
+my_remote_cluster|test_emp_copy      |TABLE          |INDEX
 ;
 
 // DESCRIBE
@@ -153,6 +157,7 @@ last_name.keyword   |VARCHAR        |keyword
 name                |VARCHAR        |keyword
 null_constant       |VARCHAR        |keyword
 salary              |INTEGER        |integer
+salary_ul           |NUMERIC        |unsigned_long
 wildcard_name       |VARCHAR        |keyword
 ;
 
@@ -184,6 +189,7 @@ last_name.keyword   |VARCHAR        |keyword
 name                |VARCHAR        |keyword
 null_constant       |VARCHAR        |keyword
 salary              |INTEGER        |integer
+salary_ul           |NUMERIC        |unsigned_long
 wildcard_name       |VARCHAR        |keyword
 ;
 
@@ -303,6 +309,7 @@ last_name.keyword   |VARCHAR        |keyword
 name                |VARCHAR        |keyword
 null_constant       |VARCHAR        |keyword
 salary              |INTEGER        |integer
+salary_ul           |NUMERIC        |unsigned_long
 wildcard_name       |VARCHAR        |keyword
 ;
 
@@ -334,6 +341,7 @@ last_name.keyword   |VARCHAR        |keyword
 name                |VARCHAR        |keyword
 null_constant       |VARCHAR        |keyword
 salary              |INTEGER        |integer
+salary_ul           |NUMERIC        |unsigned_long
 wildcard_name       |VARCHAR        |keyword
 ;
 

+ 142 - 131
x-pack/plugin/sql/qa/server/src/main/resources/single-node-only/command-sys.csv-spec

@@ -9,17 +9,17 @@ SYS COLUMNS TABLE LIKE 'test\_emp' ESCAPE '\';
 
    TABLE_CAT:s   |  TABLE_SCHEM:s|  TABLE_NAME:s |    COLUMN_NAME:s     |   DATA_TYPE:i |   TYPE_NAME:s |  COLUMN_SIZE:i| BUFFER_LENGTH:i|DECIMAL_DIGITS:i|NUM_PREC_RADIX:i | NULLABLE:i|    REMARKS:s  |  COLUMN_DEF:s |SQL_DATA_TYPE:i|SQL_DATETIME_SUB:i|CHAR_OCTET_LENGTH:i|ORDINAL_POSITION:i|IS_NULLABLE:s|SCOPE_CATALOG:s|SCOPE_SCHEMA:s|SCOPE_TABLE:s|SOURCE_DATA_TYPE:sh|IS_AUTOINCREMENT:s|IS_GENERATEDCOLUMN:s
 -----------------+---------------+---------------+----------------------+---------------+---------------+---------------+---------------+-----------------+-----------------+-----------+---------------+---------------+---------------+----------------+-----------------+----------------+---------------+---------------+---------------+---------------+----------------+----------------+------------------
-integTest        |null           |test_emp       |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |4               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |5               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO                                                
+integTest        |null           |test_emp       |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |4               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |5               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
 ;
 
 sysColumnsWithTableLikeNoEscape
@@ -30,22 +30,23 @@ SYS COLUMNS TABLE LIKE 'test_emp';
 
    TABLE_CAT:s |  TABLE_SCHEM:s|  TABLE_NAME:s |    COLUMN_NAME:s   |   DATA_TYPE:i |   TYPE_NAME:s |  COLUMN_SIZE:i| BUFFER_LENGTH:i|DECIMAL_DIGITS:i|NUM_PREC_RADIX:i | NULLABLE:i|    REMARKS:s  |  COLUMN_DEF:s |SQL_DATA_TYPE:i|SQL_DATETIME_SUB:i|CHAR_OCTET_LENGTH:i|ORDINAL_POSITION:i|IS_NULLABLE:s|SCOPE_CATALOG:s|SCOPE_SCHEMA:s|SCOPE_TABLE:s|SOURCE_DATA_TYPE:sh|IS_AUTOINCREMENT:s|IS_GENERATEDCOLUMN:s
 ---------------+---------------+---------------+--------------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+----------------+-----------------+----------------+---------------+---------------+---------------+---------------+----------------+----------------+------------------
-integTest        |null           |test_emp       |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO                                                
+integTest        |null           |test_emp       |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp       |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
 ;
 
 sysColumnsWithCatalogAndLike
@@ -53,22 +54,23 @@ SYS COLUMNS CATALOG 'integTest' TABLE LIKE 'test\_emp\_copy' ESCAPE '\';
 
    TABLE_CAT:s |  TABLE_SCHEM:s|  TABLE_NAME:s |    COLUMN_NAME:s  |   DATA_TYPE:i |   TYPE_NAME:s |  COLUMN_SIZE:i| BUFFER_LENGTH:i|DECIMAL_DIGITS:i|NUM_PREC_RADIX:i | NULLABLE:i|    REMARKS:s  |  COLUMN_DEF:s |SQL_DATA_TYPE:i|SQL_DATETIME_SUB:i|CHAR_OCTET_LENGTH:i|ORDINAL_POSITION:i|IS_NULLABLE:s|SCOPE_CATALOG:s|SCOPE_SCHEMA:s|SCOPE_TABLE:s|SOURCE_DATA_TYPE:sh|IS_AUTOINCREMENT:s|IS_GENERATEDCOLUMN:s
 ---------------+---------------+---------------+-------------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+----------------+-----------------+----------------+---------------+---------------+---------------+---------------+----------------+----------------+------------------
-integTest        |null           |test_emp_copy  |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO                                                
+integTest        |null           |test_emp_copy  |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy  |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
 ;
 
 sysColumnsOnAliasWithTableLike
@@ -76,97 +78,106 @@ SYS COLUMNS TABLE LIKE 'test\_alias' ESCAPE '\';
 
    TABLE_CAT:s |  TABLE_SCHEM:s|  TABLE_NAME:s |    COLUMN_NAME:s   |   DATA_TYPE:i |   TYPE_NAME:s |  COLUMN_SIZE:i| BUFFER_LENGTH:i|DECIMAL_DIGITS:i|NUM_PREC_RADIX:i | NULLABLE:i|    REMARKS:s  |  COLUMN_DEF:s |SQL_DATA_TYPE:i|SQL_DATETIME_SUB:i|CHAR_OCTET_LENGTH:i|ORDINAL_POSITION:i|IS_NULLABLE:s|SCOPE_CATALOG:s|SCOPE_SCHEMA:s|SCOPE_TABLE:s|SOURCE_DATA_TYPE:sh|IS_AUTOINCREMENT:s|IS_GENERATEDCOLUMN:s
 ---------------+---------------+---------------+--------------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------+----------------+-----------------+----------------+---------------+---------------+---------------+---------------+----------------+----------------+------------------
-integTest        |null           |test_alias     |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO                                                
+integTest        |null           |test_alias     |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias     |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
 ;
 
 sysColumnsAllTables
 SYS COLUMNS TABLE LIKE '%';
 
-    TABLE_CAT:s  |  TABLE_SCHEM:s|  TABLE_NAME:s |  COLUMN_NAME:s   |   DATA_TYPE:i |   TYPE_NAME:s  |  COLUMN_SIZE:i|BUFFER_LENGTH:i|DECIMAL_DIGITS:i|NUM_PREC_RADIX:i | NULLABLE:i|    REMARKS:s  |  COLUMN_DEF:s |SQL_DATA_TYPE:i|SQL_DATETIME_SUB:i|CHAR_OCTET_LENGTH:i|ORDINAL_POSITION:i|IS_NULLABLE:s|SCOPE_CATALOG:s|SCOPE_SCHEMA:s|SCOPE_TABLE:s|SOURCE_DATA_TYPE:sh|IS_AUTOINCREMENT:s|IS_GENERATEDCOLUMN:s
------------------+---------------+---------------+------------------+---------------+----------------+---------------+---------------+----------------+---------------+---------------+---------------+---------------+---------------+----------------+-----------------+----------------+---------------+---------------+---------------+---------------+----------------+----------------+------------------
-integTest        |null           |logs           |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs           |bytes_in          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs           |bytes_out         |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs           |client_ip         |12             |IP             |45             |45             |null           |null           |1              |null           |null           |12             |0               |null             |4               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs           |client_port       |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |5               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs           |dest_ip           |12             |IP             |45             |45             |null           |null           |1              |null           |null           |12             |0               |null             |6               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs           |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs           |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |8               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs_nanos     |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs_nanos     |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |logs_nanos     |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias     |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_alias_emp |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |4               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |5               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp       |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO                
-integTest        |null           |test_emp_copy  |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |19              |YES            |null           |null           |null           |null            |NO              |NO                
+    TABLE_CAT:s  |  TABLE_SCHEM:s|  TABLE_NAME:s     |  COLUMN_NAME:s   |   DATA_TYPE:i |   TYPE_NAME:s  |  COLUMN_SIZE:i|BUFFER_LENGTH:i|DECIMAL_DIGITS:i|NUM_PREC_RADIX:i | NULLABLE:i|    REMARKS:s  |  COLUMN_DEF:s |SQL_DATA_TYPE:i|SQL_DATETIME_SUB:i|CHAR_OCTET_LENGTH:i|ORDINAL_POSITION:i|IS_NULLABLE:s|SCOPE_CATALOG:s|SCOPE_SCHEMA:s|SCOPE_TABLE:s|SOURCE_DATA_TYPE:sh|IS_AUTOINCREMENT:s|IS_GENERATEDCOLUMN:s
+-----------------+---------------+-------------------+------------------+---------------+----------------+---------------+---------------+----------------+---------------+---------------+---------------+---------------+---------------+----------------+-----------------+----------------+---------------+---------------+---------------+---------------+----------------+----------------+------------------
+integTest        |null           |logs               |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs               |bytes_in          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs               |bytes_out         |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs               |client_ip         |12             |IP             |45             |45             |null           |null           |1              |null           |null           |12             |0               |null             |4               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs               |client_port       |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |5               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs               |dest_ip           |12             |IP             |45             |45             |null           |null           |1              |null           |null           |12             |0               |null             |6               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs               |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs               |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |8               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs_nanos         |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs_nanos         |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs_nanos         |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs_unsigned_long |@timestamp        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs_unsigned_long |bytes_in          |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |2               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs_unsigned_long |bytes_out         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs_unsigned_long |id                |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |4               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |logs_unsigned_long |status            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |5               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias         |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_alias_emp     |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |4               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |5               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |7               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp           |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |birth_date        |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |1               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |emp_no            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |3               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |extra.info.gender |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |6               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |extra_gender      |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |7               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |extra_no          |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |8               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |first_name        |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |9               |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |first_name.keyword|12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |10              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |gender            |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |11              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |hire_date         |93             |DATETIME       |34             |8              |null           |null           |1              |null           |null           |9              |3               |null             |12              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |languages         |-6             |BYTE           |5              |1              |null           |10             |1              |null           |null           |-6             |0               |null             |13              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |last_name         |12             |TEXT           |2147483647     |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |14              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |last_name.keyword |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |15              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |name              |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |16              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |null_constant     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |17              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |salary            |4              |INTEGER        |11             |4              |null           |10             |1              |null           |null           |4              |0               |null             |18              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |salary_ul         |2              |UNSIGNED_LONG  |20             |8              |null           |10             |1              |null           |null           |2              |0               |null             |19              |YES            |null           |null           |null           |null            |NO              |NO
+integTest        |null           |test_emp_copy      |wildcard_name     |12             |KEYWORD        |32766          |2147483647     |null           |null           |1              |null           |null           |12             |0               |2147483647       |20              |YES            |null           |null           |null           |null            |NO              |NO
 ;

+ 1 - 0
x-pack/plugin/sql/qa/server/src/main/resources/slow/frozen.csv-spec

@@ -12,6 +12,7 @@ integTest      |empty_mapping      |TABLE  |INDEX
 integTest      |frozen_emp         |TABLE  |FROZEN INDEX
 integTest      |logs               |TABLE  |INDEX
 integTest      |logs_nanos         |TABLE  |INDEX
+integTest      |logs_unsigned_long |TABLE  |INDEX
 integTest      |test_alias         |VIEW   |ALIAS
 integTest      |test_alias_emp     |VIEW   |ALIAS
 integTest      |test_emp           |TABLE  |INDEX

+ 693 - 0
x-pack/plugin/sql/qa/server/src/main/resources/unsigned-long.csv-spec

@@ -0,0 +1,693 @@
+// To mute tests follow example in file: example.csv-spec
+
+//
+// Unsigned long tests
+//
+
+arithmeticUnsignedLongCast
+SELECT 1::unsigned_long + 1 AS x;
+
+       x:ul
+---------------
+2
+;
+
+nullArithmetics
+SELECT null + 18446744073709551614 AS x;
+
+       x:ul
+---------------
+null
+;
+
+arithmeticPlus
+SELECT 18446744073709551614 + 1 AS x;
+
+       x:ul
+---------------
+18446744073709551615
+;
+
+arithmeticMultiply
+SELECT 9223372036854775807::unsigned_long * 2 AS x;
+
+       x:ul
+---------------
+18446744073709551614
+;
+
+arithmeticDivide
+SELECT 18446744073709551614 / 2 AS x;
+
+       x:ul
+---------------
+9223372036854775807
+;
+
+arithmeticModulo
+SELECT 18446744073709551614 % 10 AS x;
+
+       x:ul
+---------------
+4
+;
+
+selectWithOrderByAndComparison
+SELECT salary_ul AS x FROM test_emp_copy WHERE salary_ul > 70000 ORDER by salary_ul DESC LIMIT 1;
+
+       x:ul
+---------------
+74999
+;
+
+selectWithImplicitAgg
+SELECT MAX(salary_ul)::STRING AS x FROM test_emp_copy;
+
+       x:s
+---------------
+74999
+;
+
+selectWithGroupByCountAndOrderBy
+SELECT salary_ul AS s, count(1) AS c FROM test_emp_copy GROUP BY 1 ORDER BY 1 LIMIT 3;
+
+       s:ul    |       c:l
+---------------+---------------
+25324          |1
+25945          |1
+25976          |1
+;
+
+selectWithMathFunction
+SELECT ROUND(SIN(salary_ul), 3) AS sin, salary_ul AS sal FROM test_emp_copy ORDER BY sal DESC LIMIT 3;
+
+      sin:d    |      sal:ul
+---------------+---------------
+0.239          |74999
+-0.823         |74970
+-0.015         |74572
+;
+
+selectWithIn
+SELECT salary_ul, salary_ul + languages AS s, languages FROM test_emp_copy WHERE salary_ul IN ('74999', 74970, 74572::unsigned_long);
+
+    salary_ul:ul  |       s:ul    |   languages:bt
+------------------+---------------+---------------
+74572             |74576          |4
+74999             |null           |null
+74970             |74973          |3
+;
+
+countWithImplicitGroupBy
+SELECT MAX(salary_ul) AS m FROM test_emp_copy ORDER BY COUNT(*);
+
+       m:ul
+---------------
+74999
+;
+
+kurtosisAndSkewnessGroup
+SELECT gender, KURTOSIS(salary_ul) k, SKEWNESS(salary_ul) s FROM test_emp_copy GROUP BY gender;
+
+gender:s             | k:d                  | s:d
+
+null                 |2.2215791166941923    |-0.03373126000214023
+F                    |1.7873117044424276    |0.05504995122217512
+M                    |2.280646181070106     |0.44302407229580243
+;
+
+sumFieldWithSumLiteralAsCondition
+SELECT first_name, last_name, SUM(salary_ul) AS s, birth_date AS y, COUNT(1) FROM test_emp_copy GROUP BY 1, 2, 4 HAVING ((SUM(1) >= 1) AND (SUM(1) <= 577)) AND ((SUM(salary_ul) >= 35000) AND (SUM(salary_ul) <= 45000));
+
+  first_name:s |   last_name:s |       s:d     |           y:ts         |   COUNT(1):l
+---------------+---------------+---------------+------------------------+---------------
+null           |Brender        |36051          |1959-10-01T00:00:00.000Z|1
+null           |Joslin         |37716          |1959-01-27T00:00:00.000Z|1
+null           |Lortz          |35222          |1960-07-20T00:00:00.000Z|1
+null           |Makrucki       |37691          |1963-07-22T00:00:00.000Z|1
+null           |Swan           |39878          |1962-12-29T00:00:00.000Z|1
+Alejandro      |McAlpine       |44307          |1953-09-19T00:00:00.000Z|1
+Amabile        |Gomatam        |38645          |1955-10-04T00:00:00.000Z|1
+Basil          |Tramer         |37853          |null                    |1
+Berhard        |McFarlin       |38376          |1954-10-01T00:00:00.000Z|1
+Berni          |Genin          |37137          |1956-02-12T00:00:00.000Z|1
+Chirstian      |Koblick        |36174          |1954-05-01T00:00:00.000Z|1
+Domenick       |Tempesti       |39356          |1963-11-26T00:00:00.000Z|1
+Hilari         |Morton         |37702          |1965-01-03T00:00:00.000Z|1
+Hisao          |Lipner         |40612          |1958-01-21T00:00:00.000Z|1
+Jayson         |Mandell        |43889          |1954-09-16T00:00:00.000Z|1
+Jungsoon       |Syrzycki       |39638          |1954-02-25T00:00:00.000Z|1
+Kendra         |Hofting        |44956          |1961-05-30T00:00:00.000Z|1
+Kenroku        |Malabarba      |35742          |1962-11-07T00:00:00.000Z|1
+Margareta      |Bierman        |41933          |1960-09-06T00:00:00.000Z|1
+Mayuko         |Warwick        |40031          |1952-12-24T00:00:00.000Z|1
+Mingsen        |Casley         |39728          |null                    |1
+Mokhtar        |Bernatsky      |38992          |1955-08-28T00:00:00.000Z|1
+Saniya         |Kalloufi       |43906          |1958-02-19T00:00:00.000Z|1
+Sreekrishna    |Servieres      |44817          |1961-09-23T00:00:00.000Z|1
+Sudharsan      |Flasterstein   |43602          |1963-03-21T00:00:00.000Z|1
+Vishv          |Zockler        |39110          |1959-07-23T00:00:00.000Z|1
+Weiyi          |Meriste        |37112          |null                    |1
+Yinghua        |Dredge         |43026          |1958-05-21T00:00:00.000Z|1
+Zvonko         |Nyanchama      |42716          |null                    |1
+;
+
+histogramNumeric
+SELECT HISTOGRAM(salary_ul, 5000) AS h FROM test_emp_copy GROUP BY h;
+
+       h:ul
+---------------
+25000
+30000
+35000
+40000
+45000
+50000
+55000
+60000
+65000
+70000
+;
+
+medianAbsoluteDeviation
+schema::gender:s|mad:d
+SELECT gender, MAD(salary_ul) AS mad FROM test_emp_copy GROUP BY gender ORDER BY gender;
+
+    gender     |      mad
+---------------+---------------
+null           |10789.0
+F              |12719.0
+M              |8905.0
+;
+
+groupAndAggNotSpecifiedInTheAggregateWithHaving
+SELECT gender, MIN(salary_ul) AS min, COUNT(*) AS c FROM test_emp_copy GROUP BY gender HAVING c > 1 ORDER BY gender NULLS FIRST, MAX(salary_ul);
+
+    gender:s   |      min:ul   |       c:l
+---------------+---------------+---------------
+null           |25324          |10
+F              |25976          |33
+M              |25945          |57
+;
+
+aggNotSpecifiedWithHavingOnLargeGroupBy
+SELECT MAX(salary_ul) AS max FROM test_emp_copy GROUP BY emp_no HAVING AVG(salary_ul) > 1000 ORDER BY MIN(salary_ul) LIMIT 5;
+
+      max:ul
+---------------
+25324
+25945
+25976
+26436
+27215
+;
+
+multipleGroupingsAndOrderingByGroupsAndAggs
+SELECT gender, MIN(salary_ul + 1) AS min, COUNT(*) AS c, MAX(salary_ul) AS max FROM test_emp_copy GROUP BY gender HAVING c > 1 ORDER BY gender DESC NULLS LAST, MAX(salary_ul) ASC;
+
+    gender:s   |      min:ul   |       c:l     |      max:ul
+---------------+---------------+---------------+---------------
+M              |25946          |57             |74999
+F              |25977          |33             |74572
+null           |25325          |10             |73717
+;
+
+aggSumWithAliasWithColumnRepeatedWithOrderDesc
+SELECT gender AS g, gender, SUM(salary_ul) AS s3, SUM(salary_ul), SUM(salary_ul) AS s5 FROM test_emp_copy GROUP BY g ORDER BY s5 DESC;
+
+g:s  | gender:s  | s3:d  | SUM(salary_ul):d  | s5:d
+-----+-----------+-------+-------------------+------
+M    |M          |2671054|2671054            |2671054
+F    |F          |1666196|1666196            |1666196
+null |null       |487605 |487605             |487605
+;
+
+aggregateFunctionsWithScalars
+SELECT MAX(CASE WHEN (salary_ul - 10) > 70000 THEN (salary_ul + 12345) * 1.2 ELSE (salary_ul - 12345) * 2.7 END) AS "max",
+MIN(CASE WHEN (salary_ul - 20) > 50000 THEN (salary_ul * 1.2) - 1234 ELSE (salary_ul - 20) * 0.93 END) AS "min",
+AVG(COS(salary_ul * 1.2) + 100 * (salary_ul / 5)) AS "avg",
+SUM(salary_ul / 0.765 + sin((salary_ul + 12345) / 12)) AS "sum",
+MAD(ABS(salary_ul / -0.813) / 2 + (12345 * (salary_ul % 10))) AS "mad"
+FROM test_emp_copy;
+
+       max        |      min      |       avg       |       sum       |       mad
+------------------+---------------+-----------------+-----------------+-----------------
+155409.30000000002|23532.72       |964937.9295477575|6306995.482492277|30811.76199261993
+;
+
+aggregatesWithScalarsAndGroupByOrderByAggWithoutProjection
+schema::gender:s
+SELECT gender FROM test_emp_copy GROUP BY gender ORDER BY MAX(salary_ul % 100) DESC;
+
+    gender
+---------------
+M
+null
+F
+;
+
+percentileAggregateFunctionsWithScalars
+schema::percentile:d|percentile_rank:d|gender:s
+SELECT PERCENTILE(CASE WHEN (salary_ul / 2) > 10000 THEN (salary_ul + 12345) * 1.2 ELSE (salary_ul - 12345) * 2.7 END, 80) AS "percentile",
+PERCENTILE_RANK(CASE WHEN (salary_ul - 20) > 50000 THEN (salary_ul * 1.2) - 1234 ELSE (salary_ul - 20) * 0.93 END, 40000) AS "percentile_rank",
+gender FROM test_emp_copy
+GROUP BY gender ORDER BY gender;
+
+   percentile    | percentile_rank  |    gender
+-----------------+------------------+---------------
+86857.79999999999|32.69659025378865 |null
+94042.92000000001|37.03569653103581 |F
+87348.36         |44.337514210592246|M
+;
+
+extendedStatsAggregateFunctionsWithScalars
+schema::stddev_pop:d|stddev_samp:d|sum_of_squares:d|var_pop:d|var_samp:d|gender:s
+SELECT STDDEV_POP(CASE WHEN (salary_ul / 2) > 10000 THEN (salary_ul + 12345) * 1.2 ELSE (salary_ul - 12345) * 2.7 END) AS "stddev_pop",
+STDDEV_SAMP(CASE WHEN (salary_ul / 2) > 10000 THEN (salary_ul + 12345) * 1.2 ELSE (salary_ul - 12345) * 2.7 END) AS "stddev_samp",
+SUM_OF_SQUARES(CASE WHEN (salary_ul - 20) > 50000 THEN (salary_ul * 1.2) - 1234 ELSE (salary_ul - 20) * 0.93 END) AS "sum_of_squares",
+VAR_POP(CASE WHEN (salary_ul - 20) % 1000 > 200 THEN (salary_ul * 1.2) - 1234 ELSE (salary_ul - 20) * 0.93 END) AS "var_pop",
+VAR_SAMP(CASE WHEN (salary_ul - 20) % 1000 > 200 THEN (salary_ul * 1.2) - 1234 ELSE (salary_ul - 20) * 0.93 END) AS "var_samp",
+gender FROM test_emp_copy
+GROUP BY gender ORDER BY gender;
+
+    stddev_pop    |   stddev_samp    |   sum_of_squares    |      var_pop       |      var_samp      |    gender
+------------------+------------------+---------------------+--------------------+--------------------+---------------
+16752.73244172422 |17658.930515747525|3.06310583829007E10  |3.460331137445282E8 |3.844812374939202E8 |null
+17427.462400181845|17697.67172930331 |1.148127725047658E11 |3.1723426960671306E8|3.271478405319228E8 |F
+15702.798665784752|15842.381843421828|1.5882243113919238E11|2.529402043805585E8 |2.5745699374449703E8|M
+;
+
+groupByRoundAndTruncateWithTwoParams
+SELECT ROUND(SIN(TRUNCATE("salary_ul", 2)), 2) FROM "test_emp_copy" GROUP BY ROUND(SIN(TRUNCATE("salary_ul", 2)), 2) ORDER BY ROUND(SIN(TRUNCATE("salary_ul", 2)), 2) LIMIT 5;
+
+ROUND(SIN(TRUNCATE("salary_ul", 2)), 2)
+---------------------------------------
+-1.0
+-0.99
+-0.98
+-0.97
+-0.96
+;
+
+sumLiteralAndSumFieldWithComplexHaving
+SELECT gender, CAST(SUM("salary_ul") AS BIGINT), CAST(SUM(1) AS BIGINT), CAST(SUM(10) AS BIGINT), COUNT(*) FROM test_emp_copy GROUP BY gender HAVING ((SUM(1) >= 0) AND (SUM(1) <= 50) AND (SUM(salary_ul) >= 250000) AND (SUM(salary_ul) <= 5000000)) ORDER BY gender;
+
+    gender:s   |CAST(SUM("salary_ul") AS BIGINT):l|CAST(SUM(1) AS BIGINT):l|CAST(SUM(10) AS BIGINT):l|   COUNT(*):l
+---------------+----------------------------------+------------------------+-------------------------+---------------
+null           |487605                            |10                      |100                      |10
+F              |1666196                           |33                      |330                      |33
+;
+
+aggGroupByOnScalarWithHaving
+SELECT salary_ul + 1 AS e FROM test_emp_copy GROUP BY e HAVING AVG(salary_ul) BETWEEN 50000 AND 60000 ORDER BY e LIMIT 2;
+
+       e:ul
+---------------
+50065
+50129
+;
+
+caseGroupByProtectedDivisionByZero
+schema::x:ul
+SELECT CASE WHEN languages = 1 THEN NULL ELSE ( salary_ul / (languages - 1) ) END AS x FROM test_emp_copy GROUP BY 1 ORDER BY 1 LIMIT 10;
+
+       x
+---------------
+null
+6331
+6486
+7780
+7974
+8068
+8489
+8935
+9043
+9071
+;
+
+iifWithCompatibleIntervals
+schema::hire_date + IIF(salary_ul > 70000, INTERVAL 2 HOURS, INTERVAL 2 DAYS):ts|salary_ul:ul
+SELECT hire_date + IIF(salary_ul > 70000, INTERVAL 2 HOURS, INTERVAL 2 DAYS), salary_ul FROM test_emp_copy ORDER BY salary DESC LIMIT 10;
+
+hire_date + IIF(salary_ul > 70000, INTERVAL 2 HOURS, INTERVAL 2 DAYS)|    salary_ul
+---------------------------------------------------------------------+---------------
+1985-11-20T02:00:00.000Z                                             |74999
+1989-09-02T02:00:00.000Z                                             |74970
+1989-02-10T02:00:00.000Z                                             |74572
+1989-07-07T02:00:00.000Z                                             |73851
+1999-04-30T02:00:00.000Z                                             |73717
+1988-10-18T02:00:00.000Z                                             |73578
+1990-09-15T02:00:00.000Z                                             |71165
+1987-03-18T02:00:00.000Z                                             |70011
+1987-05-28T00:00:00.000Z                                             |69904
+1990-02-18T00:00:00.000Z                                             |68547
+;
+
+aggPercentile
+SELECT languages, PERCENTILE(salary_ul, 95) AS "95th" FROM test_emp_copy GROUP BY languages;
+
+   languages:bt|      95th:d
+---------------+-----------------
+null           |74999.0
+1              |72790.5
+2              |71924.70000000001
+3              |73638.25
+4              |72115.59999999999
+5              |61071.7
+;
+
+mathPowerNegative
+SELECT POWER(salary_ul, -1) m, first_name FROM "test_emp_copy" WHERE emp_no < 10010 ORDER BY emp_no;
+
+          m          |  first_name
+---------------------+---------------
+1.7450484250937964E-5|Georgi
+1.773961788863068E-5 |Bezalel
+1.617992071838848E-5 |Parto
+2.76441643169127E-5  |Chirstian
+1.57410905427528E-5  |Kyoichi
+1.6574127786525235E-5|Anneke
+1.3409858928284075E-5|Tzvetan
+2.2775930396756706E-5|Saniya
+1.5111675280321576E-5|Sumant
+;
+
+averageWithOneValueAndOrder
+schema::languages:bt|'F':d
+SELECT * FROM (SELECT languages, gender, salary_ul FROM test_emp_copy) PIVOT (AVG(salary_ul + 1) FOR gender IN ('F')) ORDER BY languages DESC LIMIT 4;
+   languages   |       'F'
+---------------+------------------
+5              |46706.555555555555
+4              |49292.5
+3              |53661.0
+2              |50685.4
+;
+
+sumWithInnerAggregateSumOfSquaresRound
+schema::birth_date:ts|emp_no:i|extra.info.gender:s|extra_gender:s|extra_no:i|first_name:s|gender:s|hire_date:ts|last_name:s|name:s|null_constant:s|salary:i|wildcard_name:s|1:d|2:d
+SELECT * FROM test_emp_copy PIVOT (ROUND(SUM_OF_SQUARES(salary_ul + 1)/1E6, 2) FOR languages IN (1, 2)) LIMIT 3;
+
+  birth_date   |    emp_no     |extra.info.gender| extra_gender  |   extra_no    |  first_name   |    gender     |       hire_date        |   last_name   |     name      | null_constant |    salary     | wildcard_name |       1       |       2
+---------------+---------------+-----------------+---------------+---------------+---------------+---------------+------------------------+---------------+---------------+---------------+---------------+---------------+---------------+---------------
+null           |10041          |F                |Female         |10041          |Uri            |F              |1989-11-12T00:00:00.000Z|Lenart         |Uri Lenart     |null           |56415          |Uri Lenart     |3182.77        |null
+null           |10043          |M                |Female         |10043          |Yishay         |M              |1990-10-20T00:00:00.000Z|Tzvieli        |Yishay Tzvieli |null           |34341          |Yishay Tzvieli |1179.37        |null
+null           |10044          |F                |Female         |10044          |Mingsen        |F              |1994-05-21T00:00:00.000Z|Casley         |Mingsen Casley |null           |39728          |Mingsen Casley |1578.39        |null
+;
+
+
+implicitAggAndCastMaxLargeInput
+SELECT MAX(bytes_out)::DOUBLE xd, MAX(bytes_in)::STRING xs FROM logs_unsigned_long;
+
+         xd:d       |         xs:s
+--------------------+--------------------
+1.822361547714736E19|18446744073709551615
+;
+
+implicitAggFirstLast
+SELECT FIRST(bytes_in)::BYTE xd, FIRST(bytes_out)::LONG xs FROM logs_unsigned_long;
+
+      xd:bt    |        xs:l
+---------------+------------------
+0              |352442273299370793
+;
+
+withMathFunctionLargeInput
+SELECT ROUND(SIN(bytes_out), 3) AS sin, bytes_out AS out FROM logs_unsigned_long ORDER BY sin DESC NULLS LAST LIMIT 3;
+
+      sin:d    |        out:ul
+---------------+--------------------
+0.999          |8422074124513216267
+0.999          |11563896463355414928
+0.997          |16110121334900810541
+;
+
+withMathIntoInLargeInput
+SELECT id, bytes_in, bytes_out,
+ ((bytes_out::DOUBLE + CASE WHEN status = 'OK' THEN bytes_in ELSE 0 END)/POWER(1024, 3))::UNSIGNED_LONG AS traffic_gb
+FROM logs_unsigned_long
+WHERE bytes_in IN (9223372036854775807::UNSIGNED_LONG * 2, 18446744073709551614, '18446744073709551615'::UNSIGNED_LONG);
+
+      id:i     |      bytes_in:ul   |     bytes_out:ul   |  traffic_gb:ul
+---------------+--------------------+--------------------+---------------
+20             |18446744073709551614|9891957732954625161 |26392472727
+40             |18446744073709551614|14524142879756567901|30706531324
+50             |18446744073709551615|8359170160363687272 |24964953059
+;
+
+countWithImplicitGroupByAndArithmeticLargeInput
+SELECT MAX(bytes_out) max, MIN(bytes_out) min, MAX(bytes_out) - MIN(bytes_out) diff FROM logs_unsigned_long ORDER BY COUNT(*);
+
+        max:ul      |       min:ul     |        diff:ul
+--------------------+------------------+--------------------
+18223615477147360166|352442273299370793|17871173203847989373
+
+;
+
+kurtosisAndSkewnessGroupLargeInput
+SELECT status, KURTOSIS(bytes_in) k, SKEWNESS(bytes_in) s FROM logs_unsigned_long GROUP BY status;
+
+    status     |        k         |         s
+---------------+------------------+--------------------
+Error          |2.056501455580364 |0.7571349191844446
+OK             |1.9651462247673082|-0.15628563062367107
+;
+
+
+fieldWithSumLiteralAsConditionLargeInput
+SELECT status, SUM(bytes_in) AS s, "@timestamp" AS y, COUNT(1) FROM logs_unsigned_long GROUP BY 1, 3 HAVING SUM(1) >= 3;
+
+    status:s   |          s:d        |          y:ts          |   COUNT(1):l
+---------------+---------------------+------------------------+---------------
+Error          |2.9973949656396653E19|2017-11-10T19:51:38.000Z|3
+OK             |6.232411355491008E19 |2017-11-10T20:35:55.000Z|6
+OK             |5.799662857991158E19 |2017-11-10T20:35:57.000Z|7
+OK             |3.14816340622471E19  |2017-11-10T20:36:07.000Z|3
+OK             |3.1174871328354025E19|2017-11-10T21:15:39.000Z|3
+OK             |3.3409057849369555E19|2017-11-10T21:15:40.000Z|3
+OK             |2.76229913536395E19  |2017-11-10T21:17:37.000Z|3
+;
+
+histogramNumericLargeInput
+SELECT HISTOGRAM(bytes_in, POWER(10, 9)) AS gb FROM logs_unsigned_long GROUP BY 1 LIMIT 10;
+
+        gb:ul
+-------------------
+null
+0
+74330435000000000
+154551962000000000
+195161570000000000
+316080452000000000
+369412756000000000
+754822992000000000
+905851433000000000
+1729864283000000000
+;
+
+medianAbsoluteDeviationLargeInput
+SELECT status, MAD(bytes_in) AS mad FROM logs_unsigned_long GROUP BY status ORDER BY status;
+
+    status     |         mad
+---------------+---------------------
+Error          |3.0183732936229658E18
+OK             |4.5240953206634045E18
+;
+
+
+groupAndAggNotSpecifiedInTheAggregateWithHavingLargeInput
+SELECT status, MIN(bytes_out) AS min, COUNT(*) AS c FROM logs_unsigned_long GROUP BY 1 HAVING c > 1 ORDER BY 1 NULLS FIRST, MAX(bytes_out);
+
+    status:s   |        min:ul     |       c:l
+---------------+-------------------+---------------
+Error          |4317649615355527138|9
+OK             |352442273299370793 |92
+;
+
+aggNotSpecifiedWithHavingOnLargeGroupByLargeInput
+SELECT MAX(bytes_in) AS max FROM logs_unsigned_long GROUP BY id HAVING AVG(bytes_in) > 1000 ORDER BY MIN(bytes_out) LIMIT 5;
+
+        max:ul
+--------------------
+1957665857956635540
+2408213296071189837
+9614024902524991937
+2706408999083639864
+17764691215469285192
+;
+
+multipleGroupingsAndOrderingByGroupsAndAggsLargeInput
+SELECT status, MIN(bytes_out + 1) AS min, COUNT(*) AS c, MAX(bytes_in) AS max FROM logs_unsigned_long GROUP BY status HAVING c > 1 ORDER BY status DESC NULLS LAST, MAX(bytes_in) ASC;
+
+    status:s   |       min:ul     |       c:l     |        max:ul
+---------------+------------------+---------------+--------------------
+OK             |352442273299370794|92             |18446744073709551615
+Error          |null              |9              |18345360876889252152
+;
+
+aggSumWithAliasWithColumnRepeatedWithOrderDescLargeInput
+SELECT status AS s, status, SUM(bytes_in) AS s3, SUM(bytes_in), SUM(bytes_in) AS s5 FROM logs_unsigned_long GROUP BY s ORDER BY s5 DESC;
+
+       s:s     |    status:s   |         s3:d       |   SUM(bytes_in):d  |         s5:d
+---------------+---------------+--------------------+--------------------+--------------------
+OK             |OK             |9.045581107970589E20|9.045581107970589E20|9.045581107970589E20
+Error          |Error          |3.671012330989688E19|3.671012330989688E19|3.671012330989688E19
+;
+
+aggregateFunctionsWithScalarsLargeInput
+
+SELECT MAX(CASE WHEN (bytes_out - 10) > 9223372036854775807 THEN (bytes_out + 12345) * 1.2 ELSE (bytes_out - 12345) * 2.7 END) AS max,
+MIN(CASE WHEN (bytes_out - 20) > 9223372036854775807 THEN (bytes_out * 1.2) - 1234 ELSE (bytes_out - 20) * 0.93 END) AS min,
+AVG((COS(bytes_out * 1.2) + 100) * (bytes_out / 5)) AS avg,
+SUM(bytes_out / 0.765 + sin((bytes_out + 12345) / 12)) AS sum,
+MAD(ABS(bytes_out / -0.813) / 2 + (12345 * (bytes_out % 10))) AS mad
+FROM logs_unsigned_long;
+
+        max:d       |         min:d       |        avg:d       |         sum:d       |         mad:d
+--------------------+---------------------+--------------------+---------------------+---------------------
+2.295063844173583E19|3.2777131416841485E17|1.820279192886511E20|1.1661879109640491E21|3.0865540937819786E18
+;
+
+
+aggregatesWithScalarsAndGroupByOrderByAggWithoutProjectionLargeInput
+SELECT status, MAX(bytes_in % 100) max FROM logs_unsigned_long GROUP BY status ORDER BY 2 DESC;
+
+    status:s   |      max:ul
+---------------+---------------
+OK             |99
+Error          |72
+;
+
+percentileAggregateFunctionsWithScalarsLargeInput
+SELECT PERCENTILE(CASE WHEN (bytes_out / 2) > 4E18 THEN (bytes_out + 12345) * 1.2 ELSE (bytes_out - 12345) * 2.7 END, 80) AS percentile,
+PERCENTILE_RANK(CASE WHEN (bytes_out - 20) > 4E18 THEN (bytes_out * 1.2) - 1234 ELSE (bytes_out - 20) * 0.93 END, 4E18) AS percentile_rank,
+status
+FROM logs_unsigned_long
+GROUP BY status
+ORDER BY status;
+
+     percentile      | percentile_rank  |    status
+---------------------+------------------+---------------
+1.8836190713044468E19|1.970336796004502 |Error
+1.7957483822449326E19|26.644793296251386|OK
+;
+
+extendedStatsAggregateFunctionsWithScalarsLargeInput
+SELECT STDDEV_POP(CASE WHEN (bytes_out / 2) > 10000 THEN (bytes_out + 12345) * 1.2 ELSE (bytes_out - 12345) * 2.7 END) AS stddev_pop,
+STDDEV_SAMP(CASE WHEN (bytes_out / 2) > 10000 THEN (bytes_out + 12345) * 1.2 ELSE (bytes_out - 12345) * 2.7 END) AS stddev_samp,
+SUM_OF_SQUARES(CASE WHEN (bytes_out - 20) > 50000 THEN (bytes_out * 1.2) - 1234 ELSE (bytes_out - 20) * 0.93 END) AS sum_of_squares,
+VAR_POP(CASE WHEN (bytes_out - 20) % 1000 > 200 THEN (bytes_out * 1.2) - 1234 ELSE (bytes_out - 20) * 0.93 END) AS var_pop,
+VAR_SAMP(CASE WHEN (bytes_out - 20) % 1000 > 200 THEN (bytes_out * 1.2) - 1234 ELSE (bytes_out - 20) * 0.93 END) AS var_samp,
+status
+FROM logs_unsigned_long
+GROUP BY status
+ORDER BY status;
+
+     stddev_pop      |     stddev_samp     |   sum_of_squares    |       var_pop       |      var_samp      |    status
+---------------------+---------------------+---------------------+---------------------+--------------------+---------------
+5.1879845114777528E18|5.6831522898475694E18|1.1113551085273773E39|2.9979868907159907E37|3.597584268859189E37|Error
+6.7116742512203459E18|6.7484508237837148E18|1.4906887301541836E40|4.304729535850427E37 |4.352034256024607E37|OK
+;
+
+groupByRoundAndTruncateWithTwoParamsLargeInput
+SELECT ROUND(SIN(TRUNCATE(bytes_in, 2)), 2) rst FROM logs_unsigned_long GROUP BY 1 ORDER BY 1 LIMIT 5;
+
+      rst:d
+---------------
+null
+-1.0
+-0.99
+-0.97
+-0.96
+;
+
+sumLiteralAndSumFieldWithComplexHavingLargeInput
+SELECT status, CAST(SUM(bytes_out) AS STRING), CAST(SUM(1) AS BIGINT), CAST(SUM(10) AS BIGINT), COUNT(*) FROM logs_unsigned_long GROUP BY status HAVING ((SUM(1) >= 0) AND (SUM(1) <= 50) AND (SUM(bytes_out) >= 250000) AND (SUM(bytes_out) <= 7E19)) ORDER BY status;
+
+    status:s   |CAST(SUM(bytes_out) AS STRING):s|CAST(SUM(1) AS BIGINT):l|CAST(SUM(10) AS BIGINT):l|   COUNT(*):l
+---------------+--------------------------------+------------------------+-------------------------+---------------
+Error          |6.2910783680124445E19           |9                       |90                       |9
+;
+
+aggGroupByOnScalarWithHavingLargeInput
+SELECT bytes_out + 1 AS e FROM logs_unsigned_long GROUP BY e HAVING AVG(bytes_out) BETWEEN 9E18 AND 1E19 ORDER BY e LIMIT 2;
+
+         e:ul
+-------------------
+9243820354371174975
+9336652471323200907
+;
+
+iifWithCompatibleIntervalsLargeInput
+SELECT "@timestamp" ts, "@timestamp" + IIF(bytes_out > 9E18, INTERVAL 2 HOURS, INTERVAL 2 DAYS) ts_plus, bytes_out FROM logs_unsigned_long ORDER BY bytes_out DESC LIMIT 10;
+
+           ts:ts        |        ts_plus:ts      |     bytes_out:ul
+------------------------+------------------------+--------------------
+2017-11-10T20:35:55.000Z|2017-11-12T20:35:55.000Z|null
+2017-11-10T19:51:38.000Z|2017-11-12T19:51:38.000Z|null
+2017-11-10T23:22:36.000Z|2017-11-12T23:22:36.000Z|null
+2017-11-10T00:27:03.000Z|2017-11-10T02:27:03.000Z|18223615477147360166
+2017-11-10T20:35:57.000Z|2017-11-10T22:35:57.000Z|18184253384683076090
+2017-11-10T21:15:40.000Z|2017-11-10T23:15:40.000Z|18107197698386620672
+2017-11-10T23:28:11.000Z|2017-11-11T01:28:11.000Z|17953153966527637143
+2017-11-10T21:28:34.000Z|2017-11-10T23:28:34.000Z|17857609920324506371
+2017-11-10T21:13:27.000Z|2017-11-10T23:13:27.000Z|17695317925249333633
+2017-11-10T20:36:15.000Z|2017-11-10T22:36:15.000Z|17281501450843634251
+;
+
+aggPercentileLargeInput
+SELECT status, PERCENTILE(bytes_in, 95) AS "95th" FROM logs_unsigned_long GROUP BY status;
+
+    status:s   |        95th:d
+---------------+---------------------
+Error          |1.8345360876889252E19
+OK             |1.8295214210102768E19
+;
+
+mathPowerNegativeLargeInput
+SELECT POWER(bytes_in, -1) m, id FROM logs_unsigned_long WHERE id < 10 ORDER BY id;
+
+          m:d         |      id:i
+----------------------+---------------
+2.2994842882726847E-19|1
+9.046030383433917E-20 |2
+1.3813254901492728E-19|3
+7.763447541524763E-20 |4
+1.5430743541977252E-19|5
+1.1302799995492255E-19|6
+5.530629782187966E-20 |7
+5.827842232431528E-20 |8
+5.459386906856704E-20 |9
+;
+
+averageWithOneValueAndOrderLargeInput
+SELECT * FROM (SELECT id, status, bytes_out FROM logs_unsigned_long) PIVOT (AVG(bytes_out + 1) FOR status IN ('OK', 'Error')) ORDER BY id DESC LIMIT 4;
+
+      id:i       |        'OK':d       |    'Error':d
+---------------+---------------------+---------------
+101            |null                 |null
+100            |1.5616395223975498E19|null
+99             |3.5244227329937082E17|null
+98             |5.4095497308894812E18|null
+;
+
+sumWithInnerAggregateSumOfSquaresRoundLargeInput
+SELECT * FROM logs_unsigned_long PIVOT (ROUND(SUM_OF_SQUARES(bytes_out + 1)/1E6, 2) FOR status IN ('Error', 'OK')) LIMIT 3;
+
+       @timestamp:ts    |   bytes_in:ul     |      id:i     |    'Error':d  |        'OK':d
+------------------------+-------------------+---------------+---------------+--------------------
+2017-11-10T00:00:22.000Z|0                  |80             |null           |9.223372036854776E16
+2017-11-10T00:01:04.000Z|9636626466125797351|83             |null           |9.223372036854776E16
+2017-11-10T00:01:20.000Z|74330435873664882  |82             |null           |9.223372036854776E16
+;
+
+castWithGroupByLargeInput
+SELECT (bytes_in/1E12)::LONG::STRING in_tib FROM logs_unsigned_long WHERE bytes_in - 18E18 > 0 GROUP BY 1;
+
+      in_tib:s
+--------------------
+18081123
+18098466
+18317075
+18345361
+18446744
+;

+ 73 - 0
x-pack/plugin/sql/qa/server/src/main/resources/unsigned-long.sql-spec

@@ -0,0 +1,73 @@
+// To mute tests follow example in file: example.sql-spec
+
+//
+// Unsigned long tests
+//
+
+// H2 doesn't support our unsigned_long type, casting to it isn't possible.
+// Values larger than Long.MAX_VALUE are returned as BigDecimal.
+// EXPM1 and CBRT functions not available.
+// RAND takes an int.
+// ES's CEIL & FLOOR don't work with unsigned_longs (TODO) + they can return longs, while H2's always returns doubles
+
+plus
+SELECT 18446744073709551614 + 1 AS x;
+plusLongMax
+SELECT 9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000) AS x;
+minus
+SELECT 18446744073709551615 - ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000) AS x;
+divide
+SELECT 18446744073709551615 / ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000) AS x;
+multiply
+SELECT 18446744073709551615 * 1 AS x;
+mod
+SELECT 18446744073709551615 % ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000) AS x;
+
+abs
+SELECT ABS(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+// ceil
+// SELECT CEIL(9223372036854775808 + RAND(SECOND(CURRENT_TIMESTAMP())) * 10000) AS x;
+exp
+SELECT EXP(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+// floor
+// SELECT FLOOR(9223372036854775808 + RAND(SECOND(CURRENT_TIMESTAMP())) * 10000) AS x;
+log
+SELECT LOG(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+log10
+SELECT LOG10(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+power
+SELECT POWER(4294967295, 2) AS x;
+round
+SELECT ROUND(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+sign
+SELECT SIGN(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+sqrt
+SELECT SQRT(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+truncate
+SELECT TRUNCATE(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+acos
+
+// trigonometric
+SELECT ACOS(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+asin
+SELECT ASIN(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+atan
+SELECT ATAN(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+atan2
+SELECT ATAN2(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000), 45) AS x;
+cos
+SELECT COS(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+cosh
+SELECT COSH(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+cot
+SELECT COT(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+degrees
+SELECT DEGREES(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+radians
+SELECT RADIANS(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+sin
+SELECT SIN(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+sinh
+SELECT SINH(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;
+tan
+SELECT TAN(9223372036854775808 + ROUND(RAND(SECOND(CURRENT_TIMESTAMP())) * 10000)) AS x;

+ 2 - 1
x-pack/plugin/sql/sql-proto/src/main/java/org/elasticsearch/xpack/sql/proto/SqlVersion.java

@@ -32,7 +32,7 @@ public class SqlVersion implements Comparable<SqlVersion> {
 
     public static final SqlVersion V_7_7_0 = new SqlVersion(7, 7, 0);
     public static final SqlVersion V_7_12_0 = new SqlVersion(7, 12, 0);
-    public static final SqlVersion DATE_NANOS_SUPPORT_VERSION = V_7_12_0;
+    public static final SqlVersion DATE_NANOS_SUPPORT_VERSION = V_7_12_0; // TODO: move to VersionCompatibilityChecks
 
     public SqlVersion(byte major, byte minor, byte revision) {
         this(toString(major, minor, revision), major, minor, revision);
@@ -169,6 +169,7 @@ public class SqlVersion implements Comparable<SqlVersion> {
         return hasVersionCompatibility(client) && server.compareTo(client) >= 0 && server.major - client.major <= 1;
     }
 
+    // TODO: move to VersionCompatibilityChecks
     public static boolean supportsDateNanos(SqlVersion version) {
         return DATE_NANOS_SUPPORT_VERSION.compareTo(version) <= 0;
     }

+ 6 - 7
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Analyzer.java

@@ -44,7 +44,6 @@ import org.elasticsearch.xpack.ql.plan.logical.Project;
 import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan;
 import org.elasticsearch.xpack.ql.plan.logical.UnresolvedRelation;
 import org.elasticsearch.xpack.ql.rule.RuleExecutor;
-import org.elasticsearch.xpack.ql.session.Configuration;
 import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypes;
 import org.elasticsearch.xpack.ql.type.InvalidMappedField;
@@ -59,6 +58,7 @@ import org.elasticsearch.xpack.sql.plan.logical.LocalRelation;
 import org.elasticsearch.xpack.sql.plan.logical.Pivot;
 import org.elasticsearch.xpack.sql.plan.logical.SubQueryAlias;
 import org.elasticsearch.xpack.sql.plan.logical.With;
+import org.elasticsearch.xpack.sql.session.SqlConfiguration;
 import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
 
 import java.util.ArrayList;
@@ -92,13 +92,13 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
      * Per-request specific settings needed in some of the functions (timezone, username and clustername),
      * to which they are attached.
      */
-    private final Configuration configuration;
+    private final SqlConfiguration configuration;
     /**
      * The verifier has the role of checking the analyzed tree for failures and build a list of failures.
      */
     private final Verifier verifier;
 
-    public Analyzer(Configuration configuration, FunctionRegistry functionRegistry, IndexResolution results, Verifier verifier) {
+    public Analyzer(SqlConfiguration configuration, FunctionRegistry functionRegistry, IndexResolution results, Verifier verifier) {
         this.configuration = configuration;
         this.functionRegistry = functionRegistry;
         this.indexResolution = results;
@@ -149,7 +149,7 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
     }
 
     public LogicalPlan verify(LogicalPlan plan) {
-        Collection<Failure> failures = verifier.verify(plan);
+        Collection<Failure> failures = verifier.verify(plan, configuration.version());
         if (failures.isEmpty() == false) {
             throw new VerificationException(failures);
         }
@@ -241,8 +241,7 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
                             + fa.name()
                             + "] with unsupported type ["
                             + unsupportedField.getOriginalType()
-                            + "] "
-                            + "in hierarchy (field ["
+                            + "] in hierarchy (field ["
                             + unsupportedField.getInherited()
                             + "])"
                     );
@@ -340,7 +339,7 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
         }
     }
 
-    private static class ResolveRefs extends BaseAnalyzerRule {
+    private class ResolveRefs extends BaseAnalyzerRule {
 
         @Override
         protected LogicalPlan doRule(LogicalPlan plan) {

+ 35 - 5
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Verifier.java

@@ -6,6 +6,7 @@
  */
 package org.elasticsearch.xpack.sql.analysis.analyzer;
 
+import org.elasticsearch.Version;
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.xpack.ql.capabilities.Unresolvable;
 import org.elasticsearch.xpack.ql.common.Failure;
@@ -57,6 +58,7 @@ import org.elasticsearch.xpack.sql.plan.logical.Having;
 import org.elasticsearch.xpack.sql.plan.logical.LocalRelation;
 import org.elasticsearch.xpack.sql.plan.logical.Pivot;
 import org.elasticsearch.xpack.sql.plan.logical.command.Command;
+import org.elasticsearch.xpack.sql.proto.SqlVersion;
 import org.elasticsearch.xpack.sql.stats.FeatureMetric;
 import org.elasticsearch.xpack.sql.stats.Metrics;
 import org.elasticsearch.xpack.sql.type.SqlDataTypes;
@@ -75,7 +77,10 @@ import java.util.function.Consumer;
 import static java.util.stream.Collectors.toMap;
 import static org.elasticsearch.xpack.ql.analyzer.VerifierChecks.checkFilterConditionType;
 import static org.elasticsearch.xpack.ql.common.Failure.fail;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.isTypeSupportedInVersion;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.versionIntroducingType;
 import static org.elasticsearch.xpack.ql.type.DataTypes.BINARY;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.ql.util.CollectionUtils.combine;
 import static org.elasticsearch.xpack.sql.stats.FeatureMetric.COMMAND;
 import static org.elasticsearch.xpack.sql.stats.FeatureMetric.GROUPBY;
@@ -98,12 +103,12 @@ public final class Verifier {
         this.metrics = metrics;
     }
 
-    public Map<Node<?>, String> verifyFailures(LogicalPlan plan) {
-        Collection<Failure> failures = verify(plan);
+    public Map<Node<?>, String> verifyFailures(LogicalPlan plan, SqlVersion version) {
+        Collection<Failure> failures = verify(plan, version);
         return failures.stream().collect(toMap(Failure::node, Failure::message));
     }
 
-    Collection<Failure> verify(LogicalPlan plan) {
+    Collection<Failure> verify(LogicalPlan plan, SqlVersion version) {
         Set<Failure> failures = new LinkedHashSet<>();
 
         // start bottom-up
@@ -235,6 +240,8 @@ public final class Verifier {
 
                 failures.addAll(localFailures);
             });
+
+            checkClientSupportsDataTypes(plan, failures, version);
         }
 
         // gather metrics
@@ -463,8 +470,9 @@ public final class Verifier {
             unsupported.add(e);
             return true;
         } else if (e instanceof Min || e instanceof Max) {
-            if (DataTypes.isString(((AggregateFunction) e).field().dataType())) {
-                // Min & Max on a Keyword field will be translated to First & Last respectively
+            DataType aggType = ((AggregateFunction) e).field().dataType();
+            if (DataTypes.isString(aggType) || aggType == UNSIGNED_LONG) {
+                // Min & Max on a Keyword or unsigned_long field will be translated to First & Last respectively
                 unsupported.add(e);
                 return true;
             }
@@ -995,6 +1003,28 @@ public final class Verifier {
         }));
     }
 
+    private static void checkClientSupportsDataTypes(LogicalPlan p, Set<Failure> localFailures, SqlVersion version) {
+        Version ver = Version.fromId(version.id);
+        p.output().forEach(e -> {
+            if (e.resolved() && isTypeSupportedInVersion(e.dataType(), ver) == false) {
+                localFailures.add(
+                    fail(
+                        e,
+                        "Cannot use field ["
+                            + e.name()
+                            + "] with type ["
+                            + e.dataType()
+                            + "] unsupported in version ["
+                            + version
+                            + "], upgrade required (to version ["
+                            + versionIntroducingType(e.dataType())
+                            + "] or higher)"
+                    )
+                );
+            }
+        });
+    }
+
     // check that any binary field used in WHERE, GROUP BY, HAVING or ORDER BY has doc_values, for ES to allow querying it
     private static void checkBinaryHasDocValues(LogicalPlan plan, Set<Failure> localFailures) {
         List<Tuple<FieldAttribute, String>> fields = new ArrayList<>();

+ 3 - 3
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/execution/search/Querier.java

@@ -83,7 +83,7 @@ import java.util.function.Supplier;
 
 import static java.util.Collections.singletonList;
 import static org.elasticsearch.action.ActionListener.wrap;
-import static org.elasticsearch.xpack.ql.execution.search.QlSourceBuilder.INTRODUCING_MISSING_ORDER_IN_COMPOSITE_AGGS_VERSION;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.INTRODUCING_UNSIGNED_LONG;
 
 // TODO: add retry/back-off
 public class Querier {
@@ -144,7 +144,7 @@ public class Querier {
     public static SearchRequest prepareRequest(SearchSourceBuilder source, TimeValue timeout, boolean includeFrozen, String... indices) {
         source.timeout(timeout);
 
-        SearchRequest searchRequest = new SearchRequest(INTRODUCING_MISSING_ORDER_IN_COMPOSITE_AGGS_VERSION);
+        SearchRequest searchRequest = new SearchRequest(INTRODUCING_UNSIGNED_LONG);
         searchRequest.indices(indices);
         searchRequest.source(source);
         searchRequest.allowPartialSearchResults(false);
@@ -468,7 +468,7 @@ public class Querier {
 
         private BucketExtractor createExtractor(FieldExtraction ref, BucketExtractor totalCount) {
             if (ref instanceof GroupByRef r) {
-                return new CompositeKeyExtractor(r.key(), r.property(), cfg.zoneId(), r.isDateTimeBased());
+                return new CompositeKeyExtractor(r.key(), r.property(), cfg.zoneId(), r.dataType());
             }
 
             if (ref instanceof MetricAggRef r) {

+ 43 - 16
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/execution/search/extractor/CompositeKeyExtractor.java

@@ -6,13 +6,16 @@
  */
 package org.elasticsearch.xpack.sql.execution.search.extractor;
 
+import org.elasticsearch.Version;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket;
 import org.elasticsearch.xpack.ql.execution.search.extractor.BucketExtractor;
+import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
 import org.elasticsearch.xpack.sql.common.io.SqlStreamInput;
 import org.elasticsearch.xpack.sql.querydsl.container.GroupByRef.Property;
+import org.elasticsearch.xpack.sql.type.SqlDataTypes;
 import org.elasticsearch.xpack.sql.util.DateUtils;
 
 import java.io.IOException;
@@ -20,6 +23,13 @@ import java.time.ZoneId;
 import java.util.Map;
 import java.util.Objects;
 
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.INTRODUCING_UNSIGNED_LONG;
+import static org.elasticsearch.xpack.ql.type.DataTypeConverter.toUnsignedLong;
+import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
+import static org.elasticsearch.xpack.ql.type.DataTypes.NULL;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
+import static org.elasticsearch.xpack.sql.type.SqlDataTypes.isDateBased;
+
 public class CompositeKeyExtractor implements BucketExtractor {
 
     /**
@@ -30,22 +40,27 @@ public class CompositeKeyExtractor implements BucketExtractor {
     private final String key;
     private final Property property;
     private final ZoneId zoneId;
-    private final boolean isDateTimeBased;
+    private final DataType dataType;
 
     /**
      * Constructs a new <code>CompositeKeyExtractor</code> instance.
      */
-    public CompositeKeyExtractor(String key, Property property, ZoneId zoneId, boolean isDateTimeBased) {
+    public CompositeKeyExtractor(String key, Property property, ZoneId zoneId, DataType dataType) {
         this.key = key;
         this.property = property;
         this.zoneId = zoneId;
-        this.isDateTimeBased = isDateTimeBased;
+        this.dataType = dataType;
     }
 
     CompositeKeyExtractor(StreamInput in) throws IOException {
         key = in.readString();
         property = in.readEnum(Property.class);
-        isDateTimeBased = in.readBoolean();
+        if (in.getVersion().onOrAfter(Version.fromId(INTRODUCING_UNSIGNED_LONG.id))) {
+            dataType = SqlDataTypes.fromTypeName(in.readString());
+        } else {
+            // for pre-UNSIGNED_LONG versions, the only relevant fact about the dataType was if this isDateBased() or not.
+            dataType = in.readBoolean() ? DATETIME : NULL;
+        }
 
         zoneId = SqlStreamInput.asSqlStream(in).zoneId();
     }
@@ -54,7 +69,11 @@ public class CompositeKeyExtractor implements BucketExtractor {
     public void writeTo(StreamOutput out) throws IOException {
         out.writeString(key);
         out.writeEnum(property);
-        out.writeBoolean(isDateTimeBased);
+        if (out.getVersion().onOrAfter(Version.fromId(INTRODUCING_UNSIGNED_LONG.id))) {
+            out.writeString(dataType.typeName());
+        } else {
+            out.writeBoolean(isDateBased(dataType));
+        }
     }
 
     String key() {
@@ -69,8 +88,8 @@ public class CompositeKeyExtractor implements BucketExtractor {
         return zoneId;
     }
 
-    public boolean isDateTimeBased() {
-        return isDateTimeBased;
+    public DataType dataType() {
+        return dataType;
     }
 
     @Override
@@ -92,13 +111,21 @@ public class CompositeKeyExtractor implements BucketExtractor {
 
         Object object = ((Map<?, ?>) m).get(key);
 
-        if (isDateTimeBased) {
-            if (object == null) {
-                return object;
-            } else if (object instanceof Long) {
-                object = DateUtils.asDateTimeWithMillis(((Long) object).longValue(), zoneId);
-            } else {
-                throw new SqlIllegalArgumentException("Invalid date key returned: {}", object);
+        if (object != null) {
+            if (isDateBased(dataType)) {
+                if (object instanceof Long l) {
+                    object = DateUtils.asDateTimeWithMillis(l, zoneId);
+                } else {
+                    throw new SqlIllegalArgumentException("Invalid date key returned: {}", object);
+                }
+            } else if (dataType == UNSIGNED_LONG) {
+                // For integral types we coerce the bucket type to long in composite aggs (unsigned_long is not an available choice). So
+                // when getting back a long value, this needs to be type- and value-converted to an UNSIGNED_LONG
+                if (object instanceof Number number) {
+                    object = toUnsignedLong(number);
+                } else {
+                    throw new SqlIllegalArgumentException("Invalid unsigned_long key returned: {}", object);
+                }
             }
         }
 
@@ -107,7 +134,7 @@ public class CompositeKeyExtractor implements BucketExtractor {
 
     @Override
     public int hashCode() {
-        return Objects.hash(key, property, zoneId, isDateTimeBased);
+        return Objects.hash(key, property, zoneId, dataType);
     }
 
     @Override
@@ -124,7 +151,7 @@ public class CompositeKeyExtractor implements BucketExtractor {
         return Objects.equals(key, other.key)
             && Objects.equals(property, other.property)
             && Objects.equals(zoneId, other.zoneId)
-            && Objects.equals(isDateTimeBased, other.isDateTimeBased);
+            && Objects.equals(dataType, other.dataType);
     }
 
     @Override

+ 7 - 0
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/execution/search/extractor/FieldHitExtractor.java

@@ -26,6 +26,8 @@ import java.util.List;
 import java.util.Map;
 
 import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
+import static org.elasticsearch.xpack.sql.type.SqlDataTypeConverter.convert;
 import static org.elasticsearch.xpack.sql.type.SqlDataTypes.GEO_POINT;
 import static org.elasticsearch.xpack.sql.type.SqlDataTypes.GEO_SHAPE;
 import static org.elasticsearch.xpack.sql.type.SqlDataTypes.SHAPE;
@@ -126,6 +128,11 @@ public class FieldHitExtractor extends AbstractFieldHitExtractor {
                 return DateUtils.asDateTimeWithNanos(values.toString()).withZoneSameInstant(zoneId());
             }
         }
+        if (dataType == UNSIGNED_LONG) {
+            // Unsigned longs can be returned either as such (for values exceeding long range) or as longs. Value conversion is needed
+            // since its later processing will be type dependent. (ex.: negation of UL is only "safe" for 0 values)
+            return convert(values, UNSIGNED_LONG);
+        }
 
         return null;
     }

+ 12 - 0
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/execution/search/extractor/TopHitsAggExtractor.java

@@ -21,7 +21,9 @@ import java.io.IOException;
 import java.time.ZoneId;
 import java.util.Objects;
 
+import static org.elasticsearch.xpack.ql.type.DataTypeConverter.toUnsignedLong;
 import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.sql.type.SqlDataTypes.DATE;
 
 public class TopHitsAggExtractor implements BucketExtractor {
@@ -83,6 +85,16 @@ public class TopHitsAggExtractor implements BucketExtractor {
             return DateUtils.asDateTimeWithNanos(value.toString()).withZoneSameInstant(zoneId());
         } else if (SqlDataTypes.isTimeBased(fieldDataType)) {
             return DateUtils.asTimeOnly(Long.parseLong(value.toString()), zoneId);
+        } else if (fieldDataType == UNSIGNED_LONG) {
+            if (value == null) {
+                return null;
+            } else if (value instanceof Number number) {
+                // values can be returned either as unsigned_longs or longs (if range allows), which can lead to cast exceptions
+                // when sorting rows locally -> upcast to BigInteger
+                return toUnsignedLong(number);
+            } else {
+                throw new SqlIllegalArgumentException("Invalid unsigned_long key returned: {}", value);
+            }
         } else {
             return value;
         }

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

@@ -16,6 +16,7 @@ import java.util.List;
 
 import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE;
 import static org.elasticsearch.xpack.ql.type.DataTypes.LONG;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 
 /**
  * Sum all values of a field in matching documents.
@@ -38,7 +39,8 @@ public class Sum extends NumericAggregate implements EnclosedAgg {
 
     @Override
     public DataType dataType() {
-        return field().dataType().isInteger() ? LONG : DOUBLE;
+        DataType dt = field().dataType();
+        return dt.isInteger() == false || dt == UNSIGNED_LONG ? DOUBLE : LONG;
     }
 
     @Override

+ 7 - 0
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/math/MathProcessor.java

@@ -15,6 +15,7 @@ import org.elasticsearch.xpack.ql.type.DataTypeConverter;
 import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
 
 import java.io.IOException;
+import java.math.BigInteger;
 import java.util.Random;
 import java.util.function.DoubleFunction;
 import java.util.function.Function;
@@ -30,6 +31,9 @@ public class MathProcessor implements Processor {
             if (l instanceof Float) {
                 return Math.abs(((Float) l).floatValue());
             }
+            if (l instanceof BigInteger) {
+                return ((BigInteger) l).abs();
+            }
 
             // fallback to integer
             long lo = ((Number) l).longValue();
@@ -81,6 +85,9 @@ public class MathProcessor implements Processor {
             if (l instanceof Float) {
                 return (int) Math.signum((Float) l);
             }
+            if (l instanceof BigInteger) {
+                return ((BigInteger) l).signum();
+            }
 
             return Long.signum(((Number) l).longValue());
         }),

+ 7 - 2
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/optimizer/Optimizer.java

@@ -53,6 +53,7 @@ import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan;
 import org.elasticsearch.xpack.ql.rule.Rule;
 import org.elasticsearch.xpack.ql.rule.RuleExecutor;
 import org.elasticsearch.xpack.ql.tree.Source;
+import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypes;
 import org.elasticsearch.xpack.ql.util.Holder;
 import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
@@ -107,6 +108,7 @@ import static java.util.Collections.singletonList;
 import static org.elasticsearch.xpack.ql.expression.Expressions.equalsAsAttribute;
 import static org.elasticsearch.xpack.ql.optimizer.OptimizerRules.BinaryComparisonSimplification;
 import static org.elasticsearch.xpack.ql.optimizer.OptimizerRules.PushDownAndCombineFilters;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.ql.util.CollectionUtils.combine;
 
 public class Optimizer extends RuleExecutor<LogicalPlan> {
@@ -1149,12 +1151,15 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
             Map<Expression, TopHits> maxs = new HashMap<>();
             return plan.transformExpressionsDown(NumericAggregate.class, e -> {
                 if (e instanceof Min min) {
-                    if (DataTypes.isString(min.field().dataType())) {
+                    DataType minType = min.field().dataType();
+                    // upper range unsigned longs can't be represented exactly on doubles (returned by stats agg)
+                    if (DataTypes.isString(minType) || minType == UNSIGNED_LONG) {
                         return mins.computeIfAbsent(min.field(), k -> new First(min.source(), k, null));
                     }
                 }
                 if (e instanceof Max max) {
-                    if (DataTypes.isString(max.field().dataType())) {
+                    DataType maxType = max.field().dataType();
+                    if (DataTypes.isString(maxType) || maxType == UNSIGNED_LONG) {
                         return maxs.computeIfAbsent(max.field(), k -> new Last(max.source(), k, null));
                     }
                 }

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

@@ -714,22 +714,12 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
     @Override
     public Literal visitIntegerLiteral(IntegerLiteralContext ctx) {
         Tuple<Source, String> tuple = withMinus(ctx);
-
-        long value;
         try {
-            value = Long.valueOf(StringUtils.parseLong(tuple.v2()));
+            Number value = StringUtils.parseIntegral(tuple.v2());
+            return new Literal(tuple.v1(), value, DataTypes.fromJava(value));
         } catch (QlIllegalArgumentException siae) {
             throw new ParsingException(tuple.v1(), siae.getMessage());
         }
-
-        Object val = Long.valueOf(value);
-        DataType type = DataTypes.LONG;
-        // try to downsize to int if possible (since that's the most common type)
-        if ((int) value == value) {
-            type = DataTypes.INTEGER;
-            val = Integer.valueOf((int) value);
-        }
-        return new Literal(tuple.v1(), val, type);
     }
 
     @Override

+ 1 - 1
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/Explain.java

@@ -140,7 +140,7 @@ public class Explain extends Command {
             // check errors manually to see how far the plans work out
             else {
                 // no analysis failure, can move on
-                if (session.verifier().verifyFailures(analyzedPlan).isEmpty()) {
+                if (session.verifier().verifyFailures(analyzedPlan, session.configuration().version()).isEmpty()) {
                     session.optimizedPlan(analyzedPlan, wrap(optimizedPlan -> {
                         if (type == Type.OPTIMIZED) {
                             listener.onResponse(Page.last(Rows.singleton(output(), formatPlan(format, optimizedPlan))));

+ 5 - 2
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/ShowColumns.java

@@ -6,10 +6,12 @@
  */
 package org.elasticsearch.xpack.sql.plan.logical.command;
 
+import org.elasticsearch.Version;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.xpack.ql.expression.Attribute;
 import org.elasticsearch.xpack.ql.expression.FieldAttribute;
 import org.elasticsearch.xpack.ql.expression.predicate.regex.LikePattern;
+import org.elasticsearch.xpack.ql.index.IndexCompatibility;
 import org.elasticsearch.xpack.ql.tree.NodeInfo;
 import org.elasticsearch.xpack.ql.tree.Source;
 import org.elasticsearch.xpack.ql.type.DataType;
@@ -82,13 +84,14 @@ public class ShowColumns extends Command {
             List<List<?>> rows = emptyList();
             if (indexResult.isValid()) {
                 rows = new ArrayList<>();
-                fillInRows(indexResult.get().mapping(), null, rows);
+                Version version = Version.fromId(session.configuration().version().id);
+                fillInRows(IndexCompatibility.compatible(indexResult, version).get().mapping(), null, rows);
             }
             listener.onResponse(of(session, rows));
         }, listener::onFailure));
     }
 
-    private void fillInRows(Map<String, EsField> mapping, String prefix, List<List<?>> rows) {
+    static void fillInRows(Map<String, EsField> mapping, String prefix, List<List<?>> rows) {
         for (Entry<String, EsField> e : mapping.entrySet()) {
             EsField field = e.getValue();
             DataType dt = field.getDataType();

+ 13 - 2
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysColumns.java

@@ -7,11 +7,13 @@
 package org.elasticsearch.xpack.sql.plan.logical.command.sys;
 
 import org.apache.lucene.util.Counter;
+import org.elasticsearch.Version;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.xpack.ql.expression.Attribute;
 import org.elasticsearch.xpack.ql.expression.predicate.regex.LikePattern;
 import org.elasticsearch.xpack.ql.index.EsIndex;
+import org.elasticsearch.xpack.ql.index.IndexCompatibility;
 import org.elasticsearch.xpack.ql.tree.NodeInfo;
 import org.elasticsearch.xpack.ql.tree.Source;
 import org.elasticsearch.xpack.ql.type.DataType;
@@ -153,12 +155,14 @@ public class SysColumns extends Command {
             tableCat = cluster;
         }
 
+        Version version = Version.fromId(session.configuration().version().id);
         // special case for '%' (translated to *)
         if ("*".equals(idx)) {
             session.indexResolver()
                 .resolveAsSeparateMappings(indexPattern, regex, includeFrozen, emptyMap(), ActionListener.wrap(esIndices -> {
                     List<List<?>> rows = new ArrayList<>();
                     for (EsIndex esIndex : esIndices) {
+                        IndexCompatibility.compatible(esIndex, version);
                         fillInRows(tableCat, esIndex.name(), esIndex.mapping(), null, rows, columnMatcher, mode);
                     }
                     listener.onResponse(ListCursor.of(Rows.schema(output), rows, session.configuration().pageSize()));
@@ -170,8 +174,15 @@ public class SysColumns extends Command {
                 List<List<?>> rows = new ArrayList<>();
                 // populate the data only when a target is found
                 if (r.isValid()) {
-                    EsIndex esIndex = r.get();
-                    fillInRows(tableCat, indexName, esIndex.mapping(), null, rows, columnMatcher, mode);
+                    fillInRows(
+                        tableCat,
+                        indexName,
+                        IndexCompatibility.compatible(r, version).get().mapping(),
+                        null,
+                        rows,
+                        columnMatcher,
+                        mode
+                    );
                 }
                 listener.onResponse(ListCursor.of(Rows.schema(output), rows, session.configuration().pageSize()));
             }, listener::onFailure));

+ 6 - 2
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTypes.java

@@ -6,6 +6,7 @@
  */
 package org.elasticsearch.xpack.sql.plan.logical.command.sys;
 
+import org.elasticsearch.Version;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.xpack.ql.expression.Attribute;
 import org.elasticsearch.xpack.ql.tree.NodeInfo;
@@ -23,6 +24,7 @@ import java.util.stream.Stream;
 
 import static java.util.Arrays.asList;
 import static java.util.stream.Collectors.toList;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.isTypeSupportedInVersion;
 import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN;
 import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER;
 import static org.elasticsearch.xpack.ql.type.DataTypes.SHORT;
@@ -83,7 +85,9 @@ public class SysTypes extends Command {
 
     @Override
     public final void execute(SqlSession session, ActionListener<Page> listener) {
-        Stream<DataType> values = SqlDataTypes.types().stream();
+        Stream<DataType> values = SqlDataTypes.types()
+            .stream()
+            .filter(t -> isTypeSupportedInVersion(t, Version.fromId(session.configuration().version().id)));
         if (type.intValue() != 0) {
             values = values.filter(t -> type.equals(sqlType(t).getVendorTypeNumber()));
         }
@@ -106,7 +110,7 @@ public class SysTypes extends Command {
                     isString(t),
                     // everything is searchable,
                     DatabaseMetaData.typeSearchable,
-                    // only numerics are signed
+                    // only numerics (sans UNSIGNED_LONG) are signed
                     isSigned(t) == false,
                     // no fixed precision scale SQL_FALSE
                     Boolean.FALSE,

+ 10 - 25
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/planner/QueryFolder.java

@@ -40,6 +40,7 @@ import org.elasticsearch.xpack.ql.querydsl.container.Sort.Missing;
 import org.elasticsearch.xpack.ql.querydsl.query.Query;
 import org.elasticsearch.xpack.ql.rule.Rule;
 import org.elasticsearch.xpack.ql.rule.RuleExecutor;
+import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypes;
 import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
 import org.elasticsearch.xpack.sql.expression.function.Score;
@@ -95,6 +96,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicReference;
 
+import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
 import static org.elasticsearch.xpack.ql.util.CollectionUtils.combine;
 import static org.elasticsearch.xpack.sql.expression.function.grouping.Histogram.DAY_INTERVAL;
 import static org.elasticsearch.xpack.sql.expression.function.grouping.Histogram.MONTH_INTERVAL;
@@ -554,7 +556,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
                             if (matchingGroup != null) {
                                 if (exp instanceof Attribute || exp instanceof ScalarFunction || exp instanceof GroupingFunction) {
                                     Processor action = null;
-                                    boolean isDateBased = isDateBased(exp.dataType());
+                                    DataType dataType = exp.dataType();
                                     /*
                                      * special handling of dates since aggs return the typed Date object which needs
                                      * extraction instead of handling this in the scroller, the folder handles this
@@ -562,14 +564,9 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
                                      */
                                     if (exp instanceof DateTimeHistogramFunction) {
                                         action = ((UnaryPipe) p).action();
-                                        isDateBased = true;
+                                        dataType = DATETIME;
                                     }
-                                    return new AggPathInput(
-                                        exp.source(),
-                                        exp,
-                                        new GroupByRef(matchingGroup.id(), null, isDateBased),
-                                        action
-                                    );
+                                    return new AggPathInput(exp.source(), exp, new GroupByRef(matchingGroup.id(), null, dataType), action);
                                 }
                             }
                             // or found an aggregate expression (which has to work on an attribute used for grouping)
@@ -607,19 +604,11 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
                         // attributes can only refer to declared groups
                         if (target instanceof Attribute) {
                             Check.notNull(matchingGroup, "Cannot find group [{}]", Expressions.name(target));
-                            queryC = queryC.addColumn(
-                                new GroupByRef(matchingGroup.id(), null, isDateBased(target.dataType())),
-                                id,
-                                ne.toAttribute()
-                            );
+                            queryC = queryC.addColumn(new GroupByRef(matchingGroup.id(), null, target.dataType()), id, ne.toAttribute());
                         }
                         // handle histogram
                         else if (target instanceof GroupingFunction) {
-                            queryC = queryC.addColumn(
-                                new GroupByRef(matchingGroup.id(), null, isDateBased(target.dataType())),
-                                id,
-                                ne.toAttribute()
-                            );
+                            queryC = queryC.addColumn(new GroupByRef(matchingGroup.id(), null, target.dataType()), id, ne.toAttribute());
                         }
                         // handle literal
                         else if (target.foldable()) {
@@ -650,11 +639,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
                         matchingGroup = groupingContext.groupFor(target);
                         Check.notNull(matchingGroup, "Cannot find group [{}]", Expressions.name(ne));
 
-                        queryC = queryC.addColumn(
-                            new GroupByRef(matchingGroup.id(), null, isDateBased(ne.dataType())),
-                            id,
-                            ne.toAttribute()
-                        );
+                        queryC = queryC.addColumn(new GroupByRef(matchingGroup.id(), null, ne.dataType()), id, ne.toAttribute());
                     }
                     // fallback
                     else {
@@ -667,7 +652,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
             if (a.aggregates().stream().allMatch(e -> e.anyMatch(Expression::foldable))) {
                 for (Expression grouping : a.groupings()) {
                     GroupByKey matchingGroup = groupingContext.groupFor(grouping);
-                    queryC = queryC.addColumn(new GroupByRef(matchingGroup.id(), null, false), id, null);
+                    queryC = queryC.addColumn(new GroupByRef(matchingGroup.id(), null, grouping.dataType()), id, null);
                 }
             }
             return new EsQueryExec(exec.source(), exec.index(), a.output(), queryC);
@@ -692,7 +677,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
                         // if the count points to the total track hits, enable accurate count retrieval
                         queryC = queryC.withTrackHits();
                     } else {
-                        ref = new GroupByRef(groupingAgg.id(), Property.COUNT, false);
+                        ref = new GroupByRef(groupingAgg.id(), Property.COUNT, c.dataType());
                     }
 
                     Map<String, GroupByKey> pseudoFunctions = new LinkedHashMap<>(queryC.pseudoFunctions());

+ 6 - 5
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/container/GroupByRef.java

@@ -7,6 +7,7 @@
 package org.elasticsearch.xpack.sql.querydsl.container;
 
 import org.elasticsearch.xpack.ql.execution.search.AggRef;
+import org.elasticsearch.xpack.ql.type.DataType;
 
 /**
  * Reference to a GROUP BY agg (typically this gets translated to a composite key).
@@ -20,12 +21,12 @@ public class GroupByRef extends AggRef {
 
     private final String key;
     private final Property property;
-    private final boolean isDateTimeBased;
+    private final DataType dataType;
 
-    public GroupByRef(String key, Property property, boolean isDateTimeBased) {
+    public GroupByRef(String key, Property property, DataType dataType) {
         this.key = key;
         this.property = property == null ? Property.VALUE : property;
-        this.isDateTimeBased = isDateTimeBased;
+        this.dataType = dataType;
     }
 
     public String key() {
@@ -36,8 +37,8 @@ public class GroupByRef extends AggRef {
         return property;
     }
 
-    public boolean isDateTimeBased() {
-        return isDateTimeBased;
+    public DataType dataType() {
+        return dataType;
     }
 
     @Override

+ 9 - 2
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/session/SqlSession.java

@@ -6,11 +6,13 @@
  */
 package org.elasticsearch.xpack.sql.session;
 
+import org.elasticsearch.Version;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.client.internal.Client;
 import org.elasticsearch.client.internal.ParentTaskAssigningClient;
 import org.elasticsearch.tasks.TaskCancelledException;
 import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry;
+import org.elasticsearch.xpack.ql.index.IndexCompatibility;
 import org.elasticsearch.xpack.ql.index.IndexResolution;
 import org.elasticsearch.xpack.ql.index.IndexResolver;
 import org.elasticsearch.xpack.ql.index.MappingException;
@@ -113,8 +115,13 @@ public class SqlSession implements Session {
             return;
         }
 
-        preAnalyze(parsed, c -> {
-            Analyzer analyzer = new Analyzer(configuration, functionRegistry, c, verifier);
+        preAnalyze(parsed, r -> {
+            Analyzer analyzer = new Analyzer(
+                configuration,
+                functionRegistry,
+                IndexCompatibility.compatible(r, Version.fromId(configuration.version().id)),
+                verifier
+            );
             return analyzer.analyze(parsed, verify);
         }, listener);
     }

+ 19 - 20
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverter.java

@@ -9,7 +9,6 @@ package org.elasticsearch.xpack.sql.type;
 
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
 import org.elasticsearch.xpack.ql.type.Converter;
 import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypeConverter;
@@ -21,7 +20,6 @@ import org.elasticsearch.xpack.sql.util.DateUtils;
 import java.io.IOException;
 import java.time.OffsetTime;
 import java.time.ZonedDateTime;
-import java.time.format.DateTimeParseException;
 import java.util.function.Function;
 
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.BOOL_TO_INT;
@@ -32,10 +30,12 @@ import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.DATETIME_TO_INT;
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.DATETIME_TO_LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.DATETIME_TO_SHORT;
+import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.DATETIME_TO_UNSIGNED_LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.IDENTITY;
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.INTEGER_TO_LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.RATIONAL_TO_LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.TO_NULL;
+import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.fromString;
 import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN;
 import static org.elasticsearch.xpack.ql.type.DataTypes.BYTE;
 import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
@@ -47,6 +47,7 @@ import static org.elasticsearch.xpack.ql.type.DataTypes.LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypes.NULL;
 import static org.elasticsearch.xpack.ql.type.DataTypes.SHORT;
 import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypes.isDateTime;
 import static org.elasticsearch.xpack.ql.type.DataTypes.isPrimitive;
 import static org.elasticsearch.xpack.ql.type.DataTypes.isString;
@@ -82,17 +83,11 @@ public final class SqlDataTypeConverter {
             return DATETIME;
         }
         if (left == TIME) {
-            if (right == DATE) {
-                return DATETIME;
-            }
             if (isInterval(right)) {
                 return left;
             }
         }
         if (right == TIME) {
-            if (left == DATE) {
-                return DATETIME;
-            }
             if (isInterval(left)) {
                 return right;
             }
@@ -165,6 +160,9 @@ public final class SqlDataTypeConverter {
             if (to == KEYWORD || to == TEXT) {
                 return conversionToString(from);
             }
+            if (to == UNSIGNED_LONG) {
+                return conversionToUnsignedLong(from);
+            }
             if (to == LONG) {
                 return conversionToLong(from);
             }
@@ -204,6 +202,16 @@ public final class SqlDataTypeConverter {
         return null;
     }
 
+    private static Converter conversionToUnsignedLong(DataType from) {
+        if (from == DATE) {
+            return SqlConverter.DATE_TO_UNSIGNED_LONG;
+        }
+        if (from == TIME) {
+            return SqlConverter.TIME_TO_UNSIGNED_LONG;
+        }
+        return null;
+    }
+
     private static Converter conversionToLong(DataType from) {
         if (from == DATE) {
             return SqlConverter.DATE_TO_LONG;
@@ -351,6 +359,9 @@ public final class SqlDataTypeConverter {
         DATE_TO_STRING(o -> DateUtils.toDateString((ZonedDateTime) o)),
         TIME_TO_STRING(o -> DateUtils.toTimeString((OffsetTime) o)),
 
+        DATE_TO_UNSIGNED_LONG(delegate(DATETIME_TO_UNSIGNED_LONG)),
+        TIME_TO_UNSIGNED_LONG(fromTime(DataTypeConverter::safeToUnsignedLong)),
+
         DATE_TO_LONG(delegate(DATETIME_TO_LONG)),
         TIME_TO_LONG(fromTime(value -> value)),
 
@@ -419,18 +430,6 @@ public final class SqlDataTypeConverter {
             return converter::convert;
         }
 
-        private static Function<Object, Object> fromString(Function<String, Object> converter, String to) {
-            return (Object value) -> {
-                try {
-                    return converter.apply(value.toString());
-                } catch (NumberFormatException e) {
-                    throw new QlIllegalArgumentException(e, "cannot cast [{}] to [{}]", value, to);
-                } catch (DateTimeParseException | IllegalArgumentException e) {
-                    throw new QlIllegalArgumentException(e, "cannot cast [{}] to [{}]: {}", value, to, e.getMessage());
-                }
-            };
-        }
-
         @Override
         public Object convert(Object l) {
             if (l == null) {

+ 9 - 1
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypes.java

@@ -46,6 +46,7 @@ import static org.elasticsearch.xpack.ql.type.DataTypes.OBJECT;
 import static org.elasticsearch.xpack.ql.type.DataTypes.SCALED_FLOAT;
 import static org.elasticsearch.xpack.ql.type.DataTypes.SHORT;
 import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypes.UNSUPPORTED;
 import static org.elasticsearch.xpack.ql.type.DataTypes.isDateTime;
 import static org.elasticsearch.xpack.ql.util.CollectionUtils.mapSize;
@@ -98,6 +99,7 @@ public class SqlDataTypes {
         ODBC_TO_ES.put("SQL_SMALLINT", SHORT);
         ODBC_TO_ES.put("SQL_INTEGER", INTEGER);
         ODBC_TO_ES.put("SQL_BIGINT", LONG);
+        ODBC_TO_ES.put("SQL_UBIGINT", UNSIGNED_LONG);
         ODBC_TO_ES.put("SQL_REAL", FLOAT);
         ODBC_TO_ES.put("SQL_FLOAT", DOUBLE);
         ODBC_TO_ES.put("SQL_DOUBLE", DOUBLE);
@@ -334,6 +336,9 @@ public class SqlDataTypes {
         if (dataType == LONG) {
             return JDBCType.BIGINT;
         }
+        if (dataType == UNSIGNED_LONG) {
+            return JDBCType.NUMERIC;
+        }
         if (dataType == DOUBLE) {
             return JDBCType.DOUBLE;
         }
@@ -457,6 +462,9 @@ public class SqlDataTypes {
         if (dataType == LONG) {
             return 19;
         }
+        if (dataType == UNSIGNED_LONG) {
+            return 20;
+        }
         if (dataType == DOUBLE) {
             return 15;
         }
@@ -574,7 +582,7 @@ public class SqlDataTypes {
         if (dataType == INTEGER) {
             return 11;
         }
-        if (dataType == LONG) {
+        if (dataType == LONG || dataType == UNSIGNED_LONG) {
             return 20;
         }
         if (dataType == DOUBLE) {

+ 165 - 9
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/FieldAttributeTests.java

@@ -6,7 +6,10 @@
  */
 package org.elasticsearch.xpack.sql.analysis.analyzer;
 
+import org.elasticsearch.Version;
+import org.elasticsearch.common.xcontent.XContentHelper;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xcontent.json.JsonXContent;
 import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
 import org.elasticsearch.xpack.ql.expression.Alias;
 import org.elasticsearch.xpack.ql.expression.Attribute;
@@ -16,15 +19,21 @@ import org.elasticsearch.xpack.ql.expression.FieldAttribute;
 import org.elasticsearch.xpack.ql.expression.NamedExpression;
 import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry;
 import org.elasticsearch.xpack.ql.index.EsIndex;
+import org.elasticsearch.xpack.ql.index.IndexCompatibility;
 import org.elasticsearch.xpack.ql.index.IndexResolution;
 import org.elasticsearch.xpack.ql.plan.logical.Aggregate;
 import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
 import org.elasticsearch.xpack.ql.plan.logical.Project;
+import org.elasticsearch.xpack.ql.type.DataType;
+import org.elasticsearch.xpack.ql.type.DefaultDataTypeRegistry;
 import org.elasticsearch.xpack.ql.type.EsField;
+import org.elasticsearch.xpack.ql.type.Types;
 import org.elasticsearch.xpack.ql.type.TypesTests;
 import org.elasticsearch.xpack.sql.SqlTestUtils;
 import org.elasticsearch.xpack.sql.expression.function.SqlFunctionRegistry;
 import org.elasticsearch.xpack.sql.parser.SqlParser;
+import org.elasticsearch.xpack.sql.proto.SqlVersion;
+import org.elasticsearch.xpack.sql.session.SqlConfiguration;
 import org.elasticsearch.xpack.sql.stats.Metrics;
 
 import java.util.Collections;
@@ -32,12 +41,16 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.INTRODUCING_UNSIGNED_LONG;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.isTypeSupportedInVersion;
 import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN;
 import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD;
 import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.sql.types.SqlTypesTests.loadMapping;
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.hasItem;
 import static org.hamcrest.Matchers.hasItems;
 import static org.hamcrest.Matchers.hasSize;
@@ -169,7 +182,7 @@ public class FieldAttributeTests extends ESTestCase {
     public void testStarExpansionExcludesObjectAndUnsupportedTypes() {
         LogicalPlan plan = plan("SELECT * FROM test");
         List<? extends NamedExpression> list = ((Project) plan).projections();
-        assertThat(list, hasSize(12));
+        assertThat(list, hasSize(13));
         List<String> names = Expressions.names(list);
         assertThat(names, not(hasItem("some")));
         assertThat(names, not(hasItem("some.dotted")));
@@ -295,11 +308,139 @@ public class FieldAttributeTests extends ESTestCase {
         assertEquals(expected, ex.getMessage());
     }
 
+    public void testUnsignedLongVersionCompatibility() {
+        String query = "SELECT unsigned_long FROM test";
+        String queryWithLiteral = "SELECT 18446744073709551615 AS unsigned_long";
+        String queryWithCastLiteral = "SELECT '18446744073709551615'::unsigned_long AS unsigned_long";
+        String queryWithAlias = "SELECT unsigned_long AS unsigned_long FROM test";
+        String queryWithArithmetic = "SELECT unsigned_long + 1 AS unsigned_long FROM test";
+        String queryWithCast = "SELECT long + 1::unsigned_long AS unsigned_long FROM test";
+
+        Version preUnsignedLong = Version.fromId(INTRODUCING_UNSIGNED_LONG.id - SqlVersion.MINOR_MULTIPLIER);
+        Version postUnsignedLong = Version.fromId(INTRODUCING_UNSIGNED_LONG.id + SqlVersion.MINOR_MULTIPLIER);
+        SqlConfiguration sqlConfig = SqlTestUtils.randomConfiguration(SqlVersion.fromId(preUnsignedLong.id));
+
+        for (String sql : List.of(query, queryWithLiteral, queryWithCastLiteral, queryWithAlias, queryWithArithmetic, queryWithCast)) {
+            analyzer = new Analyzer(
+                sqlConfig,
+                functionRegistry,
+                loadCompatibleIndexResolution("mapping-numeric.json", preUnsignedLong),
+                new Verifier(new Metrics())
+            );
+            VerificationException ex = expectThrows(VerificationException.class, () -> plan(sql));
+            assertThat(ex.getMessage(), containsString("Found 1 problem\nline 1:8: Cannot use field [unsigned_long]"));
+
+            for (Version v : List.of(INTRODUCING_UNSIGNED_LONG, postUnsignedLong)) {
+                analyzer = new Analyzer(
+                    SqlTestUtils.randomConfiguration(SqlVersion.fromId(v.id)),
+                    functionRegistry,
+                    loadCompatibleIndexResolution("mapping-numeric.json", v),
+                    verifier
+                );
+                LogicalPlan plan = plan(sql);
+                assertThat(plan, instanceOf(Project.class));
+                Project p = (Project) plan;
+                List<? extends NamedExpression> projections = p.projections();
+                assertThat(projections, hasSize(1));
+                Attribute attribute = projections.get(0).toAttribute();
+                assertThat(attribute.dataType(), is(UNSIGNED_LONG));
+                assertThat(attribute.name(), is("unsigned_long"));
+            }
+        }
+    }
+
+    public void testNonProjectedUnsignedLongVersionCompatibility() {
+        Version preUnsignedLong = Version.fromId(INTRODUCING_UNSIGNED_LONG.id - SqlVersion.MINOR_MULTIPLIER);
+        SqlConfiguration sqlConfig = SqlTestUtils.randomConfiguration(SqlVersion.fromId(preUnsignedLong.id));
+        analyzer = new Analyzer(
+            sqlConfig,
+            functionRegistry,
+            loadCompatibleIndexResolution("mapping-numeric.json", preUnsignedLong),
+            new Verifier(new Metrics())
+        );
+
+        String query = "SELECT unsigned_long = 1, unsigned_long::double FROM test";
+        String queryWithSubquery = "SELECT l = 1, SQRT(ul) FROM "
+            + "(SELECT unsigned_long AS ul, long AS l FROM test WHERE ul > 10) WHERE l < 100 ";
+
+        for (String sql : List.of(query, queryWithSubquery)) {
+            VerificationException ex = expectThrows(VerificationException.class, () -> plan(sql));
+            assertThat(ex.getMessage(), containsString("Cannot use field [unsigned_long] with unsupported type [UNSIGNED_LONG]"));
+        }
+    }
+
+    public void testNestedUnsignedLongVersionCompatibility() {
+        String props = """
+            {
+                "properties": {
+                    "container": {
+                        "properties": {
+                            "ul": {
+                                "type": "unsigned_long"
+                            }
+                        }
+                    }
+                }
+            }
+            """;
+        String sql = "SELECT container.ul as unsigned_long FROM test";
+
+        Version preUnsignedLong = Version.fromId(INTRODUCING_UNSIGNED_LONG.id - SqlVersion.MINOR_MULTIPLIER);
+        analyzer = new Analyzer(
+            SqlTestUtils.randomConfiguration(SqlVersion.fromId(preUnsignedLong.id)),
+            functionRegistry,
+            compatibleIndexResolution(props, preUnsignedLong),
+            new Verifier(new Metrics())
+        );
+        VerificationException ex = expectThrows(VerificationException.class, () -> plan(sql));
+        assertThat(ex.getMessage(), containsString("Cannot use field [container.ul] with unsupported type [UNSIGNED_LONG]"));
+
+        Version postUnsignedLong = Version.fromId(INTRODUCING_UNSIGNED_LONG.id + SqlVersion.MINOR_MULTIPLIER);
+        for (Version v : List.of(INTRODUCING_UNSIGNED_LONG, postUnsignedLong)) {
+            analyzer = new Analyzer(
+                SqlTestUtils.randomConfiguration(SqlVersion.fromId(v.id)),
+                functionRegistry,
+                compatibleIndexResolution(props, v),
+                verifier
+            );
+            LogicalPlan plan = plan(sql);
+            assertThat(plan, instanceOf(Project.class));
+            Project p = (Project) plan;
+            List<? extends NamedExpression> projections = p.projections();
+            assertThat(projections, hasSize(1));
+            Attribute attribute = projections.get(0).toAttribute();
+            assertThat(attribute.dataType(), is(UNSIGNED_LONG));
+            assertThat(attribute.name(), is("unsigned_long"));
+        }
+    }
+
+    public void testUnsignedLongStarExpandedVersionControlled() {
+        SqlVersion preUnsignedLong = SqlVersion.fromId(INTRODUCING_UNSIGNED_LONG.id - SqlVersion.MINOR_MULTIPLIER);
+        SqlVersion postUnsignedLong = SqlVersion.fromId(INTRODUCING_UNSIGNED_LONG.id + SqlVersion.MINOR_MULTIPLIER);
+        String query = "SELECT * FROM test";
+
+        for (SqlVersion version : List.of(preUnsignedLong, SqlVersion.fromId(INTRODUCING_UNSIGNED_LONG.id), postUnsignedLong)) {
+            SqlConfiguration config = SqlTestUtils.randomConfiguration(version);
+            // the mapping is mutated when making it "compatible", so it needs to be reloaded inside the loop.
+            analyzer = new Analyzer(
+                config,
+                functionRegistry,
+                loadCompatibleIndexResolution("mapping-numeric.json", Version.fromId(version.id)),
+                new Verifier(new Metrics())
+            );
+
+            LogicalPlan plan = plan(query);
+            assertThat(plan, instanceOf(Project.class));
+            Project p = (Project) plan;
+
+            List<DataType> projectedDataTypes = p.projections().stream().map(Expression::dataType).toList();
+            assertEquals(isTypeSupportedInVersion(UNSIGNED_LONG, Version.fromId(version.id)), projectedDataTypes.contains(UNSIGNED_LONG));
+        }
+
+    }
+
     public void testFunctionOverNonExistingFieldAsArgumentAndSameAlias() throws Exception {
-        Map<String, EsField> mapping = TypesTests.loadMapping("mapping-basic.json");
-        EsIndex index = new EsIndex("test", mapping);
-        getIndexResult = IndexResolution.valid(index);
-        analyzer = new Analyzer(SqlTestUtils.TEST_CFG, functionRegistry, getIndexResult, verifier);
+        analyzer = new Analyzer(SqlTestUtils.TEST_CFG, functionRegistry, loadIndexResolution("mapping-basic.json"), verifier);
 
         VerificationException ex = expectThrows(
             VerificationException.class,
@@ -309,10 +450,7 @@ public class FieldAttributeTests extends ESTestCase {
     }
 
     public void testFunctionWithExpressionOverNonExistingFieldAsArgumentAndSameAlias() throws Exception {
-        Map<String, EsField> mapping = TypesTests.loadMapping("mapping-basic.json");
-        EsIndex index = new EsIndex("test", mapping);
-        getIndexResult = IndexResolution.valid(index);
-        analyzer = new Analyzer(SqlTestUtils.TEST_CFG, functionRegistry, getIndexResult, verifier);
+        analyzer = new Analyzer(SqlTestUtils.TEST_CFG, functionRegistry, loadIndexResolution("mapping-basic.json"), verifier);
 
         VerificationException ex = expectThrows(
             VerificationException.class,
@@ -332,4 +470,22 @@ public class FieldAttributeTests extends ESTestCase {
         assertTrue(((Project) plan).projections().isEmpty());
     }
 
+    private static IndexResolution loadIndexResolution(String mappingName) {
+        Map<String, EsField> mapping = TypesTests.loadMapping(mappingName);
+        EsIndex index = new EsIndex("test", mapping);
+        return IndexResolution.valid(index);
+    }
+
+    private static IndexResolution loadCompatibleIndexResolution(String mappingName, Version version) {
+        return IndexCompatibility.compatible(loadIndexResolution(mappingName), version);
+    }
+
+    private static IndexResolution compatibleIndexResolution(String properties, Version version) {
+        Map<String, EsField> mapping = Types.fromEs(
+            DefaultDataTypeRegistry.INSTANCE,
+            XContentHelper.convertToMap(JsonXContent.jsonXContent, properties, randomBoolean())
+        );
+        EsIndex index = new EsIndex("test", mapping);
+        return IndexCompatibility.compatible(IndexResolution.valid(index), version);
+    }
 }

+ 14 - 0
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/VerifierErrorMessagesTests.java

@@ -1457,6 +1457,20 @@ public class VerifierErrorMessagesTests extends ESTestCase {
         );
     }
 
+    public void testMinOnUnsignedLongGroupByHavingUnsupported() {
+        assertEquals(
+            "1:62: HAVING filter is unsupported for function [MIN(unsigned_long)]",
+            error("SELECT MIN(unsigned_long) min FROM test GROUP BY text HAVING min > 10")
+        );
+    }
+
+    public void testMaxOnUnsignedLongGroupByHavingUnsupported() {
+        assertEquals(
+            "1:62: HAVING filter is unsupported for function [MAX(unsigned_long)]",
+            error("SELECT MAX(unsigned_long) max FROM test GROUP BY text HAVING max > 10")
+        );
+    }
+
     public void testProjectAliasInFilter() {
         accept("SELECT int AS i FROM test WHERE i > 10");
     }

+ 30 - 7
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/CompositeKeyExtractorTests.java

@@ -14,24 +14,40 @@ import org.elasticsearch.xpack.ql.execution.search.extractor.BucketExtractor;
 import org.elasticsearch.xpack.sql.AbstractSqlWireSerializingTestCase;
 import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
 import org.elasticsearch.xpack.sql.querydsl.container.GroupByRef.Property;
+import org.elasticsearch.xpack.sql.type.SqlDataTypes;
 import org.elasticsearch.xpack.sql.util.DateUtils;
 
+import java.math.BigInteger;
 import java.time.ZoneId;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
 import static java.util.Collections.emptyMap;
 import static java.util.Collections.singletonMap;
+import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
+import static org.elasticsearch.xpack.ql.type.DataTypes.NULL;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
+import static org.elasticsearch.xpack.ql.util.NumericUtils.UNSIGNED_LONG_MAX;
 import static org.elasticsearch.xpack.sql.util.DateUtils.UTC;
 
 public class CompositeKeyExtractorTests extends AbstractSqlWireSerializingTestCase<CompositeKeyExtractor> {
 
     public static CompositeKeyExtractor randomCompositeKeyExtractor() {
-        return new CompositeKeyExtractor(randomAlphaOfLength(16), randomFrom(asList(Property.values())), randomZone(), randomBoolean());
+        return new CompositeKeyExtractor(
+            randomAlphaOfLength(16),
+            randomFrom(asList(Property.values())),
+            randomZone(),
+            randomFrom(SqlDataTypes.types())
+        );
     }
 
     public static CompositeKeyExtractor randomCompositeKeyExtractor(ZoneId zoneId) {
-        return new CompositeKeyExtractor(randomAlphaOfLength(16), randomFrom(asList(Property.values())), zoneId, randomBoolean());
+        return new CompositeKeyExtractor(
+            randomAlphaOfLength(16),
+            randomFrom(asList(Property.values())),
+            zoneId,
+            randomFrom(SqlDataTypes.types())
+        );
     }
 
     @Override
@@ -55,18 +71,18 @@ public class CompositeKeyExtractorTests extends AbstractSqlWireSerializingTestCa
             instance.key() + "mutated",
             randomValueOtherThan(instance.property(), () -> randomFrom(Property.values())),
             randomValueOtherThan(instance.zoneId(), ESTestCase::randomZone),
-            instance.isDateTimeBased() == false
+            randomValueOtherThan(instance.dataType(), () -> randomFrom(SqlDataTypes.types()))
         );
     }
 
     public void testExtractBucketCount() {
         Bucket bucket = new TestBucket(emptyMap(), randomLong(), new Aggregations(emptyList()));
-        CompositeKeyExtractor extractor = new CompositeKeyExtractor(randomAlphaOfLength(16), Property.COUNT, randomZone(), false);
+        CompositeKeyExtractor extractor = new CompositeKeyExtractor(randomAlphaOfLength(16), Property.COUNT, randomZone(), NULL);
         assertEquals(bucket.getDocCount(), extractor.extract(bucket));
     }
 
     public void testExtractKey() {
-        CompositeKeyExtractor extractor = new CompositeKeyExtractor(randomAlphaOfLength(16), Property.VALUE, UTC, false);
+        CompositeKeyExtractor extractor = new CompositeKeyExtractor(randomAlphaOfLength(16), Property.VALUE, UTC, NULL);
 
         Object value = new Object();
         Bucket bucket = new TestBucket(singletonMap(extractor.key(), value), randomLong(), new Aggregations(emptyList()));
@@ -74,7 +90,7 @@ public class CompositeKeyExtractorTests extends AbstractSqlWireSerializingTestCa
     }
 
     public void testExtractDate() {
-        CompositeKeyExtractor extractor = new CompositeKeyExtractor(randomAlphaOfLength(16), Property.VALUE, randomZone(), true);
+        CompositeKeyExtractor extractor = new CompositeKeyExtractor(randomAlphaOfLength(16), Property.VALUE, randomZone(), DATETIME);
 
         long millis = System.currentTimeMillis();
         Bucket bucket = new TestBucket(singletonMap(extractor.key(), millis), randomLong(), new Aggregations(emptyList()));
@@ -82,7 +98,7 @@ public class CompositeKeyExtractorTests extends AbstractSqlWireSerializingTestCa
     }
 
     public void testExtractIncorrectDateKey() {
-        CompositeKeyExtractor extractor = new CompositeKeyExtractor(randomAlphaOfLength(16), Property.VALUE, randomZone(), true);
+        CompositeKeyExtractor extractor = new CompositeKeyExtractor(randomAlphaOfLength(16), Property.VALUE, randomZone(), DATETIME);
 
         Object value = new Object();
         Bucket bucket = new TestBucket(singletonMap(extractor.key(), value), randomLong(), new Aggregations(emptyList()));
@@ -90,6 +106,13 @@ public class CompositeKeyExtractorTests extends AbstractSqlWireSerializingTestCa
         assertEquals("Invalid date key returned: " + value, exception.getMessage());
     }
 
+    public void testExtractUnsignedLong() {
+        CompositeKeyExtractor extractor = new CompositeKeyExtractor(randomAlphaOfLength(16), Property.VALUE, randomZone(), UNSIGNED_LONG);
+        Long value = randomLong();
+        Bucket bucket = new TestBucket(singletonMap(extractor.key(), value), randomLong(), new Aggregations(emptyList()));
+        assertEquals(BigInteger.valueOf(value).and(UNSIGNED_LONG_MAX), extractor.extract(bucket));
+    }
+
     public static ZoneId extractZoneId(BucketExtractor extractor) {
         return extractor instanceof CompositeKeyExtractor ? ((CompositeKeyExtractor) extractor).zoneId() : null;
     }

+ 14 - 0
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/FieldHitExtractorTests.java

@@ -34,6 +34,7 @@ import static java.util.Collections.singletonList;
 import static java.util.Collections.singletonMap;
 import static org.elasticsearch.common.time.DateUtils.toMilliSeconds;
 import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.sql.type.SqlDataTypes.GEO_SHAPE;
 import static org.elasticsearch.xpack.sql.type.SqlDataTypes.SHAPE;
 import static org.elasticsearch.xpack.sql.util.DateUtils.UTC;
@@ -206,6 +207,19 @@ public class FieldHitExtractorTests extends AbstractSqlWireSerializingTestCase<F
         );
     }
 
+    public void testUnsignedLongExtraction() {
+        BigInteger bi = randomBigInteger();
+        Number number = bi.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0 ? bi.longValue() : bi;
+        Object value = randomBoolean() ? number.toString() : number;
+
+        String fieldName = randomAlphaOfLength(10);
+        DocumentField field = new DocumentField(fieldName, singletonList(value));
+        SearchHit hit = new SearchHit(1, null, singletonMap(fieldName, field), null);
+        FieldHitExtractor fe = new FieldHitExtractor(fieldName, UNSIGNED_LONG, randomZone(), randomBoolean());
+
+        assertEquals(bi, fe.extract(hit));
+    }
+
     private FieldHitExtractor getFieldHitExtractor(String fieldName) {
         return new FieldHitExtractor(fieldName, null, UTC);
     }

+ 11 - 0
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/TopHitsAggExtractorTests.java

@@ -23,6 +23,7 @@ import org.elasticsearch.xpack.sql.proto.StringUtils;
 import org.elasticsearch.xpack.sql.type.SqlDataTypes;
 import org.elasticsearch.xpack.sql.util.DateUtils;
 
+import java.math.BigInteger;
 import java.time.ZoneId;
 import java.util.Collections;
 
@@ -103,6 +104,16 @@ public class TopHitsAggExtractorTests extends AbstractSqlWireSerializingTestCase
         assertEquals(DateUtils.asDateTimeWithMillis(value, zoneId), extractor.extract(bucket));
     }
 
+    public void testExtractUnsignedLong() {
+        BigInteger bi = randomBigInteger();
+        Object value = bi.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0 ? bi.longValue() : bi;
+
+        TopHitsAggExtractor extractor = new TopHitsAggExtractor(randomAlphaOfLength(10), DataTypes.UNSIGNED_LONG, randomZone());
+        Aggregation agg = new InternalTopHits(extractor.name(), 0, 1, null, searchHitsOf(value), null);
+        Bucket bucket = new TestBucket(emptyMap(), 0, new Aggregations(singletonList(agg)));
+        assertEquals(bi, extractor.extract(bucket));
+    }
+
     private SearchHits searchHitsOf(Object value) {
         TotalHits totalHits = new TotalHits(10, TotalHits.Relation.EQUAL_TO);
         return new SearchHits(

+ 17 - 0
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/math/MathFunctionProcessorTests.java

@@ -12,6 +12,8 @@ import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
 import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation;
 
 import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Arrays;
 
 public class MathFunctionProcessorTests extends AbstractWireSerializingTestCase<MathProcessor> {
     public static MathProcessor randomMathFunctionProcessor() {
@@ -74,4 +76,19 @@ public class MathFunctionProcessorTests extends AbstractWireSerializingTestCase<
         assertEquals(4.0, proc.process(3.9));
         assertEquals(-12.0, proc.process(-12.1));
     }
+
+    public void testUnsignedLongAbs() {
+        MathProcessor proc = new MathProcessor(MathOperation.ABS);
+        BigInteger bi = randomBigInteger();
+        assertEquals(bi, proc.process(bi));
+    }
+
+    public void testUnsignedLongSign() {
+        MathProcessor proc = new MathProcessor(MathOperation.SIGN);
+        for (BigInteger bi : Arrays.asList(BigInteger.valueOf(randomNonNegativeLong()), BigInteger.ZERO)) {
+            Object val = proc.process(bi);
+            assertEquals(bi.intValue() == 0 ? 0 : 1, val);
+            assertTrue(val instanceof Integer);
+        }
+    }
 }

+ 55 - 49
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java

@@ -51,6 +51,7 @@ import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
 import org.elasticsearch.xpack.ql.plan.logical.OrderBy;
 import org.elasticsearch.xpack.ql.plan.logical.Project;
 import org.elasticsearch.xpack.ql.tree.Source;
+import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.ql.type.DataTypes;
 import org.elasticsearch.xpack.ql.type.EsField;
 import org.elasticsearch.xpack.ql.util.CollectionUtils;
@@ -143,6 +144,7 @@ import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
 import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER;
 import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD;
 import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.sql.SqlTestUtils.literal;
 import static org.elasticsearch.xpack.sql.type.SqlDataTypes.DATE;
 import static org.elasticsearch.xpack.sql.util.DateUtils.UTC;
@@ -873,60 +875,64 @@ public class OptimizerTests extends ESTestCase {
     }
 
     public void testTranslateMinToFirst() {
-        Min min1 = new Min(EMPTY, new FieldAttribute(EMPTY, "str", new EsField("str", KEYWORD, emptyMap(), true)));
-        Min min2 = new Min(EMPTY, getFieldAttribute());
+        for (DataType dataType : List.of(KEYWORD, UNSIGNED_LONG)) {
+            Min min1 = new Min(EMPTY, new FieldAttribute(EMPTY, "field", new EsField("field", dataType, emptyMap(), true)));
+            Min min2 = new Min(EMPTY, getFieldAttribute());
 
-        OrderBy plan = new OrderBy(
-            EMPTY,
-            new Aggregate(EMPTY, FROM(), emptyList(), asList(a("min1", min1), a("min2", min2))),
-            asList(
-                new Order(EMPTY, min1, OrderDirection.ASC, Order.NullsPosition.LAST),
-                new Order(EMPTY, min2, OrderDirection.ASC, Order.NullsPosition.LAST)
-            )
-        );
-        LogicalPlan result = new ReplaceMinMaxWithTopHits().apply(plan);
-        assertTrue(result instanceof OrderBy);
-        List<Order> order = ((OrderBy) result).order();
-        assertEquals(2, order.size());
-        assertEquals(First.class, order.get(0).child().getClass());
-        assertEquals(min2, order.get(1).child());
-        First first = (First) order.get(0).child();
-
-        assertTrue(((OrderBy) result).child() instanceof Aggregate);
-        List<? extends NamedExpression> aggregates = ((Aggregate) ((OrderBy) result).child()).aggregates();
-        assertEquals(2, aggregates.size());
-        assertEquals(Alias.class, aggregates.get(0).getClass());
-        assertEquals(Alias.class, aggregates.get(1).getClass());
-        assertSame(first, ((Alias) aggregates.get(0)).child());
-        assertEquals(min2, ((Alias) aggregates.get(1)).child());
+            OrderBy plan = new OrderBy(
+                EMPTY,
+                new Aggregate(EMPTY, FROM(), emptyList(), asList(a("min1", min1), a("min2", min2))),
+                asList(
+                    new Order(EMPTY, min1, OrderDirection.ASC, Order.NullsPosition.LAST),
+                    new Order(EMPTY, min2, OrderDirection.ASC, Order.NullsPosition.LAST)
+                )
+            );
+            LogicalPlan result = new ReplaceMinMaxWithTopHits().apply(plan);
+            assertTrue(result instanceof OrderBy);
+            List<Order> order = ((OrderBy) result).order();
+            assertEquals(2, order.size());
+            assertEquals(First.class, order.get(0).child().getClass());
+            assertEquals(min2, order.get(1).child());
+            First first = (First) order.get(0).child();
+
+            assertTrue(((OrderBy) result).child() instanceof Aggregate);
+            List<? extends NamedExpression> aggregates = ((Aggregate) ((OrderBy) result).child()).aggregates();
+            assertEquals(2, aggregates.size());
+            assertEquals(Alias.class, aggregates.get(0).getClass());
+            assertEquals(Alias.class, aggregates.get(1).getClass());
+            assertSame(first, ((Alias) aggregates.get(0)).child());
+            assertEquals(min2, ((Alias) aggregates.get(1)).child());
+        }
     }
 
     public void testTranslateMaxToLast() {
-        Max max1 = new Max(EMPTY, new FieldAttribute(EMPTY, "str", new EsField("str", KEYWORD, emptyMap(), true)));
-        Max max2 = new Max(EMPTY, getFieldAttribute());
+        for (DataType dataType : List.of(KEYWORD, UNSIGNED_LONG)) {
+            Max max1 = new Max(EMPTY, new FieldAttribute(EMPTY, "field", new EsField("field", dataType, emptyMap(), true)));
+            Max max2 = new Max(EMPTY, getFieldAttribute());
 
-        OrderBy plan = new OrderBy(
-            EMPTY,
-            new Aggregate(EMPTY, FROM(), emptyList(), asList(a("max1", max1), a("max2", max2))),
-            asList(
-                new Order(EMPTY, max1, OrderDirection.ASC, Order.NullsPosition.LAST),
-                new Order(EMPTY, max2, OrderDirection.ASC, Order.NullsPosition.LAST)
-            )
-        );
-        LogicalPlan result = new ReplaceMinMaxWithTopHits().apply(plan);
-        assertTrue(result instanceof OrderBy);
-        List<Order> order = ((OrderBy) result).order();
-        assertEquals(Last.class, order.get(0).child().getClass());
-        assertEquals(max2, order.get(1).child());
-        Last last = (Last) order.get(0).child();
-
-        assertTrue(((OrderBy) result).child() instanceof Aggregate);
-        List<? extends NamedExpression> aggregates = ((Aggregate) ((OrderBy) result).child()).aggregates();
-        assertEquals(2, aggregates.size());
-        assertEquals(Alias.class, aggregates.get(0).getClass());
-        assertEquals(Alias.class, aggregates.get(1).getClass());
-        assertSame(last, ((Alias) aggregates.get(0)).child());
-        assertEquals(max2, ((Alias) aggregates.get(1)).child());
+            OrderBy plan = new OrderBy(
+                EMPTY,
+                new Aggregate(EMPTY, FROM(), emptyList(), asList(a("max1", max1), a("max2", max2))),
+                asList(
+                    new Order(EMPTY, max1, OrderDirection.ASC, Order.NullsPosition.LAST),
+                    new Order(EMPTY, max2, OrderDirection.ASC, Order.NullsPosition.LAST)
+                )
+            );
+            LogicalPlan result = new ReplaceMinMaxWithTopHits().apply(plan);
+            assertTrue(result instanceof OrderBy);
+            List<Order> order = ((OrderBy) result).order();
+            assertEquals(Last.class, order.get(0).child().getClass());
+            assertEquals(max2, order.get(1).child());
+            Last last = (Last) order.get(0).child();
+
+            assertTrue(((OrderBy) result).child() instanceof Aggregate);
+            List<? extends NamedExpression> aggregates = ((Aggregate) ((OrderBy) result).child()).aggregates();
+            assertEquals(2, aggregates.size());
+            assertEquals(Alias.class, aggregates.get(0).getClass());
+            assertEquals(Alias.class, aggregates.get(1).getClass());
+            assertSame(last, ((Alias) aggregates.get(0)).child());
+            assertEquals(max2, ((Alias) aggregates.get(1)).child());
+        }
     }
 
     public void testSortAggregateOnOrderByWithTwoFields() {

+ 97 - 0
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/ShowColumnsTests.java

@@ -0,0 +1,97 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.sql.plan.logical.command;
+
+import org.elasticsearch.Version;
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.ql.index.IndexCompatibility;
+import org.elasticsearch.xpack.ql.type.EsField;
+import org.elasticsearch.xpack.sql.proto.SqlVersion;
+
+import java.sql.JDBCType;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.Arrays.asList;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.supportsUnsignedLong;
+import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN;
+import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
+import static org.elasticsearch.xpack.ql.type.DataTypes.FLOAT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER;
+import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD;
+import static org.elasticsearch.xpack.ql.type.DataTypes.NESTED;
+import static org.elasticsearch.xpack.ql.type.DataTypes.OBJECT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSUPPORTED;
+import static org.elasticsearch.xpack.sql.plan.logical.command.sys.SysColumnsTests.UNSIGNED_LONG_TEST_VERSIONS;
+import static org.elasticsearch.xpack.sql.type.SqlDataTypes.GEO_POINT;
+import static org.elasticsearch.xpack.sql.type.SqlDataTypes.GEO_SHAPE;
+import static org.elasticsearch.xpack.sql.types.SqlTypesTests.loadMapping;
+
+public class ShowColumnsTests extends ESTestCase {
+
+    public static final String JDBC_TYPE_GEOMETRY = "GEOMETRY";
+
+    public void testShowColumns() {
+        String prefix = "myIndex";
+        List<List<?>> rows = new ArrayList<>();
+        ShowColumns.fillInRows(loadMapping("mapping-multi-field-variation.json", true), prefix, rows);
+
+        List<List<?>> expect = asList(
+            asList("bool", JDBCType.BOOLEAN.getName(), BOOLEAN.typeName()),
+            asList("int", JDBCType.INTEGER.getName(), INTEGER.typeName()),
+            asList("unsigned_long", JDBCType.NUMERIC.getName(), UNSIGNED_LONG.typeName()),
+            asList("float", JDBCType.REAL.getName(), FLOAT.typeName()),
+            asList("text", JDBCType.VARCHAR.getName(), TEXT.typeName()),
+            asList("keyword", JDBCType.VARCHAR.getName(), KEYWORD.typeName()),
+            asList("date", JDBCType.TIMESTAMP.getName(), DATETIME.typeName()),
+            asList("date_nanos", JDBCType.TIMESTAMP.getName(), DATETIME.typeName()),
+            asList("unsupported", JDBCType.OTHER.getName(), UNSUPPORTED.typeName()),
+            asList("some", JDBCType.STRUCT.getName(), OBJECT.typeName()),
+            asList("some.dotted", JDBCType.STRUCT.getName(), OBJECT.typeName()),
+            asList("some.dotted.field", JDBCType.VARCHAR.getName(), KEYWORD.typeName()),
+            asList("some.string", JDBCType.VARCHAR.getName(), TEXT.typeName()),
+            asList("some.string.normalized", JDBCType.VARCHAR.getName(), KEYWORD.typeName()),
+            asList("some.string.typical", JDBCType.VARCHAR.getName(), KEYWORD.typeName()),
+            asList("some.ambiguous", JDBCType.VARCHAR.getName(), TEXT.typeName()),
+            asList("some.ambiguous.one", JDBCType.VARCHAR.getName(), KEYWORD.typeName()),
+            asList("some.ambiguous.two", JDBCType.VARCHAR.getName(), KEYWORD.typeName()),
+            asList("some.ambiguous.normalized", JDBCType.VARCHAR.getName(), KEYWORD.typeName()),
+            asList("foo_type", JDBCType.OTHER.getName(), UNSUPPORTED.typeName()),
+            asList("point", JDBC_TYPE_GEOMETRY, GEO_POINT.typeName()),
+            asList("shape", JDBC_TYPE_GEOMETRY, GEO_SHAPE.typeName()),
+            asList("nested", JDBCType.STRUCT.getName(), NESTED.typeName()),
+            asList("nested.point", JDBC_TYPE_GEOMETRY, GEO_POINT.typeName())
+        );
+
+        assertEquals(expect.size(), rows.size());
+        assertEquals(expect.get(0).size(), rows.get(0).size());
+
+        for (int i = 0; i < expect.size(); i++) {
+            List<?> expectedRow = expect.get(i);
+            List<?> receivedRow = rows.get(i);
+            assertEquals("Name mismatch in row " + i, prefix + "." + expectedRow.get(0), receivedRow.get(0));
+            assertEquals("Type mismatch in row " + i, expectedRow.get(1), receivedRow.get(1));
+            assertEquals("Mapping mismatch in row " + i, expectedRow.get(2), receivedRow.get(2));
+        }
+    }
+
+    public void testUnsignedLongFiltering() {
+        List<?> rowSupported = List.of("unsigned_long", "NUMERIC", "unsigned_long");
+        List<?> rowUnsupported = List.of("unsigned_long", "OTHER", "unsupported");
+        for (SqlVersion version : UNSIGNED_LONG_TEST_VERSIONS) {
+            List<List<?>> rows = new ArrayList<>();
+            // mapping's mutated by IndexCompatibility.compatible, needs to stay in the loop
+            Map<String, EsField> mapping = loadMapping("mapping-multi-field-variation.json", true);
+            ShowColumns.fillInRows(IndexCompatibility.compatible(mapping, Version.fromId(version.id)), null, rows);
+            assertTrue((supportsUnsignedLong(Version.fromId(version.id)) && rows.contains(rowSupported)) || rows.contains(rowUnsupported));
+        }
+    }
+}

+ 57 - 17
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysColumnsTests.java

@@ -12,6 +12,7 @@ import org.elasticsearch.core.Tuple;
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry;
 import org.elasticsearch.xpack.ql.index.EsIndex;
+import org.elasticsearch.xpack.ql.index.IndexCompatibility;
 import org.elasticsearch.xpack.ql.index.IndexResolution;
 import org.elasticsearch.xpack.ql.index.IndexResolver;
 import org.elasticsearch.xpack.ql.type.EsField;
@@ -38,11 +39,15 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 import static java.util.Collections.emptyList;
 import static java.util.Collections.singletonList;
 import static org.elasticsearch.action.ActionListener.wrap;
 import static org.elasticsearch.xpack.ql.TestUtils.UTC;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.INTRODUCING_UNSIGNED_LONG;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.isTypeSupportedInVersion;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.sql.proto.Mode.isDriver;
 import static org.elasticsearch.xpack.sql.types.SqlTypesTests.loadMapping;
 import static org.mockito.ArgumentMatchers.any;
@@ -53,11 +58,18 @@ import static org.mockito.Mockito.when;
 
 public class SysColumnsTests extends ESTestCase {
 
+    public static List<SqlVersion> UNSIGNED_LONG_TEST_VERSIONS = List.of(
+        SqlVersion.fromId(INTRODUCING_UNSIGNED_LONG.id - SqlVersion.MINOR_MULTIPLIER),
+        SqlVersion.fromId(INTRODUCING_UNSIGNED_LONG.id),
+        SqlVersion.fromId(INTRODUCING_UNSIGNED_LONG.id + SqlVersion.MINOR_MULTIPLIER),
+        SqlVersion.fromId(Version.CURRENT.id)
+    );
+
     private static final String CLUSTER_NAME = "cluster";
     private static final Map<String, EsField> MAPPING1 = loadMapping("mapping-multi-field-with-nested.json", true);
     private static final Map<String, EsField> MAPPING2 = loadMapping("mapping-multi-field-variation.json", true);
-    private static final int FIELD_COUNT1 = 19;
-    private static final int FIELD_COUNT2 = 17;
+    private static final int FIELD_COUNT1 = 20;
+    private static final int FIELD_COUNT2 = 18;
 
     private final SqlParser parser = new SqlParser();
 
@@ -68,49 +80,53 @@ public class SysColumnsTests extends ESTestCase {
         assertEquals(FIELD_COUNT2, rows.size());
         assertEquals(24, rows.get(0).size());
 
-        List<?> row = rows.get(0);
+        int index = 0;
+        List<?> row = rows.get(index++);
         assertDriverType("bool", Types.BOOLEAN, false, 1, 1, typeClass, row);
 
-        row = rows.get(1);
+        row = rows.get(index++);
         assertDriverType("int", Types.INTEGER, true, 11, 4, typeClass, row);
 
-        row = rows.get(2);
+        row = rows.get(index++);
+        assertDriverType("unsigned_long", Types.NUMERIC, true, 20, Long.BYTES, typeClass, row);
+
+        row = rows.get(index++);
         assertDriverType("float", Types.REAL, true, 15, 4, typeClass, row);
 
-        row = rows.get(3);
+        row = rows.get(index++);
         assertDriverType("text", Types.VARCHAR, false, Integer.MAX_VALUE, Integer.MAX_VALUE, typeClass, row);
 
-        row = rows.get(4);
+        row = rows.get(index++);
         assertDriverType("keyword", Types.VARCHAR, false, Short.MAX_VALUE - 1, Integer.MAX_VALUE, typeClass, row);
 
-        row = rows.get(5);
+        row = rows.get(index++);
         assertDriverType("date", Types.TIMESTAMP, false, 34, 8, typeClass, row);
 
-        row = rows.get(6);
+        row = rows.get(index++);
         assertDriverType("date_nanos", Types.TIMESTAMP, false, 34, 8, typeClass, row);
 
-        row = rows.get(7);
+        row = rows.get(index++);
         assertDriverType("some.dotted.field", Types.VARCHAR, false, Short.MAX_VALUE - 1, Integer.MAX_VALUE, typeClass, row);
 
-        row = rows.get(8);
+        row = rows.get(index++);
         assertDriverType("some.string", Types.VARCHAR, false, Integer.MAX_VALUE, Integer.MAX_VALUE, typeClass, row);
 
-        row = rows.get(9);
+        row = rows.get(index++);
         assertDriverType("some.string.normalized", Types.VARCHAR, false, Short.MAX_VALUE - 1, Integer.MAX_VALUE, typeClass, row);
 
-        row = rows.get(10);
+        row = rows.get(index++);
         assertDriverType("some.string.typical", Types.VARCHAR, false, Short.MAX_VALUE - 1, Integer.MAX_VALUE, typeClass, row);
 
-        row = rows.get(11);
+        row = rows.get(index++);
         assertDriverType("some.ambiguous", Types.VARCHAR, false, Integer.MAX_VALUE, Integer.MAX_VALUE, typeClass, row);
 
-        row = rows.get(12);
+        row = rows.get(index++);
         assertDriverType("some.ambiguous.one", Types.VARCHAR, false, Short.MAX_VALUE - 1, Integer.MAX_VALUE, typeClass, row);
 
-        row = rows.get(13);
+        row = rows.get(index++);
         assertDriverType("some.ambiguous.two", Types.VARCHAR, false, Short.MAX_VALUE - 1, Integer.MAX_VALUE, typeClass, row);
 
-        row = rows.get(14);
+        row = rows.get(index++);
         assertDriverType("some.ambiguous.normalized", Types.VARCHAR, false, Short.MAX_VALUE - 1, Integer.MAX_VALUE, typeClass, row);
     }
 
@@ -130,6 +146,30 @@ public class SysColumnsTests extends ESTestCase {
         }
     }
 
+    public void testUnsignedLongFiltering() {
+        for (Mode mode : List.of(Mode.JDBC, Mode.ODBC)) {
+            for (SqlVersion version : UNSIGNED_LONG_TEST_VERSIONS) {
+                List<List<?>> rows = new ArrayList<>();
+                // mapping's mutated by IndexCompatibility.compatible, needs to stay in the loop
+                Map<String, EsField> mapping = loadMapping("mapping-multi-field-variation.json", true);
+                SysColumns.fillInRows(
+                    "test",
+                    "index",
+                    IndexCompatibility.compatible(mapping, Version.fromId(version.id)),
+                    null,
+                    rows,
+                    null,
+                    mode
+                );
+                List<String> types = rows.stream().map(row -> name(row).toString()).collect(Collectors.toList());
+                assertEquals(
+                    isTypeSupportedInVersion(UNSIGNED_LONG, Version.fromId(version.id)),
+                    types.contains(UNSIGNED_LONG.toString().toLowerCase(Locale.ROOT))
+                );
+            }
+        }
+    }
+
     private static Object name(List<?> list) {
         return list.get(3);
     }

+ 27 - 0
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTypesTests.java

@@ -28,10 +28,16 @@ import org.elasticsearch.xpack.sql.types.SqlTypesTests;
 import org.elasticsearch.xpack.sql.util.DateUtils;
 
 import java.sql.JDBCType;
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import static java.util.Arrays.asList;
 import static org.elasticsearch.action.ActionListener.wrap;
+import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.isTypeSupportedInVersion;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
+import static org.elasticsearch.xpack.sql.plan.logical.command.sys.SysColumnsTests.UNSIGNED_LONG_TEST_VERSIONS;
 import static org.mockito.Mockito.mock;
 
 public class SysTypesTests extends ESTestCase {
@@ -78,6 +84,7 @@ public class SysTypesTests extends ESTestCase {
             "LONG",
             "BINARY",
             "NULL",
+            "UNSIGNED_LONG",
             "INTEGER",
             "SHORT",
             "HALF_FLOAT",
@@ -132,6 +139,26 @@ public class SysTypesTests extends ESTestCase {
         }, ex -> fail(ex.getMessage())));
     }
 
+    public void testUnsignedLongFiltering() {
+        Set<SqlVersion> versions = new HashSet<>(UNSIGNED_LONG_TEST_VERSIONS);
+        versions.add(null);
+        for (SqlVersion version : versions) {
+            for (Mode mode : Mode.values()) {
+                Tuple<Command, SqlSession> cmd = sql("SYS TYPES", mode, version);
+
+                cmd.v1().execute(cmd.v2(), wrap(p -> {
+                    SchemaRowSet r = (SchemaRowSet) p.rowSet();
+                    List<String> types = new ArrayList<>();
+                    r.forEachRow(rv -> types.add((String) rv.column(0)));
+                    assertEquals(
+                        isTypeSupportedInVersion(UNSIGNED_LONG, Version.fromId(cmd.v2().configuration().version().id)),
+                        types.contains(UNSIGNED_LONG.toString())
+                    );
+                }, ex -> fail(ex.getMessage())));
+            }
+        }
+    }
+
     public void testSysTypesDefaultFiltering() {
         Tuple<Command, SqlSession> cmd = sql("SYS TYPES 0");
 

+ 3 - 2
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorSpecTests.java

@@ -15,7 +15,6 @@ import org.elasticsearch.xpack.ql.index.EsIndex;
 import org.elasticsearch.xpack.ql.index.IndexResolution;
 import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
 import org.elasticsearch.xpack.ql.type.EsField;
-import org.elasticsearch.xpack.sql.SqlTestUtils;
 import org.elasticsearch.xpack.sql.analysis.analyzer.Analyzer;
 import org.elasticsearch.xpack.sql.analysis.analyzer.Verifier;
 import org.elasticsearch.xpack.sql.expression.function.SqlFunctionRegistry;
@@ -33,6 +32,8 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
+import static org.elasticsearch.xpack.sql.SqlTestUtils.TEST_CFG;
+
 public class QueryTranslatorSpecTests extends ESTestCase {
 
     private static final List<String> TEST_FILENAMES = List.of("querytranslator_tests.txt", "querytranslator_subqueries_tests.txt");
@@ -48,7 +49,7 @@ public class QueryTranslatorSpecTests extends ESTestCase {
             Map<String, EsField> mapping = SqlTypesTests.loadMapping(mappingFile);
             EsIndex test = new EsIndex("test", mapping);
             IndexResolution getIndexResult = IndexResolution.valid(test);
-            analyzer = new Analyzer(SqlTestUtils.TEST_CFG, new SqlFunctionRegistry(), getIndexResult, new Verifier(new Metrics()));
+            analyzer = new Analyzer(TEST_CFG, new SqlFunctionRegistry(), getIndexResult, new Verifier(new Metrics()));
             optimizer = new Optimizer();
             planner = new Planner();
         }

+ 46 - 0
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverterTests.java

@@ -16,6 +16,7 @@ import org.elasticsearch.xpack.ql.type.Converter;
 import org.elasticsearch.xpack.ql.type.DataType;
 import org.elasticsearch.xpack.sql.util.DateUtils;
 
+import java.math.BigInteger;
 import java.time.OffsetTime;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
@@ -33,6 +34,7 @@ import static org.elasticsearch.xpack.ql.type.DataTypes.LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypes.NULL;
 import static org.elasticsearch.xpack.ql.type.DataTypes.SHORT;
 import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT;
+import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;
 import static org.elasticsearch.xpack.ql.type.DataTypes.UNSUPPORTED;
 import static org.elasticsearch.xpack.sql.type.SqlDataTypeConverter.commonType;
 import static org.elasticsearch.xpack.sql.type.SqlDataTypeConverter.converterFor;
@@ -151,6 +153,16 @@ public class SqlDataTypeConverterTests extends ESTestCase {
             Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(Double.MAX_VALUE));
             assertEquals("[" + Double.MAX_VALUE + "] out of [long] range", e.getMessage());
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+            BigInteger bi = BigInteger.valueOf(randomNonNegativeLong());
+            assertEquals(date(bi.longValue()), conversion.convert(bi));
+
+            BigInteger tooLarge = bi.add(BigInteger.valueOf(Long.MAX_VALUE));
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(tooLarge));
+            assertEquals("[" + tooLarge + "] out of [long] range", e.getMessage());
+        }
         {
             Converter conversion = converterFor(INTEGER, to);
             assertNull(conversion.convert(null));
@@ -223,6 +235,16 @@ public class SqlDataTypeConverterTests extends ESTestCase {
             Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(Double.MAX_VALUE));
             assertEquals("[" + Double.MAX_VALUE + "] out of [long] range", e.getMessage());
         }
+        {
+            Converter conversion = converterFor(UNSIGNED_LONG, to);
+            assertNull(conversion.convert(null));
+            BigInteger bi = BigInteger.valueOf(randomNonNegativeLong());
+            assertEquals(time(bi.longValue()), conversion.convert(bi));
+
+            BigInteger tooLarge = bi.add(BigInteger.valueOf(Long.MAX_VALUE));
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(tooLarge));
+            assertEquals("[" + tooLarge + "] out of [long] range", e.getMessage());
+        }
         {
             Converter conversion = converterFor(INTEGER, to);
             assertNull(conversion.convert(null));
@@ -513,6 +535,30 @@ public class SqlDataTypeConverterTests extends ESTestCase {
         }
     }
 
+    public void testConversionToUnsignedLong() {
+        DataType to = UNSIGNED_LONG;
+        {
+            Converter conversion = converterFor(DATE, to);
+            assertNull(conversion.convert(null));
+
+            long l = randomNonNegativeLong();
+            ZonedDateTime zdt = asDateOnly(l);
+            assertEquals(BigInteger.valueOf(zdt.toEpochSecond() * 1000), conversion.convert(zdt));
+
+            ZonedDateTime zdtn = asDateOnly(-l);
+            Exception e = expectThrows(QlIllegalArgumentException.class, () -> conversion.convert(zdtn));
+            assertEquals("[" + zdtn.toEpochSecond() * 1000 + "] out of [unsigned_long] range", e.getMessage());
+        }
+        {
+            Converter conversion = converterFor(TIME, to);
+            assertNull(conversion.convert(null));
+
+            long l = randomLong();
+            OffsetTime ot = asTimeOnly(l);
+            assertEquals(BigInteger.valueOf(ot.atDate(DateUtils.EPOCH).toInstant().toEpochMilli()), conversion.convert(ot));
+        }
+    }
+
     public void testConversionToInt() {
         DataType to = INTEGER;
         {