Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/changelog/118324.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 118324
summary: Allow the data type of `null` in filters
area: ES|QL
type: bug
issues:
- 116351
6 changes: 6 additions & 0 deletions docs/changelog/125832.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 125832
summary: "ESQL: Fix `NULL` handling in `IN` clause"
area: ES|QL
type: bug
issues:
- 119950
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,28 @@ emp_no:integer | languages:integer | height:double | x:double | y:double | z:dou
10020 | null | 1.41 | 1.41 | 1.41 | 40031.0 | 40031
10021 | null | 1.47 | 1.47 | 1.47 | 60408.0 | 60408
;

whereNull
FROM employees
| WHERE NULL and emp_no <= 10021
| SORT first_name, last_name
| EVAL fullname = CONCAT(first_name, " ", last_name)
| KEEP fullname, job_positions, salary, salary_change
| limit 5
;

fullname:keyword | job_positions:keyword | salary:integer | salary_change:double
;

inConvertedNull
required_capability: filter_in_converted_null
FROM employees
| WHERE emp_no in (10021, 10022, null::int)
| KEEP emp_no, first_name, last_name
| SORT emp_no
;

emp_no:integer | first_name:keyword | last_name:keyword
10021 | Ramzi | Erde
10022 | Shahaf | Famili
;
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,12 @@ public enum Cap {
*/
AGGREGATE_METRIC_DOUBLE_SORTING(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),

/**
* Support for filter in converted null.
* See <a href="https://github.com/elastic/elasticsearch/issues/125832"> ESQL: Fix `NULL` handling in `IN` clause #125832 </a>
*/
FILTER_IN_CONVERTED_NULL,

/**
* When creating constant null blocks in {@link org.elasticsearch.compute.lucene.ValuesSourceReaderOperator}, we also handed off
* the ownership of that block - but didn't account for the fact that the caller might close it, leading to double releases
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ private Query translate(TranslatorHandler handler) {
List<Query> queries = new ArrayList<>();

for (Expression rhs : list()) {
if (DataType.isNull(rhs.dataType()) == false) {
if (Expressions.isGuaranteedNull(rhs) == false) {
if (needsTypeSpecificValueHandling(attribute.dataType())) {
// delegates to BinaryComparisons translator to ensure consistent handling of date and time values
// TODO:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,33 @@ public void testPeriodAndDurationInEval() {

public void testFilterNonBoolField() {
assertEquals("1:19: Condition expression needs to be boolean, found [INTEGER]", error("from test | where emp_no"));

assertEquals(
"1:19: Condition expression needs to be boolean, found [KEYWORD]",
error("from test | where concat(first_name, \"foobar\")")
);
}

public void testFilterNullField() {
// `where null` should return empty result set
query("from test | where null");

// Value null of type `BOOLEAN`
query("from test | where null::boolean");

// Provide `NULL` type in `EVAL`
query("from t | EVAL x = null | where x");

// `to_string(null)` is of `KEYWORD` type null, resulting in `to_string(null) == "abc"` being of `BOOLEAN`
query("from t | where to_string(null) == \"abc\"");

// Other DataTypes can contain null values
assertEquals("1:19: Condition expression needs to be boolean, found [KEYWORD]", error("from test | where null::string"));
assertEquals("1:19: Condition expression needs to be boolean, found [INTEGER]", error("from test | where null::integer"));
assertEquals(
"1:45: Condition expression needs to be boolean, found [DATETIME]",
error("from test | EVAL x = null::datetime | where x")
);
}

public void testFilterDateConstant() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,25 @@
import org.elasticsearch.geo.GeometryTestUtils;
import org.elasticsearch.geo.ShapeTestUtils;
import org.elasticsearch.xpack.esql.core.expression.Expression;
import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
import org.elasticsearch.xpack.esql.core.expression.FoldContext;
import org.elasticsearch.xpack.esql.core.expression.Literal;
import org.elasticsearch.xpack.esql.core.querydsl.query.TermsQuery;
import org.elasticsearch.xpack.esql.core.tree.Source;
import org.elasticsearch.xpack.esql.core.type.DataType;
import org.elasticsearch.xpack.esql.core.type.EsField;
import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase;
import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.WildcardLikeTests;
import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
import org.junit.AfterClass;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;

import static org.elasticsearch.xpack.esql.EsqlTestUtils.of;
Expand Down Expand Up @@ -79,6 +85,16 @@ private static Literal L(Object value) {
return of(EMPTY, value);
}

public void testConvertedNull() {
In in = new In(
EMPTY,
new FieldAttribute(Source.EMPTY, "field", new EsField("suffix", DataType.KEYWORD, Map.of(), true)),
Arrays.asList(ONE, new Literal(Source.EMPTY, null, randomFrom(DataType.types())), THREE)
);
var query = in.asQuery(TranslatorHandler.TRANSLATOR_HANDLER);
assertEquals(new TermsQuery(EMPTY, "field", Set.of(1, 3)), query);
}

@ParametersFactory
public static Iterable<Object[]> parameters() {
List<TestCaseSupplier> suppliers = new ArrayList<>();
Expand Down
Loading