Skip Null in SET and REMOVE clauses
Summary: openCypher expects removing/setting properties and labels on Null vertices/edges does not produce an error. Instead, Nulls are simply skipped. Reviewers: florijan, mislav.bradac, buda Reviewed By: mislav.bradac Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D375
This commit is contained in:
parent
8d8ef19694
commit
30a4f40093
@ -513,6 +513,9 @@ bool SetProperty::SetPropertyCursor::Pull(Frame &frame,
|
||||
case TypedValue::Type::Edge:
|
||||
lhs.Value<EdgeAccessor>().PropsSet(self_.lhs_->property_, rhs);
|
||||
break;
|
||||
case TypedValue::Type::Null:
|
||||
// Skip setting properties on Null (can occur in optional match).
|
||||
break;
|
||||
default:
|
||||
throw QueryRuntimeException(
|
||||
"Properties can only be set on Vertices and Edges");
|
||||
@ -553,6 +556,9 @@ bool SetProperties::SetPropertiesCursor::Pull(Frame &frame,
|
||||
case TypedValue::Type::Edge:
|
||||
Set(lhs.Value<EdgeAccessor>(), rhs);
|
||||
break;
|
||||
case TypedValue::Type::Null:
|
||||
// Skip setting properties on Null (can occur in optional match).
|
||||
break;
|
||||
default:
|
||||
throw QueryRuntimeException(
|
||||
"Properties can only be set on Vertices and Edges");
|
||||
@ -620,6 +626,9 @@ bool SetLabels::SetLabelsCursor::Pull(Frame &frame,
|
||||
if (!input_cursor_->Pull(frame, symbol_table)) return false;
|
||||
|
||||
TypedValue &vertex_value = frame[self_.input_symbol_];
|
||||
// Skip setting labels on Null (can occur in optional match).
|
||||
if (vertex_value.IsNull()) return true;
|
||||
|
||||
auto &vertex = vertex_value.Value<VertexAccessor>();
|
||||
vertex.SwitchNew();
|
||||
for (auto label : self_.labels_) vertex.add_label(label);
|
||||
@ -658,6 +667,9 @@ bool RemoveProperty::RemovePropertyCursor::Pull(
|
||||
case TypedValue::Type::Edge:
|
||||
lhs.Value<EdgeAccessor>().PropsErase(self_.lhs_->property_);
|
||||
break;
|
||||
case TypedValue::Type::Null:
|
||||
// Skip removing properties on Null (can occur in optional match).
|
||||
break;
|
||||
default:
|
||||
// TODO consider throwing a TypedValueException here
|
||||
// deal with this when we'll be overhauling error-feedback
|
||||
@ -689,6 +701,9 @@ bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame,
|
||||
if (!input_cursor_->Pull(frame, symbol_table)) return false;
|
||||
|
||||
TypedValue &vertex_value = frame[self_.input_symbol_];
|
||||
// Skip removing labels on Null (can occur in optional match).
|
||||
if (vertex_value.IsNull()) return true;
|
||||
|
||||
auto &vertex = vertex_value.Value<VertexAccessor>();
|
||||
vertex.SwitchNew();
|
||||
for (auto label : self_.labels_) vertex.remove_label(label);
|
||||
|
@ -854,3 +854,85 @@ TEST(QueryPlan, MergeNoInput) {
|
||||
dba->advance_command();
|
||||
EXPECT_EQ(1, CountIterable(dba->vertices()));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, SetPropertyOnNull) {
|
||||
// SET (Null).prop = 42
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto prop = dba->property("prop");
|
||||
auto null = LITERAL(TypedValue::Null);
|
||||
auto literal = LITERAL(42);
|
||||
auto n_prop = storage.Create<PropertyLookup>(null, prop);
|
||||
auto once = std::make_shared<Once>();
|
||||
auto set_op = std::make_shared<plan::SetProperty>(once, n_prop, literal);
|
||||
EXPECT_EQ(1, PullAll(set_op, *dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, SetPropertiesOnNull) {
|
||||
// OPTIONAL MATCH (n) SET n = n
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
auto n_ident = IDENT("n");
|
||||
symbol_table[*n_ident] = n.sym_;
|
||||
auto optional = std::make_shared<plan::Optional>(nullptr, n.op_,
|
||||
std::vector<Symbol>{n.sym_});
|
||||
auto set_op = std::make_shared<plan::SetProperties>(
|
||||
optional, n.sym_, n_ident, plan::SetProperties::Op::REPLACE);
|
||||
EXPECT_EQ(0, CountIterable(dba->vertices()));
|
||||
EXPECT_EQ(1, PullAll(set_op, *dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, SetLabelsOnNull) {
|
||||
// OPTIONAL MATCH (n) SET n :label
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->label("label");
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
auto n_ident = IDENT("n");
|
||||
symbol_table[*n_ident] = n.sym_;
|
||||
auto optional = std::make_shared<plan::Optional>(nullptr, n.op_,
|
||||
std::vector<Symbol>{n.sym_});
|
||||
auto set_op = std::make_shared<plan::SetLabels>(
|
||||
optional, n.sym_, std::vector<GraphDbTypes::Label>{label});
|
||||
EXPECT_EQ(0, CountIterable(dba->vertices()));
|
||||
EXPECT_EQ(1, PullAll(set_op, *dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, RemovePropertyOnNull) {
|
||||
// REMOVE (Null).prop
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto prop = dba->property("prop");
|
||||
auto null = LITERAL(TypedValue::Null);
|
||||
auto n_prop = storage.Create<PropertyLookup>(null, prop);
|
||||
auto once = std::make_shared<Once>();
|
||||
auto remove_op = std::make_shared<plan::RemoveProperty>(once, n_prop);
|
||||
EXPECT_EQ(1, PullAll(remove_op, *dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, RemoveLabelsOnNull) {
|
||||
// OPTIONAL MATCH (n) REMOVE n :label
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->label("label");
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
auto n_ident = IDENT("n");
|
||||
symbol_table[*n_ident] = n.sym_;
|
||||
auto optional = std::make_shared<plan::Optional>(nullptr, n.op_,
|
||||
std::vector<Symbol>{n.sym_});
|
||||
auto remove_op = std::make_shared<plan::RemoveLabels>(
|
||||
optional, n.sym_, std::vector<GraphDbTypes::Label>{label});
|
||||
EXPECT_EQ(0, CountIterable(dba->vertices()));
|
||||
EXPECT_EQ(1, PullAll(remove_op, *dba, symbol_table));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user