Skip to content

TUR-313: Query: reject a MERGE key that is null at run time - #1185

Merged
rjb32 merged 1 commit into
mainfrom
remyboutonnet/tur-313-query-merge-on-a-property-that-is-null-at-run-time-creates
Oct 23, 2026
Merged

rjb32 merged 1 commit into
mainfrom
remyboutonnet/tur-313-query-merge-on-a-property-that-is-null-at-run-time-creates

Conversation

@rjb32

@rjb32 rjb32 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Reject a MERGE whose key property is null on any row.

@rjb32

rjb32 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Note

AI-generated summary.

Summary

NLMergeExecutor::run now calls throwIfKeyIsNull between extracting the key values and matching the rows; holdsValue moved to NLWriteProperties

The analyzer rejects a MERGE key that is null by type. A key that is null on some rows only reached the executor, which wrote the entity without that property. The check now runs in the executor, on every row's key values, before any row is matched or written.

 NLMergeExecutor::run
   extractProperties(rowCount)
   for each node
     throwIfBoundNodeIsNull
+    throwIfKeyIsNull(node._properties)
+  for each hop
+    throwIfKeyIsNull(hop._properties)
   for each row
     matchRow(row)        // match, or writeRow

The error text is the analyzer's: MERGE cannot match on property 'name', which is null.

Evidence

  • Before: 5 of the 6 new MergeRejectionTest cases failed: each query succeeded instead of being rejected.
    After: test_query_ir_merge_rejection passes all 11 cases.
rejectsANodeKeyThatIsNullByType           MERGE (t:Tag {name: 'k', flag: 1 < 'a'})                        (analyzer, passed before)
rejectsANodeKeyThatIsNullOnOneRow         UNWIND [null, 'a'] AS v MERGE (t:Tag {name: v}) RETURN t.name
rejectsANodeKeyThatIsNullOnTheLastRow     UNWIND ['a', 'b', null] AS v MERGE (t:Tag {name: v})
rejectsANodeKeyACaseMakesNullOnOneRow     MATCH (p:Person) MERGE (t:Tag {name: CASE WHEN p.name = 'Remy' THEN null ELSE p.name END})
rejectsANodeKeyReadFromAMissingProperty   MATCH (p:Person) MERGE (t:Tag {name: 'x', age: p.age})
rejectsAnEdgeKeyThatIsNullOnOneRow        MATCH (a:Person {name: 'Remy'}), (b:Person {name: 'Adam'}) UNWIND [1, null] AS w MERGE (a)-[:PROBE {weight: w}]->(b)

The 57 test_query_ir_(merge|set|write|create|subquery) targets and V3QueryTestSuite pass.

Merge Danger

Door: two-way

Blast Radius: MERGE

A MERGE with a null key on any row now fails where it used to succeed. Neo4j fails the same queries.

@rjb32
rjb32 merged commit f1dac52 into main Oct 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant