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

Add support for VERSION field type in SQL and EQL #85502

Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0e7f61a
Add support for VERSION field type in SQL and EQL
luigidellaquila Mar 30, 2022
f5c79f8
Update docs/changelog/85502.yaml
luigidellaquila Mar 30, 2022
dbe5c67
Add SQL csv-spec tests for VERSION fields
luigidellaquila Mar 30, 2022
c3e8803
Merge remote-tracking branch 'luigidellaquila/enhancement/support_ver…
luigidellaquila Mar 30, 2022
965b6c1
Fix test cases
luigidellaquila Mar 31, 2022
7d2361d
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine Mar 31, 2022
288b5f8
Fix test to consider v 8.3 as version of introduction of the feature
luigidellaquila Mar 31, 2022
9f8cb6e
Fix frozen csv test cases
luigidellaquila Mar 31, 2022
3a59ec8
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine Mar 31, 2022
f449255
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine Mar 31, 2022
dfe4013
Fix further tests
luigidellaquila Mar 31, 2022
c56cf37
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine Mar 31, 2022
22936d2
Merge remote-tracking branch 'luigidellaquila/enhancement/support_ver…
luigidellaquila Mar 31, 2022
2f16de6
Implement comparison of Version fields (folding)
luigidellaquila Apr 1, 2022
43402e3
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine Apr 11, 2022
85697ad
Manage compatibility
luigidellaquila Apr 12, 2022
0a0eaf6
Fix test cases
luigidellaquila Apr 12, 2022
feb82fe
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine May 9, 2022
eae32e1
Add support for ORDER BY versionValueCalculatedWithScript
luigidellaquila May 9, 2022
49a643b
Merge branch 'master' into enhancement/support_version_data_type_in_ql
luigidellaquila May 10, 2022
401d12e
Add further tests and address review comments
luigidellaquila May 12, 2022
c5040b2
Merge branch 'master' into enhancement/support_version_data_type_in_ql
luigidellaquila May 12, 2022
9e52c2f
Fix based on review suggestions
luigidellaquila May 17, 2022
c9fe537
Merge branch 'master' into enhancement/support_version_data_type_in_ql
luigidellaquila May 19, 2022
4384010
Add further fixes based on reviews
luigidellaquila May 20, 2022
b266021
Merge branch 'master' into enhancement/support_version_data_type_in_ql
luigidellaquila May 26, 2022
4ddef7f
Update version for bwc checks (to v 8.4.0)
luigidellaquila May 26, 2022
aaa77b0
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine May 30, 2022
d8b5473
Implement review suggestions
luigidellaquila Jun 1, 2022
ff9139e
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine Jun 1, 2022
e31a21f
Revert unnescessary changes to mapper-version
luigidellaquila Jun 8, 2022
dacefd6
Merge remote-tracking branch 'luigidellaquila/enhancement/support_ver…
luigidellaquila Jun 8, 2022
a92defd
Implement review suggestions
luigidellaquila Jun 8, 2022
9bfaf86
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine Jun 8, 2022
e59952d
Merge remote-tracking branch 'luigidellaquila/enhancement/support_ver…
luigidellaquila Jun 8, 2022
89aa381
Fix compile problems after merge from master
luigidellaquila Jun 8, 2022
dd12a67
Fix failing test case (due to refactoring on master)
luigidellaquila Jun 8, 2022
e644334
Merge branch 'master' into enhancement/support_version_data_type_in_ql
elasticmachine Jun 8, 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/85502.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 85502
summary: Add support for VERSION field type in SQL and EQL
area: Query Languages
type: enhancement
issues:
- 83375
1 change: 1 addition & 0 deletions docs/reference/sql/language/data-types.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ s|SQL precision
| <<binary, `binary`>> | binary | VARBINARY | 2,147,483,647
| <<date, `date`>> | datetime | TIMESTAMP | 29
| <<ip, `ip`>> | ip | VARCHAR | 39
| <<version, `version`>> | version | VARCHAR | 32,766

