Copilot commented on code in PR #2347:
URL: https://github.com/apache/age/pull/2347#discussion_r2879755062


##########
src/backend/parser/cypher_gram.y:
##########
@@ -89,7 +93,7 @@
                  LIMIT
                  MATCH MERGE
                  NOT NULL_P
-                 OPERATOR OPTIONAL OR ORDER
+                 ON OPERATOR OPTIONAL OR ORDER

Review Comment:
   The `ON` token is added to the `%token` list here (making it a lexical 
keyword), but it is NOT added to the `safe_keywords` production rule later in 
the file (around lines 2431-2477). All other keywords added as tokens in this 
file are also listed in `safe_keywords` so they can be used as identifiers, 
property names, or labels via the `schema_name` → `reserved_keyword` → 
`safe_keywords` path.
   
   By omitting `ON` from `safe_keywords`, property keys or node labels named 
`on` (e.g., `n.on`, `MATCH (n:on)`) will now fail to parse with a syntax error. 
This is a breaking change for any graph using `on` as a property name or label. 
Adding `| ON { $$ = KEYWORD_STRDUP($1); }` to the `safe_keywords` rule would 
fix this.



##########
regress/sql/cypher_merge.sql:
##########
@@ -868,9 +868,95 @@ SELECT * FROM cypher('issue_1630', $$ MATCH (n) DETACH 
DELETE n $$) AS (a agtype
 SELECT * FROM cypher('issue_1709', $$ MATCH (n) DETACH DELETE n $$) AS (a 
agtype);
 SELECT * FROM cypher('issue_1446', $$ MATCH (n) DETACH DELETE n $$) AS (a 
agtype);
 
+--
+-- ON CREATE SET / ON MATCH SET tests (issue #1619)
+--
+SELECT create_graph('merge_actions');
+
+-- Basic ON CREATE SET: first run creates the node
+SELECT * FROM cypher('merge_actions', $$
+  MERGE (n:Person {name: 'Alice'})
+    ON CREATE SET n.created = true
+  RETURN n.name, n.created
+$$) AS (name agtype, created agtype);
+
+-- ON MATCH SET: second run matches the existing node
+SELECT * FROM cypher('merge_actions', $$
+  MERGE (n:Person {name: 'Alice'})
+    ON MATCH SET n.found = true
+  RETURN n.name, n.created, n.found
+$$) AS (name agtype, created agtype, found agtype);
+
+-- Both ON CREATE SET and ON MATCH SET (first run = create)
+SELECT * FROM cypher('merge_actions', $$
+  MERGE (n:Person {name: 'Bob'})
+    ON CREATE SET n.created = true
+    ON MATCH SET n.matched = true
+  RETURN n.name, n.created, n.matched
+$$) AS (name agtype, created agtype, matched agtype);
+
+-- Both ON CREATE SET and ON MATCH SET (second run = match)
+SELECT * FROM cypher('merge_actions', $$
+  MERGE (n:Person {name: 'Bob'})
+    ON CREATE SET n.created = true
+    ON MATCH SET n.matched = true
+  RETURN n.name, n.created, n.matched
+$$) AS (name agtype, created agtype, matched agtype);
+
+-- ON CREATE SET with MERGE after MATCH (Case 1: has predecessor, first run = 
create)
+SELECT * FROM cypher('merge_actions', $$
+  MATCH (a:Person {name: 'Alice'})
+  MERGE (a)-[:KNOWS]->(b:Person {name: 'Charlie'})
+    ON CREATE SET b.source = 'merge_create'
+  RETURN a.name, b.name, b.source
+$$) AS (a agtype, b agtype, source agtype);
+
+-- ON MATCH SET with MERGE after MATCH (Case 1: has predecessor, second run = 
match)
+SELECT * FROM cypher('merge_actions', $$
+  MATCH (a:Person {name: 'Alice'})
+  MERGE (a)-[:KNOWS]->(b:Person {name: 'Charlie'})
+    ON MATCH SET b.visited = true
+  RETURN a.name, b.name, b.visited
+$$) AS (a agtype, b agtype, visited agtype);
+
+-- Multiple SET items in a single ON CREATE SET
+SELECT * FROM cypher('merge_actions', $$
+  MERGE (n:Person {name: 'Dave'})
+    ON CREATE SET n.a = 1, n.b = 2
+  RETURN n.name, n.a, n.b
+$$) AS (name agtype, a agtype, b agtype);
+
+-- Reverse order: ON MATCH before ON CREATE should work
+SELECT * FROM cypher('merge_actions', $$
+  MERGE (n:Person {name: 'Eve'})
+    ON MATCH SET n.seen = true
+    ON CREATE SET n.new = true
+  RETURN n.name, n.new
+$$) AS (name agtype, new agtype);
+
+-- Error: ON CREATE SET specified more than once
+SELECT * FROM cypher('merge_actions', $$
+  MERGE (n:Person {name: 'Bad'})
+    ON CREATE SET n.a = 1
+    ON CREATE SET n.b = 2
+  RETURN n
+$$) AS (n agtype);
+
+-- Error: ON MATCH SET specified more than once
+SELECT * FROM cypher('merge_actions', $$
+  MERGE (n:Person {name: 'Bad'})
+    ON MATCH SET n.a = 1
+    ON MATCH SET n.b = 2
+  RETURN n
+$$) AS (n agtype);
+

Review Comment:
   There is no test covering the interaction of ON CREATE SET / ON MATCH SET 
with chained (non-terminal) MERGE statements, which exercises the 
eager-buffering code path added in PR #2344. The non-terminal MERGE path (lines 
664-750 in `cypher_merge.c`) has ON CREATE SET and ON MATCH SET logic, but the 
tests only cover Case 1 with a MATCH predecessor (not a MERGE-then-MERGE 
chain). A test like:
   
   ```
   MERGE (a:A {name: 'X'}) ON CREATE SET a.new = true
   MERGE (b:B {name: 'Y'}) ON CREATE SET b.new = true
   RETURN a, b
   ```
   
   or with a chained terminal MERGE following a non-terminal MERGE with ON SET 
would validate that the eager buffering path handles ON SET correctly.
   ```suggestion
   
   -- Chained MERGE with ON CREATE SET in non-terminal and terminal clauses
   SELECT * FROM cypher('merge_actions', $$
     MERGE (a:Person {name: 'ChainCreateA'})
       ON CREATE SET a.new = true
     MERGE (b:Person {name: 'ChainCreateB'})
       ON CREATE SET b.new = true
     RETURN a.name, a.new, b.name, b.new
   $$) AS (a_name agtype, a_new agtype, b_name agtype, b_new agtype);
   
   -- Chained MERGE with non-terminal ON CREATE SET and terminal ON MATCH SET
   -- Setup an existing node to be matched by the second MERGE
   SELECT * FROM cypher('merge_actions', $$
     CREATE (p:Person {name: 'ChainMatch', seen: false})
   $$) AS (n agtype);
   
   SELECT * FROM cypher('merge_actions', $$
     MERGE (a:Person {name: 'ChainCreateOnce'})
       ON CREATE SET a.created = true
     MERGE (b:Person {name: 'ChainMatch'})
       ON MATCH SET b.seen = true
     RETURN a.name, a.created, b.name, b.seen
   $$) AS (a_name agtype, a_created agtype, b_name agtype, b_seen agtype);
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to