diff --git a/src/query/interpret/eval.hpp b/src/query/interpret/eval.hpp index 3c5c6263e..d0927b30d 100644 --- a/src/query/interpret/eval.hpp +++ b/src/query/interpret/eval.hpp @@ -157,9 +157,14 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> { _list.type()); } auto list = _list.Value<std::vector<TypedValue>>(); - if (literal.IsNull()) { - return TypedValue::Null; - } + + // If literal is NULL there is no need to try to compare it with every + // element in the list since result of every comparison will be NULL. There + // is one special case that we must test explicitly: if list is empty then + // result is false since no comparison will be performed. + if (list.size() == 0U) return false; + if (literal.IsNull()) return TypedValue::Null; + auto has_null = false; for (const auto &element : list) { auto result = literal == element; diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp index 14cc3e71d..a4f881978 100644 --- a/tests/unit/query_expression_evaluator.cpp +++ b/tests/unit/query_expression_evaluator.cpp @@ -344,6 +344,21 @@ TEST(ExpressionEvaluator, InListOperator) { auto value = op->Accept(eval.eval); EXPECT_TRUE(value.IsNull()); } + { + // Null literal. + auto *op = storage.Create<InListOperator>( + storage.Create<PrimitiveLiteral>(TypedValue::Null), list_literal); + auto value = op->Accept(eval.eval); + EXPECT_TRUE(value.IsNull()); + } + { + // Null literal, empty list. + auto *op = storage.Create<InListOperator>( + storage.Create<PrimitiveLiteral>(TypedValue::Null), + storage.Create<ListLiteral>(std::vector<Expression *>())); + auto value = op->Accept(eval.eval); + EXPECT_FALSE(value.ValueBool()); + } } TEST(ExpressionEvaluator, ListMapIndexingOperator) {