Remove case_sensitive request option (#63218) (#63244)

Make EQL case sensitive by default and adapt some of the string functions
Remove the case sensitive option from Between string function
Add case_insensitive option to term and wildcard queries usage

(cherry picked from commit 7550e0664c8c2f1f13519036c759b1e76345551f)
This commit is contained in:
Andrei Stefan 2020-10-05 22:04:42 +03:00 committed by GitHub
parent 1a6837883a
commit 76bba601ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 298 additions and 434 deletions

View File

@ -39,7 +39,6 @@ public class EqlSearchRequest implements Validatable, ToXContentObject {
private QueryBuilder filter = null;
private String timestampField = "@timestamp";
private String eventCategoryField = "event.category";
private boolean isCaseSensitive = true;
private int size = 10;
private int fetchSize = 1000;
@ -55,7 +54,6 @@ public class EqlSearchRequest implements Validatable, ToXContentObject {
static final String KEY_TIMESTAMP_FIELD = "timestamp_field";
static final String KEY_TIEBREAKER_FIELD = "tiebreaker_field";
static final String KEY_EVENT_CATEGORY_FIELD = "event_category_field";
static final String KEY_CASE_SENSITIVE = "case_sensitive";
static final String KEY_SIZE = "size";
static final String KEY_FETCH_SIZE = "fetch_size";
static final String KEY_QUERY = "query";
@ -81,7 +79,6 @@ public class EqlSearchRequest implements Validatable, ToXContentObject {
builder.field(KEY_EVENT_CATEGORY_FIELD, eventCategoryField());
builder.field(KEY_SIZE, size());
builder.field(KEY_FETCH_SIZE, fetchSize());
builder.field(KEY_CASE_SENSITIVE, isCaseSensitive());
builder.field(KEY_QUERY, query);
if (waitForCompletionTimeout != null) {
@ -143,15 +140,6 @@ public class EqlSearchRequest implements Validatable, ToXContentObject {
return this;
}
public boolean isCaseSensitive() {
return this.isCaseSensitive;
}
public EqlSearchRequest isCaseSensitive(boolean isCaseSensitive) {
this.isCaseSensitive = isCaseSensitive;
return this;
}
public int size() {
return this.size;
}
@ -232,7 +220,6 @@ public class EqlSearchRequest implements Validatable, ToXContentObject {
Objects.equals(tiebreakerField, that.tiebreakerField) &&
Objects.equals(eventCategoryField, that.eventCategoryField) &&
Objects.equals(query, that.query) &&
Objects.equals(isCaseSensitive, that.isCaseSensitive) &&
Objects.equals(waitForCompletionTimeout, that.waitForCompletionTimeout) &&
Objects.equals(keepAlive, that.keepAlive) &&
Objects.equals(keepOnCompletion, that.keepOnCompletion);
@ -250,7 +237,6 @@ public class EqlSearchRequest implements Validatable, ToXContentObject {
tiebreakerField,
eventCategoryField,
query,
isCaseSensitive,
waitForCompletionTimeout,
keepAlive,
keepOnCompletion);

View File

@ -486,34 +486,6 @@ GET /my-index-000001/_eql/search
----
// TEST[setup:sec_logs]
[discrete]
[[eql-search-case-sensitive]]
=== Run a case-sensitive EQL search
By default, matching for EQL queries is case-insensitive. You can use the
`case_sensitive` parameter to toggle case sensitivity on or off.
The following search request contains a query that matches `process` events
with a `process.executable` containing `System32`.
Because `case_sensitive` is `true`, this query only matches `process.executable`
values containing `System32` with the exact same capitalization. A
`process.executable` value containing `system32` or `SYSTEM32` would not match
this query.
[source,console]
----
GET /my-index-000001/_eql/search
{
"keep_on_completion": true,
"case_sensitive": true,
"query": """
process where stringContains(process.executable, "System32")
"""
}
----
// TEST[setup:sec_logs]
[discrete]
[[eql-search-async]]
=== Run an async EQL search

View File

@ -40,7 +40,6 @@ public abstract class BaseEqlSpecTestCase extends ESRestTestCase {
private final String query;
private final String name;
private final long[] eventIds;
private final boolean caseSensitive;
@Before
private void setup() throws Exception {
@ -74,28 +73,22 @@ public abstract class BaseEqlSpecTestCase extends ESRestTestCase {
name = "" + (counter);
}
boolean[] values = spec.caseSensitive() == null ? new boolean[] { true, false } : new boolean[] { spec.caseSensitive() };
for (boolean sensitive : values) {
String prefixed = name + (sensitive ? "-sensitive" : "-insensitive");
results.add(new Object[] { spec.query(), prefixed, spec.expectedEventIds(), sensitive });
}
results.add(new Object[] { spec.query(), name, spec.expectedEventIds() });
}
return results;
}
BaseEqlSpecTestCase(String index, String query, String name, long[] eventIds, boolean caseSensitive) {
BaseEqlSpecTestCase(String index, String query, String name, long[] eventIds) {
this.index = index;
this.query = query;
this.name = name;
this.eventIds = eventIds;
this.caseSensitive = caseSensitive;
}
public void test() throws Exception {
assertResponse(runQuery(index, query, caseSensitive));
assertResponse(runQuery(index, query));
}
protected void assertResponse(EqlSearchResponse response) {
@ -111,9 +104,8 @@ public abstract class BaseEqlSpecTestCase extends ESRestTestCase {
}
}
protected EqlSearchResponse runQuery(String index, String query, boolean isCaseSensitive) throws Exception {
protected EqlSearchResponse runQuery(String index, String query) throws Exception {
EqlSearchRequest request = new EqlSearchRequest(index, query);
request.isCaseSensitive(isCaseSensitive);
request.tiebreakerField("event.sequence");
// some queries return more than 10 results
request.size(50);

View File

@ -20,8 +20,8 @@ public abstract class EqlExtraSpecTestCase extends BaseEqlSpecTestCase {
return asArray(EqlSpecLoader.load("/test_extra.toml", true, new HashSet<>()));
}
public EqlExtraSpecTestCase(String query, String name, long[] eventIds, boolean caseSensitive) {
super(TEST_EXTRA_INDEX, query, name, eventIds, caseSensitive);
public EqlExtraSpecTestCase(String query, String name, long[] eventIds) {
super(TEST_EXTRA_INDEX, query, name, eventIds);
}
@Override

View File

@ -19,12 +19,6 @@ public class EqlSpec {
private String query;
private long[] expectedEventIds;
// flag to dictate which modes are supported for the test
// null -> apply the test to both modes (case sensitive and case insensitive)
// TRUE -> case sensitive
// FALSE -> case insensitive
private Boolean caseSensitive = null;
public String name() {
return name;
}
@ -73,14 +67,6 @@ public class EqlSpec {
this.expectedEventIds = expectedEventIds;
}
public void caseSensitive(Boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
public Boolean caseSensitive() {
return this.caseSensitive;
}
public EqlSpec withSensitivity(boolean caseSensitive) {
EqlSpec spec = new EqlSpec();
spec.name = name;
@ -90,7 +76,6 @@ public class EqlSpec {
spec.query = query;
spec.expectedEventIds = expectedEventIds;
spec.caseSensitive = caseSensitive;
return spec;
}
@ -102,10 +87,6 @@ public class EqlSpec {
str = appendWithComma(str, "description", description);
str = appendWithComma(str, "note", note);
if (caseSensitive != null) {
str = appendWithComma(str, "case_sensitive", Boolean.toString(caseSensitive));
}
if (tags != null) {
str = appendWithComma(str, "tags", Arrays.toString(tags));
}
@ -128,13 +109,12 @@ public class EqlSpec {
EqlSpec that = (EqlSpec) other;
return Objects.equals(this.query(), that.query())
&& Objects.equals(this.caseSensitive, that.caseSensitive);
return Objects.equals(this.query(), that.query());
}
@Override
public int hashCode() {
return Objects.hash(this.query, this.caseSensitive);
return Objects.hash(this.query);
}
private static String appendWithComma(String str, String name, String append) {

View File

@ -73,20 +73,6 @@ public class EqlSpecLoader {
spec.note(getTrimmedString(table, "note"));
spec.description(getTrimmedString(table, "description"));
Boolean caseSensitive = table.getBoolean("case_sensitive");
Boolean caseInsensitive = table.getBoolean("case_insensitive");
// if case_sensitive is TRUE and case_insensitive is not TRUE (FALSE or NULL), then the test is case sensitive only
if (Boolean.TRUE.equals(caseSensitive)) {
if (Boolean.FALSE.equals(caseInsensitive) || caseInsensitive == null) {
spec.caseSensitive(true);
}
}
// if case_sensitive is not TRUE (FALSE or NULL) and case_insensitive is TRUE, then the test is case insensitive only
else if (Boolean.TRUE.equals(caseInsensitive)) {
spec.caseSensitive(false);
}
// in all other cases, the test should run no matter the case sensitivity (should test both scenarios)
List<?> arr = table.getList("tags");
if (arr != null) {
String tags[] = new String[arr.size()];

View File

@ -51,7 +51,7 @@ public abstract class EqlSpecTestCase extends BaseEqlSpecTestCase {
return "serial_event_id";
}
public EqlSpecTestCase(String query, String name, long[] eventIds, boolean caseSensitive) {
super(TEST_INDEX, query, name, eventIds, caseSensitive);
public EqlSpecTestCase(String query, String name, long[] eventIds) {
super(TEST_INDEX, query, name, eventIds);
}
}

View File

@ -177,13 +177,11 @@ expected_event_ids = [1, 2]
[[queries]]
name = "compareTwoFields1"
# test that it works for comparing field <--> field
case_insensitive = true
query = 'process where serial_event_id < 5 and process_name <= parent_process_name'
expected_event_ids = [2, 3]
[[queries]]
name = "compareTwoFields2"
case_sensitive = true
query = 'process where serial_event_id < 5 and process_name <= parent_process_name'
expected_event_ids = [2]
@ -219,39 +217,33 @@ expected_event_ids = [1]
[[queries]]
name = "processWithStringComparisonCaseSensitive1"
case_sensitive = true
notes = "s == 0x73; S == 0x53"
query = 'process where process_name >= "system idle process" and process_name <= "System Idle Process"'
expected_event_ids = []
[[queries]]
name = "processWithStringComparisonCaseInsensitive1"
case_insensitive = true
query = 'process where process_name >= "system idle process" and process_name <= "System Idle Process"'
expected_event_ids = [1]
[[queries]]
name = "processWithStringComparisonCaseInsensitive2"
case_insensitive = true
query = 'process where process_name >= "SYSTE" and process_name < "systex"'
expected_event_ids = [1, 2]
[[queries]]
name = "processWithStringComparisonCaseInsensitive3"
case_insensitive = true
query = 'process where process_name >= "sysT" and process_name < "SYsTeZZZ"'
expected_event_ids = [1, 2]
[[queries]]
name = "processWithStringComparisonCaseInsensitive4"
case_insensitive = true
query = 'process where process_name >= "SYSTE" and process_name <= "systex"'
expected_event_ids = [1, 2]
[[queries]]
name = "processWithStringEqualityCaseInsensitive1"
case_insensitive = true
query = '''
process where process_name : "VMACTHLP.exe" and unique_pid == 12
| filter true
@ -268,7 +260,6 @@ expected_event_ids = [3, 34, 48]
[[queries]]
name = "processNameINCaseInsensitive1"
case_insensitive = true
query = '''
process where process_name in ("python.exe", "SMSS.exe", "explorer.exe")
| unique process_name
@ -277,7 +268,6 @@ expected_event_ids = [3, 34, 48]
[[queries]]
name = "processNameINCaseInsensitive2"
case_insensitive = true
query = '''
process where process_name in ("python.exe", "smss.exe", "Explorer.exe")
| unique length(process_name)
@ -294,7 +284,6 @@ expected_event_ids = [3, 48]
[[queries]]
name = "processNameINWithUnique2"
case_insensitive = true
query = '''
process where process_name in ("Python.exe", "smss.exe", "explorer.exe")
| unique process_name != "python.exe"
@ -348,7 +337,6 @@ expected_event_ids = [3, 48, 50, 54]
[[queries]]
name = "lengthCaseInsensitive1"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where length(bytes_written_string_list) == 2 and bytes_written_string_list[1] : "EN"
@ -446,7 +434,6 @@ expected_event_ids = [2, 50, 51]
[[queries]]
name = "twoINsCaseInsensitive"
case_insensitive = true
query = '''
process where opcode in (1,3) and process_name in (parent_process_name, "SYSTEM")
'''
@ -454,7 +441,6 @@ expected_event_ids = [2, 50, 51]
[[queries]]
name = "simpleTailWithSort"
case_insensitive = true
expected_event_ids = [92, 95, 96, 91]
query = '''
file where true
@ -1319,7 +1305,6 @@ any where process_name : "svchost.exe"
[[queries]]
name = "arrayContainsCaseInsensitive1"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "En-uS")
@ -1327,7 +1312,6 @@ registry where arrayContains(bytes_written_string_list, "En-uS")
[[queries]]
name = "arrayContainsCaseInsensitive2"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "En")
@ -1335,7 +1319,6 @@ registry where arrayContains(bytes_written_string_list, "En")
[[queries]]
name = "lengthCaseInsensitive2"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where length(bytes_written_string_list) > 0 and bytes_written_string_list[0] : "EN-us"
@ -1343,7 +1326,6 @@ registry where length(bytes_written_string_list) > 0 and bytes_written_string_li
[[queries]]
name = "arrayCaseInsensitive1"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where bytes_written_string_list[0] : "EN-us"
@ -1351,7 +1333,6 @@ registry where bytes_written_string_list[0] : "EN-us"
[[queries]]
name = "arrayCaseInsensitive2"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where bytes_written_string_list[1] : "EN"
@ -1360,7 +1341,6 @@ registry where bytes_written_string_list[1] : "EN"
[[queries]]
name = "arrayContainsCaseInsensitive3"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "en-US")
@ -1368,7 +1348,6 @@ registry where arrayContains(bytes_written_string_list, "en-US")
[[queries]]
name = "arrayContainsCaseInsensitive4"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "en")
@ -1376,7 +1355,6 @@ registry where arrayContains(bytes_written_string_list, "en")
[[queries]]
name = "arrayCaseInsensitive3"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where length(bytes_written_string_list) > 0 and bytes_written_string_list[0] : "en-US"
@ -1433,7 +1411,6 @@ expected_event_ids = [98]
[[queries]]
name = "stringEqualsCaseInsensitive1"
case_insensitive = true
query = '''
process where "net.EXE" == original_file_name
| filter process_name:"net*.exe"
@ -1443,7 +1420,6 @@ note = "check that case insensitive comparisons are performed even for lhs strin
[[queries]]
name = "stringEqualsCaseInsensitive2"
case_insensitive = true
query = '''
process where process_name == original_file_name and process_name:"net*.exe"
'''
@ -1452,7 +1428,6 @@ note = "check that case insensitive comparisons are performed for fields."
[[queries]]
name = "fieldsComparisonCaseInsensitive"
case_insensitive = true
query = '''
process where original_file_name == process_name and length(original_file_name) > 0
'''
@ -1461,17 +1436,14 @@ description = "check that case insensitive comparisons are performed for fields.
[[queries]]
name = "startsWithCaseSensitive"
case_sensitive = true
query = '''
file where opcode==0 and startsWith(file_name, "explorer.")
'''
expected_event_ids = [88]
description = "check built-in string functions"
[[queries]]
name = "startsWithCaseInsensitive1"
case_insensitive = true
query = '''
file where opcode==0 and startsWith(file_name, "explorer.")
'''
@ -1481,7 +1453,6 @@ description = "check built-in string functions"
[[queries]]
name = "startsWithCaseInsensitive2"
case_insensitive = true
query = '''
file where opcode==0 and startsWith(file_name, "exploRER.")
'''
@ -1490,7 +1461,6 @@ description = "check built-in string functions"
[[queries]]
name = "startsWithCaseInsensitive3"
case_insensitive = true
query = '''
file where opcode==0 and startsWith(file_name, "expLORER.exe")
'''
@ -1508,7 +1478,6 @@ description = "check built-in string functions"
[[queries]]
name = "endsWithCaseInsensitive"
case_insensitive = true
query = '''
file where opcode==0 and endsWith(file_name, "loREr.exe")
'''
@ -1525,7 +1494,6 @@ description = "check built-in string functions"
[[queries]]
name = "endsWithAndCondition"
case_insensitive = true
query = '''
file where opcode==0 and serial_event_id == 88 and startsWith("explorer.exeaAAAA", "EXPLORER.exe")
'''
@ -1542,7 +1510,6 @@ description = "check built-in string functions"
[[queries]]
name = "indexOfCaseInsensitive"
case_insensitive = true
query = '''
file where opcode==0 and indexOf(file_name, "plore") == 2 and indexOf(file_name, ".pf") == null
'''
@ -1559,7 +1526,6 @@ description = "check built-in string functions"
[[queries]]
name = "indexOf2"
case_sensitive = true
query = '''
file where opcode==0 and indexOf(file_name, "plorer.", 0) == 2
'''
@ -1568,7 +1534,6 @@ description = "check built-in string functions"
[[queries]]
name = "indexOf3"
case_insensitive = true
query = '''
file where opcode==0 and indexOf(file_name, "plorer.", 0) == 2
'''
@ -1577,7 +1542,6 @@ description = "check built-in string functions"
[[queries]]
name = "indexOf4"
case_sensitive = true
query = '''
file where opcode==0 and indexOf(file_name, "plorer.", 2) != null
'''
@ -1586,7 +1550,6 @@ description = "check built-in string functions"
[[queries]]
name = "indexOf5"
case_insensitive = true
query = '''
file where opcode==0 and indexOf(file_name, "plorer.", 2) != null
'''
@ -1611,7 +1574,6 @@ description = "check built-in string functions"
[[queries]]
name = "indexOf8"
case_insensitive = true
query = '''
file where opcode==0 and indexOf(file_name, "plorer.", 2) == 2
'''
@ -1620,7 +1582,6 @@ description = "check substring ranges"
[[queries]]
name = "indexOf9"
case_sensitive = true
query = '''
file where opcode==0 and indexOf(file_name, "plorer.", 2) == 2
'''
@ -1629,7 +1590,6 @@ description = "check substring ranges"
[[queries]]
name = "indexOf10"
case_sensitive = true
query = '''
file where opcode==0 and indexOf(file_name, "explorer.", 0) == 0
'''
@ -1638,7 +1598,6 @@ description = "check substring ranges"
[[queries]]
name = "indexOf11"
case_insensitive = true
query = '''
file where opcode==0 and indexOf(file_name, "explorer.", 0) == 0
'''
@ -1647,7 +1606,6 @@ description = "check substring ranges"
[[queries]]
name = "substring1"
case_insensitive = true
query = '''
file where serial_event_id==88 and substring(file_name, 0, 4) : "expl"
'''
@ -1656,7 +1614,6 @@ description = "check substring ranges"
[[queries]]
name = "substring2"
case_sensitive = true
query = '''
file where substring(file_name, 1, 3) == "xp"
'''
@ -1665,7 +1622,6 @@ description = "check substring ranges"
[[queries]]
name = "substring3"
case_insensitive = true
query = '''
file where substring(file_name, 1, 3) : "xp"
'''
@ -1754,7 +1710,6 @@ description = "test string concatenation"
[[queries]]
name = "concatCaseInsensitive"
case_insensitive = true
query = '''
process where concat(serial_event_id, ":", process_name, opcode) : "5:winINIT.exe3"
'''
@ -1763,7 +1718,6 @@ description = "test string concatenation"
[[queries]]
name = "fieldComparisonCaseInsensitive"
case_insensitive = true
query = '''
process where process_name != original_file_name and length(original_file_name) > 0
'''
@ -1781,7 +1735,6 @@ registry where arraySearch(bytes_written_string_list, a, a : "en-US")
[[queries]]
name = "arraySearchCaseSensitive"
case_sensitive = true
expected_event_ids = []
description = "test arraySearch functionality for lists of strings, and lists of objects"
query = '''
@ -1790,7 +1743,6 @@ registry where arraySearch(bytes_written_string_list, a, a : "EN-US")
[[queries]]
name = "arraySearchCaseInsensitive1"
case_insensitive = true
expected_event_ids = [57]
description = "test arraySearch functionality for lists of strings, and lists of objects"
query = '''
@ -1799,7 +1751,6 @@ registry where arraySearch(bytes_written_string_list, a, a : "en-us")
[[queries]]
name = "arraySearchCaseInsensitive2"
case_insensitive = true
expected_event_ids = [57]
description = "test arraySearch functionality for lists of strings, and lists of objects"
query = '''
@ -1889,7 +1840,6 @@ network where safe(divide(process_name, process_name))
[[queries]]
name = "nestedSetComparisons"
case_insensitive = true
query = '''
file where serial_event_id == 82 and (true == (process_name in ("svchost.EXE", "bad.exe", "bad2.exe")))
'''
@ -1898,7 +1848,6 @@ description = "nested set comparisons"
[[queries]]
name = "arrayCount1"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayCount(bytes_written_string_list, s, s : "*-us") == 1
@ -1906,7 +1855,6 @@ registry where arrayCount(bytes_written_string_list, s, s : "*-us") == 1
[[queries]]
name = "arrayCount2"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayCount(bytes_written_string_list, s, s : "*en*") == 2
@ -1914,7 +1862,6 @@ registry where arrayCount(bytes_written_string_list, s, s : "*en*") == 2
[[queries]]
name = "arrayContainsCaseInsensitive5"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "missing", "en-US")
@ -1952,7 +1899,6 @@ query = "file where serial_event_id % 40 == 2"
[[queries]]
name = "betweenCaseInsensitive1"
case_insensitive = true
expected_event_ids = [1, 2]
query = '''
process where between(process_name, "s", "e") : "yst"
@ -1960,7 +1906,6 @@ process where between(process_name, "s", "e") : "yst"
[[queries]]
name = "betweenCaseInsensitive2"
case_insensitive = true
expected_event_ids = [1, 2]
query = '''
process where between(process_name, "s", "e", false) : "yst"
@ -1968,7 +1913,6 @@ process where between(process_name, "s", "e", false) : "yst"
[[queries]]
name = "betweenCaseSensitive"
case_sensitive = true
expected_event_ids = [1, 2, 42]
query = '''
process where between(process_name, "s", "e", false) : "t"
@ -1983,7 +1927,6 @@ process where between(process_name, "S", "e", true) : "ystem Idle Proc"
[[queries]]
name = "betweenCaseInsensitive3"
case_insensitive = true
expected_event_ids = [1]
query = '''
process where between(process_name, "s", "e", true) : "ystem Idle Proc"
@ -2034,7 +1977,6 @@ network where cidrMatch(source_address, "0.0.0.0/0")
[[queries]]
name = "lengthCaseSensitive"
case_sensitive = true
expected_event_ids = [7, 14, 29, 44]
query = '''
process where length(between(process_name, "g", "e")) > 0
@ -2042,7 +1984,6 @@ process where length(between(process_name, "g", "e")) > 0
[[queries]]
name = "lengthCaseInsensitiveAndBetween"
case_insensitive = true
expected_event_ids = [7, 14, 22, 29, 44]
query = '''
process where length(between(process_name, "g", "e")) > 0

View File

@ -8,6 +8,99 @@
# in order to allow at least one round-trip test with the test harness.
# This will be removed once the EQL implementation is wired and actually supports this query.
[[queries]]
name = "startsWithCaseInsensitive1"
query = '''
file where opcode==0 and startsWith(file_name, "explorer.")
'''
expected_event_ids = [88, 92]
description = "check built-in string functions"
[[queries]]
name = "startsWithCaseInsensitive2"
query = '''
file where opcode==0 and startsWith(file_name, "exploRER.")
'''
expected_event_ids = [88, 92]
description = "check built-in string functions"
[[queries]]
name = "startsWithCaseInsensitive3"
query = '''
file where opcode==0 and startsWith(file_name, "expLORER.exe")
'''
expected_event_ids = [88, 92]
description = "check built-in string functions"
[[queries]]
name = "endsWithCaseInsensitive"
query = '''
file where opcode==0 and endsWith(file_name, "loREr.exe")
'''
expected_event_ids = [88]
description = "check built-in string functions"
[[queries]]
name = "endsWithAndCondition"
query = '''
file where opcode==0 and serial_event_id == 88 and startsWith("explorer.exeaAAAA", "EXPLORER.exe")
'''
expected_event_ids = [88]
description = "check built-in string functions"
[[queries]]
name = "indexOf3"
query = '''
file where opcode==0 and indexOf(file_name, "plorer.", 0) == 2
'''
expected_event_ids = [88, 92]
description = "check built-in string functions"
[[queries]]
name = "indexOf5"
query = '''
file where opcode==0 and indexOf(file_name, "plorer.", 2) != null
'''
expected_event_ids = [88, 92]
description = "check built-in string functions"
[[queries]]
name = "indexOf8"
query = '''
file where opcode==0 and indexOf(file_name, "plorer.", 2) == 2
'''
expected_event_ids = [88, 92]
description = "check substring ranges"
[[queries]]
name = "indexOf11"
query = '''
file where opcode==0 and indexOf(file_name, "explorer.", 0) == 0
'''
expected_event_ids = [88, 92]
description = "check substring ranges"
[[queries]]
name = "betweenCaseInsensitive1"
expected_event_ids = [1, 2]
query = '''
process where between(process_name, "s", "e") : "yst"
'''
[[queries]]
name = "betweenCaseInsensitive2"
expected_event_ids = [1, 2]
query = '''
process where between(process_name, "s", "e", false) : "yst"
'''
[[queries]]
name = "betweenCaseInsensitive3"
expected_event_ids = [1]
query = '''
process where between(process_name, "s", "e", true) : "ystem Idle Proc"
'''
[[queries]]
name = "twoSequencesWithKeys"
query = '''
@ -93,13 +186,11 @@ expected_event_ids = [7, 8]
[[queries]]
name = "compareTwoFields1"
case_insensitive = true
query = 'process where serial_event_id < 5 and process_name <= parent_process_name'
expected_event_ids = [2, 3]
[[queries]]
name = "compareTwoFields2"
case_sensitive = true
query = 'process where serial_event_id < 5 and process_name <= parent_process_name'
expected_event_ids = [2]
@ -107,32 +198,27 @@ expected_event_ids = [2]
[[queries]]
name = "processWithStringComparisonCaseInsensitive1"
case_insensitive = true
query = 'process where process_name >= "system idle process" and process_name <= "System Idle Process"'
expected_event_ids = [1]
[[queries]]
name = "processWithStringComparisonCaseInsensitive2"
case_insensitive = true
query = 'process where process_name >= "SYSTE" and process_name < "systex"'
expected_event_ids = [1, 2]
[[queries]]
name = "processWithStringComparisonCaseInsensitive3"
case_insensitive = true
query = 'process where process_name >= "sysT" and process_name < "SYsTeZZZ"'
expected_event_ids = [1, 2]
[[queries]]
name = "processWithStringComparisonCaseInsensitive4"
case_insensitive = true
query = 'process where process_name >= "SYSTE" and process_name <= "systex"'
expected_event_ids = [1, 2]
[[queries]]
name = "processWithStringEqualityCaseInsensitive1"
case_insensitive = true
query = '''
process where process_name : "VMACTHLP.exe" and unique_pid == 12
| filter true
@ -149,7 +235,6 @@ expected_event_ids = [3, 34, 48]
[[queries]]
name = "processNameINCaseInsensitive1"
case_insensitive = true
query = '''
process where process_name in ("python.exe", "SMSS.exe", "explorer.exe")
| unique process_name
@ -158,7 +243,6 @@ expected_event_ids = [3, 34, 48]
[[queries]]
name = "processNameINCaseInsensitive2"
case_insensitive = true
query = '''
process where process_name in ("python.exe", "smss.exe", "Explorer.exe")
| unique length(process_name)
@ -175,7 +259,6 @@ expected_event_ids = [3, 48]
[[queries]]
name = "processNameINWithUnique2"
case_insensitive = true
query = '''
process where process_name in ("Python.exe", "smss.exe", "explorer.exe")
| unique process_name != "python.exe"
@ -229,7 +312,6 @@ expected_event_ids = [3, 48, 50, 54]
[[queries]]
name = "lengthCaseInsensitive"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where length(bytes_written_string_list) == 2 and bytes_written_string_list[1] : "EN"
@ -282,7 +364,6 @@ expected_event_ids = [2, 50, 51]
[[queries]]
name = "twoINsCaseInsensitive"
case_insensitive = true
query = '''
process where opcode in (1,3) and process_name in (parent_process_name, "SYSTEM")
'''
@ -290,7 +371,6 @@ expected_event_ids = [2, 50, 51]
[[queries]]
name = "simpleTailWithSort"
case_insensitive = true
expected_event_ids = [92, 95, 96, 91]
query = '''
file where true
@ -716,7 +796,6 @@ any where process_name : "svchost.exe"
[[queries]]
name = "arrayContainsCaseInsensitive1"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "En-uS")
@ -724,7 +803,6 @@ registry where arrayContains(bytes_written_string_list, "En-uS")
[[queries]]
name = "arrayContainsCaseInsensitive2"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "En")
@ -732,7 +810,6 @@ registry where arrayContains(bytes_written_string_list, "En")
[[queries]]
name = "lengthCaseInsensitive"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where length(bytes_written_string_list) > 0 and bytes_written_string_list[0] : "EN-us"
@ -740,7 +817,6 @@ registry where length(bytes_written_string_list) > 0 and bytes_written_string_li
[[queries]]
name = "arrayCaseInsensitive1"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where bytes_written_string_list[0] : "EN-us"
@ -748,7 +824,6 @@ registry where bytes_written_string_list[0] : "EN-us"
[[queries]]
name = "arrayCaseInsensitive2"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where bytes_written_string_list[1] : "EN"
@ -757,7 +832,6 @@ registry where bytes_written_string_list[1] : "EN"
[[queries]]
name = "arrayContainsCaseInsensitive3"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "en-US")
@ -765,7 +839,6 @@ registry where arrayContains(bytes_written_string_list, "en-US")
[[queries]]
name = "arrayContainsCaseInsensitive4"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "en")
@ -773,7 +846,6 @@ registry where arrayContains(bytes_written_string_list, "en")
[[queries]]
name = "arrayCaseInsensitive3"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where length(bytes_written_string_list) > 0 and bytes_written_string_list[0] : "en-US"
@ -831,7 +903,6 @@ expected_event_ids = [98]
[[queries]]
name = "stringEqualsCaseInsensitive1"
case_insensitive = true
query = '''
process where "net.EXE" == original_file_name
| filter process_name:"net*.exe"
@ -841,7 +912,6 @@ note = "check that case insensitive comparisons are performed even for lhs strin
[[queries]]
name = "stringEqualsCaseInsensitive2"
case_insensitive = true
query = '''
process where process_name == original_file_name and process_name:"net*.exe"
'''
@ -850,7 +920,6 @@ note = "check that case insensitive comparisons are performed for fields."
[[queries]]
name = "fieldsComparisonCaseInsensitive"
case_insensitive = true
query = '''
process where original_file_name == process_name and length(original_file_name) > 0
'''
@ -859,7 +928,6 @@ description = "check that case insensitive comparisons are performed for fields.
[[queries]]
name = "substring3"
case_insensitive = true
query = '''
file where substring(file_name, 1, 3) : "xp"
'''
@ -876,7 +944,6 @@ description = "test built-in math functions"
[[queries]]
name = "concatCaseInsensitive"
case_insensitive = true
query = '''
process where concat(serial_event_id, ":", process_name, opcode) : "5:winINIT.exe3"
'''
@ -885,7 +952,6 @@ description = "test string concatenation"
[[queries]]
name = "fieldComparisonCaseInsensitive"
case_insensitive = true
query = '''
process where process_name != original_file_name and length(original_file_name) > 0
'''
@ -903,7 +969,6 @@ registry where arraySearch(bytes_written_string_list, a, a : "en-US")
[[queries]]
name = "arraySearchCaseSensitive"
case_sensitive = true
expected_event_ids = []
description = "test arraySearch functionality for lists of strings, and lists of objects"
query = '''
@ -912,7 +977,6 @@ registry where arraySearch(bytes_written_string_list, a, a : "EN-US")
[[queries]]
name = "arraySearchCaseInsensitive1"
case_insensitive = true
expected_event_ids = [57]
description = "test arraySearch functionality for lists of strings, and lists of objects"
query = '''
@ -921,7 +985,6 @@ registry where arraySearch(bytes_written_string_list, a, a : "en-us")
[[queries]]
name = "arraySearchCaseInsensitive2"
case_insensitive = true
expected_event_ids = [57]
description = "test arraySearch functionality for lists of strings, and lists of objects"
query = '''
@ -1011,7 +1074,6 @@ network where safe(divide(process_name, process_name))
[[queries]]
name = "nestedSetComparisons"
case_insensitive = true
query = '''
file where serial_event_id == 82 and (true == (process_name in ("svchost.EXE", "bad.exe", "bad2.exe")))
'''
@ -1020,7 +1082,6 @@ description = "nested set comparisons"
[[queries]]
name = "arrayCount1"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayCount(bytes_written_string_list, s, s : "*-us") == 1
@ -1028,7 +1089,6 @@ registry where arrayCount(bytes_written_string_list, s, s : "*-us") == 1
[[queries]]
name = "arrayCount2"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayCount(bytes_written_string_list, s, s : "*en*") == 2
@ -1036,7 +1096,6 @@ registry where arrayCount(bytes_written_string_list, s, s : "*en*") == 2
[[queries]]
name = "arrayContainsCaseInsensitive5"
case_insensitive = true
expected_event_ids = [57]
query = '''
registry where arrayContains(bytes_written_string_list, "missing", "en-US")
@ -1069,7 +1128,6 @@ expected_event_ids = [1, 2,
# TODO: update toggles for this function
[[queries]]
name = "betweenCaseSensitive"
case_sensitive = true
expected_event_ids = [1, 2, 42]
query = '''
process where between(process_name, "s", "e", false) : "t"
@ -1078,7 +1136,6 @@ process where between(process_name, "s", "e", false) : "t"
# TODO: add toggles to this function so it's not always insensitive
[[queries]]
name = "lengthCaseSensitive"
case_sensitive = true
expected_event_ids = [7, 14, 29, 44]
query = '''
process where length(between(process_name, "g", "e")) > 0

View File

@ -12,7 +12,7 @@ import org.elasticsearch.test.junit.annotations.TestLogging;
@TestLogging(value = "org.elasticsearch.xpack.eql:TRACE", reason = "results logging")
public class EqlExtraIT extends EqlExtraSpecTestCase {
public EqlExtraIT(String query, String name, long[] eventIds, boolean caseSensitive) {
super(query, name, eventIds, caseSensitive);
public EqlExtraIT(String query, String name, long[] eventIds) {
super(query, name, eventIds);
}
}

View File

@ -10,7 +10,7 @@ import org.elasticsearch.test.eql.EqlSpecTestCase;
public class EqlSpecIT extends EqlSpecTestCase {
public EqlSpecIT(String query, String name, long[] eventIds, boolean caseSensitive) {
super(query, name, eventIds, caseSensitive);
public EqlSpecIT(String query, String name, long[] eventIds) {
super(query, name, eventIds);
}
}

View File

@ -50,7 +50,6 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
private int size = RequestDefaults.SIZE;
private int fetchSize = RequestDefaults.FETCH_SIZE;
private String query;
private boolean isCaseSensitive = false;
// Async settings
private TimeValue waitForCompletionTimeout = null;
@ -67,7 +66,6 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
static final String KEY_WAIT_FOR_COMPLETION_TIMEOUT = "wait_for_completion_timeout";
static final String KEY_KEEP_ALIVE = "keep_alive";
static final String KEY_KEEP_ON_COMPLETION = "keep_on_completion";
static final String KEY_CASE_SENSITIVE = "case_sensitive";
static final ParseField FILTER = new ParseField(KEY_FILTER);
static final ParseField TIMESTAMP_FIELD = new ParseField(KEY_TIMESTAMP_FIELD);
@ -79,7 +77,6 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
static final ParseField WAIT_FOR_COMPLETION_TIMEOUT = new ParseField(KEY_WAIT_FOR_COMPLETION_TIMEOUT);
static final ParseField KEEP_ALIVE = new ParseField(KEY_KEEP_ALIVE);
static final ParseField KEEP_ON_COMPLETION = new ParseField(KEY_KEEP_ON_COMPLETION);
static final ParseField CASE_SENSITIVE = new ParseField(KEY_CASE_SENSITIVE);
private static final ObjectParser<EqlSearchRequest, Void> PARSER = objectParser(EqlSearchRequest::new);
@ -103,7 +100,9 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
this.keepAlive = in.readOptionalTimeValue();
this.keepOnCompletion = in.readBoolean();
}
isCaseSensitive = in.readBoolean();
if (in.getVersion().before(Version.V_7_10_0)) {
in.readBoolean();
}
}
@Override
@ -178,7 +177,6 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
builder.field(KEY_KEEP_ALIVE, keepAlive);
}
builder.field(KEY_KEEP_ON_COMPLETION, keepOnCompletion);
builder.field(KEY_CASE_SENSITIVE, isCaseSensitive);
return builder;
}
@ -203,7 +201,6 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
parser.declareField(EqlSearchRequest::keepAlive,
(p, c) -> TimeValue.parseTimeValue(p.text(), KEY_KEEP_ALIVE), KEEP_ALIVE, ObjectParser.ValueType.VALUE);
parser.declareBoolean(EqlSearchRequest::keepOnCompletion, KEEP_ON_COMPLETION);
parser.declareBoolean(EqlSearchRequest::isCaseSensitive, CASE_SENSITIVE);
return parser;
}
@ -293,13 +290,6 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
return this;
}
public boolean isCaseSensitive() { return this.isCaseSensitive; }
public EqlSearchRequest isCaseSensitive(boolean isCaseSensitive) {
this.isCaseSensitive = isCaseSensitive;
return this;
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
@ -317,7 +307,9 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
out.writeOptionalTimeValue(keepAlive);
out.writeBoolean(keepOnCompletion);
}
out.writeBoolean(isCaseSensitive);
if (out.getVersion().onOrAfter(Version.V_7_10_0)) {
out.writeBoolean(true);
}
}
@Override
@ -341,8 +333,7 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
Objects.equals(eventCategoryField, that.eventCategoryField) &&
Objects.equals(query, that.query) &&
Objects.equals(waitForCompletionTimeout, that.waitForCompletionTimeout) &&
Objects.equals(keepAlive, that.keepAlive) &&
Objects.equals(isCaseSensitive, that.isCaseSensitive);
Objects.equals(keepAlive, that.keepAlive);
}
@ -359,8 +350,7 @@ public class EqlSearchRequest extends ActionRequest implements IndicesRequest.Re
eventCategoryField,
query,
waitForCompletionTimeout,
keepAlive,
isCaseSensitive);
keepAlive);
}
@Override

View File

@ -54,9 +54,4 @@ public class EqlSearchRequestBuilder extends ActionRequestBuilder<EqlSearchReque
request.query(query);
return this;
}
public EqlSearchRequestBuilder isCaseSensitive(boolean isCaseSensitive) {
request.isCaseSensitive(isCaseSensitive);
return this;
}
}

View File

@ -40,7 +40,7 @@ public class EqlFunctionRegistry extends FunctionRegistry {
// Scalar functions
// String
new FunctionDefinition[] {
def(Between.class, Between::new, 2, "between"),
def(Between.class, Between::new, "between"),
def(CIDRMatch.class, CIDRMatch::new, "cidrmatch"),
def(Concat.class, Concat::new, "concat"),
def(EndsWith.class, EndsWith::new, "endswith"),

View File

@ -32,20 +32,20 @@ import static org.elasticsearch.xpack.ql.expression.gen.script.ParamsBuilder.par
/**
* EQL specific between function.
* between(source, left, right[, greedy=false, case_sensitive=false])
* between(source, left, right[, greedy=false])
* Extracts a substring from source thats between left and right substrings
*/
public class Between extends ScalarFunction implements OptionalArgument {
private final Expression input, left, right, greedy, caseSensitive;
public Between(Source source, Expression input, Expression left, Expression right, Expression greedy, Expression caseSensitive) {
super(source, Arrays.asList(input, left, right, toDefault(greedy), toDefault(caseSensitive)));
public Between(Source source, Expression input, Expression left, Expression right, Expression greedy) {
super(source, Arrays.asList(input, left, right, toDefault(greedy)));
this.input = input;
this.left = left;
this.right = right;
this.greedy = arguments().get(3);
this.caseSensitive = arguments().get(4);
this.caseSensitive = Literal.TRUE;
}
private static Expression toDefault(Expression exp) {
@ -73,12 +73,12 @@ public class Between extends ScalarFunction implements OptionalArgument {
return resolution;
}
resolution = isBoolean(greedy, sourceText(), Expressions.ParamOrdinal.FOURTH);
if (resolution.unresolved()) {
return resolution;
}
return isBoolean(caseSensitive, sourceText(), Expressions.ParamOrdinal.FIFTH);
return isBoolean(greedy, sourceText(), Expressions.ParamOrdinal.FOURTH);
// if (resolution.unresolved()) {
// return resolution;
// }
//
// return isBoolean(caseSensitive, sourceText(), Expressions.ParamOrdinal.FIFTH);
}
@Override
@ -100,7 +100,7 @@ public class Between extends ScalarFunction implements OptionalArgument {
@Override
protected NodeInfo<? extends Expression> info() {
return NodeInfo.create(this, Between::new, input, left, right, greedy, caseSensitive);
return NodeInfo.create(this, Between::new, input, left, right, greedy);
}
@Override
@ -146,10 +146,10 @@ public class Between extends ScalarFunction implements OptionalArgument {
@Override
public Expression replaceChildren(List<Expression> newChildren) {
if (newChildren.size() != 5) {
throw new IllegalArgumentException("expected [5] children but received [" + newChildren.size() + "]");
if (newChildren.size() != 4) {
throw new IllegalArgumentException("expected [4] children but received [" + newChildren.size() + "]");
}
return new Between(source(), newChildren.get(0), newChildren.get(1), newChildren.get(2), newChildren.get(3), newChildren.get(4));
return new Between(source(), newChildren.get(0), newChildren.get(1), newChildren.get(2), newChildren.get(3));
}
}

View File

@ -6,7 +6,6 @@
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
import org.elasticsearch.xpack.eql.session.EqlConfiguration;
import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.expression.Expressions;
import org.elasticsearch.xpack.ql.expression.Expressions.ParamOrdinal;
@ -47,7 +46,7 @@ public class EndsWith extends CaseSensitiveScalarFunction {
@Override
public boolean isCaseSensitive() {
return ((EqlConfiguration) configuration()).isCaseSensitive();
return true;
}
@Override

View File

@ -6,7 +6,6 @@
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
import org.elasticsearch.xpack.eql.session.EqlConfiguration;
import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.expression.Expressions;
import org.elasticsearch.xpack.ql.expression.Expressions.ParamOrdinal;
@ -50,7 +49,7 @@ public class IndexOf extends CaseSensitiveScalarFunction implements OptionalArgu
@Override
public boolean isCaseSensitive() {
return ((EqlConfiguration) configuration()).isCaseSensitive();
return true;
}
@Override

View File

@ -6,7 +6,6 @@
package org.elasticsearch.xpack.eql.expression.function.scalar.string;
import org.elasticsearch.xpack.eql.session.EqlConfiguration;
import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.session.Configuration;
import org.elasticsearch.xpack.ql.tree.Source;
@ -19,7 +18,7 @@ public class StartsWith extends org.elasticsearch.xpack.ql.expression.function.s
@Override
public boolean isCaseSensitive() {
return ((EqlConfiguration) configuration()).isCaseSensitive();
return true;
}
}

View File

@ -132,6 +132,6 @@ public class StringContains extends CaseSensitiveScalarFunction {
@Override
public boolean isCaseSensitive() {
return eqlConfiguration().isCaseSensitive();
return true;
}
}

View File

@ -131,7 +131,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
}
if (target != null) {
Expression like = new Like(e.source(), target, StringUtils.toLikePattern(wildString));
Expression like = new Like(e.source(), target, StringUtils.toLikePattern(wildString), true);
if (e instanceof InsensitiveNotEquals) {
like = new Not(e.source(), like);
}

View File

@ -103,7 +103,7 @@ final class QueryTranslator {
// (which is important for strings)
name = ((FieldAttribute) bc.left()).exactAttribute().name();
}
Query query = new TermQuery(source, name, value);
Query query = new TermQuery(source, name, value, true);
if (bc instanceof InsensitiveNotEquals) {
query = new NotQuery(source, query);

View File

@ -119,7 +119,7 @@ public class TransportEqlSearchAction extends HandledTransportAction<EqlSearchRe
.fetchSize(request.fetchSize());
EqlConfiguration cfg = new EqlConfiguration(request.indices(), zoneId, username, clusterName, filter, timeout, includeFrozen,
request.isCaseSensitive(), request.fetchSize(), clientId, new TaskId(nodeId, task.getId()), task);
request.fetchSize(), clientId, new TaskId(nodeId, task.getId()), task);
planExecutor.eql(cfg, request.query(), params, wrap(r -> listener.onResponse(createResponse(r, task.getExecutionId())),
listener::onFailure));
}

View File

@ -23,14 +23,13 @@ public class EqlConfiguration extends org.elasticsearch.xpack.ql.session.Configu
private final boolean includeFrozenIndices;
private final TaskId taskId;
private final EqlSearchTask task;
private final boolean isCaseSensitive;
private final int fetchSize;
@Nullable
private final QueryBuilder filter;
public EqlConfiguration(String[] indices, ZoneId zi, String username, String clusterName, QueryBuilder filter, TimeValue requestTimeout,
boolean includeFrozen, boolean isCaseSensitive, int fetchSize, String clientId, TaskId taskId,
boolean includeFrozen, int fetchSize, String clientId, TaskId taskId,
EqlSearchTask task) {
super(zi, username, clusterName);
@ -39,7 +38,6 @@ public class EqlConfiguration extends org.elasticsearch.xpack.ql.session.Configu
this.requestTimeout = requestTimeout;
this.clientId = clientId;
this.includeFrozenIndices = includeFrozen;
this.isCaseSensitive = isCaseSensitive;
this.taskId = taskId;
this.task = task;
this.fetchSize = fetchSize;
@ -73,10 +71,6 @@ public class EqlConfiguration extends org.elasticsearch.xpack.ql.session.Configu
return includeFrozenIndices;
}
public boolean isCaseSensitive() {
return isCaseSensitive;
}
public boolean isCancelled() {
return task.isCancelled();
}

View File

@ -31,23 +31,11 @@ public final class EqlTestUtils {
private EqlTestUtils() {
}
public static final EqlConfiguration TEST_CFG_CASE_INSENSITIVE = new EqlConfiguration(new String[] {"none"},
org.elasticsearch.xpack.ql.util.DateUtils.UTC, "nobody", "cluster", null, TimeValue.timeValueSeconds(30), false, false,
123, "", new TaskId("test", 123), null);
public static final EqlConfiguration TEST_CFG_CASE_SENSITIVE = new EqlConfiguration(new String[] {"none"},
org.elasticsearch.xpack.ql.util.DateUtils.UTC, "nobody", "cluster", null, TimeValue.timeValueSeconds(30), false, true,
public static final EqlConfiguration TEST_CFG = new EqlConfiguration(new String[] {"none"},
org.elasticsearch.xpack.ql.util.DateUtils.UTC, "nobody", "cluster", null, TimeValue.timeValueSeconds(30), false,
123, "", new TaskId("test", 123), null);
public static EqlConfiguration randomConfiguration() {
return internalRandomConfiguration(randomBoolean());
}
public static EqlConfiguration randomConfigurationWithCaseSensitive(boolean isCaseSensitive) {
return internalRandomConfiguration(isCaseSensitive);
}
private static EqlConfiguration internalRandomConfiguration(boolean isCaseSensitive) {
return new EqlConfiguration(new String[]{randomAlphaOfLength(16)},
randomZone(),
randomAlphaOfLength(16),
@ -55,7 +43,6 @@ public final class EqlTestUtils {
null,
new TimeValue(randomNonNegativeLong()),
randomBoolean(),
isCaseSensitive,
randomIntBetween(1, 1000),
randomAlphaOfLength(16),
new TaskId(randomAlphaOfLength(10), randomNonNegativeLong()),

View File

@ -42,18 +42,13 @@ public class EqlRequestParserTests extends ESTestCase {
EqlSearchRequest::fromXContent);
assertParsingErrorMessage("{\"query\" : \"whatever\", \"size\":\"abc\"}", "failed to parse field [size]",
EqlSearchRequest::fromXContent);
assertParsingErrorMessage("{\"case_sensitive\" : \"whatever\"}", "failed to parse field [case_sensitive]",
EqlSearchRequest::fromXContent);
boolean setIsCaseSensitive = randomBoolean();
boolean isCaseSensitive = randomBoolean();
EqlSearchRequest request = generateRequest("endgame-*", "{\"filter\" : {\"match\" : {\"foo\":\"bar\"}}, "
+ "\"timestamp_field\" : \"tsf\", "
+ "\"event_category_field\" : \"etf\","
+ "\"size\" : \"101\","
+ "\"query\" : \"file where user != 'SYSTEM' by file_path\""
+ (setIsCaseSensitive ? (",\"case_sensitive\" : " + isCaseSensitive) : "")
+ "}", EqlSearchRequest::fromXContent);
+ "\"query\" : \"file where user != 'SYSTEM' by file_path\"}"
, EqlSearchRequest::fromXContent);
assertArrayEquals(new String[]{"endgame-*"}, request.indices());
assertNotNull(request.query());
assertTrue(request.filter() instanceof MatchQueryBuilder);
@ -65,7 +60,6 @@ public class EqlRequestParserTests extends ESTestCase {
assertEquals(101, request.size());
assertEquals(1000, request.fetchSize());
assertEquals("file where user != 'SYSTEM' by file_path", request.query());
assertEquals(setIsCaseSensitive && isCaseSensitive, request.isCaseSensitive());
}
private EqlSearchRequest generateRequest(String index, String json, Function<XContentParser, EqlSearchRequest> fromXContent)

View File

@ -37,7 +37,7 @@ public class VerifierTests extends ESTestCase {
private LogicalPlan accept(IndexResolution resolution, String eql) {
PreAnalyzer preAnalyzer = new PreAnalyzer();
Analyzer analyzer = new Analyzer(EqlTestUtils.TEST_CFG_CASE_INSENSITIVE, new EqlFunctionRegistry(), new Verifier(new Metrics()));
Analyzer analyzer = new Analyzer(EqlTestUtils.TEST_CFG, new EqlFunctionRegistry(), new Verifier(new Metrics()));
return analyzer.analyze(preAnalyzer.preAnalyze(parser.createStatement(eql), resolution));
}

View File

@ -39,8 +39,7 @@ public class BetweenFunctionPipeTests extends AbstractNodeTestCase<BetweenFuncti
randomStringLiteral(),
randomStringLiteral(),
randomStringLiteral(),
randomFrom(true, false) ? randomBooleanLiteral() : null,
randomBooleanLiteral())
randomFrom(true, false) ? randomBooleanLiteral() : null)
.makePipe());
}

View File

@ -11,8 +11,9 @@ import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
import org.elasticsearch.xpack.ql.expression.Literal;
import org.elasticsearch.xpack.ql.expression.LiteralTests;
import org.elasticsearch.xpack.ql.session.Configuration;
import org.junit.Assume;
import static org.elasticsearch.xpack.eql.EqlTestUtils.randomConfigurationWithCaseSensitive;
import static org.elasticsearch.xpack.eql.EqlTestUtils.randomConfiguration;
import static org.elasticsearch.xpack.ql.expression.function.scalar.FunctionTestUtils.l;
import static org.elasticsearch.xpack.ql.tree.Source.EMPTY;
import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD;
@ -20,10 +21,8 @@ import static org.hamcrest.Matchers.startsWith;
public class EndsWithFunctionProcessorTests extends ESTestCase {
final Configuration caseInsensitive = randomConfigurationWithCaseSensitive(false);
public void testEndsWithFunctionWithValidInputCaseSensitive() {
final Configuration caseSensitive = randomConfigurationWithCaseSensitive(true);
final Configuration caseSensitive = randomConfiguration();
assertEquals(true, new EndsWith(EMPTY, l("foobarbar"), l("r"), caseSensitive).makePipe().asProcessor().process(null));
assertEquals(false, new EndsWith(EMPTY, l("foobarbar"), l("R"), caseSensitive).makePipe().asProcessor().process(null));
assertEquals(true, new EndsWith(EMPTY, l("foobarbar"), l("bar"), caseSensitive).makePipe().asProcessor().process(null));
@ -42,6 +41,9 @@ public class EndsWithFunctionProcessorTests extends ESTestCase {
}
public void testEndsWithFunctionWithValidInputCaseInsensitive() {
Assume.assumeTrue(false); //TODO: revisit after we decide on functions case sensitivity handling
final Configuration caseInsensitive = randomConfiguration();
assertEquals(true, new EndsWith(EMPTY, l("foobarbar"), l("r"), caseInsensitive).makePipe().asProcessor().process(null));
assertEquals(true, new EndsWith(EMPTY, l("foobarbar"), l("R"), caseInsensitive).makePipe().asProcessor().process(null));
assertEquals(false, new EndsWith(EMPTY, l("foobar"), l("foo"), caseInsensitive).makePipe().asProcessor().process(null));
@ -58,21 +60,23 @@ public class EndsWithFunctionProcessorTests extends ESTestCase {
}
public void testEndsWithFunctionInputsValidation() {
Configuration config = randomConfiguration();
QlIllegalArgumentException siae = expectThrows(QlIllegalArgumentException.class,
() -> new EndsWith(EMPTY, l(5), l("foo"), caseInsensitive).makePipe().asProcessor().process(null));
() -> new EndsWith(EMPTY, l(5), l("foo"), config).makePipe().asProcessor().process(null));
assertEquals("A string/char is required; received [5]", siae.getMessage());
siae = expectThrows(QlIllegalArgumentException.class,
() -> new EndsWith(EMPTY, l("bar"), l(false), caseInsensitive).makePipe().asProcessor().process(null));
() -> new EndsWith(EMPTY, l("bar"), l(false), config).makePipe().asProcessor().process(null));
assertEquals("A string/char is required; received [false]", siae.getMessage());
}
public void testEndsWithFunctionWithRandomInvalidDataType() {
Configuration config = randomConfiguration();
Literal literal = randomValueOtherThanMany(v -> v.dataType() == KEYWORD, () -> LiteralTests.randomLiteral());
QlIllegalArgumentException siae = expectThrows(QlIllegalArgumentException.class,
() -> new EndsWith(EMPTY, literal, l("foo"), caseInsensitive).makePipe().asProcessor().process(null));
() -> new EndsWith(EMPTY, literal, l("foo"), config).makePipe().asProcessor().process(null));
assertThat(siae.getMessage(), startsWith("A string/char is required; received"));
siae = expectThrows(QlIllegalArgumentException.class,
() -> new EndsWith(EMPTY, l("foo"), literal, caseInsensitive).makePipe().asProcessor().process(null));
() -> new EndsWith(EMPTY, l("foo"), literal, config).makePipe().asProcessor().process(null));
assertThat(siae.getMessage(), startsWith("A string/char is required; received"));
}
}

View File

@ -11,8 +11,9 @@ import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
import org.elasticsearch.xpack.ql.expression.Literal;
import org.elasticsearch.xpack.ql.expression.LiteralTests;
import org.elasticsearch.xpack.ql.session.Configuration;
import org.junit.Assume;
import static org.elasticsearch.xpack.eql.EqlTestUtils.randomConfigurationWithCaseSensitive;
import static org.elasticsearch.xpack.eql.EqlTestUtils.randomConfiguration;
import static org.elasticsearch.xpack.ql.expression.function.scalar.FunctionTestUtils.l;
import static org.elasticsearch.xpack.ql.tree.Source.EMPTY;
import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD;
@ -20,9 +21,10 @@ import static org.hamcrest.Matchers.startsWith;
public class IndexOfFunctionProcessorTests extends ESTestCase {
final Configuration caseInsensitive = randomConfigurationWithCaseSensitive(false);
public void testIndexOfFunctionWithValidInputInsensitive() {
Assume.assumeTrue(false); //TODO: revisit after we decide on functions case sensitivity handling
final Configuration caseInsensitive = randomConfiguration();
assertEquals(5, new IndexOf(EMPTY, l("foobarbar"), l("r"), l(null), caseInsensitive).makePipe().asProcessor().process(null));
assertEquals(5, new IndexOf(EMPTY, l("foobaRbar"), l("r"), l(null), caseInsensitive).makePipe().asProcessor().process(null));
assertEquals(0, new IndexOf(EMPTY, l("foobar"), l("Foo"), l(null), caseInsensitive).makePipe().asProcessor().process(null));
@ -44,7 +46,7 @@ public class IndexOfFunctionProcessorTests extends ESTestCase {
}
public void testIndexOfFunctionWithValidInputSensitive() {
final Configuration caseSensitive = randomConfigurationWithCaseSensitive(true);
final Configuration caseSensitive = randomConfiguration();
assertEquals(5, new IndexOf(EMPTY, l("foobarbar"), l("r"), l(null), caseSensitive).makePipe().asProcessor().process(null));
assertEquals(8, new IndexOf(EMPTY, l("foobaRbar"), l("r"), l(null), caseSensitive).makePipe().asProcessor().process(null));
assertEquals(4, new IndexOf(EMPTY, l("foobARbar"), l("AR"), l(null), caseSensitive).makePipe().asProcessor().process(null));
@ -67,30 +69,32 @@ public class IndexOfFunctionProcessorTests extends ESTestCase {
}
public void testIndexOfFunctionInputsValidation() {
Configuration config = randomConfiguration();
QlIllegalArgumentException siae = expectThrows(QlIllegalArgumentException.class,
() -> new IndexOf(EMPTY, l(5), l("foo"), l(null), caseInsensitive).makePipe().asProcessor().process(null));
() -> new IndexOf(EMPTY, l(5), l("foo"), l(null), config).makePipe().asProcessor().process(null));
assertEquals("A string/char is required; received [5]", siae.getMessage());
siae = expectThrows(QlIllegalArgumentException.class,
() -> new IndexOf(EMPTY, l("bar"), l(false), l(2), caseInsensitive).makePipe().asProcessor().process(null));
() -> new IndexOf(EMPTY, l("bar"), l(false), l(2), config).makePipe().asProcessor().process(null));
assertEquals("A string/char is required; received [false]", siae.getMessage());
siae = expectThrows(QlIllegalArgumentException.class,
() -> new IndexOf(EMPTY, l("bar"), l("a"), l("1"), caseInsensitive).makePipe().asProcessor().process(null));
() -> new IndexOf(EMPTY, l("bar"), l("a"), l("1"), config).makePipe().asProcessor().process(null));
assertEquals("A number is required; received [1]", siae.getMessage());
}
public void testIndexOfFunctionWithRandomInvalidDataType() {
Configuration config = randomConfiguration();
Literal stringLiteral = randomValueOtherThanMany(v -> v.dataType() == KEYWORD, () -> LiteralTests.randomLiteral());
QlIllegalArgumentException siae = expectThrows(QlIllegalArgumentException.class,
() -> new IndexOf(EMPTY, stringLiteral, l("foo"), l(1), caseInsensitive).makePipe().asProcessor().process(null));
() -> new IndexOf(EMPTY, stringLiteral, l("foo"), l(1), config).makePipe().asProcessor().process(null));
assertThat(siae.getMessage(), startsWith("A string/char is required; received"));
siae = expectThrows(QlIllegalArgumentException.class,
() -> new IndexOf(EMPTY, l("foo"), stringLiteral, l(2), caseInsensitive).makePipe().asProcessor().process(null));
() -> new IndexOf(EMPTY, l("foo"), stringLiteral, l(2), config).makePipe().asProcessor().process(null));
assertThat(siae.getMessage(), startsWith("A string/char is required; received"));
Literal numericLiteral = randomValueOtherThanMany(v -> v.dataType().isNumeric(), () -> LiteralTests.randomLiteral());
siae = expectThrows(QlIllegalArgumentException.class,
() -> new IndexOf(EMPTY, l("foo"), l("o"), numericLiteral, caseInsensitive).makePipe().asProcessor().process(null));
() -> new IndexOf(EMPTY, l("foo"), l("o"), numericLiteral, config).makePipe().asProcessor().process(null));
assertThat(siae.getMessage(), startsWith("A number is required; received"));
}
}

View File

@ -13,18 +13,18 @@ import org.elasticsearch.xpack.ql.tree.Source;
import java.util.function.Supplier;
import static org.elasticsearch.xpack.eql.EqlTestUtils.randomConfigurationWithCaseSensitive;
import static org.elasticsearch.xpack.eql.EqlTestUtils.randomConfiguration;
public class StartsWithFunctionProcessorTests extends org.elasticsearch.xpack.ql.expression.function.scalar.string.StartsWithProcessorTests{
@Override
protected Supplier<Boolean> isCaseSensitiveGenerator() {
return () -> randomBoolean();
return () -> Boolean.TRUE;
}
@Override
protected Supplier<Configuration> configurationGenerator() {
return () -> randomConfigurationWithCaseSensitive(isCaseSensitive);
return () -> randomConfiguration();
}
@Override

View File

@ -16,16 +16,10 @@ public class EqlFoldSpec {
private final String description;
private final String expression;
private final Object expected;
// flag to dictate which modes are supported for the test
// null -> apply the test to both modes (case sensitive and case insensitive)
// TRUE -> case sensitive
// FALSE -> case insensitive
private Boolean caseSensitive = null;
EqlFoldSpec(String name, String description, Boolean caseSensitive, String expression, Object expected) {
EqlFoldSpec(String name, String description, String expression, Object expected) {
this.name = name;
this.description = description;
this.caseSensitive = caseSensitive;
this.expression = expression;
this.expected = expected;
}
@ -38,15 +32,10 @@ public class EqlFoldSpec {
return expected;
}
public Boolean caseSensitive() {
return caseSensitive;
}
public String toString() {
StringBuilder sb = new StringBuilder();
appendWithComma(sb, "name", name);
appendWithComma(sb, "expression", expression);
appendWithComma(sb, "case_sensitive", caseSensitive == null ? "null" : caseSensitive);
appendWithComma(sb, "expected", expected == null ? "null" : expected);
return sb.toString();
}
@ -78,12 +67,11 @@ public class EqlFoldSpec {
EqlFoldSpec that = (EqlFoldSpec) other;
return Objects.equals(this.expression, that.expression)
&& Objects.equals(this.caseSensitive, that.caseSensitive);
return Objects.equals(this.expression, that.expression);
}
@Override
public int hashCode() {
return Objects.hash(this.expression, this.caseSensitive);
return Objects.hash(this.expression);
}
}

View File

@ -40,20 +40,6 @@ public class EqlFoldSpecLoader {
TomlTable fold = table.getTomlTable("fold");
String description = getTrimmedString(table, "description");
Boolean cs = null;
Boolean caseSensitive = table.getBoolean("case_sensitive");
Boolean caseInsensitive = table.getBoolean("case_insensitive");
// if case_sensitive is TRUE and case_insensitive is not TRUE (FALSE or NULL), then the test is case sensitive only
if (Boolean.TRUE.equals(caseSensitive)) {
if (Boolean.FALSE.equals(caseInsensitive) || caseInsensitive == null) {
cs = true;
}
}
// if case_sensitive is not TRUE (FALSE or NULL) and case_insensitive is TRUE, then the test is case insensitive only
else if (Boolean.TRUE.equals(caseInsensitive)) {
cs = false;
}
// in all other cases, the test should run no matter the case sensitivity (should test both scenarios)
if (fold != null) {
List<TomlTable> tests = fold.getArrayTable("tests");
@ -61,7 +47,7 @@ public class EqlFoldSpecLoader {
for (TomlTable test : tests) {
String expression = getTrimmedString(test, "expression");
Object expected = test.get("expected");
EqlFoldSpec spec = new EqlFoldSpec(name, description, cs, expression, expected);
EqlFoldSpec spec = new EqlFoldSpec(name, description, expression, expected);
testSpecs.add(spec);
}
}

View File

@ -60,7 +60,7 @@ import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static org.elasticsearch.xpack.eql.EqlTestUtils.TEST_CFG_CASE_INSENSITIVE;
import static org.elasticsearch.xpack.eql.EqlTestUtils.TEST_CFG;
import static org.elasticsearch.xpack.ql.TestUtils.UTC;
import static org.elasticsearch.xpack.ql.expression.Literal.TRUE;
import static org.elasticsearch.xpack.ql.tree.Source.EMPTY;
@ -84,9 +84,9 @@ public class OptimizerTests extends ESTestCase {
private LogicalPlan accept(IndexResolution resolution, String eql) {
PreAnalyzer preAnalyzer = new PreAnalyzer();
PostAnalyzer postAnalyzer = new PostAnalyzer();
Analyzer analyzer = new Analyzer(TEST_CFG_CASE_INSENSITIVE, new EqlFunctionRegistry(), new Verifier(new Metrics()));
Analyzer analyzer = new Analyzer(TEST_CFG, new EqlFunctionRegistry(), new Verifier(new Metrics()));
return optimizer.optimize(postAnalyzer.postAnalyze(analyzer.analyze(preAnalyzer.preAnalyze(parser.createStatement(eql),
resolution)), TEST_CFG_CASE_INSENSITIVE));
resolution)), TEST_CFG));
}
private LogicalPlan accept(String eql) {

View File

@ -29,8 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static org.elasticsearch.xpack.eql.EqlTestUtils.TEST_CFG_CASE_INSENSITIVE;
import static org.elasticsearch.xpack.eql.EqlTestUtils.TEST_CFG_CASE_SENSITIVE;
import static org.elasticsearch.xpack.eql.EqlTestUtils.TEST_CFG;
import static org.elasticsearch.xpack.ql.tree.Source.EMPTY;
public class TomlFoldTests extends ESTestCase {
@ -40,8 +39,7 @@ public class TomlFoldTests extends ESTestCase {
private static EqlParser parser = new EqlParser();
private static final EqlFunctionRegistry functionRegistry = new EqlFunctionRegistry();
private static Verifier verifier = new Verifier(new Metrics());
private static Analyzer caseSensitiveAnalyzer = new Analyzer(TEST_CFG_CASE_SENSITIVE, functionRegistry, verifier);
private static Analyzer caseInsensitiveAnalyzer = new Analyzer(TEST_CFG_CASE_INSENSITIVE, functionRegistry, verifier);
private static Analyzer analyzer = new Analyzer(TEST_CFG, functionRegistry, verifier);
private final int num;
private final EqlFoldSpec spec;
@ -70,30 +68,6 @@ public class TomlFoldTests extends ESTestCase {
}
public void test() {
// run both tests if case sensitivity doesn't matter
if (spec.caseSensitive() == null) {
testCaseSensitive(spec);
testCaseInsensitive(spec);
}
// run only the case sensitive test
else if (spec.caseSensitive()) {
testCaseSensitive(spec);
}
// run only the case insensitive test
else {
testCaseInsensitive(spec);
}
}
private void testCaseSensitive(EqlFoldSpec spec) {
testWithAnalyzer(caseSensitiveAnalyzer, spec);
}
private void testCaseInsensitive(EqlFoldSpec spec) {
testWithAnalyzer(caseInsensitiveAnalyzer, spec);
}
private void testWithAnalyzer(Analyzer analyzer, EqlFoldSpec spec) {
Expression expr = parser.createExpression(spec.expression());
LogicalPlan logicalPlan = new Project(EMPTY, new LocalRelation(EMPTY, emptyList()),
singletonList(new Alias(Source.EMPTY, "test", expr)));

View File

@ -33,13 +33,13 @@ public class QueryFolderFailTests extends AbstractQueryFolderTestCase {
"process where between(process_name, \"s\") == \"yst\"",
"process where between(null) == \"yst\"",
"process where between(process_name, null) == \"yst\"",
"process where between(process_name, \"s\", \"e\", false, false, true) == \"yst\"",
"process where between(process_name, \"s\", \"e\", false, false) == \"yst\"",
};
for (String query : queries) {
ParsingException e = expectThrows(ParsingException.class,
() -> plan(query));
assertEquals("line 1:16: error building [between]: expects between three and five arguments", e.getMessage());
assertEquals("line 1:16: error building [between]: expects three or four arguments", e.getMessage());
}
}
@ -56,10 +56,6 @@ public class QueryFolderFailTests extends AbstractQueryFolderTestCase {
assertEquals("1:15: fourth argument of [between(process_name, \"s\", \"e\", \"true\")] must be [boolean], " +
"found value [\"true\"] type [keyword]",
error("process where between(process_name, \"s\", \"e\", \"true\")"));
assertEquals("1:15: fifth argument of [between(process_name, \"s\", \"e\", false, 2)] must be [boolean], " +
"found value [2] type [integer]",
error("process where between(process_name, \"s\", \"e\", false, 2)"));
}
public void testCIDRMatchAgainstField() {

View File

@ -10,14 +10,12 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.Strings;
import org.elasticsearch.xpack.eql.plan.physical.EsQueryExec;
import org.elasticsearch.xpack.eql.plan.physical.PhysicalPlan;
import org.junit.Assume;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import static org.hamcrest.Matchers.containsString;
@ -110,13 +108,6 @@ public class QueryFolderOkTests extends AbstractQueryFolderTestCase {
}
public void test() {
String testName = name.toLowerCase(Locale.ROOT);
// skip tests that do not make sense from case sensitivity point of view
boolean isCaseSensitiveValidTest = testName.endsWith("sensitive") == false
|| testName.endsWith("-casesensitive") && configuration.isCaseSensitive()
|| testName.endsWith("-caseinsensitive") && configuration.isCaseSensitive() == false;
Assume.assumeTrue(isCaseSensitiveValidTest);
PhysicalPlan p = plan(query);
assertEquals(EsQueryExec.class, p.getClass());
EsQueryExec eqe = (EsQueryExec) p;

View File

@ -23,6 +23,8 @@ registry where not pid;
process where process_name : "net.exe" and command_line : "* user*.exe";
process where process_name : "net.EXE" and command_line : "* user*.EXE";
process where command_line : "~!@#$%^&*();'[]{}\\|<>?,./:\"-= ' ";
process where
@ -33,6 +35,8 @@ process where process_name in ("net.exe", "cmd.exe", "at.exe");
process where command_line : "*.exe *admin*" or command_line : "* a b*";
process where command_line : "*.eXe *aDMin*" or command_line : "* a b*";
process where pid in (1,2,3,4,5,6,7,8) and abc : 100 and def : 200 and ghi : 300 and jkl : x;
process where ppid != pid;

View File

@ -10,6 +10,8 @@
// ...
// <expectation n>
// ;
// NOTE: do not use whitespaces in the relevant parts of the query itself, as they will be removed. For example 'process where process_name : "System Idle Process"'
// The whitespaces between System Idle Process will be removed and the assertion will fail.
basic
@ -21,7 +23,7 @@ null
singleNumericFilterEquals
process where serial_event_id == 1
;
"term":{"serial_event_id":{"value":1
"term":{"serial_event_id":{"value":1,"boost":1.0}
;
singleNumericFilterLess
@ -48,10 +50,16 @@ process where serial_event_id >= 4
"range":{"serial_event_id":{"from":4,"to":null,"include_lower":true,"include_upper":false
;
caseInsensitiveEquals
process where process_name : "test"
;
"term":{"process_name":{"value":"test","case_insensitive":true,"boost":1.0}
;
mixedTypeFilter
process where process_name : "notepad.exe" or (serial_event_id < 4.5 and serial_event_id >= 3.1)
;
"term":{"process_name":{"value":"notepad.exe"
"term":{"process_name":{"value":"notepad.exe","case_insensitive":true,"boost":1.0}
"range":{"serial_event_id":{"from":3.1,"to":4.5,"include_lower":true,"include_upper":false
;
@ -70,35 +78,35 @@ process where process_name in ("python.exe", "SMSS.exe", "explorer.exe")
equalsAndInFilter
process where process_path : "*\\red_ttp\\wininit.*" and opcode in (0,1,2,3)
;
"wildcard":{"process_path":{"wildcard":"*\\\\red_ttp\\\\wininit.*"
{"terms":{"opcode":[0,1,2,3]
"wildcard":{"process_path":{"wildcard":"*\\\\red_ttp\\\\wininit.*","case_insensitive":true,"boost":1.0}}},
{"terms":{"opcode":[0,1,2,3],"boost":1.0}}
;
functionEqualsTrue
process where cidrMatch(source_address, "10.0.0.0/8") == true
;
{"bool":{"must":[{"term":{"event.category":{"value":"process"
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}
{"terms":{"source_address":["10.0.0.0/8"]
;
functionEqualsFalse
process where cidrMatch(source_address, "10.0.0.0/8") == false
;
{"bool":{"must":[{"term":{"event.category":{"value":"process"
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}
{"bool":{"must_not":[{"terms":{"source_address":["10.0.0.0/8"]
;
functionNotEqualsTrue
process where cidrMatch(source_address, "10.0.0.0/8") != true
;
{"bool":{"must":[{"term":{"event.category":{"value":"process"
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}
{"bool":{"must_not":[{"terms":{"source_address":["10.0.0.0/8"]
;
functionNotEqualsFalse
process where cidrMatch(source_address, "10.0.0.0/8") != false
;
{"bool":{"must":[{"term":{"event.category":{"value":"process"
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}
{"terms":{"source_address":["10.0.0.0/8"]
;
@ -112,13 +120,8 @@ process where endsWith(process_path, "x") == true and endsWith(process_path, "yx
twoFunctionsEqualsBooleanLiterals-caseInsensitive
process where endsWith(process_path, "x") == true and endsWith(process_path, "yx") != true
;
"bool":{"must":[{"term":{"event.category":{"value":"process"
"must":[{"script":{"script":{"source":"InternalQlScriptUtils.nullSafeFilter(
InternalEqlScriptUtils.endsWith(InternalQlScriptUtils.docValue(doc,params.v0),params.v1,params.v2))","lang":"painless",
"params":{"v0":"process_path","v1":"x","v2":false}}
"script":{"script":{"source":"InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.not(
InternalEqlScriptUtils.endsWith(InternalQlScriptUtils.docValue(doc,params.v0),params.v1,params.v2)))","lang":"painless",
"params":{"v0":"process_path","v1":"yx","v2":false}}
{"bool":{"must":[{"wildcard":{"process_path":{"wildcard":"*x","boost":1.0}}},
{"bool":{"must_not":[{"wildcard":{"process_path":{"wildcard":"*yx","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}}],"adjust_pure_negative":true,"boost":1.0}}
;
endsWithKeywordFieldFunction-caseSensitive
@ -138,9 +141,8 @@ process where endsWith(hostname, "c")
endsWithFunction-caseInsensitive
process where endsWith(user_name, "c")
;
"script":{"source":"InternalQlScriptUtils.nullSafeFilter(InternalEqlScriptUtils.endsWith(
InternalQlScriptUtils.docValue(doc,params.v0),params.v1,params.v2))",
"params":{"v0":"user_name","v1":"c","v2":false}}
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}}},
{"wildcard":{"user_name":{"wildcard":"*c","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}}
;
lengthFunctionWithExactSubField
@ -170,9 +172,8 @@ InternalEqlScriptUtils.length(InternalQlScriptUtils.docValue(doc,params.v0)),par
startsWithFunction-caseInsensitive
process where startsWith(user_name, "A")
;
"script":{"source":"InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.startsWith(
InternalQlScriptUtils.docValue(doc,params.v0),params.v1,params.v2))",
"params":{"v0":"user_name","v1":"A","v2":false}}
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}}},
{"prefix":{"user_name":{"value":"A","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}}
;
startsWithFunctionSimple-caseSensitive
@ -207,9 +208,8 @@ process where stringContains(hostname, "foo")
stringContains-caseInsensitive
process where stringContains(process_name, "foo")
;
"script":{"source":"InternalQlScriptUtils.nullSafeFilter(InternalEqlScriptUtils.stringContains(
InternalQlScriptUtils.docValue(doc,params.v0),params.v1,params.v2))"
"params":{"v0":"process_name","v1":"foo","v2":false}
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}}},
{"wildcard":{"process_name":{"wildcard":"*foo*","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}}
;
@ -234,7 +234,7 @@ process where indexOf(user_name, "A", 2) > 0
;
"script":{"source":"InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.gt(
InternalEqlScriptUtils.indexOf(InternalQlScriptUtils.docValue(doc,params.v0),params.v1,params.v2,params.v3),params.v4))",
"params":{"v0":"user_name","v1":"A","v2":2,"v3":false,"v4":0}
"params":{"v0":"user_name","v1":"A","v2":2,"v3":true,"v4":0}
;
substringFunction
@ -250,7 +250,7 @@ process where between(process_name, "s", "e") : "yst"
;
"script":{"source":"InternalQlScriptUtils.nullSafeFilter(InternalEqlScriptUtils.seq(
InternalEqlScriptUtils.between(InternalQlScriptUtils.docValue(doc,params.v0),params.v1,params.v2,params.v3,params.v4),params.v5))",
"params":{"v0":"process_name","v1":"s","v2":"e","v3":false,"v4":false,"v5":"yst"}
"params":{"v0":"process_name","v1":"s","v2":"e","v3":false,"v4":true,"v5":"yst"}
;
concatFunction
@ -264,35 +264,35 @@ InternalEqlScriptUtils.concat([InternalQlScriptUtils.docValue(doc,params.v0),par
cidrMatchFunctionOne
process where cidrMatch(source_address, "10.0.0.0/8")
;
{"bool":{"must":[{"term":{"event.category":{"value":"process"
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}
{"terms":{"source_address":["10.0.0.0/8"]
;
cidrMatchFunctionOneBool
process where cidrMatch(source_address, "10.0.0.0/8") == true
;
{"bool":{"must":[{"term":{"event.category":{"value":"process"
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}
{"terms":{"source_address":["10.0.0.0/8"]
;
cidrMatchFunctionTwo
process where cidrMatch(source_address, "10.0.0.0/8", "192.168.0.0/16")
;
{"bool":{"must":[{"term":{"event.category":{"value":"process"
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}
{"terms":{"source_address":["10.0.0.0/8","192.168.0.0/16"]
;
cidrMatchFunctionTwoWithOr
process where cidrMatch(source_address, "10.0.0.0/8") or cidrMatch(source_address, "192.168.0.0/16")
;
{"bool":{"must":[{"term":{"event.category":{"value":"process"
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}
{"bool":{"should":[{"terms":{"source_address":["10.0.0.0/8"],"boost":1.0}},{"terms":{"source_address":["192.168.0.0/16"],"boost":1.0}}
;
cidrMatchFunctionThree
process where cidrMatch(source_address, "10.0.0.0/8", "192.168.0.0/16", "2001:db8::/32")
;
{"bool":{"must":[{"term":{"event.category":{"value":"process"
{"bool":{"must":[{"term":{"event.category":{"value":"process","boost":1.0}
{"terms":{"source_address":["10.0.0.0/8","192.168.0.0/16","2001:db8::/32"]
;
@ -351,34 +351,34 @@ InternalEqlScriptUtils.number(InternalQlScriptUtils.docValue(doc,params.v0),para
numberFunctionFoldedComparison
process where serial_event_id == number("-32.5");
{"term":{"serial_event_id":{"value":-32.5,
{"term":{"serial_event_id":{"value":-32.5,"boost":1.0}
;
numberFunctionFoldedHexComparison
process where serial_event_id == number("0x32", 16);
{"term":{"serial_event_id":{"value":50,
{"term":{"serial_event_id":{"value":50,"boost":1.0}
;
wildcardFunctionSingleArgument
process where wildcard(process_path, "*\\red_ttp\\wininit.*")
;
"wildcard":{"process_path":{"wildcard":"*\\\\red_ttp\\\\wininit.*"
"wildcard":{"process_path":{"wildcard":"*\\\\red_ttp\\\\wininit.*","boost":1.0}}
;
wildcardFunctionTwoArguments
process where wildcard(process_path, "*\\red_ttp\\wininit.*", "*\\abc\\*")
;
"wildcard":{"process_path":{"wildcard":"*\\\\red_ttp\\\\wininit.*"
"wildcard":{"process_path":{"wildcard":"*\\\\abc\\\\*"
"wildcard":{"process_path":{"wildcard":"*\\\\red_ttp\\\\wininit.*","boost":1.0}}
"wildcard":{"process_path":{"wildcard":"*\\\\abc\\\\*","boost":1.0}}
;
wildcardFunctionThreeArguments
process where wildcard(process_path, "*\\red_ttp\\wininit.*", "*\\abc\\*", "*def*")
;
"wildcard":{"process_path":{"wildcard":"*\\\\red_ttp\\\\wininit.*"
"wildcard":{"process_path":{"wildcard":"*\\\\abc\\\\*"
"wildcard":{"process_path":{"wildcard":"*def*"
"wildcard":{"process_path":{"wildcard":"*\\\\red_ttp\\\\wininit.*","boost":1.0}}
"wildcard":{"process_path":{"wildcard":"*\\\\abc\\\\*","boost":1.0}}
"wildcard":{"process_path":{"wildcard":"*def*","boost":1.0}}
;

View File

@ -210,7 +210,6 @@ description = "Fold string comparisons"
[string_case_sensitive_match_comparison]
description = "Fold string comparisons"
case_sensitive = true
[[string_case_sensitive_match_comparison.fold.tests]]
expression = '"Foo" == "foo"'

View File

@ -104,16 +104,14 @@ description = "Test the `endsWith` function with case matching"
[endswith_insensitive]
description = "Test the `endsWith` function with case insensitivity"
case_insensitive = true
[[endswith_insensitive.fold.tests]]
expression = 'endsWith("FooBarBaz", "baz")'
expected = true
expected = false
[endswith_sensitive]
description = "Test the `endsWith` function with case sensitivity"
case_sensitive = true
[[endswith_sensitive.fold.tests]]
expression = 'endsWith("FooBarBaz", "baz")'
@ -331,7 +329,6 @@ description = "Test the `startsWith` function"
[startswith_case_sensitive]
description = "Test the `startsWith` function with case-sensitive matching"
case_sensitive = true
[[startswith_case_sensitive.tests]]
expression = '''startsWith("FooBar", "Foo")'''
@ -344,7 +341,6 @@ case_sensitive = true
[startswith_case_insensitive]
description = "Test the `startsWith` function with case-insensitive matching"
case_insensitive = true
[[startswith_case_insensitive.fold.tests]]
expression = '''startsWith("FooBar", "Foo")'''
@ -352,11 +348,11 @@ case_insensitive = true
[[startswith_case_insensitive.fold.tests]]
expression = '''startsWith("FooBar", "FOO")'''
expected = true
expected = false
[[startswith_case_insensitive.fold.tests]]
expression = '''startsWith("FooBar", "foo")'''
expected = true
expected = false
[[startswith_case_insensitive.fold.tests]]
expression = '''startsWith("FooBar", "Bar")'''
@ -498,11 +494,10 @@ description = "Test that `wildcard` folds with correct case matches."
[wildcard_case_insensitive]
description = "Test that `wildcard` function folds case insensitive as expected."
case_insensitive = true
[[wildcard_case_insensitive.fold.tests]]
expression = 'wildcard("FOO", "f*o*o*")'
expected = true
expected = false
[[wildcard_case_insensitive.fold.tests]]
expression = 'wildcard("bar", "f*o*o*")'
@ -511,7 +506,6 @@ case_insensitive = true
[wildcard_case_sensitive]
description = "Test that `wildcard` folds case-sensitive matches."
case_sensitive = true
[[wildcard_case_sensitive.fold.tests]]
expression = 'wildcard("Foo", "F*o*o*")'

View File

@ -420,13 +420,16 @@ public class FunctionRegistry {
public static <T extends Function> FunctionDefinition def(Class<T> function,
FourParametersFunctionBuilder<T> ctorRef, String... names) {
FunctionBuilder builder = (source, children, distinct, cfg) -> {
if (children.size() != 4) {
boolean hasMinimumThree = OptionalArgument.class.isAssignableFrom(function);
if (hasMinimumThree && (children.size() > 4 || children.size() < 3)) {
throw new QlIllegalArgumentException("expects three or four arguments");
} else if (!hasMinimumThree && children.size() != 4) {
throw new QlIllegalArgumentException("expects exactly four arguments");
}
if (distinct) {
throw new QlIllegalArgumentException("does not support DISTINCT yet it was specified");
}
return ctorRef.build(source, children.get(0), children.get(1), children.get(2), children.get(3));
return ctorRef.build(source, children.get(0), children.get(1), children.get(2), children.size() == 4 ? children.get(3) : null);
};
return def(function, builder, false, names);
}

View File

@ -9,19 +9,43 @@ import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.tree.NodeInfo;
import org.elasticsearch.xpack.ql.tree.Source;
import java.util.Objects;
public class Like extends RegexMatch<LikePattern> {
private final boolean caseInsensitive;
public Like(Source source, Expression left, LikePattern pattern) {
this(source, left, pattern, false);
}
public Like(Source source, Expression left, LikePattern pattern, boolean caseInsensitive) {
super(source, left, pattern);
this.caseInsensitive = caseInsensitive;
}
@Override
protected NodeInfo<Like> info() {
return NodeInfo.create(this, Like::new, field(), pattern());
return NodeInfo.create(this, Like::new, field(), pattern(), caseInsensitive());
}
@Override
protected Like replaceChild(Expression newLeft) {
return new Like(source(), newLeft, pattern());
return new Like(source(), newLeft, pattern(), caseInsensitive());
}
public boolean caseInsensitive() {
return caseInsensitive;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj) && Objects.equals(((Like) obj).caseInsensitive(), caseInsensitive());
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), caseInsensitive());
}
}

View File

@ -32,7 +32,6 @@ import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.LessT
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.NotEquals;
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.NullEquals;
import org.elasticsearch.xpack.ql.expression.predicate.regex.Like;
import org.elasticsearch.xpack.ql.expression.predicate.regex.LikePattern;
import org.elasticsearch.xpack.ql.expression.predicate.regex.RLike;
import org.elasticsearch.xpack.ql.expression.predicate.regex.RegexMatch;
import org.elasticsearch.xpack.ql.querydsl.query.BoolQuery;
@ -127,8 +126,8 @@ public final class ExpressionTranslators {
if (e.field() instanceof FieldAttribute) {
targetFieldName = handler.nameOf(((FieldAttribute) e.field()).exactAttribute());
if (e instanceof Like) {
LikePattern p = ((Like) e).pattern();
q = new WildcardQuery(e.source(), targetFieldName, p.asLuceneWildcard());
Like l = (Like) e;
q = new WildcardQuery(e.source(), targetFieldName, l.pattern().asLuceneWildcard(), l.caseInsensitive());
}
if (e instanceof RLike) {

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.ql.querydsl.query;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.xpack.ql.tree.Source;
import java.util.Objects;
@ -16,11 +17,17 @@ public class TermQuery extends LeafQuery {
private final String term;
private final Object value;
private final boolean caseInsensitive;
public TermQuery(Source source, String term, Object value) {
this(source, term, value, false);
}
public TermQuery(Source source, String term, Object value, boolean caseInsensitive) {
super(source);
this.term = term;
this.value = value;
this.caseInsensitive = caseInsensitive;
}
public String term() {
@ -31,14 +38,20 @@ public class TermQuery extends LeafQuery {
return value;
}
public Boolean caseInsensitive() {
return caseInsensitive;
}
@Override
public QueryBuilder asBuilder() {
return termQuery(term, value);
TermQueryBuilder qb = termQuery(term, value);
// ES does not allow case_insensitive to be set to "false", it should be either "true" or not specified
return caseInsensitive == false ? qb : qb.caseInsensitive(caseInsensitive);
}
@Override
public int hashCode() {
return Objects.hash(term, value);
return Objects.hash(term, value, caseInsensitive);
}
@Override
@ -53,7 +66,8 @@ public class TermQuery extends LeafQuery {
TermQuery other = (TermQuery) obj;
return Objects.equals(term, other.term)
&& Objects.equals(value, other.value);
&& Objects.equals(value, other.value)
&& Objects.equals(caseInsensitive, other.caseInsensitive);
}
@Override

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.ql.querydsl.query;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.WildcardQueryBuilder;
import org.elasticsearch.xpack.ql.tree.Source;
import java.util.Objects;
@ -15,11 +16,17 @@ import static org.elasticsearch.index.query.QueryBuilders.wildcardQuery;
public class WildcardQuery extends LeafQuery {
private final String field, query;
private final boolean caseInsensitive;
public WildcardQuery(Source source, String field, String query) {
this(source, field, query, false);
}
public WildcardQuery(Source source, String field, String query, boolean caseInsensitive) {
super(source);
this.field = field;
this.query = query;
this.caseInsensitive = caseInsensitive;
}
public String field() {
@ -30,14 +37,20 @@ public class WildcardQuery extends LeafQuery {
return query;
}
public Boolean caseInsensitive() {
return caseInsensitive;
}
@Override
public QueryBuilder asBuilder() {
return wildcardQuery(field, query);
WildcardQueryBuilder wb = wildcardQuery(field, query);
// ES does not allow case_insensitive to be set to "false", it should be either "true" or not specified
return caseInsensitive == false ? wb : wb.caseInsensitive(caseInsensitive);
}
@Override
public int hashCode() {
return Objects.hash(field, query);
return Objects.hash(field, query, caseInsensitive);
}
@Override
@ -52,7 +65,8 @@ public class WildcardQuery extends LeafQuery {
WildcardQuery other = (WildcardQuery) obj;
return Objects.equals(field, other.field)
&& Objects.equals(query, other.query);
&& Objects.equals(query, other.query)
&& Objects.equals(caseInsensitive, other.caseInsensitive);
}
@Override