Skip to content

Commit

Permalink
fix: Remove cypher read clause restriction. (#601)
Browse files Browse the repository at this point in the history
(cherry picked from commit 21d37de)
  • Loading branch information
emotionbug committed Dec 19, 2022
1 parent c6e0e05 commit f1bdb55
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 81 deletions.
15 changes: 13 additions & 2 deletions src/backend/executor/nodeModifyGraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,19 @@ ExecModifyGraph(PlanState *pstate)

/* pass lower bound CID to subplan */
svCid = estate->es_snapshot->curcid;
estate->es_snapshot->curcid =
mgstate->modify_cid + MODIFY_CID_LOWER_BOUND;

switch (plan->operation)
{
case GWROP_MERGE:
case GWROP_DELETE:
estate->es_snapshot->curcid =
mgstate->modify_cid + MODIFY_CID_NLJOIN_MATCH;
break;
default:
estate->es_snapshot->curcid =
mgstate->modify_cid + MODIFY_CID_LOWER_BOUND;
break;
}

slot = ExecProcNode(mgstate->subplan);

Expand Down
31 changes: 0 additions & 31 deletions src/backend/executor/nodeNestloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@ ExecNestLoop(PlanState *pstate)

for (;;)
{
CommandId svCid = InvalidCommandId;

/*
* If we don't have an outer tuple, get the next one and reset the
* inner scan.
Expand Down Expand Up @@ -170,19 +168,9 @@ ExecNestLoop(PlanState *pstate)
*/
ENL1_printf("getting new inner tuple");

if (node->js.jointype == JOIN_CYPHER_MERGE ||
node->js.jointype == JOIN_CYPHER_DELETE)
{
svCid = innerPlan->state->es_snapshot->curcid;
innerPlan->state->es_snapshot->curcid = node->nl_graphwrite_cid;
}

innerTupleSlot = ExecProcNode(innerPlan);
econtext->ecxt_innertuple = innerTupleSlot;

if (svCid != InvalidCommandId)
innerPlan->state->es_snapshot->curcid = svCid;

if (TupIsNull(innerTupleSlot))
{
ENL1_printf("no inner tuple, need new outer tuple");
Expand Down Expand Up @@ -288,7 +276,6 @@ NestLoopState *
ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
{
NestLoopState *nlstate;
CommandId svCid = InvalidCommandId;

/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
Expand Down Expand Up @@ -325,26 +312,8 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
eflags |= EXEC_FLAG_REWIND;
else
eflags &= ~EXEC_FLAG_REWIND;

if (node->join.jointype == JOIN_CYPHER_MERGE ||
node->join.jointype == JOIN_CYPHER_DELETE)
{
/*
* Modify the CID to see the graph pattern created by MERGE CREATE
* or to not see it deleted by DELETE.
*/
nlstate->nl_graphwrite_cid =
estate->es_snapshot->curcid + MODIFY_CID_NLJOIN_MATCH;

svCid = estate->es_snapshot->curcid;
estate->es_snapshot->curcid = nlstate->nl_graphwrite_cid;
}

innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags);

if (svCid != InvalidCommandId)
estate->es_snapshot->curcid = svCid;

/*
* Initialize result slot, type and projection.
*/
Expand Down
53 changes: 7 additions & 46 deletions src/backend/parser/analyze.c
Original file line number Diff line number Diff line change
Expand Up @@ -3038,8 +3038,6 @@ transformCypherStmt(ParseState *pstate, CypherStmt *stmt)
CypherClause *clause;
NodeTag type;
bool valid = true;
NodeTag update_type = T_Invalid;
bool read = false;

clause = (CypherClause *) stmt->last;
type = cypherClauseTag(clause);
Expand All @@ -3053,7 +3051,6 @@ transformCypherStmt(ParseState *pstate, CypherStmt *stmt)
case T_CypherDeleteClause:
case T_CypherSetClause:
case T_CypherMergeClause:
update_type = type;
break;
default:
valid = false;
Expand All @@ -3072,7 +3069,13 @@ transformCypherStmt(ParseState *pstate, CypherStmt *stmt)
switch (type)
{
case T_CypherMatchClause:
read = true;
case T_CypherCreateClause:
case T_CypherDeleteClause:
case T_CypherSetClause:
case T_CypherMergeClause:
case T_CypherLoadClause:
case T_CypherUnwindClause:
/* do nothing. */
break;
case T_CypherProjection:
if (cypherProjectionKind(clause->detail) == CP_RETURN)
Expand All @@ -3081,48 +3084,6 @@ transformCypherStmt(ParseState *pstate, CypherStmt *stmt)
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("RETURN must be at the end of the query")));
}
else
{
/* CP_WITH */
if (update_type != T_Invalid &&
update_type != T_CypherCreateClause)
read = true;
}
break;
case T_CypherCreateClause:
if (update_type == T_Invalid ||
update_type == T_CypherMergeClause)
{
update_type = T_CypherCreateClause;
}
if (read)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("Cypher read clauses cannot follow update clauses")));
break;
case T_CypherDeleteClause:
case T_CypherSetClause:
if (read)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("Cypher read clauses cannot follow update clauses")));
break;
case T_CypherMergeClause:
if (update_type == T_Invalid ||
update_type == T_CypherCreateClause)
{
update_type = T_CypherMergeClause;
}
if (read)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("Cypher read clauses cannot follow update clauses")));
break;
case T_CypherLoadClause:
read = true;
break;
case T_CypherUnwindClause:
read = true;
break;
default:
elog(ERROR, "unrecognized Cypher clause type: %d", type);
Expand Down
5 changes: 4 additions & 1 deletion src/test/regress/expected/cypher_dml.out
Original file line number Diff line number Diff line change
Expand Up @@ -2839,7 +2839,10 @@ MATCH (a) DETACH DELETE a;
-- wrong case
MERGE (a:v1) MERGE (b:v2 {name: a.notexistent});
MERGE (a:v1) MATCH (b:v2 {name: a.name}) RETURN a, b;
ERROR: Cypher read clauses cannot follow update clauses
a | b
---+---
(0 rows)

