From d3838a1095ef00564316aaaa2d4f370c1e8e3947 Mon Sep 17 00:00:00 2001
From: Andreja Tonev <andreja.tonev@memgraph.io>
Date: Mon, 4 Mar 2024 16:57:39 +0100
Subject: [PATCH] Allow query with a write subquery to omit RETURN

---
 src/query/frontend/ast/ast.hpp                      |  2 ++
 src/query/frontend/ast/cypher_main_visitor.cpp      | 13 +++++++++++++
 .../tests/memgraph_V1/features/create.feature       | 12 ++++++++++++
 3 files changed, 27 insertions(+)

diff --git a/src/query/frontend/ast/ast.hpp b/src/query/frontend/ast/ast.hpp
index ad3cdb7c5..6b67edaf0 100644
--- a/src/query/frontend/ast/ast.hpp
+++ b/src/query/frontend/ast/ast.hpp
@@ -2004,6 +2004,7 @@ class SingleQuery : public memgraph::query::Tree, public utils::Visitable<Hierar
   }
 
   std::vector<memgraph::query::Clause *> clauses_;
+  bool has_update{};
 
   SingleQuery *Clone(AstStorage *storage) const override {
     SingleQuery *object = storage->Create<SingleQuery>();
@@ -2011,6 +2012,7 @@ class SingleQuery : public memgraph::query::Tree, public utils::Visitable<Hierar
     for (auto i4 = 0; i4 < clauses_.size(); ++i4) {
       object->clauses_[i4] = clauses_[i4] ? clauses_[i4]->Clone(storage) : nullptr;
     }
+    object->has_update = has_update;
     return object;
   }
 
diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp
index d3747bc3f..98fe8a09a 100644
--- a/src/query/frontend/ast/cypher_main_visitor.cpp
+++ b/src/query/frontend/ast/cypher_main_visitor.cpp
@@ -1150,6 +1150,17 @@ antlrcpp::Any CypherMainVisitor::visitSingleQuery(MemgraphCypher::SingleQueryCon
       if (has_return) {
         throw SemanticException("CALL can't be put after RETURN clause.");
       }
+      const auto *single_query = call_subquery->cypher_query_->single_query_;
+      if (single_query) {
+        has_update |= single_query->has_update;
+        for (auto *cypher_union : call_subquery->cypher_query_->cypher_unions_) {
+          if (has_update) break;
+          const auto *single_query = cypher_union->single_query_;
+          if (single_query) {
+            has_update |= single_query->has_update;
+          }
+        }
+      }
     } else if (utils::IsSubtype(clause_type, Unwind::kType)) {
       check_write_procedure("UNWIND");
       if (has_update || has_return) {
@@ -1220,6 +1231,8 @@ antlrcpp::Any CypherMainVisitor::visitSingleQuery(MemgraphCypher::SingleQueryCon
       }
     }
   }
+
+  single_query->has_update = has_update;
   return single_query;
 }
 
diff --git a/tests/gql_behave/tests/memgraph_V1/features/create.feature b/tests/gql_behave/tests/memgraph_V1/features/create.feature
index 0bdb159f4..0143786ed 100644
--- a/tests/gql_behave/tests/memgraph_V1/features/create.feature
+++ b/tests/gql_behave/tests/memgraph_V1/features/create.feature
@@ -175,3 +175,15 @@ Feature: Create
             CREATE (a:A) CREATE (a:B)
             """
         Then an error should be raised
+
+    Scenario: CREATE via CALL:
+        When executing query:
+            """
+            UNWIND range(1,10) as id
+            CALL {
+                WITH id
+                CREATE (b:B {prop: 1})
+                CREATE (b)-[:IN]->(z)
+            };
+            """
+        Then the result should be empty