Plan set operations

Summary:
Inline and remove GenProduce.
It doesn't do anything useful, so instantiating `Produce` can be done
inline.

Add dummy MakeCursor overrides for set operators so that the build passes.

Reviewers: florijan, mislav.bradac

Reviewed By: mislav.bradac

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D193
This commit is contained in:
Teon Banek 2017-03-28 11:04:28 +02:00
parent e40bd83636
commit 68e94e64e4
5 changed files with 89 additions and 8 deletions

View File

@ -579,6 +579,10 @@ class SetProperty : public Clause {
protected:
SetProperty(int uid) : Clause(uid) {}
SetProperty(int uid, PropertyLookup *property_lookup, Expression *expression)
: Clause(uid),
property_lookup_(property_lookup),
expression_(expression) {}
};
class SetProperties : public Clause {
@ -597,6 +601,12 @@ class SetProperties : public Clause {
protected:
SetProperties(int uid) : Clause(uid) {}
SetProperties(int uid, Identifier *identifier, Expression *expression,
bool update = false)
: Clause(uid),
identifier_(identifier),
expression_(expression),
update_(update) {}
};
class SetLabels : public Clause {
@ -613,6 +623,9 @@ class SetLabels : public Clause {
protected:
SetLabels(int uid) : Clause(uid) {}
SetLabels(int uid, Identifier *identifier,
const std::vector<GraphDb::Label> &labels)
: Clause(uid), identifier_(identifier), labels_(labels) {}
};
// It would be better to call this AstTree, but we already have a class Tree,

View File

@ -820,6 +820,11 @@ class SetProperty : public LogicalOperator {
Expression *rhs)
: input_(input), lhs_(lhs), rhs_(rhs) {}
std::unique_ptr<Cursor> MakeCursor(GraphDbAccessor &db) override {
return nullptr;
}
void Accept(LogicalOperatorVisitor &visitor) override {
visitor.Visit(*this);
input_->Accept(visitor);
@ -847,6 +852,10 @@ class SetProperties : public LogicalOperator {
const Symbol input_symbol, Expression *rhs, Op op)
: input_(input), input_symbol_(input_symbol), rhs_(rhs), op_(op) {}
std::unique_ptr<Cursor> MakeCursor(GraphDbAccessor &db) override {
return nullptr;
}
void Accept(LogicalOperatorVisitor &visitor) override {
visitor.Visit(*this);
input_->Accept(visitor);
@ -867,6 +876,10 @@ class SetLabels : public LogicalOperator {
const std::vector<GraphDb::Label> &labels)
: input_(input), input_symbol_(input_symbol), labels_(labels) {}
std::unique_ptr<Cursor> MakeCursor(GraphDbAccessor &db) override {
return nullptr;
}
void Accept(LogicalOperatorVisitor &visitor) override {
visitor.Visit(*this);
input_->Accept(visitor);

View File

@ -71,7 +71,7 @@ auto GenCreateForPattern(Pattern &pattern, LogicalOperator *input_op,
auto collect = [&](LogicalOperator *last_op, NodeAtom *prev_node,
EdgeAtom *edge, NodeAtom *node) {
// Store the symbol from the first node as the input to CreateExpand.
auto input_symbol = symbol_table.at(*prev_node->identifier_);
const auto &input_symbol = symbol_table.at(*prev_node->identifier_);
// If the expand node was already bound, then we need to indicate this,
// so that CreateExpand only creates an edge.
bool node_existing = false;
@ -123,7 +123,7 @@ auto GenMatch(Match &match, LogicalOperator *input_op,
auto collect = [&](LogicalOperator *last_op, NodeAtom *prev_node,
EdgeAtom *edge, NodeAtom *node) {
// Store the symbol from the first node as the input to Expand.
auto input_symbol = symbol_table.at(*prev_node->identifier_);
const auto &input_symbol = symbol_table.at(*prev_node->identifier_);
// If the expand symbols were already bound, then we need to indicate
// this as a cycle. The Expand will then check whether the pattern holds
// instead of writing the expansion to symbols.
@ -161,11 +161,6 @@ auto GenMatch(Match &match, LogicalOperator *input_op,
return last_op;
}
auto GenReturn(Return &ret, LogicalOperator *input_op) {
return new Produce(std::shared_ptr<LogicalOperator>(input_op),
ret.named_expressions_);
}
} // namespace
std::unique_ptr<LogicalOperator> MakeLogicalPlan(
@ -183,12 +178,28 @@ std::unique_ptr<LogicalOperator> MakeLogicalPlan(
if (auto *match = dynamic_cast<Match *>(clause_ptr)) {
input_op = GenMatch(*match, input_op, symbol_table, bound_symbols);
} else if (auto *ret = dynamic_cast<Return *>(clause_ptr)) {
input_op = GenReturn(*ret, input_op);
input_op = new Produce(std::shared_ptr<LogicalOperator>(input_op),
ret->named_expressions_);
} else if (auto *create = dynamic_cast<Create *>(clause_ptr)) {
input_op = GenCreate(*create, input_op, symbol_table, bound_symbols);
} else if (auto *del = dynamic_cast<query::Delete *>(clause_ptr)) {
input_op = new plan::Delete(std::shared_ptr<LogicalOperator>(input_op),
del->expressions_, del->detach_);
} else if (auto *set = dynamic_cast<query::SetProperty *>(clause_ptr)) {
input_op =
new plan::SetProperty(std::shared_ptr<LogicalOperator>(input_op),
set->property_lookup_, set->expression_);
} else if (auto *set = dynamic_cast<query::SetProperties *>(clause_ptr)) {
auto op = set->update_ ? plan::SetProperties::Op::UPDATE
: plan::SetProperties::Op::REPLACE;
const auto &input_symbol = symbol_table.at(*set->identifier_);
input_op =
new plan::SetProperties(std::shared_ptr<LogicalOperator>(input_op),
input_symbol, set->expression_, op);
} else if (auto *set = dynamic_cast<query::SetLabels *>(clause_ptr)) {
const auto &input_symbol = symbol_table.at(*set->identifier_);
input_op = new plan::SetLabels(std::shared_ptr<LogicalOperator>(input_op),
input_symbol, set->labels_);
} else {
throw NotYetImplemented();
}

View File

@ -102,6 +102,33 @@ auto GetDelete(AstTreeStorage &storage, std::vector<Expression *> exprs,
return del;
}
///
/// Create a set property clause for given property lookup and the right hand
/// side expression.
///
auto GetSet(AstTreeStorage &storage, PropertyLookup *prop_lookup,
Expression *expr) {
return storage.Create<SetProperty>(prop_lookup, expr);
}
///
/// Create a set properties clause for given identifier name and the right hand
/// side expression.
///
auto GetSet(AstTreeStorage &storage, const std::string &name, Expression *expr,
bool update = false) {
return storage.Create<SetProperties>(storage.Create<Identifier>(name), expr,
update);
}
///
/// Create a set labels clause for given identifier name and labels.
///
auto GetSet(AstTreeStorage &storage, const std::string &name,
std::vector<GraphDb::Label> labels) {
return storage.Create<SetLabels>(storage.Create<Identifier>(name), labels);
}
} // namespace test_common
} // namespace query
@ -135,5 +162,6 @@ auto GetDelete(AstTreeStorage &storage, std::vector<Expression *> exprs,
#define DELETE(...) query::test_common::GetDelete(storage, {__VA_ARGS__})
#define DETACH_DELETE(...) \
query::test_common::GetDelete(storage, {__VA_ARGS__}, true)
#define SET(...) query::test_common::GetSet(storage, __VA_ARGS__)
#define QUERY(...) query::test_common::GetQuery(storage, {__VA_ARGS__})
#define LESS(expr1, expr2) storage.Create<query::LessOperator>((expr1), (expr2))

View File

@ -35,6 +35,9 @@ class PlanChecker : public LogicalOperatorVisitor {
void Visit(EdgeFilter &op) override { AssertType(op); }
void Visit(Filter &op) override { AssertType(op); }
void Visit(Produce &op) override { AssertType(op); }
void Visit(SetProperty &op) override { AssertType(op); }
void Visit(SetProperties &op) override { AssertType(op); }
void Visit(SetLabels &op) override { AssertType(op); }
private:
void AssertType(const LogicalOperator &op) {
@ -153,4 +156,17 @@ TEST(TestLogicalPlanner, MatchDelete) {
CheckPlan(*query, {typeid(ScanAll).hash_code(), typeid(Delete).hash_code()});
}
TEST(TestLogicalPlanner, MatchNodeSet) {
// Test MATCH (n) SET n.prop = 42, n = n, n :label
AstTreeStorage storage;
std::string prop("prop");
std::string label("label");
auto query = QUERY(MATCH(PATTERN(NODE("n"))),
SET(PROPERTY_LOOKUP("n", &prop), LITERAL(42)),
SET("n", IDENT("n")), SET("n", {&label}));
CheckPlan(*query,
{typeid(ScanAll).hash_code(), typeid(SetProperty).hash_code(),
typeid(SetProperties).hash_code(), typeid(SetLabels).hash_code()});
}
}