diff --git a/docs/reference/sql/language/data-types.asciidoc b/docs/reference/sql/language/data-types.asciidoc index 811bb1ac6a47f..2c799dc7276eb 100644 --- a/docs/reference/sql/language/data-types.asciidoc +++ b/docs/reference/sql/language/data-types.asciidoc @@ -13,21 +13,22 @@ s|SQL precision 4+h| Core types -| <> | null | NULL | 0 -| <> | boolean | BOOLEAN | 1 -| <> | byte | TINYINT | 3 -| <> | short | SMALLINT | 5 -| <> | integer | INTEGER | 10 -| <> | long | BIGINT | 19 -| <> | double | DOUBLE | 15 -| <> | float | REAL | 7 -| <> | half_float | FLOAT | 3 -| <> | scaled_float | DOUBLE | 15 -| <> | keyword | VARCHAR | 32,766 -| <> | text | VARCHAR | 2,147,483,647 -| <> | binary | VARBINARY | 2,147,483,647 -| <> | datetime | TIMESTAMP | 29 -| <> | ip | VARCHAR | 39 +| <> | null | NULL | 0 +| <> | boolean | BOOLEAN | 1 +| <> | byte | TINYINT | 3 +| <> | short | SMALLINT | 5 +| <> | integer | INTEGER | 10 +| <> | long | BIGINT | 19 +| <> | double | DOUBLE | 15 +| <> | float | REAL | 7 +| <> | half_float | FLOAT | 3 +| <> | scaled_float | DOUBLE | 15 +| <> | keyword | VARCHAR | 32,766 +| <> | constant_keyword| VARCHAR | 32,766 +| <> | text | VARCHAR | 2,147,483,647 +| <> | binary | VARBINARY | 2,147,483,647 +| <> | datetime | TIMESTAMP | 29 +| <> | ip | VARCHAR | 39 4+h| Complex types diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/execution/search/extractor/AbstractFieldHitExtractor.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/execution/search/extractor/AbstractFieldHitExtractor.java index cbb50605f72e2..3439626887ac0 100644 --- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/execution/search/extractor/AbstractFieldHitExtractor.java +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/execution/search/extractor/AbstractFieldHitExtractor.java @@ -28,6 +28,7 @@ import java.util.Objects; import java.util.StringJoiner; +import static org.elasticsearch.xpack.ql.type.DataTypes.CONSTANT_KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.SCALED_FLOAT; @@ -213,6 +214,7 @@ protected Object unwrapMultiValue(Object values) { protected boolean isFromDocValuesOnly(DataType dataType) { return dataType == KEYWORD // because of ignore_above. || dataType == DATETIME + || dataType == CONSTANT_KEYWORD // because a non-existent value is considered the constant value itself || dataType == SCALED_FLOAT; // because of scaling_factor } diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/index/IndexResolver.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/index/IndexResolver.java index 5d003dd80bf08..2b8cddfcf8b15 100644 --- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/index/IndexResolver.java +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/index/IndexResolver.java @@ -25,6 +25,7 @@ import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.xpack.ql.QlIllegalArgumentException; +import org.elasticsearch.xpack.ql.type.ConstantKeywordEsField; import org.elasticsearch.xpack.ql.type.DataType; import org.elasticsearch.xpack.ql.type.DataTypeRegistry; import org.elasticsearch.xpack.ql.type.DateEsField; @@ -60,6 +61,7 @@ import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; import static org.elasticsearch.action.ActionListener.wrap; +import static org.elasticsearch.xpack.ql.type.DataTypes.CONSTANT_KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.OBJECT; @@ -298,8 +300,13 @@ public static IndexResolution mergedMappings(DataTypeRegistry typeRegistry, Stri StringBuilder errorMessage = new StringBuilder(); boolean hasUnmapped = types.containsKey(UNMAPPED); + // a keyword field and a constant_keyword field with the same name in two different indices are considered "compatible" + // since a common use case of constant_keyword field involves two indices with a field having the same name: one being + // a keyword, the other being a constant_keyword + boolean hasCompatibleKeywords = types.containsKey(KEYWORD.esType()) && types.containsKey(CONSTANT_KEYWORD.esType()); + int allowedTypesCount = (hasUnmapped ? 2 : 1) + (hasCompatibleKeywords ? 1 : 0); - if (types.size() > (hasUnmapped ? 2 : 1)) { + if (types.size() > allowedTypesCount) { // build the error message // and create a MultiTypeField @@ -344,6 +351,11 @@ public static IndexResolution mergedMappings(DataTypeRegistry typeRegistry, Stri } } + // if there are both a keyword and a constant_keyword type for this field, only keep the keyword as a common compatible type + if (hasCompatibleKeywords) { + types.remove(CONSTANT_KEYWORD.esType()); + } + // everything checks return null; }); @@ -435,6 +447,9 @@ private static EsField createField(DataTypeRegistry typeRegistry, String fieldNa if (esType == DATETIME) { return new DateEsField(fieldName, props, isAggregateable); } + if (esType == CONSTANT_KEYWORD) { + return new ConstantKeywordEsField(fieldName); + } if (esType == UNSUPPORTED) { return new UnsupportedEsField(fieldName, typeName, null, props); } @@ -501,14 +516,14 @@ private static List buildIndices(DataTypeRegistry typeRegistry, String[ for (Entry> entry : sortedFields) { String fieldName = entry.getKey(); - Map types = entry.getValue(); // ignore size added by the mapper plugin if (FIELD_NAMES_BLACKLIST.contains(fieldName)) { continue; } - // apply verification + Map types = new LinkedHashMap<>(entry.getValue()); + // apply verification and possibly remove the "duplicate" CONSTANT_KEYWORD field type final InvalidMappedField invalidField = validityVerifier.apply(fieldName, types); // filter meta fields and unmapped diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/ConstantKeywordEsField.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/ConstantKeywordEsField.java new file mode 100644 index 0000000000000..9983599dc4def --- /dev/null +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/ConstantKeywordEsField.java @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.xpack.ql.type; + +import java.util.Collections; + +import static org.elasticsearch.xpack.ql.type.DataTypes.CONSTANT_KEYWORD; + +/** + * SQL-related information about an index field with a constant_keyword type + */ +public class ConstantKeywordEsField extends KeywordEsField { + + public ConstantKeywordEsField(String name) { + super(name, CONSTANT_KEYWORD, Collections.emptyMap(), true, Short.MAX_VALUE, false, false); + } + +} diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypeConverter.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypeConverter.java index 5400659c75ab4..a325f9287355e 100644 --- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypeConverter.java +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypeConverter.java @@ -21,6 +21,7 @@ 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.CONSTANT_KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; import static org.elasticsearch.xpack.ql.type.DataTypes.FLOAT; @@ -59,9 +60,12 @@ public static DataType commonType(DataType left, DataType right) { return left; } if (isString(left) && isString(right)) { - if (left == TEXT) { + if (left == TEXT || right == TEXT) { return TEXT; } + if (left == KEYWORD) { + return KEYWORD; + } return right; } if (left.isNumeric() && right.isNumeric()) { @@ -120,7 +124,7 @@ public static Converter converterFor(DataType from, DataType to) { return DefaultConverter.TO_NULL; } // proper converters - if (to == KEYWORD || to == TEXT) { + if (to == KEYWORD || to == TEXT || to == CONSTANT_KEYWORD) { return conversionToString(from); } if (to == LONG) { diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypes.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypes.java index ccdc35f8e78b7..f09402743335e 100644 --- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypes.java +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/DataTypes.java @@ -20,33 +20,34 @@ public final class DataTypes { // @formatter:off - public static final DataType UNSUPPORTED = new DataType("UNSUPPORTED", null, 0, false, false, false); + public static final DataType UNSUPPORTED = new DataType("UNSUPPORTED", null, 0, false, false, false); - public static final DataType NULL = new DataType("null", 0, false, false, false); + public static final DataType NULL = new DataType("null", 0, false, false, false); - public static final DataType BOOLEAN = new DataType("boolean", 1, false, false, false); + public static final DataType BOOLEAN = new DataType("boolean", 1, false, false, false); // integer numeric - public static final DataType BYTE = new DataType("byte", Byte.BYTES, true, false, true); - 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 BYTE = new DataType("byte", Byte.BYTES, true, false, true); + 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); // 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); - public static final DataType HALF_FLOAT = new DataType("half_float", Float.BYTES, false, true, true); - public static final DataType SCALED_FLOAT = new DataType("scaled_float", Long.BYTES, false, true, true); + 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); + public static final DataType HALF_FLOAT = new DataType("half_float", Float.BYTES, false, true, true); + public static final DataType SCALED_FLOAT = new DataType("scaled_float", Long.BYTES, false, true, true); // string - public static final DataType KEYWORD = new DataType("keyword", Integer.MAX_VALUE, false, false, true); - public static final DataType TEXT = new DataType("text", Integer.MAX_VALUE, false, false, false); + public static final DataType KEYWORD = new DataType("keyword", Integer.MAX_VALUE, false, false, true); + public static final DataType TEXT = new DataType("text", Integer.MAX_VALUE, false, false, false); + public static final DataType CONSTANT_KEYWORD = new DataType("constant_keyword", Integer.MAX_VALUE, false, false, true); // date - public static final DataType DATETIME = new DataType("DATETIME", "date", Long.BYTES, false, false, true); + public static final DataType DATETIME = new DataType("DATETIME", "date", Long.BYTES, false, false, true); // ip public static final DataType IP = new DataType("ip", 45, false, false, true); // binary - public static final DataType BINARY = new DataType("binary", Integer.MAX_VALUE, false, false, true); + public static final DataType BINARY = new DataType("binary", Integer.MAX_VALUE, false, false, true); // complex types - public static final DataType OBJECT = new DataType("object", 0, false, false, false); - public static final DataType NESTED = new DataType("nested", 0, false, false, false); + public static final DataType OBJECT = new DataType("object", 0, false, false, false); + public static final DataType NESTED = new DataType("nested", 0, false, false, false); //@formatter:on private static final Collection TYPES = unmodifiableList(Arrays.asList( @@ -63,6 +64,7 @@ public final class DataTypes { SCALED_FLOAT, KEYWORD, TEXT, + CONSTANT_KEYWORD, DATETIME, IP, BINARY, @@ -134,7 +136,7 @@ public static boolean isUnsupported(DataType from) { } public static boolean isString(DataType t) { - return t == KEYWORD || t == TEXT; + return t == KEYWORD || t == TEXT || t == CONSTANT_KEYWORD; } public static boolean isPrimitive(DataType t) { diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/KeywordEsField.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/KeywordEsField.java index 78d84946da4c9..65c679a5ad034 100644 --- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/KeywordEsField.java +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/KeywordEsField.java @@ -29,7 +29,12 @@ public KeywordEsField(String name, Map properties, boolean hasD public KeywordEsField(String name, Map properties, boolean hasDocValues, int precision, boolean normalized, boolean isAlias) { - super(name, KEYWORD, properties, hasDocValues, isAlias); + this(name, KEYWORD, properties, hasDocValues, precision, normalized, isAlias); + } + + protected KeywordEsField(String name, DataType esDataType, Map properties, boolean hasDocValues, int precision, + boolean normalized, boolean isAlias) { + super(name, esDataType, properties, hasDocValues, isAlias); this.precision = precision; this.normalized = normalized; } diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/TextEsField.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/TextEsField.java index e3e325be23f33..777fa9baea8c6 100644 --- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/TextEsField.java +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/TextEsField.java @@ -11,6 +11,7 @@ import java.util.Map; import java.util.function.Function; +import static org.elasticsearch.xpack.ql.type.DataTypes.CONSTANT_KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; @@ -44,7 +45,7 @@ public Exact getExactInfo() { private Tuple findExact() { EsField field = null; for (EsField property : getProperties().values()) { - if (property.getDataType() == KEYWORD && property.getExactInfo().hasExact()) { + if ((property.getDataType() == KEYWORD || property.getDataType() == CONSTANT_KEYWORD) && property.getExactInfo().hasExact()) { if (field != null) { return new Tuple<>(null, "Multiple exact keyword candidates available for [" + getName() + "]; specify which one to use"); diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/Types.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/Types.java index 44202b006fcf6..136d6e8155451 100644 --- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/Types.java +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/type/Types.java @@ -14,6 +14,7 @@ import java.util.Map.Entry; import static java.util.Collections.emptyMap; +import static org.elasticsearch.xpack.ql.type.DataTypes.CONSTANT_KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.NESTED; @@ -89,6 +90,8 @@ private static void walkMapping(DataTypeRegistry typeRegistry, String name, Obje int length = intSetting(content.get("ignore_above"), Short.MAX_VALUE); boolean normalized = Strings.hasText(textSetting(content.get("normalizer"), null)); field = new KeywordEsField(name, properties, docValues, length, normalized); + } else if (esDataType == CONSTANT_KEYWORD) { + field = new ConstantKeywordEsField(name); } else if (esDataType == DATETIME) { field = new DateEsField(name, properties, docValues); } else if (esDataType == UNSUPPORTED) { diff --git a/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/DataTypeConversionTests.java b/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/DataTypeConversionTests.java index 5e6ca1d8ea840..60a5c478cb7c6 100644 --- a/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/DataTypeConversionTests.java +++ b/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/DataTypeConversionTests.java @@ -17,6 +17,7 @@ import static org.elasticsearch.xpack.ql.type.DataTypeConverter.converterFor; 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.CONSTANT_KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; import static org.elasticsearch.xpack.ql.type.DataTypes.FLOAT; @@ -360,6 +361,7 @@ public void testCommonType() { assertEquals(BOOLEAN, commonType(BOOLEAN, BOOLEAN)); assertEquals(NULL, commonType(NULL, NULL)); assertEquals(INTEGER, commonType(INTEGER, KEYWORD)); + assertEquals(DOUBLE, commonType(DOUBLE, CONSTANT_KEYWORD)); assertEquals(LONG, commonType(TEXT, LONG)); assertEquals(SHORT, commonType(SHORT, BYTE)); assertEquals(FLOAT, commonType(BYTE, FLOAT)); @@ -369,6 +371,11 @@ public void testCommonType() { // strings assertEquals(TEXT, commonType(TEXT, KEYWORD)); assertEquals(TEXT, commonType(KEYWORD, TEXT)); + assertEquals(TEXT, commonType(TEXT, CONSTANT_KEYWORD)); + assertEquals(TEXT, commonType(CONSTANT_KEYWORD, TEXT)); + assertEquals(KEYWORD, commonType(KEYWORD, CONSTANT_KEYWORD)); + assertEquals(KEYWORD, commonType(CONSTANT_KEYWORD, KEYWORD)); + assertEquals(CONSTANT_KEYWORD, commonType(CONSTANT_KEYWORD, CONSTANT_KEYWORD)); } public void testEsDataTypes() { diff --git a/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java b/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java index 9958d00b02929..7adbf9306d7b8 100644 --- a/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java +++ b/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java @@ -14,6 +14,7 @@ import java.util.Map; import static java.util.Collections.emptyMap; +import static org.elasticsearch.xpack.ql.type.DataTypes.CONSTANT_KEYWORD; 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; @@ -135,9 +136,10 @@ public void testMultiField() { assertThat(DataTypes.isPrimitive(field.getDataType()), is(true)); assertThat(field.getDataType(), is(TEXT)); Map fields = field.getProperties(); - assertThat(fields.size(), is(2)); + assertThat(fields.size(), is(3)); assertThat(fields.get("raw").getDataType(), is(KEYWORD)); assertThat(fields.get("english").getDataType(), is(TEXT)); + assertThat(fields.get("constant").getDataType(), is(CONSTANT_KEYWORD)); } public void testMultiFieldTooManyOptions() { @@ -148,9 +150,10 @@ public void testMultiFieldTooManyOptions() { assertThat(DataTypes.isPrimitive(field.getDataType()), is(true)); assertThat(field, instanceOf(TextEsField.class)); Map fields = field.getProperties(); - assertThat(fields.size(), is(2)); + assertThat(fields.size(), is(3)); assertThat(fields.get("raw").getDataType(), is(KEYWORD)); assertThat(fields.get("english").getDataType(), is(TEXT)); + assertThat(fields.get("constant").getDataType(), is(CONSTANT_KEYWORD)); } public void testNestedDoc() { @@ -173,6 +176,13 @@ public void testIpField() { assertThat(dt.getDataType().typeName(), is("ip")); } + public void testConstantKeywordField() { + Map mapping = loadMapping("mapping-constant-keyword.json"); + assertThat(mapping.size(), is(1)); + EsField dt = mapping.get("full_name"); + assertThat(dt.getDataType().typeName(), is("constant_keyword")); + } + public void testUnsupportedTypes() { Map mapping = loadMapping("mapping-unsupported.json"); EsField dt = mapping.get("range"); diff --git a/x-pack/plugin/ql/src/test/resources/mapping-constant-keyword.json b/x-pack/plugin/ql/src/test/resources/mapping-constant-keyword.json new file mode 100644 index 0000000000000..7f248dc26fba6 --- /dev/null +++ b/x-pack/plugin/ql/src/test/resources/mapping-constant-keyword.json @@ -0,0 +1,8 @@ +{ + "properties" : { + "full_name" : { + "type" : "constant_keyword", + "value" : "foo" + } + } +} diff --git a/x-pack/plugin/ql/src/test/resources/mapping-multi-field.json b/x-pack/plugin/ql/src/test/resources/mapping-multi-field.json index 9e293d4271333..8adc4c64e8476 100644 --- a/x-pack/plugin/ql/src/test/resources/mapping-multi-field.json +++ b/x-pack/plugin/ql/src/test/resources/mapping-multi-field.json @@ -9,6 +9,10 @@ "english" : { "type" : "text", "analyzer" : "english" + }, + "constant" : { + "type" : "constant_keyword", + "value" : "some constant value" } } } diff --git a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/EsType.java b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/EsType.java index 0b96204fd5d7e..9eae74d18019a 100644 --- a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/EsType.java +++ b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/EsType.java @@ -25,6 +25,7 @@ public enum EsType implements SQLType { SCALED_FLOAT( Types.FLOAT), KEYWORD( Types.VARCHAR), TEXT( Types.VARCHAR), + CONSTANT_KEYWORD( Types.VARCHAR), OBJECT( Types.STRUCT), NESTED( Types.STRUCT), BINARY( Types.VARBINARY), diff --git a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeConverter.java b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeConverter.java index bf72b4454e40e..888fb8632d217 100644 --- a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeConverter.java +++ b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeConverter.java @@ -210,6 +210,7 @@ static Object convert(Object v, EsType columnType, String typeString) throws SQL case BOOLEAN: case TEXT: case KEYWORD: + case CONSTANT_KEYWORD: return v; // These types are already represented correctly in JSON case BYTE: return ((Number) v).byteValue(); // Parser might return it as integer or long - need to update to the correct type @@ -323,6 +324,7 @@ private static Boolean asBoolean(Object val, EsType columnType, String typeStrin return Boolean.valueOf(Integer.signum(((Number) val).intValue()) != 0); case KEYWORD: case TEXT: + case CONSTANT_KEYWORD: return Boolean.valueOf((String) val); default: return failConversion(val, columnType, typeString, Boolean.class); @@ -345,6 +347,7 @@ private static Byte asByte(Object val, EsType columnType, String typeString) thr return safeToByte(safeToLong(((Number) val).doubleValue())); case KEYWORD: case TEXT: + case CONSTANT_KEYWORD: try { return Byte.valueOf((String) val); } catch (NumberFormatException e) { @@ -372,6 +375,7 @@ private static Short asShort(Object val, EsType columnType, String typeString) t return safeToShort(safeToLong(((Number) val).doubleValue())); case KEYWORD: case TEXT: + case CONSTANT_KEYWORD: try { return Short.valueOf((String) val); } catch (NumberFormatException e) { @@ -398,6 +402,7 @@ private static Integer asInteger(Object val, EsType columnType, String typeStrin return safeToInt(safeToLong(((Number) val).doubleValue())); case KEYWORD: case TEXT: + case CONSTANT_KEYWORD: try { return Integer.valueOf((String) val); } catch (NumberFormatException e) { @@ -429,6 +434,7 @@ private static Long asLong(Object val, EsType columnType, String typeString) thr // return ((Number) val).longValue(); case KEYWORD: case TEXT: + case CONSTANT_KEYWORD: try { return Long.valueOf((String) val); } catch (NumberFormatException e) { @@ -456,6 +462,7 @@ private static Float asFloat(Object val, EsType columnType, String typeString) t return Float.valueOf(((Number) val).floatValue()); case KEYWORD: case TEXT: + case CONSTANT_KEYWORD: try { return Float.valueOf((String) val); } catch (NumberFormatException e) { @@ -482,6 +489,7 @@ private static Double asDouble(Object val, EsType columnType, String typeString) return Double.valueOf(((Number) val).doubleValue()); case KEYWORD: case TEXT: + case CONSTANT_KEYWORD: try { return Double.valueOf((String) val); } catch (NumberFormatException e) { diff --git a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeUtils.java b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeUtils.java index 511cf92be5665..0fc929c900bfe 100644 --- a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeUtils.java +++ b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/TypeUtils.java @@ -76,6 +76,7 @@ private TypeUtils() {} types.put(EsType.SCALED_FLOAT, Double.class); types.put(EsType.KEYWORD, String.class); types.put(EsType.TEXT, String.class); + types.put(EsType.CONSTANT_KEYWORD, String.class); types.put(EsType.BINARY, byte[].class); types.put(EsType.DATETIME, Timestamp.class); types.put(EsType.IP, String.class); @@ -157,7 +158,7 @@ static EsType of(String name) throws SQLException { } static boolean isString(EsType dataType) { - return dataType == EsType.KEYWORD || dataType == EsType.TEXT; + return dataType == EsType.KEYWORD || dataType == EsType.TEXT || dataType == EsType.CONSTANT_KEYWORD; } static EsType of(Class clazz) throws SQLException { diff --git a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/FieldExtractorTestCase.java b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/FieldExtractorTestCase.java index 4a760b97cd23c..150db29a2f58e 100644 --- a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/FieldExtractorTestCase.java +++ b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/FieldExtractorTestCase.java @@ -103,6 +103,40 @@ public void testKeywordField() throws IOException { assertResponse(expected, runSql("SELECT keyword_field FROM test")); } + /* + * "constant_keyword_field": { + * "type": "constant_keyword", + * "value": "foo" + * } + */ + public void testConstantKeywordField() throws IOException { + String value = randomAlphaOfLength(20); + // _source for `constant_keyword` fields doesn't matter, as they should be taken from docvalue_fields + boolean explicitSourceSetting = randomBoolean(); // default (no _source setting) or explicit setting + boolean enableSource = randomBoolean(); // enable _source at index level + + Map indexProps = new HashMap<>(1); + indexProps.put("_source", enableSource); + + Map> fieldProps = null; + if (randomBoolean()) { + fieldProps = new HashMap<>(1); + Map fieldProp = new HashMap<>(1); + fieldProp.put("value", value); + fieldProps.put("constant_keyword_field", fieldProp); + } + + createIndexWithFieldTypeAndProperties("constant_keyword", fieldProps, explicitSourceSetting ? indexProps : null); + index("{\"constant_keyword_field\":\"" + value + "\"}"); + + Map expected = new HashMap<>(); + expected.put("columns", Arrays.asList( + columnInfo("plain", "constant_keyword_field", "constant_keyword", JDBCType.VARCHAR, Integer.MAX_VALUE) + )); + expected.put("rows", singletonList(singletonList(value))); + assertResponse(expected, runSql("SELECT constant_keyword_field FROM test")); + } + /* * "long/integer/short/byte_field": { * "type": "long/integer/short/byte" diff --git a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DataLoader.java b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DataLoader.java index d2dffe21e1013..e362349f332d3 100644 --- a/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DataLoader.java +++ b/x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/DataLoader.java @@ -123,13 +123,11 @@ private static void loadEmpDatasetIntoEs(RestClient client, String index, String createString("first_name", createIndex); createString("last_name", createIndex); createIndex.startObject("gender").field("type", "keyword"); - if (extraFields) { - createIndex.field("copy_to", "extra_gender"); - } createIndex.endObject(); if (extraFields) { - createIndex.startObject("extra_gender").field("type", "keyword").endObject(); + createIndex.startObject("extra_gender").field("type", "constant_keyword").endObject(); + createIndex.startObject("null_constant").field("type", "constant_keyword").endObject(); createIndex.startObject("extra.info.gender") .field("type", "alias") .field("path", "gender") @@ -198,6 +196,9 @@ private static void loadEmpDatasetIntoEs(RestClient client, String index, String } 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\""); + } } } // append department diff --git a/x-pack/plugin/sql/qa/src/main/resources/alias.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/alias.csv-spec index 6c51bbf3dc69b..440434796a163 100644 --- a/x-pack/plugin/sql/qa/src/main/resources/alias.csv-spec +++ b/x-pack/plugin/sql/qa/src/main/resources/alias.csv-spec @@ -41,7 +41,7 @@ emp_no |INTEGER |integer extra |STRUCT |object extra.info |STRUCT |object extra.info.gender |VARCHAR |keyword -extra_gender |VARCHAR |keyword +extra_gender |VARCHAR |constant_keyword extra_no |INTEGER |integer first_name |VARCHAR |text first_name.keyword |VARCHAR |keyword @@ -50,6 +50,7 @@ hire_date |TIMESTAMP |datetime languages |TINYINT |byte last_name |VARCHAR |text last_name.keyword |VARCHAR |keyword +null_constant |VARCHAR |constant_keyword salary |INTEGER |integer ; @@ -69,7 +70,7 @@ emp_no |INTEGER |integer extra |STRUCT |object extra.info |STRUCT |object extra.info.gender |VARCHAR |keyword -extra_gender |VARCHAR |keyword +extra_gender |VARCHAR |constant_keyword extra_no |INTEGER |integer first_name |VARCHAR |text first_name.keyword |VARCHAR |keyword @@ -78,6 +79,7 @@ hire_date |TIMESTAMP |datetime languages |TINYINT |byte last_name |VARCHAR |text last_name.keyword |VARCHAR |keyword +null_constant |VARCHAR |constant_keyword salary |INTEGER |integer ; diff --git a/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec index b17ba988472be..c8ea838745c46 100644 --- a/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec +++ b/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec @@ -276,7 +276,7 @@ emp_no |INTEGER |integer extra |STRUCT |object extra.info |STRUCT |object extra.info.gender |VARCHAR |keyword -extra_gender |VARCHAR |keyword +extra_gender |VARCHAR |constant_keyword extra_no |INTEGER |integer first_name |VARCHAR |text first_name.keyword |VARCHAR |keyword @@ -285,6 +285,7 @@ hire_date |TIMESTAMP |datetime languages |TINYINT |byte last_name |VARCHAR |text last_name.keyword |VARCHAR |keyword +null_constant |VARCHAR |constant_keyword salary |INTEGER |integer ; @@ -304,7 +305,7 @@ emp_no |INTEGER |integer extra |STRUCT |object extra.info |STRUCT |object extra.info.gender |VARCHAR |keyword -extra_gender |VARCHAR |keyword +extra_gender |VARCHAR |constant_keyword extra_no |INTEGER |integer first_name |VARCHAR |text first_name.keyword |VARCHAR |keyword @@ -313,6 +314,7 @@ hire_date |TIMESTAMP |datetime languages |TINYINT |byte last_name |VARCHAR |text last_name.keyword |VARCHAR |keyword +null_constant |VARCHAR |constant_keyword salary |INTEGER |integer ; diff --git a/x-pack/plugin/sql/qa/src/main/resources/constant-keyword.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/constant-keyword.csv-spec new file mode 100644 index 0000000000000..42257a8890ebd --- /dev/null +++ b/x-pack/plugin/sql/qa/src/main/resources/constant-keyword.csv-spec @@ -0,0 +1,163 @@ +// To mute tests follow example in file: example.csv-spec + +// +// Tests testing constant_keyword (introduced in ES 7.7) +// + +// filtering + +filterEquals +SELECT extra_gender g FROM "test_emp_copy" WHERE g = 'Female' LIMIT 5; + + g +--------------- +Female +Female +Female +Female +Female +; + +filterNotEquals +SELECT COUNT(*) AS c FROM "test_emp_copy" WHERE extra_gender <> 'Female'; + + c:l +--------------- +0 +; + +aggWithNullFilter +SELECT COUNT(*) count FROM test_emp_copy WHERE extra_gender IS NOT NULL; + + count:l +--------------- +100 +; + +// Awaits for https://github.com/elastic/elasticsearch/issues/53545 +aggWithNullFilter-Ignore +SELECT COUNT(*) count FROM test_emp_copy WHERE null_constant IS NULL; + + count:l +--------------- +100 +; + +functionOverAlias +SELECT BIT_LENGTH(extra_gender) bit FROM test_emp_copy ORDER BY extra_gender LIMIT 1; + + bit +--------------- +48 +; + + +singlePercentileWithoutComma +SELECT extra_gender AS gender, PERCENTILE(emp_no, 97) p1 FROM test_emp_copy GROUP BY extra_gender; + +gender:s | p1:d +Female |10097.5 +; + +percentileRank +SELECT extra_gender AS gender, PERCENTILE_RANK(emp_no, 10025) rank FROM test_emp_copy GROUP BY extra_gender; + +gender:s | rank:d +---------------+--------------- +Female |24.5 +; + +aggSumWithAliasWithColumnRepeatedWithOrderDesc +SELECT extra_gender AS g, extra_gender, SUM(salary) AS s3, SUM(salary), SUM(salary) AS s5 FROM test_emp_copy GROUP BY extra_gender; + + g:s | extra_gender:s | s3:i | SUM(salary):i | s5:i +---------------+----------------+---------------+---------------+--------------- +Female |Female |4824855 |4824855 |4824855 +; + +topHitsAsMinAndMaxAndGroupBy +schema::extra_gender:s|min:s|max:s|first:s|last:s +SELECT extra_gender, MIN(first_name) as min, MAX(first_name) as max, FIRST(first_name) as first, LAST(first_name) as last FROM test_emp_copy GROUP BY extra_gender ORDER BY extra_gender; + + extra_gender | min | max | first | last +---------------+---------------+---------------+---------------+--------------- +Female |Alejandro |Zvonko |Alejandro |Zvonko +; + +medianAbsoluteDeviationOnTwoFields +schema::extra_gender:s|avg:l|mad_s:l|mad_l:d +SELECT extra_gender, FLOOR(AVG(salary)) AS avg, FLOOR(MAD(salary)) AS mad_s, MAD(languages) AS mad_l FROM test_emp_copy GROUP BY extra_gender ORDER BY extra_gender; + + extra_gender | avg | mad_s | mad_l +---------------+-------------+-------------+--------------- +Female |48248 |10096 |1 +; + +caseGroupByAndHaving +schema::count:l|extra_gender:s|languages:byte +SELECT count(*) AS count, extra_gender, languages FROM test_emp_copy +GROUP BY 2, 3 HAVING CASE WHEN count(*) > 10 THEN 'many' ELSE 'a few' END = 'many' +ORDER BY 1, 3; + + count | extra_gender | languages +---------------+---------------+--------------- +15 |Female |1 +17 |Female |3 +18 |Female |4 +19 |Female |2 +21 |Female |5 +; + +whereFieldWithRLikeAndGroupByOrderBy +SELECT last_name l, extra_gender g, COUNT(*) c, MAX(salary) AS sal FROM test_emp_copy WHERE emp_no < 10050 AND (last_name RLIKE 'B.*' OR extra_gender = 'F') GROUP BY g, l ORDER BY sal; + + l:s | g:s | c:l | sal:i +---------------+---------------+---------------+--------------- +Berztiss |Female |1 |28336 +Brender |Female |1 |36051 +Bridgland |Female |1 |48942 +Bouloucos |Female |1 |58715 +Bamford |Female |1 |61805 +; + +multipleGroupingsAndOrderingByGroupsWithFunctions_2 +SELECT first_name f, last_name l, LCASE(extra_gender) g, CONCAT(UCASE(first_name), LCASE(last_name)) c FROM test_emp_copy GROUP BY f, LCASE(extra_gender), l, c ORDER BY c DESC, first_name, l ASC, g LIMIT 3; + + f:s | l:s | g:s | c:s +---------------+---------------+---------------+--------------- +null |Swan |female |swan +null |Reistad |female |reistad +null |Portugali |female |portugali +; + +isNotNullWithCount +SELECT extra_gender IS NOT NULL AS bool, COUNT(*) FROM test_emp_copy GROUP BY extra_gender; + + bool:b | COUNT(*):l +------------------------+--------------- +true |100 +; + +likeWithCount1 +SELECT COUNT(*) FROM test_emp_copy WHERE extra_gender LIKE 'F%'; + + COUNT(*):l +--------------- +100 +; + +likeWithCount2 +SELECT COUNT(*) FROM test_emp_copy WHERE extra_gender LIKE '%m%'; + + COUNT(*):l +--------------- +100 +; + +likeWithCount3 +SELECT COUNT(*) FROM test_emp_copy WHERE extra_gender NOT LIKE '%m%'; + + COUNT(*):l +--------------- +0 +; \ No newline at end of file diff --git a/x-pack/plugin/sql/qa/src/main/resources/single-node-only/command-sys.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/single-node-only/command-sys.csv-spec index 711df01849103..dee74303b9bda 100644 --- a/x-pack/plugin/sql/qa/src/main/resources/single-node-only/command-sys.csv-spec +++ b/x-pack/plugin/sql/qa/src/main/resources/single-node-only/command-sys.csv-spec @@ -29,19 +29,20 @@ 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 |29 |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 |29 |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 |salary |4 |INTEGER |11 |4 |null |10 |1 |null |null |4 |0 |null |16 |YES |null |null |null |null |NO |NO +integTest |null |test_emp |birth_date |93 |DATETIME |29 |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 |CONSTANT_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 |29 |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 |null_constant |12 |CONSTANT_KEYWORD|32766 |2147483647 |null |null |1 |null |null |12 |0 |2147483647 |16 |YES |null |null |null |null |NO |NO +integTest |null |test_emp |salary |4 |INTEGER |11 |4 |null |10 |1 |null |null |4 |0 |null |17 |YES |null |null |null |null |NO |NO ; sysColumnsWithCatalogAndLike @@ -49,19 +50,20 @@ 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 |29 |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 |29 |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|salary |4 |INTEGER |11 |4 |null |10 |1 |null |null |4 |0 |null |16 |YES |null |null |null |null |NO |NO +integTest |null |test_emp_copy|birth_date |93 |DATETIME |29 |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 |CONSTANT_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 |29 |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|null_constant |12 |CONSTANT_KEYWORD|32766 |2147483647 |null |null |1 |null |null |12 |0 |2147483647 |16 |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 |17 |YES |null |null |null |null |NO |NO ; sysColumnsOnAliasWithTableLike @@ -69,55 +71,57 @@ 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 |29 |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 |29 |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 |salary |4 |INTEGER |11 |4 |null |10 |1 |null |null |4 |0 |null |16 |YES |null |null |null |null |NO |NO +integTest |null |test_alias |birth_date |93 |DATETIME |29 |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 |CONSTANT_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 |29 |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 |null_constant |12 |CONSTANT_KEYWORD|32766 |2147483647 |null |null |1 |null |null |12 |0 |2147483647 |16 |YES |null |null |null |null |NO |NO +integTest |null |test_alias |salary |4 |INTEGER |11 |4 |null |10 |1 |null |null |4 |0 |null |17 |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 |29 |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 |test_emp |birth_date |93 |DATETIME |29 |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 |29 |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 |salary |4 |INTEGER |11 |4 |null |10 |1 |null |null |4 |0 |null |11 |YES |null |null |null |null |NO |NO -integTest |null |test_emp_copy |birth_date |93 |DATETIME |29 |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 |29 |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 |salary |4 |INTEGER |11 |4 |null |10 |1 |null |null |4 |0 |null |16 |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 |29 |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 |test_emp |birth_date |93 |DATETIME |29 |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 |29 |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 |salary |4 |INTEGER |11 |4 |null |10 |1 |null |null |4 |0 |null |11 |YES |null |null |null |null |NO |NO +integTest |null |test_emp_copy |birth_date |93 |DATETIME |29 |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 |CONSTANT_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 |29 |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 |null_constant |12 |CONSTANT_KEYWORD|32766 |2147483647 |null |null |1 |null |null |12 |0 |2147483647 |16 |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 |17 |YES |null |null |null |null |NO |NO ; diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverter.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverter.java index e958ce1aa830d..bb5156a47b35b 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverter.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverter.java @@ -36,6 +36,7 @@ import static org.elasticsearch.xpack.ql.type.DataTypeConverter.DefaultConverter.TO_NULL; 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.CONSTANT_KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; import static org.elasticsearch.xpack.ql.type.DataTypes.FLOAT; @@ -159,7 +160,7 @@ public static Converter converterFor(DataType from, DataType to) { } // extend the default converter with DATE and TIME if (from == DATE || from == TIME) { - if (to == KEYWORD || to == TEXT) { + if (to == KEYWORD || to == TEXT || to == CONSTANT_KEYWORD) { return conversionToString(from); } if (to == LONG) { diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypes.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypes.java index c61e99abf26d9..f36a3e4e4df7d 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypes.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/SqlDataTypes.java @@ -30,6 +30,7 @@ import static org.elasticsearch.xpack.ql.type.DataTypes.BINARY; 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.CONSTANT_KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; import static org.elasticsearch.xpack.ql.type.DataTypes.FLOAT; @@ -269,6 +270,7 @@ public static boolean isFromDocValuesOnly(DataType dataType) { || dataType == DATE // because of date formats || dataType == DATETIME || dataType == SCALED_FLOAT // because of scaling_factor + || dataType == CONSTANT_KEYWORD || dataType == GEO_POINT || dataType == GEO_SHAPE || dataType == SHAPE; @@ -334,6 +336,9 @@ public static SQLType sqlType(DataType dataType) { if (dataType == TEXT) { return JDBCType.VARCHAR; } + if (dataType == CONSTANT_KEYWORD) { + return JDBCType.VARCHAR; + } if (dataType == DATETIME) { return JDBCType.TIMESTAMP; } @@ -457,6 +462,9 @@ public static int defaultPrecision(DataType dataType) { if (dataType == TEXT) { return 32766; } + if (dataType == CONSTANT_KEYWORD) { + return 15; + } if (dataType == DATETIME) { return 3; } @@ -577,6 +585,9 @@ public static int displaySize(DataType dataType) { if (dataType == TEXT) { return dataType.size(); } + if (dataType == CONSTANT_KEYWORD) { + return 32766; + } if (dataType == DATETIME) { return 29; } diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/index/IndexResolverTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/index/IndexResolverTests.java index b53d1cbdf8133..614cc24ec44aa 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/index/IndexResolverTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/index/IndexResolverTests.java @@ -10,10 +10,12 @@ import org.elasticsearch.xpack.ql.index.EsIndex; import org.elasticsearch.xpack.ql.index.IndexResolution; import org.elasticsearch.xpack.ql.index.IndexResolver; +import org.elasticsearch.xpack.ql.type.ConstantKeywordEsField; import org.elasticsearch.xpack.ql.type.DataType; import org.elasticsearch.xpack.ql.type.EsField; import org.elasticsearch.xpack.ql.type.InvalidMappedField; import org.elasticsearch.xpack.ql.type.KeywordEsField; +import org.elasticsearch.xpack.ql.type.TextEsField; import org.elasticsearch.xpack.sql.type.SqlDataTypeRegistry; import java.util.ArrayList; @@ -26,6 +28,7 @@ import static java.util.Collections.singletonMap; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; +import static org.elasticsearch.xpack.ql.type.DataTypes.CONSTANT_KEYWORD; 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; @@ -268,6 +271,52 @@ public void testMergeIncompatibleCapabilitiesOfObjectFields() throws Exception { ((InvalidMappedField) esField).errorMessage()); } + public void testConstantKeywordTwoIndicesScenario() throws Exception { + Map> fieldCaps = new HashMap<>(); + addFieldCaps(fieldCaps, "name", "text", true, false); + addFieldCaps(fieldCaps, "wheels_count", "constant_keyword", true, true); + addFieldCaps(fieldCaps, "motor", "keyword", true, true); + + Map multi = new HashMap<>(); + multi.put("keyword", new FieldCapabilities("cycle_type", "keyword", true, true, new String[] { "other_cycles" }, null, null, + Collections.emptyMap())); + multi.put("constant_keyword", new FieldCapabilities("cycle_type", "constant_keyword", true, false, new String[] { "bicycles" }, + null, null, Collections.emptyMap())); + fieldCaps.put("cycle_type", multi); + + String wildcard = "*"; + IndexResolution resolution = mergedMappings(wildcard, new String[] { "other_cycles", "bicycles" }, fieldCaps); + + assertTrue(resolution.isValid()); + + EsIndex esIndex = resolution.get(); + assertEquals(wildcard, esIndex.name()); + EsField esField = null; + Map props = esIndex.mapping(); + + assertEquals(4, props.size()); + assertTrue(props.containsKey("cycle_type")); + assertTrue(props.containsKey("name")); + assertTrue(props.containsKey("wheels_count")); + assertTrue(props.containsKey("motor")); + + esField = props.get("cycle_type"); + assertTrue(esField instanceof KeywordEsField); + assertEquals(KEYWORD, ((KeywordEsField) esField).getDataType()); + + esField = props.get("name"); + assertTrue(esField instanceof TextEsField); + assertEquals(TEXT, ((TextEsField) esField).getDataType()); + + esField = props.get("wheels_count"); + assertTrue(esField instanceof ConstantKeywordEsField); + assertEquals(CONSTANT_KEYWORD, ((ConstantKeywordEsField) esField).getDataType()); + + esField = props.get("motor"); + assertTrue(esField instanceof KeywordEsField); + assertEquals(KEYWORD, ((KeywordEsField) esField).getDataType()); + } + public void testSeparateSameMappingDifferentIndices() throws Exception { Map oneMapping = loadMapping("mapping-basic.json", true); Map sameMapping = loadMapping("mapping-basic.json", true); @@ -383,7 +432,7 @@ private static boolean isSearchable(DataType type) { } private static boolean isAggregatable(DataType type) { - return type.isNumeric() || type == KEYWORD || type == DATETIME; + return type.isNumeric() || type == KEYWORD || type == DATETIME || type == CONSTANT_KEYWORD; } private static class UpdateableFieldCapabilities extends FieldCapabilities { diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTypesTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTypesTests.java index 17bc17bbec4b8..e0bf79b830e00 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTypesTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTypesTests.java @@ -46,7 +46,7 @@ public void testSysTypes() { Command cmd = sql("SYS TYPES").v1(); List names = asList("BYTE", "LONG", "BINARY", "NULL", "INTEGER", "SHORT", "HALF_FLOAT", "FLOAT", "DOUBLE", "SCALED_FLOAT", - "IP", "KEYWORD", "TEXT", "BOOLEAN", "DATE", "TIME", "DATETIME", + "CONSTANT_KEYWORD", "IP", "KEYWORD", "TEXT", "BOOLEAN", "DATE", "TIME", "DATETIME", "INTERVAL_YEAR", "INTERVAL_MONTH", "INTERVAL_DAY", "INTERVAL_HOUR", "INTERVAL_MINUTE", "INTERVAL_SECOND", "INTERVAL_YEAR_TO_MONTH", "INTERVAL_DAY_TO_HOUR", "INTERVAL_DAY_TO_MINUTE", "INTERVAL_DAY_TO_SECOND", "INTERVAL_HOUR_TO_MINUTE", "INTERVAL_HOUR_TO_SECOND", "INTERVAL_MINUTE_TO_SECOND", @@ -107,7 +107,9 @@ public void testSysTypesMultipleMatches() { cmd.execute(session(), wrap(p -> { SchemaRowSet r = (SchemaRowSet) p.rowSet(); - assertEquals(3, r.size()); + assertEquals(4, r.size()); + assertEquals("CONSTANT_KEYWORD", r.column(0)); + assertTrue(r.advanceRow()); assertEquals("IP", r.column(0)); assertTrue(r.advanceRow()); assertEquals("KEYWORD", r.column(0)); diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverterTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverterTests.java index b39dd8bcaa897..c445a84b236ca 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverterTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/type/SqlDataTypeConverterTests.java @@ -22,6 +22,7 @@ import static java.util.stream.Collectors.toList; 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.CONSTANT_KEYWORD; import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; import static org.elasticsearch.xpack.ql.type.DataTypes.FLOAT; @@ -631,6 +632,7 @@ public void testCommonType() { assertEquals(BOOLEAN, commonType(BOOLEAN, BOOLEAN)); assertEquals(NULL, commonType(NULL, NULL)); assertEquals(INTEGER, commonType(INTEGER, KEYWORD)); + assertEquals(DOUBLE, commonType(DOUBLE, CONSTANT_KEYWORD)); assertEquals(LONG, commonType(TEXT, LONG)); assertEquals(SHORT, commonType(SHORT, BYTE)); assertEquals(FLOAT, commonType(BYTE, FLOAT)); @@ -640,6 +642,11 @@ public void testCommonType() { // strings assertEquals(TEXT, commonType(TEXT, KEYWORD)); assertEquals(TEXT, commonType(KEYWORD, TEXT)); + assertEquals(TEXT, commonType(TEXT, CONSTANT_KEYWORD)); + assertEquals(TEXT, commonType(CONSTANT_KEYWORD, TEXT)); + assertEquals(KEYWORD, commonType(KEYWORD, CONSTANT_KEYWORD)); + assertEquals(KEYWORD, commonType(CONSTANT_KEYWORD, KEYWORD)); + assertEquals(CONSTANT_KEYWORD, commonType(CONSTANT_KEYWORD, CONSTANT_KEYWORD)); // numeric and intervals assertEquals(INTERVAL_YEAR_TO_MONTH, commonType(INTERVAL_YEAR_TO_MONTH, LONG));