Fix returning NULL on map projection from a null value (#1119)

This commit is contained in:
Ante Pušić 2023-09-09 12:43:25 +02:00 committed by GitHub
parent 9e4babcdbb
commit 0403b67073
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 31 additions and 6 deletions

View File

@ -1105,6 +1105,8 @@ class MapProjectionLiteral : public memgraph::query::BaseLiteral {
DEFVISITABLE(ExpressionVisitor<void>);
bool Accept(HierarchicalTreeVisitor &visitor) override {
if (visitor.PreVisit(*this)) {
map_variable_->Accept(visitor);
for (auto pair : elements_) {
if (!pair.second) continue;

View File

@ -763,20 +763,27 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
TypedValue::TMap result(ctx_->memory);
TypedValue::TMap all_properties_lookup(ctx_->memory);
auto map_variable = literal.map_variable_->Accept(*this);
if (map_variable.IsNull()) {
return TypedValue(ctx_->memory);
}
for (const auto &[property_key, property_value] : literal.elements_) {
if (property_key.name == kAllPropertiesSelector.data()) {
auto maybe_all_properties_lookup = property_value->Accept(*this);
if (maybe_all_properties_lookup.type() != TypedValue::Type::Map) {
throw QueryRuntimeException("Expected a map from AllPropertiesLookup, got {}.",
maybe_all_properties_lookup.type());
LOG_FATAL("Expected a map from AllPropertiesLookup, got {}.", maybe_all_properties_lookup.type());
}
all_properties_lookup = std::move(maybe_all_properties_lookup.ValueMap());
continue;
}
result.emplace(property_key.name, property_value->Accept(*this));
}
if (!all_properties_lookup.empty()) result.merge(all_properties_lookup);
return TypedValue(result, ctx_->memory);

View File

@ -98,6 +98,11 @@ class ReturnBodyContext : public HierarchicalTreeVisitor {
auto it = has_aggregation_.end();
auto elements_it = literal.elements_.begin();
std::advance(it, -literal.elements_.size());
if (literal.GetTypeInfo() == MapProjectionLiteral::kType) {
// Erase the map variable. Grammar-wise, its a variable and thus never has aggregations.
std::advance(it, -1);
it = has_aggregation_.erase(it);
}
while (it != has_aggregation_.end()) {
if (*it) {
has_aggr = true;
@ -446,9 +451,9 @@ class ReturnBodyContext : public HierarchicalTreeVisitor {
std::vector<Expression *> group_by_;
std::unordered_set<Symbol> group_by_used_symbols_;
// Flag stack indicating whether an expression contains an aggregation. A
// stack is needed so that we differentiate the case where a child
// sub-expression has an aggregation, while the other child doesn't. For
// example AST, (+ (sum x) y)
// stack is needed to address the case where one child sub-expression has
// an aggregation, while the other child does not.
// For example, the AST (+ (sum x) y) is as follows:
// * (sum x) -- Has an aggregation.
// * y -- Doesn't, we need to group by this.
// * (+ (sum x) y) -- The whole expression has an aggregation, so we don't

View File

@ -4,7 +4,7 @@ Feature: Map projection
When executing query:
"""
WITH {} AS map
RETURN map {} as result
RETURN map {} AS result
"""
Then the result should be:
| result |
@ -26,6 +26,17 @@ Feature: Map projection
| result |
| {age: 85, lastName: 'Freeman', name: 'Morgan', oscars: 1} |
Scenario: Projecting from a null value
When executing query:
"""
WITH "value" AS var
OPTIONAL MATCH (n:Nonexistent)
RETURN n {.*} AS result0, n {.prop} AS result1, n {prop: "value"} AS result2, n {var} AS result3;
"""
Then the result should be:
| result0 | result1 | result2 | result3 |
| null | null | null | null |
Scenario: Projecting a nonexistent property
When executing query:
"""