[8.14] [ES|QL] Improve validation for some ES|QL scenarios (#181381) (#181428)

# Backport

This will backport the following commits from `main` to `8.14`:
- [[ES|QL] Improve validation for some ES|QL scenarios
(#181381)](https://github.com/elastic/kibana/pull/181381)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Marco
Liberati","email":"dej611@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-04-23T12:26:11Z","message":"[ES|QL]
Improve validation for some ES|QL scenarios (#181381)\n\n##
Summary\r\n\r\nFixes some issues with specific types in ES|QL query
validation:\r\n* comparator operators now support `ip` type too\r\n*
`==` and `!=` support `boolean` type now\r\n* column/variable/returnType
of `any` type will skip strict type\r\nvalidation\r\n\r\n<img
width=\"534\" alt=\"Screenshot 2024-04-23 at 10 00
10\"\r\nsrc=\"81fb0cfa-d7e8-4cff-b834-efcaedbec14e\">\r\n<img
width=\"547\" alt=\"Screenshot 2024-04-23 at 09 53
12\"\r\nsrc=\"c1badb21-8a92-44cf-9532-576087a8383d\">\r\n<img
width=\"484\" alt=\"Screenshot 2024-04-23 at 09 52
58\"\r\nsrc=\"4e142260-1053-4a6b-a85e-3397e7a0256a\">\r\n<img
width=\"508\" alt=\"Screenshot 2024-04-23 at 09 52
53\"\r\nsrc=\"3e729f4e-fc34-43ad-b4ea-a4a558fe66c2\">\r\n\r\n\r\n###
Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"cc94a663115642439d3087edf63714151013aa23","branchLabelMapping":{"^v8.15.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","backport:prev-minor","Feature:ES|QL","v8.14.0","Team:ESQL","v8.15.0"],"title":"[ES|QL]
Improve validation for some ES|QL
scenarios","number":181381,"url":"https://github.com/elastic/kibana/pull/181381","mergeCommit":{"message":"[ES|QL]
Improve validation for some ES|QL scenarios (#181381)\n\n##
Summary\r\n\r\nFixes some issues with specific types in ES|QL query
validation:\r\n* comparator operators now support `ip` type too\r\n*
`==` and `!=` support `boolean` type now\r\n* column/variable/returnType
of `any` type will skip strict type\r\nvalidation\r\n\r\n<img
width=\"534\" alt=\"Screenshot 2024-04-23 at 10 00
10\"\r\nsrc=\"81fb0cfa-d7e8-4cff-b834-efcaedbec14e\">\r\n<img
width=\"547\" alt=\"Screenshot 2024-04-23 at 09 53
12\"\r\nsrc=\"c1badb21-8a92-44cf-9532-576087a8383d\">\r\n<img
width=\"484\" alt=\"Screenshot 2024-04-23 at 09 52
58\"\r\nsrc=\"4e142260-1053-4a6b-a85e-3397e7a0256a\">\r\n<img
width=\"508\" alt=\"Screenshot 2024-04-23 at 09 52
53\"\r\nsrc=\"3e729f4e-fc34-43ad-b4ea-a4a558fe66c2\">\r\n\r\n\r\n###
Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"cc94a663115642439d3087edf63714151013aa23"}},"sourceBranch":"main","suggestedTargetBranches":["8.14"],"targetPullRequestStates":[{"branch":"8.14","label":"v8.14.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.15.0","branchLabelMappingKey":"^v8.15.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/181381","number":181381,"mergeCommit":{"message":"[ES|QL]
Improve validation for some ES|QL scenarios (#181381)\n\n##
Summary\r\n\r\nFixes some issues with specific types in ES|QL query
validation:\r\n* comparator operators now support `ip` type too\r\n*
`==` and `!=` support `boolean` type now\r\n* column/variable/returnType
of `any` type will skip strict type\r\nvalidation\r\n\r\n<img
width=\"534\" alt=\"Screenshot 2024-04-23 at 10 00
10\"\r\nsrc=\"81fb0cfa-d7e8-4cff-b834-efcaedbec14e\">\r\n<img
width=\"547\" alt=\"Screenshot 2024-04-23 at 09 53
12\"\r\nsrc=\"c1badb21-8a92-44cf-9532-576087a8383d\">\r\n<img
width=\"484\" alt=\"Screenshot 2024-04-23 at 09 52
58\"\r\nsrc=\"4e142260-1053-4a6b-a85e-3397e7a0256a\">\r\n<img
width=\"508\" alt=\"Screenshot 2024-04-23 at 09 52
53\"\r\nsrc=\"3e729f4e-fc34-43ad-b4ea-a4a558fe66c2\">\r\n\r\n\r\n###
Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"cc94a663115642439d3087edf63714151013aa23"}}]}]
BACKPORT-->

Co-authored-by: Marco Liberati <dej611@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2024-04-23 09:48:29 -04:00 committed by GitHub
parent 2a5bc89e8a
commit d8c8a5b048
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 666 additions and 10 deletions

View file

@ -47,9 +47,11 @@ function createComparisonDefinition(
{
name,
description,
extraSignatures = [],
}: {
name: string;
description: string;
extraSignatures?: FunctionDefinition['signatures'];
},
validate?: FunctionDefinition['validate']
): FunctionDefinition {
@ -82,6 +84,14 @@ function createComparisonDefinition(
],
returnType: 'boolean',
},
{
params: [
{ name: 'left', type: 'ip' },
{ name: 'right', type: 'ip' },
],
returnType: 'boolean',
},
...extraSignatures,
],
};
}
@ -180,6 +190,15 @@ export const builtinFunctions: FunctionDefinition[] = [
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.equalToDoc', {
defaultMessage: 'Equal to',
}),
extraSignatures: [
{
params: [
{ name: 'left', type: 'boolean' },
{ name: 'right', type: 'boolean' },
],
returnType: 'boolean',
},
],
},
{
name: '!=',
@ -189,6 +208,15 @@ export const builtinFunctions: FunctionDefinition[] = [
defaultMessage: 'Not equal to',
}
),
extraSignatures: [
{
params: [
{ name: 'left', type: 'boolean' },
{ name: 'right', type: 'boolean' },
],
returnType: 'boolean',
},
],
},
{
name: '<',

View file

@ -380,7 +380,9 @@ export function isEqualType(
if (arg.type === 'function') {
if (isSupportedFunction(arg.name, parentCommand).supported) {
const fnDef = buildFunctionLookup().get(arg.name)!;
return fnDef.signatures.some((signature) => argType === signature.returnType);
return fnDef.signatures.some(
(signature) => signature.returnType === 'any' || argType === signature.returnType
);
}
}
if (arg.type === 'timeInterval') {
@ -397,7 +399,8 @@ export function isEqualType(
return false;
}
const wrappedTypes = Array.isArray(validHit.type) ? validHit.type : [validHit.type];
return wrappedTypes.some((ct) => argType === ct);
// if final type is of type any make it pass for now
return wrappedTypes.some((ct) => ct === 'any' || argType === ct);
}
}

View file

@ -2984,6 +2984,24 @@
],
"warning": []
},
{
"query": "row var = to_ip(\"127.0.0.1\") > to_ip(\"127.0.0.1\")",
"error": [],
"warning": []
},
{
"query": "row var = now() > now()",
"error": [],
"warning": []
},
{
"query": "row var = false > false",
"error": [
"Argument of [>] must be [number], found value [false] type [boolean]",
"Argument of [>] must be [number], found value [false] type [boolean]"
],
"warning": []
},
{
"query": "row var = 5 >= 0",
"error": [],
@ -3013,6 +3031,24 @@
],
"warning": []
},
{
"query": "row var = to_ip(\"127.0.0.1\") >= to_ip(\"127.0.0.1\")",
"error": [],
"warning": []
},
{
"query": "row var = now() >= now()",
"error": [],
"warning": []
},
{
"query": "row var = false >= false",
"error": [
"Argument of [>=] must be [number], found value [false] type [boolean]",
"Argument of [>=] must be [number], found value [false] type [boolean]"
],
"warning": []
},
{
"query": "row var = 5 < 0",
"error": [],
@ -3042,6 +3078,24 @@
],
"warning": []
},
{
"query": "row var = to_ip(\"127.0.0.1\") < to_ip(\"127.0.0.1\")",
"error": [],
"warning": []
},
{
"query": "row var = now() < now()",
"error": [],
"warning": []
},
{
"query": "row var = false < false",
"error": [
"Argument of [<] must be [number], found value [false] type [boolean]",
"Argument of [<] must be [number], found value [false] type [boolean]"
],
"warning": []
},
{
"query": "row var = 5 <= 0",
"error": [],
@ -3071,6 +3125,24 @@
],
"warning": []
},
{
"query": "row var = to_ip(\"127.0.0.1\") <= to_ip(\"127.0.0.1\")",
"error": [],
"warning": []
},
{
"query": "row var = now() <= now()",
"error": [],
"warning": []
},
{
"query": "row var = false <= false",
"error": [
"Argument of [<=] must be [number], found value [false] type [boolean]",
"Argument of [<=] must be [number], found value [false] type [boolean]"
],
"warning": []
},
{
"query": "row var = 5 == 0",
"error": [],
@ -3100,6 +3172,65 @@
],
"warning": []
},
{
"query": "row var = to_ip(\"127.0.0.1\") == to_ip(\"127.0.0.1\")",
"error": [],
"warning": []
},
{
"query": "row var = now() == now()",
"error": [],
"warning": []
},
{
"query": "row var = false == false",
"error": [],
"warning": []
},
{
"query": "row var = 5 != 0",
"error": [],
"warning": []
},
{
"query": "row var = NOT 5 != 0",
"error": [],
"warning": []
},
{
"query": "row var = (numberField != 0)",
"error": [
"Unknown column [numberField]"
],
"warning": []
},
{
"query": "row var = (NOT (5 != 0))",
"error": [],
"warning": []
},
{
"query": "row var = \"a\" != 0",
"error": [
"Argument of [!=] must be [number], found value [\"a\"] type [string]"
],
"warning": []
},
{
"query": "row var = to_ip(\"127.0.0.1\") != to_ip(\"127.0.0.1\")",
"error": [],
"warning": []
},
{
"query": "row var = now() != now()",
"error": [],
"warning": []
},
{
"query": "row var = false != false",
"error": [],
"warning": []
},
{
"query": "row var = 1 + 1",
"error": [],
@ -3110,6 +3241,11 @@
"error": [],
"warning": []
},
{
"query": "row var = now() + now()",
"error": [],
"warning": []
},
{
"query": "row var = 1 - 1",
"error": [],
@ -3120,6 +3256,11 @@
"error": [],
"warning": []
},
{
"query": "row var = now() - now()",
"error": [],
"warning": []
},
{
"query": "row var = 1 * 1",
"error": [],
@ -3130,6 +3271,14 @@
"error": [],
"warning": []
},
{
"query": "row var = now() * now()",
"error": [
"Argument of [*] must be [number], found value [now()] type [date]",
"Argument of [*] must be [number], found value [now()] type [date]"
],
"warning": []
},
{
"query": "row var = 1 / 1",
"error": [],
@ -3140,6 +3289,14 @@
"error": [],
"warning": []
},
{
"query": "row var = now() / now()",
"error": [
"Argument of [/] must be [number], found value [now()] type [date]",
"Argument of [/] must be [number], found value [now()] type [date]"
],
"warning": []
},
{
"query": "row var = 1 % 1",
"error": [],
@ -3150,6 +3307,14 @@
"error": [],
"warning": []
},
{
"query": "row var = now() % now()",
"error": [
"Argument of [%] must be [number], found value [now()] type [date]",
"Argument of [%] must be [number], found value [now()] type [date]"
],
"warning": []
},
{
"query": "row var = \"a\" like \"?a\"",
"error": [],
@ -5158,12 +5323,40 @@
"warning": []
},
{
"query": "from a_index | eval stringField > 0",
"query": "from a_index | where stringField > 0",
"error": [
"Argument of [>] must be [number], found value [stringField] type [string]"
],
"warning": []
},
{
"query": "from a_index | where stringField > stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField > numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | where dateField > dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | where booleanField > booleanField",
"error": [
"Argument of [>] must be [number], found value [booleanField] type [boolean]",
"Argument of [>] must be [number], found value [booleanField] type [boolean]"
],
"warning": []
},
{
"query": "from a_index | where ipField > ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField >= 0",
"error": [],
@ -5190,12 +5383,40 @@
"warning": []
},
{
"query": "from a_index | eval stringField >= 0",
"query": "from a_index | where stringField >= 0",
"error": [
"Argument of [>=] must be [number], found value [stringField] type [string]"
],
"warning": []
},
{
"query": "from a_index | where stringField >= stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField >= numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | where dateField >= dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | where booleanField >= booleanField",
"error": [
"Argument of [>=] must be [number], found value [booleanField] type [boolean]",
"Argument of [>=] must be [number], found value [booleanField] type [boolean]"
],
"warning": []
},
{
"query": "from a_index | where ipField >= ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField < 0",
"error": [],
@ -5222,12 +5443,40 @@
"warning": []
},
{
"query": "from a_index | eval stringField < 0",
"query": "from a_index | where stringField < 0",
"error": [
"Argument of [<] must be [number], found value [stringField] type [string]"
],
"warning": []
},
{
"query": "from a_index | where stringField < stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField < numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | where dateField < dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | where booleanField < booleanField",
"error": [
"Argument of [<] must be [number], found value [booleanField] type [boolean]",
"Argument of [<] must be [number], found value [booleanField] type [boolean]"
],
"warning": []
},
{
"query": "from a_index | where ipField < ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField <= 0",
"error": [],
@ -5254,12 +5503,40 @@
"warning": []
},
{
"query": "from a_index | eval stringField <= 0",
"query": "from a_index | where stringField <= 0",
"error": [
"Argument of [<=] must be [number], found value [stringField] type [string]"
],
"warning": []
},
{
"query": "from a_index | where stringField <= stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField <= numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | where dateField <= dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | where booleanField <= booleanField",
"error": [
"Argument of [<=] must be [number], found value [booleanField] type [boolean]",
"Argument of [<=] must be [number], found value [booleanField] type [boolean]"
],
"warning": []
},
{
"query": "from a_index | where ipField <= ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField == 0",
"error": [],
@ -5286,12 +5563,94 @@
"warning": []
},
{
"query": "from a_index | eval stringField == 0",
"query": "from a_index | where stringField == 0",
"error": [
"Argument of [==] must be [number], found value [stringField] type [string]"
],
"warning": []
},
{
"query": "from a_index | where stringField == stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField == numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | where dateField == dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | where booleanField == booleanField",
"error": [],
"warning": []
},
{
"query": "from a_index | where ipField == ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField != 0",
"error": [],
"warning": []
},
{
"query": "from a_index | where NOT numberField != 0",
"error": [],
"warning": []
},
{
"query": "from a_index | where (numberField != 0)",
"error": [],
"warning": []
},
{
"query": "from a_index | where (NOT (numberField != 0))",
"error": [],
"warning": []
},
{
"query": "from a_index | where 1 != 0",
"error": [],
"warning": []
},
{
"query": "from a_index | where stringField != 0",
"error": [
"Argument of [!=] must be [number], found value [stringField] type [string]"
],
"warning": []
},
{
"query": "from a_index | where stringField != stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | where numberField != numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | where dateField != dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | where booleanField != booleanField",
"error": [],
"warning": []
},
{
"query": "from a_index | where ipField != ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | where - numberField > 0",
"error": [],
@ -11418,6 +11777,34 @@
],
"warning": []
},
{
"query": "from a_index | eval stringField > stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField > numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval dateField > dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval booleanField > booleanField",
"error": [
"Argument of [>] must be [number], found value [booleanField] type [boolean]",
"Argument of [>] must be [number], found value [booleanField] type [boolean]"
],
"warning": []
},
{
"query": "from a_index | eval ipField > ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField >= 0",
"error": [],
@ -11450,6 +11837,34 @@
],
"warning": []
},
{
"query": "from a_index | eval stringField >= stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField >= numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval dateField >= dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval booleanField >= booleanField",
"error": [
"Argument of [>=] must be [number], found value [booleanField] type [boolean]",
"Argument of [>=] must be [number], found value [booleanField] type [boolean]"
],
"warning": []
},
{
"query": "from a_index | eval ipField >= ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField < 0",
"error": [],
@ -11482,6 +11897,34 @@
],
"warning": []
},
{
"query": "from a_index | eval stringField < stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField < numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval dateField < dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval booleanField < booleanField",
"error": [
"Argument of [<] must be [number], found value [booleanField] type [boolean]",
"Argument of [<] must be [number], found value [booleanField] type [boolean]"
],
"warning": []
},
{
"query": "from a_index | eval ipField < ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField <= 0",
"error": [],
@ -11514,6 +11957,34 @@
],
"warning": []
},
{
"query": "from a_index | eval stringField <= stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField <= numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval dateField <= dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval booleanField <= booleanField",
"error": [
"Argument of [<=] must be [number], found value [booleanField] type [boolean]",
"Argument of [<=] must be [number], found value [booleanField] type [boolean]"
],
"warning": []
},
{
"query": "from a_index | eval ipField <= ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField == 0",
"error": [],
@ -11546,6 +12017,31 @@
],
"warning": []
},
{
"query": "from a_index | eval stringField == stringField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField == numberField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval dateField == dateField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval booleanField == booleanField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval ipField == ipField",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField + 1",
"error": [],
@ -11561,6 +12057,11 @@
"error": [],
"warning": []
},
{
"query": "from a_index | eval now() + now()",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField - 1",
"error": [],
@ -11576,6 +12077,11 @@
"error": [],
"warning": []
},
{
"query": "from a_index | eval now() - now()",
"error": [],
"warning": []
},
{
"query": "from a_index | eval numberField * 1",
"error": [],
@ -11591,6 +12097,14 @@
"error": [],
"warning": []
},
{
"query": "from a_index | eval now() * now()",
"error": [
"Argument of [*] must be [number], found value [now()] type [date]",
"Argument of [*] must be [number], found value [now()] type [date]"
],
"warning": []
},
{
"query": "from a_index | eval numberField / 1",
"error": [],
@ -11606,6 +12120,14 @@
"error": [],
"warning": []
},
{
"query": "from a_index | eval now() / now()",
"error": [
"Argument of [/] must be [number], found value [now()] type [date]",
"Argument of [/] must be [number], found value [now()] type [date]"
],
"warning": []
},
{
"query": "from a_index | eval numberField % 1",
"error": [],
@ -11621,6 +12143,14 @@
"error": [],
"warning": []
},
{
"query": "from a_index | eval now() % now()",
"error": [
"Argument of [%] must be [number], found value [now()] type [date]",
"Argument of [%] must be [number], found value [now()] type [date]"
],
"warning": []
},
{
"query": "from a_index | eval 1/0",
"error": [],
@ -11900,6 +12430,26 @@
"error": [],
"warning": []
},
{
"query": "from a_index | eval result = case(false, 0, 1), round(result)",
"error": [],
"warning": []
},
{
"query": "from a_index | eval result = case(false, 0, 1) | stats sum(result)",
"error": [],
"warning": []
},
{
"query": "from a_index | eval result = case(false, 0, 1) | stats var0 = sum(result)",
"error": [],
"warning": []
},
{
"query": "from a_index | eval round(case(false, 0, 1))",
"error": [],
"warning": []
},
{
"query": "from a_index | eval 1 anno",
"error": [
@ -14836,6 +15386,16 @@
"error": [],
"warning": []
},
{
"query": "from a_index | stats sum(case(false, 0, 1))",
"error": [],
"warning": []
},
{
"query": "from a_index | stats var0 = sum( case(false, 0, 1))",
"error": [],
"warning": []
},
{
"query": "from a_index | sort ",
"error": [

View file

@ -656,7 +656,7 @@ describe('validation logic', () => {
}
}
}
for (const op of ['>', '>=', '<', '<=', '==']) {
for (const op of ['>', '>=', '<', '<=', '==', '!=']) {
testErrorsAndWarnings(`row var = 5 ${op} 0`, []);
testErrorsAndWarnings(`row var = NOT 5 ${op} 0`, []);
testErrorsAndWarnings(`row var = (numberField ${op} 0)`, ['Unknown column [numberField]']);
@ -664,10 +664,30 @@ describe('validation logic', () => {
testErrorsAndWarnings(`row var = "a" ${op} 0`, [
`Argument of [${op}] must be [number], found value ["a"] type [string]`,
]);
testErrorsAndWarnings(`row var = to_ip("127.0.0.1") ${op} to_ip("127.0.0.1")`, []);
testErrorsAndWarnings(`row var = now() ${op} now()`, []);
testErrorsAndWarnings(
`row var = false ${op} false`,
['==', '!='].includes(op)
? []
: [
`Argument of [${op}] must be [number], found value [false] type [boolean]`,
`Argument of [${op}] must be [number], found value [false] type [boolean]`,
]
);
}
for (const op of ['+', '-', '*', '/', '%']) {
testErrorsAndWarnings(`row var = 1 ${op} 1`, []);
testErrorsAndWarnings(`row var = (5 ${op} 1)`, []);
testErrorsAndWarnings(
`row var = now() ${op} now()`,
['+', '-'].includes(op)
? []
: [
`Argument of [${op}] must be [number], found value [now()] type [date]`,
`Argument of [${op}] must be [number], found value [now()] type [date]`,
]
);
}
for (const op of ['like', 'rlike']) {
@ -1064,15 +1084,26 @@ describe('validation logic', () => {
testErrorsAndWarnings(`from a_index | where ${nValue} > 0`, []);
testErrorsAndWarnings(`from a_index | where NOT ${nValue} > 0`, []);
}
for (const op of ['>', '>=', '<', '<=', '==']) {
for (const op of ['>', '>=', '<', '<=', '==', '!=']) {
testErrorsAndWarnings(`from a_index | where numberField ${op} 0`, []);
testErrorsAndWarnings(`from a_index | where NOT numberField ${op} 0`, []);
testErrorsAndWarnings(`from a_index | where (numberField ${op} 0)`, []);
testErrorsAndWarnings(`from a_index | where (NOT (numberField ${op} 0))`, []);
testErrorsAndWarnings(`from a_index | where 1 ${op} 0`, []);
testErrorsAndWarnings(`from a_index | eval stringField ${op} 0`, [
testErrorsAndWarnings(`from a_index | where stringField ${op} 0`, [
`Argument of [${op}] must be [number], found value [stringField] type [string]`,
]);
for (const type of ['string', 'number', 'date', 'boolean', 'ip']) {
testErrorsAndWarnings(
`from a_index | where ${type}Field ${op} ${type}Field`,
type !== 'boolean' || ['==', '!='].includes(op)
? []
: [
`Argument of [${op}] must be [number], found value [${type}Field] type [${type}]`,
`Argument of [${op}] must be [number], found value [${type}Field] type [${type}]`,
]
);
}
}
for (const nesting of NESTED_DEPTHS) {
@ -1643,11 +1674,31 @@ describe('validation logic', () => {
testErrorsAndWarnings(`from a_index | eval stringField ${op} 0`, [
`Argument of [${op}] must be [number], found value [stringField] type [string]`,
]);
for (const type of ['string', 'number', 'date', 'boolean', 'ip']) {
testErrorsAndWarnings(
`from a_index | eval ${type}Field ${op} ${type}Field`,
type !== 'boolean' || ['==', '!='].includes(op)
? []
: [
`Argument of [${op}] must be [number], found value [${type}Field] type [${type}]`,
`Argument of [${op}] must be [number], found value [${type}Field] type [${type}]`,
]
);
}
}
for (const op of ['+', '-', '*', '/', '%']) {
testErrorsAndWarnings(`from a_index | eval numberField ${op} 1`, []);
testErrorsAndWarnings(`from a_index | eval (numberField ${op} 1)`, []);
testErrorsAndWarnings(`from a_index | eval 1 ${op} 1`, []);
testErrorsAndWarnings(
`from a_index | eval now() ${op} now()`,
['+', '-'].includes(op)
? []
: [
`Argument of [${op}] must be [number], found value [now()] type [date]`,
`Argument of [${op}] must be [number], found value [now()] type [date]`,
]
);
}
for (const divideByZeroExpr of ['1/0', 'var = 1/0', '1 + 1/0']) {
testErrorsAndWarnings(
@ -1745,6 +1796,17 @@ describe('validation logic', () => {
testErrorsAndWarnings(`from a_index | eval mv_sort(["a", "b"], "ASC")`, []);
testErrorsAndWarnings(`from a_index | eval mv_sort(["a", "b"], "DESC")`, []);
testErrorsAndWarnings(`from a_index | eval result = case(false, 0, 1), round(result)`, []);
testErrorsAndWarnings(
`from a_index | eval result = case(false, 0, 1) | stats sum(result)`,
[]
);
testErrorsAndWarnings(
`from a_index | eval result = case(false, 0, 1) | stats var0 = sum(result)`,
[]
);
testErrorsAndWarnings(`from a_index | eval round(case(false, 0, 1))`, []);
describe('date math', () => {
testErrorsAndWarnings('from a_index | eval 1 anno', [
'EVAL does not support [date_period] in expression [1 anno]',
@ -2251,6 +2313,9 @@ describe('validation logic', () => {
`FROM index | STATS AVG(numberField) by round(numberField) + 1 | EVAL \`round(numberField) + 1\` / 2`,
[]
);
testErrorsAndWarnings(`from a_index | stats sum(case(false, 0, 1))`, []);
testErrorsAndWarnings(`from a_index | stats var0 = sum( case(false, 0, 1))`, []);
});
describe('sort', () => {