From 28fbeb8e9dc4606ba07926dd48d1a6551a5cabfa Mon Sep 17 00:00:00 2001 From: Teon Banek Date: Fri, 19 May 2017 16:01:01 +0200 Subject: [PATCH] Raise if MATCH is after OPTIONAL MATCH Reviewers: florijan, mislav.bradac Reviewed By: mislav.bradac Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D383 --- src/query/frontend/ast/cypher_main_visitor.cpp | 14 ++++++++++++-- tests/unit/cypher_main_visitor.cpp | 6 ++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp index f5ab0c273..00b801dc7 100644 --- a/src/query/frontend/ast/cypher_main_visitor.cpp +++ b/src/query/frontend/ast/cypher_main_visitor.cpp @@ -41,11 +41,21 @@ antlrcpp::Any CypherMainVisitor::visitSingleQuery( // consecutive SET clauses are undefined behaviour in neo4j. bool has_update = false; bool has_return = false; + bool has_optional_match = false; for (Clause *clause : query_->clauses_) { - if (dynamic_cast(clause) || dynamic_cast(clause)) { + if (dynamic_cast(clause)) { + if (has_update || has_return) { + throw SemanticException("Unwind can't be after return or update clause"); + } + } else if (auto *match = dynamic_cast(clause)) { if (has_update || has_return) { throw SemanticException("Match can't be after return or update clause"); } + if (match->optional_) { + has_optional_match = true; + } else if (has_optional_match) { + throw SemanticException("Match can't be after optional match"); + } } else if (dynamic_cast(clause) || dynamic_cast(clause) || dynamic_cast(clause) || @@ -67,7 +77,7 @@ antlrcpp::Any CypherMainVisitor::visitSingleQuery( if (has_return) { throw SemanticException("Return can't be before with"); } - has_update = has_return = false; + has_update = has_return = has_optional_match = false; } else { debug_assert(false, "Can't happen"); } diff --git a/tests/unit/cypher_main_visitor.cpp b/tests/unit/cypher_main_visitor.cpp index 733832614..f58332dbe 100644 --- a/tests/unit/cypher_main_visitor.cpp +++ b/tests/unit/cypher_main_visitor.cpp @@ -1095,6 +1095,12 @@ TEST(CypherMainVisitorTest, ClausesOrdering) { ASSERT_THROW(AstGenerator("RETURN 1 AS n UNWIND n AS x RETURN x"), SemanticException); + ASSERT_THROW(AstGenerator("OPTIONAL MATCH (n) MATCH (m) RETURN n, m"), + SemanticException); + AstGenerator("OPTIONAL MATCH (n) WITH n MATCH (m) RETURN n, m"); + AstGenerator("OPTIONAL MATCH (n) OPTIONAL MATCH (m) RETURN n, m"); + AstGenerator("MATCH (n) OPTIONAL MATCH (m) RETURN n, m"); + AstGenerator("CREATE (n)"); ASSERT_THROW(AstGenerator("SET n:x MATCH (n) RETURN n"), SemanticException); AstGenerator("REMOVE n.x SET n.x = 1");