SIGN IN SIGN UP

Fix: MERGE followed by CREATE creates endless nodes (#4080)

Closes #1333

**Root cause:**
`GenMerge` plans `merge_match` with `storage::View::NEW` so MERGE can
see vertices created by earlier clauses in the same query. The
underlying skip-list iterator has a `nullptr` end-sentinel, so a
downstream `CREATE` in the same query kept feeding new nodes back into
the running scan — producing unbounded node creation and OOM on `MERGE
(n0) MERGE (n1) CREATE (c0)`.

This is fundamentally an iterator-semantic problem: `View::NEW` is
correct for cross-clause visibility, but bulk iteration should be scoped
to entries that existed when the iterable opened — same guarantee most
MVCC systems provide for cursors.

**Fix:**
Bound every in-memory vertex iterable by a GID high-water mark captured
at construction. `storage->vertex_id_.load(acquire)` at that moment is
the "next GID to be assigned" and therefore an exclusive upper bound on
every vertex already in storage. Anything appended after that has `gid
>= max_gid_` and is filtered out by the iterator's advance loop.

Per-iterable behaviour:
- `AllVerticesIterable` (used by `ScanAll`) — vertex skip-list is
GID-ordered, so the iterator terminates on the first out-of-scope entry.
- `InMemoryLabelIndex::Iterable` + `ChunkedIterable` (used by
`ScanAllByLabel`) — index is not GID-ordered, so out-of-scope entries
are skipped individually.
- `InMemoryLabelPropertyIndex::Iterable<Entry/DescEntry>` +
`ChunkedIterable<EntryT>` (used by `ScanAllByLabelProperties`) — same
skip-and-continue.

Cross-clause `View::NEW` visibility is preserved: any vertex created by
an earlier clause has `gid < max_gid_` and remains visible. The
watermark only filters writes that happen *after* the iterable opens.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
D
David Ivekovic committed
9173bf03fc0d2269b6961dcc2ea27ae970cba2ec
Parent: 487a349
Committed by GitHub <noreply@github.com> on 5/19/2026, 8:49:57 AM