4+h| Complex types

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"transID": 2,
"process.entity_id": 512,
"process.pid": 123,
"version": "1.5.0",
"sequence": 18
},
{
Expand All @@ -120,6 +121,7 @@
"transID": 0,
"process.entity_id": 512,
"process.pid": 123,
"version": "1.5.0",
"sequence": 19
},
{
Expand All @@ -128,6 +130,7 @@
"transID": 0,
"process.entity_id": 512,
"process.pid": 123,
"version": "1.2.4",
"sequence": 20
},
{
Expand All @@ -136,6 +139,7 @@
"transID": 0,
"process.entity_id": 512,
"process.pid": 123,
"version": "1.11.3",
"sequence": 21
},
{
Expand All @@ -144,6 +148,7 @@
"transID": 0,
"process.entity_id": 512,
"process.pid": 123,
"version": "bad",
"sequence": 22
},
{
Expand All @@ -152,6 +157,7 @@
"transID": 0,
"process.entity_id": 512,
"process.pid": 123,
"version": "1.2.4-SNAPSHOT",
"sequence": 23
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
"optional_field_default_null": {
"type": "keyword",
"null_value": "NULL"
},
"version": {
"type": "version"
}
}
}
70 changes: 66 additions & 4 deletions x-pack/plugin/eql/qa/common/src/main/resources/test_extra.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ expected_event_ids = []
[[queries]]
name = "sequenceOptionalFieldAsKeyAndFirstFilter"
query = '''
sequence by ?x
sequence by ?x
[OPTIONAL where ?x == null]
[OPTIONAL where true]
'''
Expand Down Expand Up @@ -137,7 +137,7 @@ expected_event_ids = [12,13,14,
join_keys = ["null","123",
"null","null",
"512","123"]

[[queries]]
name = "sequenceOneKeyOptional_1"
query = '''
Expand All @@ -159,7 +159,7 @@ expected_event_ids = [12,13,14,
18,19,20]
join_keys = ["null","123",
"512","123"]

[[queries]]
name = "sequenceNoOptionalKeys"
query = '''
Expand Down Expand Up @@ -195,7 +195,7 @@ expected_event_ids = [12,13,14,
join_keys = ["null","123",
"null","null",
"512","123"]

[[queries]]
name = "sequenceWithOptionalFieldsAndUntil_2"
query = '''
Expand All @@ -209,3 +209,65 @@ expected_event_ids = [12,13,14,
join_keys = ["null","123",
"null","null"]

[[queries]]
name = "sequenceWithVersionCheck"
query = '''
sequence by transID
[ file where version == "1.2.4" ]
[ file where version == "1.11.3" ]
'''
expected_event_ids = [20, 21]
join_keys = ["0"]

[[queries]]
name = "sequenceWithVersionRangeCheck"
query = '''
sequence by transID
[ file where version == "1.2.4" ]
[ file where version > "1.5.0" ]
'''
expected_event_ids = [20, 21]
join_keys = ["0"]

[[queries]]
name = "sequenceWithVersionRangeCheck2"
query = '''
sequence by transID
[ file where version == "1.2.4" ]
[ file where version < "1.5.0" ]
'''
expected_event_ids = [20, 23]
join_keys = ["0"]


[[queries]]
name = "sequenceWithInvalidVersion"
query = '''
sequence by transID
[ file where version == "1.2.4" ]
[ file where version == "bad" ]
'''
expected_event_ids = [20, 22]
join_keys = ["0"]


[[queries]]
name = "sequenceWithVersionConcat"
query = '''
sequence by transID
Copy link
Contributor

Choose a reason for hiding this comment

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

can a version also be the join key?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, adding a specific test case

[ file where CONCAT(version, "") == "1.2.4" ]
[ file where version == "bad" ]
'''
expected_event_ids = [20, 22]
join_keys = ["0"]


[[queries]]
name = "sequenceWithVersionJoinKey"
query = '''
sequence by version
[ process where true ]
[ file where true ]
'''
expected_event_ids = [18, 19]
join_keys = ["1.5.0"]
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import org.elasticsearch.search.fetch.subphase.FieldAndFormat;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.NestedSortBuilder;
import org.elasticsearch.search.sort.ScriptSortBuilder.ScriptSortType;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.xpack.eql.querydsl.container.QueryContainer;
import org.elasticsearch.xpack.ql.execution.search.QlSourceBuilder;
Expand Down Expand Up @@ -133,10 +132,7 @@ private static void sorting(QueryContainer container, SearchSourceBuilder source
}
}
} else if (sortable instanceof ScriptSort ss) {
sortBuilder = scriptSort(
ss.script().toPainless(),
ss.script().outputType().isNumeric() ? ScriptSortType.NUMBER : ScriptSortType.STRING
);
sortBuilder = scriptSort(ss.script().toPainless(), ss.script().outputType().scriptSortType());
}

if (sortBuilder != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.elasticsearch.painless.spi.WhitelistLoader;
import org.elasticsearch.script.AggregationScript;
import org.elasticsearch.script.BucketAggregationSelectorScript;
import org.elasticsearch.script.BytesRefSortScript;
import org.elasticsearch.script.FieldScript;
import org.elasticsearch.script.FilterScript;
import org.elasticsearch.script.NumberSortScript;
Expand All @@ -36,6 +37,7 @@ public Map<ScriptContext<?>, List<Whitelist>> getContextWhitelists() {
whitelist.put(FieldScript.CONTEXT, list);
whitelist.put(NumberSortScript.CONTEXT, list);
whitelist.put(StringSortScript.CONTEXT, list);
whitelist.put(BytesRefSortScript.CONTEXT, list);
whitelist.put(BucketAggregationSelectorScript.CONTEXT, list);
return whitelist;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public void testQueryCondition() {
assertEquals("1:11: Condition expression needs to be boolean, found [TEXT]", error("any where hostname"));
assertEquals("1:11: Condition expression needs to be boolean, found [KEYWORD]", error("any where constant_keyword"));
assertEquals("1:11: Condition expression needs to be boolean, found [IP]", error("any where source_address"));
assertEquals("1:11: Condition expression needs to be boolean, found [VERSION]", error("any where version"));
}

public void testQueryStartsWithNumber() {
Expand Down Expand Up @@ -363,6 +364,11 @@ public void testIP() {
accept(idxr, "foo where ip_addr == 0");
}

public void testVersion() {
final IndexResolution idxr = loadIndexResolution("mapping-version.json");
accept(idxr, "foo where version_number == \"2.1.4\"");
}

public void testJoin() {
final IndexResolution idxr = loadIndexResolution("mapping-join.json");
accept(idxr, "foo where serial_event_id == 0");
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugin/eql/src/test/resources/mapping-default.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@
},
"bool" : {
"type" : "boolean"
},
"version" : {
"type" : "version"
}
}
}
17 changes: 17 additions & 0 deletions x-pack/plugin/eql/src/test/resources/mapping-version.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"properties" : {
"event" : {
"properties" : {
"category" : {
"type" : "keyword"
}
}
},
"@timestamp" : {
"type" : "date"
},
"version_number" : {
"type" : "version"
}
}
}
14 changes: 14 additions & 0 deletions x-pack/plugin/eql/src/test/resources/querytranslator_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -901,3 +901,17 @@ process where pid > 100 and pid < 200
// the "not" has an undefined location of where it should be used in the Painless script
// disjunctionInsideFunctionWithNot
// process where string(pid > 5 and pid != 10) == \"true\"


versionFieldAutomaticConversion
process where version > "2"
;
{"range":{"version":{"gt":"2"
;

versionFieldCast
process where CONCAT(version, constant_keyword) > "2"
;
{"script":{"source":"InternalEqlScriptUtils.multiValueDocValues(doc,params.v0,X0->InternalEqlScriptUtils.multiValueDocValues(doc,params.v1,X1->InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.gt(InternalEqlScriptUtils.concat([X0,X1]),params.v2))))"
"params":{"v0":"version","v1":"constant_keyword","v2":"2"}}
;
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
* lexically in ASCII sort order. Numeric identifiers always have lower precedence than non-numeric identifiers.
* </ul>
*/
class VersionEncoder {
public class VersionEncoder {
Copy link
Member

Choose a reason for hiding this comment

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

Since the code touches on code outside QL, please find one of the authors/team responsible for the code to review these changes.
If only constants are being used, it's fine to copy them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, actually these changes are a leftover from the previous attempts to support Version without impacting on the Search/Painless implementation, but since we went with a more complete solution (see #85990), we don't need them anymore.


public static final byte NUMERIC_MARKER_BYTE = (byte) 0x01;
public static final byte PRERELEASE_SEPARATOR_BYTE = (byte) 0x02;
Expand Down Expand Up @@ -175,7 +175,7 @@ static boolean legalVersionString(VersionParts versionParts) {
return legalMainVersion && legalPreRelease && legalBuildSuffix;
}

static class EncodedVersion {
public static class EncodedVersion {

public final boolean isLegal;
public final boolean isPreRelease;
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugin/ql/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ archivesBaseName = 'x-pack-ql'

dependencies {
api "org.antlr:antlr4-runtime:${antlrVersion}"
api project(path: xpackModule('mapper-version'))
compileOnly project(path: xpackModule('core'))
testApi(project(xpackModule('ql:test-fixtures'))) {
exclude group: 'org.elasticsearch.plugin', module: 'ql'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/
package org.elasticsearch.xpack.ql.expression.predicate.operator.comparison;

import org.elasticsearch.xpack.versionfield.Version;

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

Expand Down Expand Up @@ -71,13 +73,21 @@ static Integer compare(Object l, Object r) {
return null;
}
// typical number comparison
if (l instanceof Number && r instanceof Number) {
return compare((Number) l, (Number) r);
if (l instanceof Number lN && r instanceof Number rN) {
return compare(lN, rN);
}

// automatic conversion for versions
Copy link
Contributor

Choose a reason for hiding this comment

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

is this still needed? Shouldn't by now the runtime type always be Version?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It depends on how tolerant we want to be with automatic casts in situations like local folding (e.g WHERE '1.2.0' < '1.11.0'::version) and function evaluation (eg. IIF(version > '1.1', 1, 0)).

In general, we do not do it for local folding (eg. for numbers '2' > 1 returns false) but we do it for field queries (eg. id > '3' will evaluate to true even if id is numeric, same with version > 1.2).

IMHO this is an inconsistency: the same operation should have the same behavior, locally and in _search.
Since local folding is just an optimization or a fallback in most of the cases, so I tend to consider the automatic cast as the expected behavior.

So from my point of view we should leave it as it is

Copy link
Contributor

Choose a reason for hiding this comment

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

I would tend to not make an exception for Version. Since we have this distinction between local execution and queries it should at least be consistent across types.

if (l instanceof Version lV && r instanceof String rStr) {
return lV.compareTo(new Version(rStr));
}
if (l instanceof String lStr && r instanceof Version rV) {
return new Version(lStr).compareTo(rV);
}

if (l instanceof Comparable && r instanceof Comparable) {
if (l instanceof Comparable lC && r instanceof Comparable) {
try {
return Integer.valueOf(((Comparable) l).compareTo(r));
return Integer.valueOf(lC.compareTo(r));
} catch (ClassCastException cce) {
// when types are not compatible, cce is thrown
// fall back to null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,24 @@
import org.elasticsearch.xpack.ql.type.DataType;

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

public final class VersionCompatibilityChecks {

public static final Version INTRODUCING_UNSIGNED_LONG = V_8_2_0;
public static final Version INTRODUCING_VERSION_FIELD_TYPE = V_8_4_0;

private VersionCompatibilityChecks() {}

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

Expand All @@ -34,10 +40,20 @@ public static boolean supportsUnsignedLong(Version version) {
return INTRODUCING_UNSIGNED_LONG.compareTo(version) <= 0;
}

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

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

return null;
}
Expand Down
Loading