Fix any function implementation

Summary: Change any function's handling of Null elements in a list

Reviewers: mferencevic

Reviewed By: mferencevic

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2787
This commit is contained in:
jseljan 2020-06-16 13:44:00 +02:00
parent 098333f735
commit 21cee1eaec
4 changed files with 111 additions and 4 deletions

View File

@ -534,6 +534,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
}
const auto &list = list_value.ValueList();
const auto &symbol = symbol_table_->at(*any.identifier_);
bool has_value = false;
for (const auto &element : list) {
frame_->at(symbol) = element;
auto result = any.where_->expression_->Accept(*this);
@ -542,11 +543,19 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
"Predicate of ANY must evaluate to boolean, got {}.",
result.type());
}
if (result.IsNull() || result.ValueBool()) {
return result;
if (!result.IsNull()) {
has_value = true;
if (result.ValueBool()) {
return TypedValue(true, ctx_->memory);
}
}
}
return TypedValue(false, ctx_->memory);
// Return Null if all elements are Null
if (!has_value) {
return TypedValue(ctx_->memory);
} else {
return TypedValue(false, ctx_->memory);
}
}
TypedValue Visit(ParameterLookup &param_lookup) override {

View File

@ -38,7 +38,7 @@ class UsedSymbolsCollector : public HierarchicalTreeVisitor {
}
bool PostVisit(Any &any) override {
// Remove the symbol which is bound by all, because we are only interested
// Remove the symbol which is bound by any, because we are only interested
// in free (unbound) symbols.
symbols_.erase(symbol_table_.at(*any.identifier_));
return true;

View File

@ -712,6 +712,80 @@ Feature: Functions
"""
Then an error should be raised
Scenario: Any test 01:
When executing query:
"""
RETURN any(x IN [1, 2, 3] WHERE x > 0) AS a
"""
Then the result should be:
| a |
| true |
Scenario: Any test 02:
When executing query:
"""
RETURN any(x IN [1, 2, 3] WHERE x = 0) AS a
"""
Then the result should be:
| a |
| false |
Scenario: Any test 03:
When executing query:
"""
RETURN any(x IN ["a", "b", "c"] WHERE x = 1) AS a
"""
Then the result should be:
| a |
| false |
Scenario: Any test 04:
When executing query:
"""
RETURN any(x IN [Null, Null, Null] WHERE x = 0) AS a
"""
Then the result should be:
| a |
| null |
Scenario: Any test 05:
When executing query:
"""
RETURN any(x IN [Null, Null, 0] WHERE x = 0) AS a
"""
Then the result should be:
| a |
| true |
Scenario: Any test 06:
When executing query:
"""
RETURN any(x IN [Null, Null, 0] WHERE x > 0) AS a
"""
Then the result should be:
| a |
| false |
Scenario: Any test 07:
When executing query:
"""
RETURN any(x IN [Null, Null, Null] WHERE x = Null) AS a
"""
Then the result should be:
| a |
| null |
Scenario: Any test 08:
When executing query:
"""
RETURN any(x IN ["a", "b", "c"] WHERE x = Null) AS a
"""
Then the result should be:
| a |
| null |
Scenario: Reduce test 01:
When executing query:
"""

View File

@ -804,6 +804,30 @@ TEST_F(ExpressionEvaluatorTest, FunctionAnyNullList) {
EXPECT_TRUE(value.IsNull());
}
TEST_F(ExpressionEvaluatorTest, FunctionAnyNullElementInList1) {
AstStorage storage;
auto *ident_x = IDENT("x");
auto *any = ANY("x", LIST(LITERAL(0), LITERAL(storage::PropertyValue())),
WHERE(EQ(ident_x, LITERAL(0))));
const auto x_sym = symbol_table.CreateSymbol("x", true);
any->identifier_->MapTo(x_sym);
ident_x->MapTo(x_sym);
auto value = Eval(any);
EXPECT_TRUE(value.ValueBool());
}
TEST_F(ExpressionEvaluatorTest, FunctionAnyNullElementInList2) {
AstStorage storage;
auto *ident_x = IDENT("x");
auto *any = ANY("x", LIST(LITERAL(1), LITERAL(storage::PropertyValue())),
WHERE(EQ(ident_x, LITERAL(0))));
const auto x_sym = symbol_table.CreateSymbol("x", true);
any->identifier_->MapTo(x_sym);
ident_x->MapTo(x_sym);
auto value = Eval(any);
EXPECT_FALSE(value.ValueBool());
}
TEST_F(ExpressionEvaluatorTest, FunctionAnyWhereWrongType) {
AstStorage storage;
auto *any = ANY("x", LIST(LITERAL(1)), WHERE(LITERAL(2)));