MERGE (a:v1) MERGE (b:v2 {name: a.name}) MERGE (a);
ERROR: duplicate variable "a"
LINE 1: MERGE (a:v1) MERGE (b:v2 {name: a.name}) MERGE (a);
Expand Down
45 changes: 45 additions & 0 deletions src/test/regress/expected/cypher_dml2.out
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,51 @@ drop cascades to vlabel v_type
drop cascades to vlabel v_sub
drop cascades to elabel e_user_title
drop cascades to elabel e_title_type
-- #589 ( Cypher read clauses cannot follow update clauses )
CREATE GRAPH cypher_dml2;
SET GRAPH_PATH to cypher_dml2;
CREATE VLABEL main;
CREATE ELABEL main2;
CREATE (n:another {id: 593}) RETURN n.id;
id
-----
593
(1 row)

MERGE (n:main {id: 593})
ON CREATE SET n.id = 593
WITH n
MATCH (g: another)
WHERE g.id = 593
MERGE (g)-[:main2]->(n);
MATCH ()-[e:main2]-() RETURN e;
e
-----------------------
main2[4.1][5.1,3.1]{}
main2[4.1][5.1,3.1]{}
(2 rows)

MATCH (g: another) RETURN g;
g
-------------------------
another[5.1]{"id": 593}
(1 row)

MATCH (g: main) RETURN g;
g
----------------------
main[3.1]{"id": 593}
(1 row)

DROP GRAPH cypher_dml2 CASCADE;
NOTICE: drop cascades to 6 other objects
DETAIL: drop cascades to sequence cypher_dml2.ag_label_seq
drop cascades to vlabel ag_vertex
drop cascades to elabel ag_edge
drop cascades to vlabel main
drop cascades to elabel main2
drop cascades to vlabel another
-- fix: Includes necessary JOINs of vertices (#599)
CREATE GRAPH cypher_dml2;
SET GRAPH_PATH to cypher_dml2;
CREATE ({id: 1})-[:e1]->({id: 2})-[:e1]->({id: 3})-[:e1]->({id: 4})
Expand Down
5 changes: 4 additions & 1 deletion src/test/regress/expected/cypher_eager.out
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,10 @@ MATCH (a) RETURN properties(a);
-- wrong case
MERGE (a:v1) MERGE (b:v2 {name: a.notexistent});
MERGE (a:v1) MATCH (b:v2 {name: a.name}) RETURN a, b;
ERROR: Cypher read clauses cannot follow update clauses
a | b
---+---
(0 rows)

MERGE (a:v1) MERGE (b:v2 {name: a.name}) MERGE (a);
ERROR: duplicate variable "a"
LINE 1: MERGE (a:v1) MERGE (b:v2 {name: a.name}) MERGE (a);
Expand Down
23 changes: 23 additions & 0 deletions src/test/regress/sql/cypher_dml2.sql
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,29 @@ SELECT * FROM _trigger_history;

DROP GRAPH cypher_dml2 CASCADE;

-- #589 ( Cypher read clauses cannot follow update clauses )
CREATE GRAPH cypher_dml2;
SET GRAPH_PATH to cypher_dml2;

CREATE VLABEL main;
CREATE ELABEL main2;

CREATE (n:another {id: 593}) RETURN n.id;

MERGE (n:main {id: 593})
ON CREATE SET n.id = 593
WITH n
MATCH (g: another)
WHERE g.id = 593
MERGE (g)-[:main2]->(n);

MATCH ()-[e:main2]-() RETURN e;
MATCH (g: another) RETURN g;
MATCH (g: main) RETURN g;

DROP GRAPH cypher_dml2 CASCADE;

-- fix: Includes necessary JOINs of vertices (#599)
CREATE GRAPH cypher_dml2;
SET GRAPH_PATH to cypher_dml2;

Expand Down

0 comments on commit f1bdb55

Please sign in to comment.