Query::Plan::Produce - added support for Produce without input

Reviewers: teon.banek, buda

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D189
This commit is contained in:
florijan 2017-03-27 15:31:58 +02:00
parent 34cdbc2f39
commit d387651205
3 changed files with 53 additions and 15 deletions

View File

@ -668,6 +668,17 @@ class Filter : public LogicalOperator {
Expression *expression_;
};
/**
* A logical operator that places an arbitrary number
* if named expressions on the frame (the logical operator
* for the RETURN clause).
*
* Supports optional input. When the input is provided,
* it is Pulled from and the Produce succeds once for
* every input Pull (typically a MATCH/RETURN query).
* When the input is not provided (typically a standalone
* RETURN clause) the Produce's pull succeeds exactly once.
*/
class Produce : public LogicalOperator {
public:
Produce(std::shared_ptr<LogicalOperator> input,
@ -678,7 +689,7 @@ class Produce : public LogicalOperator {
void Accept(LogicalOperatorVisitor &visitor) override {
visitor.Visit(*this);
input_->Accept(visitor);
if (input_) input_->Accept(visitor);
visitor.PostVisit(*this);
}
@ -692,21 +703,32 @@ class Produce : public LogicalOperator {
class ProduceCursor : public Cursor {
public:
ProduceCursor(Produce &self, GraphDbAccessor &db)
: self_(self), input_cursor_(self_.input_->MakeCursor(db)) {}
: self_(self),
input_cursor_(self.input_ ? self_.input_->MakeCursor(db) : nullptr) {}
bool Pull(Frame &frame, SymbolTable &symbol_table) override {
ExpressionEvaluator evaluator(frame, symbol_table);
if (input_cursor_->Pull(frame, symbol_table)) {
for (auto named_expr : self_.named_expressions_) {
named_expr->Accept(evaluator);
if (input_cursor_) {
if (input_cursor_->Pull(frame, symbol_table)) {
for (auto named_expr : self_.named_expressions_)
named_expr->Accept(evaluator);
return true;
}
return false;
} else if (!did_produce_) {
for (auto named_expr : self_.named_expressions_)
named_expr->Accept(evaluator);
did_produce_ = true;
return true;
}
return false;
} else
return false;
}
private:
Produce &self_;
// optional, see class documentation
std::unique_ptr<Cursor> input_cursor_;
// control switch when creating only one node (nullptr input)
bool did_produce_{false};
};
private:
@ -787,7 +809,5 @@ class Delete : public LogicalOperator {
// ignored when deleting edges
bool detach_;
};
} // namespace plan
} // namespace query
} // namespace plan
} // namespace query

View File

@ -156,10 +156,6 @@ auto GenMatch(Match &match, LogicalOperator *input_op,
}
auto GenReturn(Return &ret, LogicalOperator *input_op) {
if (!input_op) {
// TODO: Support standalone RETURN clause (e.g. RETURN 2)
throw NotYetImplemented();
}
return new Produce(std::shared_ptr<LogicalOperator>(input_op),
ret.named_expressions_);
}

View File

@ -143,6 +143,28 @@ TEST(Interpreter, MatchReturn) {
EXPECT_EQ(result.GetResults().size(), 2);
}
TEST(Interpreter, StandaloneReturn) {
Dbms dbms;
auto dba = dbms.active();
// add a few nodes to the database
dba->insert_vertex();
dba->insert_vertex();
dba->advance_command();
AstTreeStorage storage;
SymbolTable symbol_table;
auto output = NEXPR("n", LITERAL(42));
auto produce = MakeProduce(std::shared_ptr<LogicalOperator>(nullptr), output);
symbol_table[*output] = symbol_table.CreateSymbol("named_expression_1");
ResultStreamFaker result = CollectProduce(produce, symbol_table, *dba);
EXPECT_EQ(result.GetResults().size(), 1);
EXPECT_EQ(result.GetResults()[0].size(), 1);
EXPECT_EQ(result.GetResults()[0][0].Value<int64_t>(), 42);
}
TEST(Interpreter, NodeFilterLabelsAndProperties) {
Dbms dbms;
auto dba = dbms.active();