Skip to content

QL: add unsigned_long type support #65145

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 56 commits into from
Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
5b2ae44
Add unsigned_long type support to QL
bpintea Nov 17, 2020
56b6e3d
style fixes
bpintea Nov 17, 2020
0b648ae
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea Nov 19, 2020
9eda683
Make JDBC QA tests version aware
bpintea Nov 19, 2020
dced577
Disable UL for 7.11 till after merging it in
bpintea Nov 19, 2020
30360f4
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea Nov 19, 2020
e2a2363
Refactor UL gating based on version
bpintea Nov 22, 2020
ab5eaa0
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea Nov 22, 2020
672df32
Minor clean-ups
bpintea Nov 23, 2020
93ece7c
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea Nov 23, 2020
cbcb148
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea Nov 27, 2020
85447c1
Address reivew comments
bpintea Nov 27, 2020
6a8ac44
Merge branch 'master' into feat/unsigned_long
elasticmachine Nov 30, 2020
6801bd5
Remove stale comment
bpintea Nov 30, 2020
9210138
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea Nov 30, 2020
c9bfffd
Filter out UL from * expansion. Drop client check
bpintea Nov 30, 2020
2d64608
Revert FieldExtractorTestCase: no float to UL
bpintea Nov 30, 2020
754d026
Address review comments
bpintea Dec 8, 2020
6119fd3
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea Dec 8, 2020
d89513c
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea Dec 16, 2020
46a072e
Add 'SHOW COLUMNS' tests
bpintea Dec 16, 2020
0897d8e
Switch UNSIGNED_LONG to NUMERIC xDBC type
bpintea Dec 16, 2020
1b906ec
Update test
bpintea Dec 16, 2020
346b566
Merge branch 'master' into feat/unsigned_long
elasticmachine Dec 16, 2020
f99eeec
Style fix
bpintea Dec 16, 2020
a8c586b
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea Jan 13, 2021
0799d72
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea May 27, 2021
f5be346
Merge remote-tracking branch 'upstream/master' into feat/unsigned_long
bpintea May 27, 2021
9664e23
License header fix
bpintea May 27, 2021
91bd1d6
Merge branch 'master' into feat/unsigned_long
bpintea Jul 21, 2021
f8c20db
Update target release.Update test to 4-dig. years
bpintea Jul 21, 2021
c1718b5
Merge branch 'master' into feat/unsigned_long
bpintea Jul 21, 2021
9b5bc54
Merge branch 'master' into feat/unsigned_long
bpintea Aug 17, 2021
71e707b
Merge branch 'master' into feat/unsigned_long
bpintea Sep 1, 2021
51a4f84
Add Painless-driven testing
bpintea Sep 2, 2021
c6a170c
Merge branch 'master' into feat/unsigned_long
bpintea Sep 2, 2021
38b1450
Merge branch 'master' into feat/unsigned_long
bpintea Dec 2, 2021
d398757
Merge branch 'master' into feat/unsigned_long
elasticmachine Dec 2, 2021
bbfcd93
Merge branch 'master' into feat/unsigned_long
bpintea Dec 14, 2021
509892c
Extend value extraction as unsigned long
bpintea Dec 23, 2021
d03cb1d
Address review comments
bpintea Dec 23, 2021
35149d8
Merge branch 'master' into feat/unsigned_long
bpintea Dec 23, 2021
0943d4b
Remove ShowColumns UL version-dep filtering
bpintea Dec 23, 2021
8ebfad1
Extract mapping reading out of loops
bpintea Dec 23, 2021
64f02f7
Resolve UL fields to unsupported in resolver
bpintea Jan 4, 2022
95d8c02
Merge branch 'master' into feat/unsigned_long
bpintea Jan 4, 2022
67d38aa
Merge branch 'master' into feat/unsigned_long
bpintea Jan 10, 2022
41be569
Merge branch 'master' into feat/unsigned_long
bpintea Jan 31, 2022
f6c3a8e
Address review comments
bpintea Jan 31, 2022
abda408
Update docs/changelog/65145.yaml
Jan 31, 2022
c14a41f
Merge branch 'master' into feat/unsigned_long
bpintea Feb 2, 2022
5302100
Extract UL to Unsupported map transf. to own class
bpintea Feb 2, 2022
fba1d65
Move compat filtering out of the Analyzer
bpintea Feb 2, 2022
80c79d4
Merge branch 'master' into feat/unsigned_long
bpintea Feb 3, 2022
6ce3a1e
Apply review comments. Bump UL intro version
bpintea Feb 3, 2022
4ef30c1
Merge branch 'master' into feat/unsigned_long
elasticmachine Feb 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/changelog/65145.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 65145
summary: Add `unsigned_long` type support
area: Query Languages
type: enhancement
issues:
- 63312
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package org.elasticsearch.xpack.eql.session;

import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.client.internal.ParentTaskAssigningClient;
Expand Down Expand Up @@ -120,6 +121,7 @@ private <T> void preAnalyze(LogicalPlan parsed, ActionListener<LogicalPlan> list
indexWildcard,
configuration.indicesOptions(),
configuration.runtimeMappings(),
Version.CURRENT,
map(listener, r -> preAnalyzer.preAnalyze(parsed, r))
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
* 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<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ protected ScriptTemplate scriptWithField(FieldAttribute field) {
return field.dataType() != UNSIGNED_LONG
? new ScriptTemplate(processScript(Scripts.DOC_VALUE), params, dataType())
: new ScriptTemplate(
processScript(formatTemplate(format("{ql}.", "nullSafeCastToUnsignedLong({})", Scripts.DOC_VALUE))),
processScript(format("{ql}.", "nullSafeCastToUnsignedLong({})", Scripts.DOC_VALUE)),
params,
UNSIGNED_LONG
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;

import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
Expand Down Expand Up @@ -68,10 +69,12 @@
import static org.elasticsearch.common.Strings.hasText;
import static org.elasticsearch.common.regex.Regex.simpleMatch;
import static org.elasticsearch.transport.RemoteClusterAware.buildRemoteIndexName;
import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.supportsUnsignedLong;
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;
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.util.StringUtils.qualifyAndJoinIndices;
import static org.elasticsearch.xpack.ql.util.StringUtils.splitQualifiedIndex;
Expand Down Expand Up @@ -366,12 +369,16 @@ public void resolveAsMergedMapping(
String indexWildcard,
IndicesOptions indicesOptions,
Map<String, Object> runtimeMappings,
Version version,
ActionListener<IndexResolution> listener
) {
FieldCapabilitiesRequest fieldRequest = createFieldCapsRequest(indexWildcard, indicesOptions, runtimeMappings);
client.fieldCaps(
fieldRequest,
ActionListener.wrap(response -> listener.onResponse(mergedMappings(typeRegistry, indexWildcard, response)), listener::onFailure)
ActionListener.wrap(
response -> listener.onResponse(mergedMappings(typeRegistry, indexWildcard, response, version)),
listener::onFailure
)
);
}

Expand All @@ -382,27 +389,32 @@ public void resolveAsMergedMapping(
String indexWildcard,
boolean includeFrozen,
Map<String, Object> runtimeMappings,
Version version,
ActionListener<IndexResolution> listener
) {
FieldCapabilitiesRequest fieldRequest = createFieldCapsRequest(indexWildcard, includeFrozen, runtimeMappings);
client.fieldCaps(
fieldRequest,
ActionListener.wrap(response -> listener.onResponse(mergedMappings(typeRegistry, indexWildcard, response)), listener::onFailure)
ActionListener.wrap(
response -> listener.onResponse(mergedMappings(typeRegistry, indexWildcard, response, version)),
listener::onFailure
)
);
}

public static IndexResolution mergedMappings(
DataTypeRegistry typeRegistry,
String indexPattern,
FieldCapabilitiesResponse fieldCapsResponse
FieldCapabilitiesResponse fieldCapsResponse,
Version version
) {

if (fieldCapsResponse.getIndices().length == 0) {
return IndexResolution.notFound(indexPattern);
}

// merge all indices onto the same one
List<EsIndex> indices = buildIndices(typeRegistry, null, fieldCapsResponse, null, i -> indexPattern, (n, types) -> {
List<EsIndex> indices = buildIndices(typeRegistry, null, fieldCapsResponse, null, i -> indexPattern, version, (n, types) -> {
StringBuilder errorMessage = new StringBuilder();

boolean hasUnmapped = types.containsKey(UNMAPPED);
Expand Down Expand Up @@ -473,7 +485,8 @@ private static EsField createField(
Map<String, Map<String, FieldCapabilities>> globalCaps,
Map<String, EsField> hierarchicalMapping,
Map<String, EsField> flattedMapping,
Function<String, EsField> field
Function<String, EsField> field,
Version version
) {

Map<String, EsField> parentProps = hierarchicalMapping;
Expand All @@ -493,18 +506,26 @@ private static EsField createField(
// lack of parent implies the field is an alias
if (map == null) {
// as such, create the field manually, marking the field to also be an alias
fieldFunction = s -> createField(typeRegistry, s, OBJECT.esType(), new TreeMap<>(), false, true);
fieldFunction = s -> createField(typeRegistry, s, OBJECT.esType(), new TreeMap<>(), false, true, version);
} else {
Iterator<FieldCapabilities> iterator = map.values().iterator();
FieldCapabilities parentCap = iterator.next();
if (iterator.hasNext() && UNMAPPED.equals(parentCap.getType())) {
parentCap = iterator.next();
}
final FieldCapabilities parentC = parentCap;
fieldFunction = s -> createField(typeRegistry, s, parentC.getType(), new TreeMap<>(), parentC.isAggregatable(), false);
fieldFunction = s -> createField(
typeRegistry,
s,
parentC.getType(),
new TreeMap<>(),
parentC.isAggregatable(),
false,
version
);
}

parent = createField(typeRegistry, parentName, globalCaps, hierarchicalMapping, flattedMapping, fieldFunction);
parent = createField(typeRegistry, parentName, globalCaps, hierarchicalMapping, flattedMapping, fieldFunction, version);
}
parentProps = parent.getProperties();
}
Expand Down Expand Up @@ -537,7 +558,8 @@ private static EsField createField(
String typeName,
Map<String, EsField> props,
boolean isAggregateable,
boolean isAlias
boolean isAlias,
Version version
) {
DataType esType = typeRegistry.fromEs(typeName);

Expand All @@ -553,7 +575,7 @@ private static EsField createField(
if (esType == DATETIME) {
return DateEsField.dateEsField(fieldName, props, isAggregateable);
}
if (esType == UNSUPPORTED) {
if (esType == UNSUPPORTED || (esType == UNSIGNED_LONG && supportsUnsignedLong(version) == false)) {
return new UnsupportedEsField(fieldName, typeName, null, props);
}

Expand Down Expand Up @@ -591,6 +613,7 @@ public void resolveAsSeparateMappings(
String javaRegex,
boolean includeFrozen,
Map<String, Object> runtimeMappings,
Version version,
ActionListener<List<EsIndex>> listener
) {
FieldCapabilitiesRequest fieldRequest = createFieldCapsRequest(indexWildcard, includeFrozen, runtimeMappings);
Expand All @@ -600,10 +623,12 @@ public void resolveAsSeparateMappings(
.getAliases(
createGetAliasesRequest(response, includeFrozen),
wrap(
aliases -> { listener.onResponse(separateMappings(typeRegistry, javaRegex, response, aliases.getAliases())); },
aliases -> {
listener.onResponse(separateMappings(typeRegistry, javaRegex, response, aliases.getAliases(), version));
},
ex -> {
if (ex instanceof IndexNotFoundException || ex instanceof ElasticsearchSecurityException) {
listener.onResponse(separateMappings(typeRegistry, javaRegex, response, null));
listener.onResponse(separateMappings(typeRegistry, javaRegex, response, null, version));
} else {
listener.onFailure(ex);
}
Expand All @@ -625,9 +650,10 @@ public static List<EsIndex> separateMappings(
DataTypeRegistry typeRegistry,
String javaRegex,
FieldCapabilitiesResponse fieldCaps,
ImmutableOpenMap<String, List<AliasMetadata>> aliases
ImmutableOpenMap<String, List<AliasMetadata>> aliases,
Version version
) {
return buildIndices(typeRegistry, javaRegex, fieldCaps, aliases, Function.identity(), (s, cap) -> null);
return buildIndices(typeRegistry, javaRegex, fieldCaps, aliases, Function.identity(), version, (s, cap) -> null);
}

private static class Fields {
Expand All @@ -645,6 +671,7 @@ private static List<EsIndex> buildIndices(
FieldCapabilitiesResponse fieldCapsResponse,
ImmutableOpenMap<String, List<AliasMetadata>> aliases,
Function<String, String> indexNameProcessor,
Version version,
BiFunction<String, Map<String, FieldCapabilities>, InvalidMappedField> validityVerifier
) {

Expand Down Expand Up @@ -780,8 +807,10 @@ private static List<EsIndex> buildIndices(
typeCap.getType(),
emptyMap(),
typeCap.isAggregatable(),
isAliasFieldType.get()
)
isAliasFieldType.get(),
version
),
version
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,22 @@
* 2.0.
*/

package org.elasticsearch.xpack.sql.session;
package org.elasticsearch.xpack.ql.index;

import org.elasticsearch.Version;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.xpack.ql.type.DataType;
import org.elasticsearch.xpack.sql.proto.SqlVersion;

import static org.elasticsearch.Version.V_8_1_0;
import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;

public final class VersionCompatibilityChecks {

public static final SqlVersion INTRODUCING_UNSIGNED_LONG = SqlVersion.fromId(V_8_1_0.id);
public static final Version INTRODUCING_UNSIGNED_LONG = V_8_1_0;

private VersionCompatibilityChecks() {}

/**
* Is the provided {@code dataType} being supported in the provided {@code version}?
*/
public static boolean isTypeSupportedInVersion(DataType dataType, SqlVersion version) {
public static boolean isTypeSupportedInVersion(DataType dataType, Version version) {
if (dataType == UNSIGNED_LONG) {
return supportsUnsignedLong(version);
}
Expand All @@ -33,11 +30,11 @@ public static boolean isTypeSupportedInVersion(DataType dataType, SqlVersion ver
/**
* Does the provided {@code version} support the unsigned_long type (PR#60050)?
*/
public static boolean supportsUnsignedLong(SqlVersion version) {
public static boolean supportsUnsignedLong(Version version) {
return INTRODUCING_UNSIGNED_LONG.compareTo(version) <= 0;
}

public static @Nullable SqlVersion versionIntroducingType(DataType dataType) {
public static @Nullable Version versionIntroducingType(DataType dataType) {
if (dataType == UNSIGNED_LONG) {
return INTRODUCING_UNSIGNED_LONG;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package org.elasticsearch.xpack.ql.type;

import org.elasticsearch.Version;
import org.elasticsearch.common.Strings;
import org.elasticsearch.core.Booleans;

Expand All @@ -15,32 +16,34 @@
import java.util.Map.Entry;

import static java.util.Collections.emptyMap;
import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.supportsUnsignedLong;
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;
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;

public abstract class Types {

@SuppressWarnings("unchecked")
public static Map<String, EsField> fromEs(DataTypeRegistry typeRegistry, Map<String, Object> asMap) {
public static Map<String, EsField> fromEs(DataTypeRegistry typeRegistry, Map<String, Object> asMap, Version version) {
Map<String, Object> props = null;
if (asMap != null && asMap.isEmpty() == false) {
props = (Map<String, Object>) asMap.get("properties");
}
return props == null || props.isEmpty() ? emptyMap() : startWalking(typeRegistry, props);
return props == null || props.isEmpty() ? emptyMap() : startWalking(typeRegistry, props, version);
}

private static Map<String, EsField> startWalking(DataTypeRegistry typeRegistry, Map<String, Object> mapping) {
private static Map<String, EsField> startWalking(DataTypeRegistry typeRegistry, Map<String, Object> mapping, Version version) {
Map<String, EsField> types = new LinkedHashMap<>();

if (mapping == null) {
return emptyMap();
}
for (Entry<String, Object> entry : mapping.entrySet()) {
walkMapping(typeRegistry, entry.getKey(), entry.getValue(), types);
walkMapping(typeRegistry, entry.getKey(), entry.getValue(), types, version);
}

return types;
Expand All @@ -65,7 +68,13 @@ private static DataType getType(DataTypeRegistry typeRegistry, Map<String, Objec
}

@SuppressWarnings("unchecked")
private static void walkMapping(DataTypeRegistry typeRegistry, String name, Object value, Map<String, EsField> mapping) {
private static void walkMapping(
DataTypeRegistry typeRegistry,
String name,
Object value,
Map<String, EsField> mapping,
Version version
) {
// object type - only root or nested docs supported
if (value instanceof Map) {
Map<String, Object> content = (Map<String, Object>) value;
Expand All @@ -74,17 +83,17 @@ private static void walkMapping(DataTypeRegistry typeRegistry, String name, Obje
DataType esDataType = getType(typeRegistry, content);
final Map<String, EsField> properties;
if (esDataType == OBJECT || esDataType == NESTED) {
properties = fromEs(typeRegistry, content);
properties = fromEs(typeRegistry, content, version);
} else if (content.containsKey("fields")) {
// Check for multifields
Object fields = content.get("fields");
if (fields instanceof Map) {
properties = startWalking(typeRegistry, (Map<String, Object>) fields);
properties = startWalking(typeRegistry, (Map<String, Object>) fields, version);
} else {
properties = Collections.emptyMap();
}
} else {
properties = fromEs(typeRegistry, content);
properties = fromEs(typeRegistry, content, version);
}
boolean docValues = boolSetting(content.get("doc_values"), esDataType.hasDocValues());
final EsField field;
Expand All @@ -96,7 +105,7 @@ private static void walkMapping(DataTypeRegistry typeRegistry, String name, Obje
field = new KeywordEsField(name, properties, docValues, length, normalized);
} else if (esDataType == DATETIME) {
field = DateEsField.dateEsField(name, properties, docValues);
} else if (esDataType == UNSUPPORTED) {
} else if (esDataType == UNSUPPORTED || (esDataType == UNSIGNED_LONG && supportsUnsignedLong(version) == false)) {
String type = content.get("type").toString();
field = new UnsupportedEsField(name, type, null, properties);
propagateUnsupportedType(name, type, properties);
Expand Down
Loading