From 2512ad87c9787750448a05e0e985279a71c29884 Mon Sep 17 00:00:00 2001 From: Rafsun Masud Date: Tue, 28 Nov 2023 11:35:19 -0800 Subject: [PATCH] Fix issue #1398 - SET followed by DELETE does not delete (#1414) In the DELETE executor, tuples were being locked\deleted using the command ID returned by GetCurrentCommandId(). However, the original tuples were retrieved using a command ID stored in the estate. To fix it- before the retrieval of a tuple, estate command IDs are set using GetCurrentCommandId() so it matches if the tuple is to be deleted later. Additional changes: ------------------- Fixed an incorrect cypher_delete test. The query `MATCH (n1)-[e]->() DELETE n1, e RETURN n1` should be able to delete n1 and e without requiring DETACH DELETE. TODO: ----- It may be a good idea to audit the executors for any inconsistent use of command IDs. --- regress/expected/cypher_delete.out | 75 ++++++++++++++++++++++++++-- regress/sql/cypher_delete.sql | 19 +++++++ src/backend/executor/cypher_delete.c | 4 ++ 3 files changed, 95 insertions(+), 3 deletions(-) diff --git a/regress/expected/cypher_delete.out b/regress/expected/cypher_delete.out index 7ac07dfda..3cdbbf8bb 100644 --- a/regress/expected/cypher_delete.out +++ b/regress/expected/cypher_delete.out @@ -234,14 +234,17 @@ SELECT * FROM cypher('cypher_delete', $$CREATE (n:v)-[:e]->(:v)$$) AS (a agtype) (0 rows) SELECT * FROM cypher('cypher_delete', $$MATCH(n1)-[e]->() DELETE n1, e RETURN n1$$) AS (a agtype); -ERROR: Cannot delete a vertex that has edge(s). Delete the edge(s) first, or try DETACH DELETE. + a +----------------------------------------------------------------- + {"id": 844424930131990, "label": "v", "properties": {}}::vertex +(1 row) + --Cleanup SELECT * FROM cypher('cypher_delete', $$MATCH(n) DETACH DELETE n RETURN n$$) AS (a agtype); a ----------------------------------------------------------------- - {"id": 844424930131990, "label": "v", "properties": {}}::vertex {"id": 844424930131991, "label": "v", "properties": {}}::vertex -(2 rows) +(1 row) SELECT * FROM cypher('cypher_delete', $$MATCH(n) RETURN n$$) AS (a agtype); a @@ -758,6 +761,72 @@ NOTICE: graph "detach_delete" has been dropped (1 row) +-- +-- SET followed by DELETE +-- +SELECT create_graph('setdelete'); +NOTICE: graph "setdelete" has been created + create_graph +-------------- + +(1 row) + +-- MATCH (x) SET x DELETE x +SELECT * FROM cypher('setdelete', $$ CREATE (:A), (:A), (:A) $$) as ("CREATE" agtype); + CREATE +-------- +(0 rows) + +SELECT * FROM cypher('setdelete', $$ MATCH (x:A) SET x.age = 24 DELETE x $$) as ("SET + DELETE" agtype); + SET + DELETE +-------------- +(0 rows) + +SELECT id as "expected: 0 rows" FROM setdelete._ag_label_vertex; + expected: 0 rows +------------------ +(0 rows) + +-- MATCH (n)-[e]->(m) SET e DETACH DELETE n +SELECT * FROM cypher('setdelete', $$ CREATE (:n)-[:e]->(:m), (:n)-[:e]->(:m) $$) AS ("CREATE" agtype); + CREATE +-------- +(0 rows) + +SELECT * FROM cypher('setdelete', $$ MATCH (n)-[e]->(m) SET e.i = 1 DETACH DELETE n RETURN id(m) $$) AS ("SET + DETACH DELETE" agtype); + SET + DETACH DELETE +--------------------- + 1688849860263937 + 1688849860263938 +(2 rows) + +SELECT id as "expected: 2 rows (m vertices)" FROM setdelete._ag_label_vertex; + expected: 2 rows (m vertices) +------------------------------- + 1688849860263937 + 1688849860263938 +(2 rows) + +SELECT id as "expected: 0 rows" FROM setdelete._ag_label_edge; + expected: 0 rows +------------------ +(0 rows) + +-- clean up +SELECT drop_graph('setdelete', true); +NOTICE: drop cascades to 6 other objects +DETAIL: drop cascades to table setdelete._ag_label_vertex +drop cascades to table setdelete._ag_label_edge +drop cascades to table setdelete."A" +drop cascades to table setdelete.n +drop cascades to table setdelete.e +drop cascades to table setdelete.m +NOTICE: graph "setdelete" has been dropped + drop_graph +------------ + +(1 row) + -- -- Clean up -- diff --git a/regress/sql/cypher_delete.sql b/regress/sql/cypher_delete.sql index f0d98b6ec..4ddea60c2 100644 --- a/regress/sql/cypher_delete.sql +++ b/regress/sql/cypher_delete.sql @@ -283,6 +283,25 @@ SELECT * FROM cypher('detach_delete', $$ MATCH ()-[e]->() RETURN e.name $$) as ( SELECT drop_graph('detach_delete', true); +-- +-- SET followed by DELETE +-- +SELECT create_graph('setdelete'); + +-- MATCH (x) SET x DELETE x +SELECT * FROM cypher('setdelete', $$ CREATE (:A), (:A), (:A) $$) as ("CREATE" agtype); +SELECT * FROM cypher('setdelete', $$ MATCH (x:A) SET x.age = 24 DELETE x $$) as ("SET + DELETE" agtype); +SELECT id as "expected: 0 rows" FROM setdelete._ag_label_vertex; + +-- MATCH (n)-[e]->(m) SET e DETACH DELETE n +SELECT * FROM cypher('setdelete', $$ CREATE (:n)-[:e]->(:m), (:n)-[:e]->(:m) $$) AS ("CREATE" agtype); +SELECT * FROM cypher('setdelete', $$ MATCH (n)-[e]->(m) SET e.i = 1 DETACH DELETE n RETURN id(m) $$) AS ("SET + DETACH DELETE" agtype); +SELECT id as "expected: 2 rows (m vertices)" FROM setdelete._ag_label_vertex; +SELECT id as "expected: 0 rows" FROM setdelete._ag_label_edge; + +-- clean up +SELECT drop_graph('setdelete', true); + -- -- Clean up -- diff --git a/src/backend/executor/cypher_delete.c b/src/backend/executor/cypher_delete.c index 2ffc3b847..fcfa8b569 100644 --- a/src/backend/executor/cypher_delete.c +++ b/src/backend/executor/cypher_delete.c @@ -437,6 +437,8 @@ static void process_delete_list(CustomScanState *node) /* * Setup the scan description, with the correct snapshot and scan keys. */ + estate->es_snapshot->curcid = GetCurrentCommandId(false); + estate->es_output_cid = GetCurrentCommandId(false); scan_desc = table_beginscan(resultRelInfo->ri_RelationDesc, estate->es_snapshot, 1, scan_keys); @@ -501,6 +503,8 @@ static void check_for_connected_edges(CustomScanState *node) resultRelInfo = create_entity_result_rel_info(estate, graph_name, label_name); + estate->es_snapshot->curcid = GetCurrentCommandId(false); + estate->es_output_cid = GetCurrentCommandId(false); scan_desc = table_beginscan(resultRelInfo->ri_RelationDesc, estate->es_snapshot, 0, NULL); slot = ExecInitExtraTupleSlot(