Skip to content
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

QL: add unsigned_long type support #65145

Merged
merged 56 commits into from
Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
bpintea 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 @@ -49,7 +49,6 @@
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.LessThanOrEqual;
import org.elasticsearch.xpack.ql.expression.predicate.regex.Like;
import org.elasticsearch.xpack.ql.tree.Source;
import org.elasticsearch.xpack.ql.type.DataType;
import org.elasticsearch.xpack.ql.type.DataTypes;
import org.elasticsearch.xpack.ql.util.StringUtils;

Expand Down Expand Up @@ -240,10 +239,9 @@ public Literal visitIntegerLiteral(EqlBaseParser.IntegerLiteralContext ctx) {
Source source = source(ctx);
String text = ctx.getText();

long value;

try {
value = Long.valueOf(StringUtils.parseLong(text));
Number value = StringUtils.parseIntegral(text);
return new Literal(source, value, DataTypes.fromJava(value));
} catch (QlIllegalArgumentException siae) {
// if it's too large, then quietly try to parse as a float instead
try {
Expand All @@ -252,16 +250,6 @@ public Literal visitIntegerLiteral(EqlBaseParser.IntegerLiteralContext ctx) {

throw new ParsingException(source, siae.getMessage());
}

Object val = Long.valueOf(value);
DataType type = DataTypes.LONG;

// try to downsize to int if possible (since that's the most common type)
if ((int) value == value) {
type = DataTypes.INTEGER;
val = Integer.valueOf((int) value);
}
return new Literal(source, val, type);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class org.elasticsearch.xpack.ql.expression.function.scalar.whitelist.InternalQl
double nullSafeSortNumeric(Number)
String nullSafeSortString(Object)
Number nullSafeCastNumeric(Number, String)
Number nullSafeCastToUnsignedLong(Number)

#
# ASCII Functions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ public void testNumeric() {
accept(idxr, "foo where float_field == 0");
accept(idxr, "foo where half_float_field == 0");
accept(idxr, "foo where scaled_float_field == 0");
accept(idxr, "foo where unsigned_long_field == 0");

// Test query against unsupported field type int
assertEquals(
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugin/eql/src/test/resources/mapping-numeric.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
"scaled_float_field": {
"type" : "scaled_float"
},
"unsigned_long_field" : {
"type": "unsigned_long"
},
"wrong_int_type_field": {
"type" : "int"
}
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 @@ -12,6 +12,7 @@
import org.elasticsearch.xpack.ql.expression.function.Function;
import org.elasticsearch.xpack.ql.expression.function.aggregate.AggregateFunction;
import org.elasticsearch.xpack.ql.expression.function.grouping.GroupingFunction;
import org.elasticsearch.xpack.ql.expression.gen.script.Params;
import org.elasticsearch.xpack.ql.expression.gen.script.ParamsBuilder;
import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate;
import org.elasticsearch.xpack.ql.expression.gen.script.Scripts;
Expand All @@ -24,10 +25,12 @@
import java.util.List;

import static java.util.Collections.emptyList;
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
import static org.elasticsearch.xpack.ql.expression.gen.script.ParamsBuilder.paramsBuilder;
import static org.elasticsearch.xpack.ql.expression.gen.script.Scripts.PARAM;
import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
import static org.elasticsearch.xpack.ql.type.DataTypes.LONG;
import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG;

/**
* A {@code ScalarFunction} is a {@code Function} that takes values from some
Expand Down Expand Up @@ -150,7 +153,15 @@ protected ScriptTemplate scriptWithGrouping(GroupingFunction grouping) {
}

protected ScriptTemplate scriptWithField(FieldAttribute field) {
return new ScriptTemplate(processScript(Scripts.DOC_VALUE), paramsBuilder().variable(field.name()).build(), dataType());
Params params = paramsBuilder().variable(field.name()).build();
// unsigned_long fields get returned in scripts as plain longs, so a conversion is required
return field.dataType() != UNSIGNED_LONG
? new ScriptTemplate(processScript(Scripts.DOC_VALUE), params, dataType())
: new ScriptTemplate(
processScript(format("{ql}.", "nullSafeCastToUnsignedLong({})", Scripts.DOC_VALUE)),
params,
UNSIGNED_LONG
);
}

protected String processScript(String script) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Map;

import static org.elasticsearch.xpack.ql.type.DataTypeConverter.convert;
import static org.elasticsearch.xpack.ql.type.DataTypeConverter.toUnsignedLong;
import static org.elasticsearch.xpack.ql.type.DataTypes.fromTypeName;

public class InternalQlScriptUtils {
Expand Down Expand Up @@ -58,6 +59,10 @@ public static Number nullSafeCastNumeric(Number number, String typeName) {
return number == null || Double.isNaN(number.doubleValue()) ? null : (Number) convert(number, fromTypeName(typeName));
}

public static Number nullSafeCastToUnsignedLong(Number number) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this new method creates a bwc issue in mixed node environments. Maybe consider bumping the minCompatibleShardNode version in org/elasticsearch/xpack/sql/execution/search/Querier.java:147 and cover it in SqlCompatIT.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the minCompatibleShardNode.
The test with bwcVersion nodes would fail indeed, but due to missing UL SQL support, not just missing script, while script support current version nodes is validated in other tests, so not sure how to add a meaningful test specifically for this.

return number == null || Double.isNaN(number.doubleValue()) ? null : toUnsignedLong(number);
}

//
// Operators
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

import org.elasticsearch.xpack.ql.QlIllegalArgumentException;

import java.math.BigInteger;
import java.util.function.BiFunction;

import static org.elasticsearch.xpack.ql.util.NumericUtils.asUnsignedLong;

/**
* Arithmetic operation using the type widening rules of the JLS 5.6.2 namely
* widen to double or float or long or int in this order.
Expand Down Expand Up @@ -43,6 +46,10 @@ public static Number add(Number l, Number r) {
if (l instanceof Float || r instanceof Float) {
return Float.valueOf(l.floatValue() + r.floatValue());
}
if (l instanceof BigInteger || r instanceof BigInteger) {
BigInteger bi = asBigInteger(l).add(asBigInteger(r));
return asUnsignedLong(bi);
}
if (l instanceof Long || r instanceof Long) {
return Long.valueOf(Math.addExact(l.longValue(), r.longValue()));
}
Expand All @@ -61,6 +68,10 @@ public static Number sub(Number l, Number r) {
if (l instanceof Float || r instanceof Float) {
return Float.valueOf(l.floatValue() - r.floatValue());
}
if (l instanceof BigInteger || r instanceof BigInteger) {
BigInteger bi = asBigInteger(l).subtract(asBigInteger(r));
return asUnsignedLong(bi);
}
if (l instanceof Long || r instanceof Long) {
return Long.valueOf(Math.subtractExact(l.longValue(), r.longValue()));
}
Expand All @@ -79,6 +90,13 @@ public static Number mul(Number l, Number r) {
if (l instanceof Float || r instanceof Float) {
return Float.valueOf(l.floatValue() * r.floatValue());
}
if (l instanceof BigInteger || r instanceof BigInteger) {
BigInteger bi = asBigInteger(l).multiply(asBigInteger(r));
// Note: in case of unsigned_long overflow (or underflow, with negative fixed point numbers), the exception is thrown.
// This is unlike the way some other traditional RDBMS that support unsigned types work, which simply promote the result to a
// floating point type, but in line with how our implementation treats other fixed point type operations (i.e. Math#xxExact()).
return asUnsignedLong(bi);
}
if (l instanceof Long || r instanceof Long) {
return Long.valueOf(Math.multiplyExact(l.longValue(), r.longValue()));
}
Expand All @@ -97,6 +115,10 @@ public static Number div(Number l, Number r) {
if (l instanceof Float || r instanceof Float) {
return l.floatValue() / r.floatValue();
}
if (l instanceof BigInteger || r instanceof BigInteger) {
BigInteger bi = asBigInteger(l).divide(asBigInteger(r));
return asUnsignedLong(bi);
}
if (l instanceof Long || r instanceof Long) {
return l.longValue() / r.longValue();
}
Expand All @@ -115,6 +137,10 @@ public static Number mod(Number l, Number r) {
if (l instanceof Float || r instanceof Float) {
return Float.valueOf(l.floatValue() % r.floatValue());
}
if (l instanceof BigInteger || r instanceof BigInteger) {
BigInteger bi = asBigInteger(l).remainder(asBigInteger(r));
return asUnsignedLong(bi);
}
if (l instanceof Long || r instanceof Long) {
return Long.valueOf(l.longValue() % r.longValue());
}
Expand All @@ -141,10 +167,20 @@ static Number negate(Number n) {
}
return Float.valueOf(-n.floatValue());
}
if (n instanceof BigInteger) {
if (((BigInteger) n).signum() != 0) {
bpintea marked this conversation as resolved.
Show resolved Hide resolved
throw new ArithmeticException("unsigned_long overflow"); // in the scope of the unsigned_long type
}
return n;
}
if (n instanceof Long) {
return Long.valueOf(Math.negateExact(n.longValue()));
}

return Integer.valueOf(Math.negateExact(n.intValue()));
}

public static BigInteger asBigInteger(Number n) {
return n instanceof BigInteger ? (BigInteger) n : BigInteger.valueOf(n.longValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
*/
package org.elasticsearch.xpack.ql.expression.predicate.operator.comparison;

import java.math.BigInteger;
import java.util.Set;

import static org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.Arithmetics.asBigInteger;

/**
* Comparison utilities.
*/
Expand Down Expand Up @@ -92,6 +95,9 @@ private static Integer compare(Number l, Number r) {
if (l instanceof Float || r instanceof Float) {
return Float.compare(l.floatValue(), r.floatValue());
}
if (l instanceof BigInteger || r instanceof BigInteger) {
return asBigInteger(l).compareTo(asBigInteger(r));
}
if (l instanceof Long || r instanceof Long) {
return Long.compare(l.longValue(), r.longValue());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.ql.index;

import org.elasticsearch.Version;
import org.elasticsearch.xpack.ql.type.DataType;
import org.elasticsearch.xpack.ql.type.EsField;
import org.elasticsearch.xpack.ql.type.UnsupportedEsField;

import java.util.Map;

import static org.elasticsearch.xpack.ql.index.VersionCompatibilityChecks.isTypeSupportedInVersion;
import static org.elasticsearch.xpack.ql.type.DataTypes.isPrimitive;
import static org.elasticsearch.xpack.ql.type.Types.propagateUnsupportedType;

public final class IndexCompatibility {

public static Map<String, EsField> compatible(Map<String, EsField> mapping, Version version) {
for (Map.Entry<String, EsField> entry : mapping.entrySet()) {
EsField esField = entry.getValue();
DataType dataType = esField.getDataType();
if (isPrimitive(dataType) == false) {
compatible(esField.getProperties(), version);
} else if (isTypeSupportedInVersion(dataType, version) == false) {
EsField field = new UnsupportedEsField(entry.getKey(), dataType.name(), null, esField.getProperties());
entry.setValue(field);
propagateUnsupportedType(entry.getKey(), dataType.name(), esField.getProperties());
}
}
return mapping;
}

public static EsIndex compatible(EsIndex esIndex, Version version) {
compatible(esIndex.mapping(), version);
return esIndex;
}

public static IndexResolution compatible(IndexResolution indexResolution, Version version) {
if (indexResolution.isValid()) {
compatible(indexResolution.get(), version);
}
return indexResolution;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.ql.index;

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

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

public final class VersionCompatibilityChecks {

public static final Version INTRODUCING_UNSIGNED_LONG = V_8_2_0;

private VersionCompatibilityChecks() {}

public static boolean isTypeSupportedInVersion(DataType dataType, Version version) {
if (dataType == UNSIGNED_LONG) {
return supportsUnsignedLong(version);
}
return true;
}

/**
* Does the provided {@code version} support the unsigned_long type (PR#60050)?
*/
public static boolean supportsUnsignedLong(Version version) {
return INTRODUCING_UNSIGNED_LONG.compareTo(version) <= 0;
}

public static @Nullable Version versionIntroducingType(DataType dataType) {
if (dataType == UNSIGNED_LONG) {
return INTRODUCING_UNSIGNED_LONG;
}

return null;
}
}
Loading