Skip to content

fix(cypher): parse and apply the full multi-key ORDER BY list, keeping LIMIT (#1334) - #1436

Merged
DeusData merged 2 commits into
mainfrom
fix/1334-multikey-orderby-limit
Aug 5, 2026
Merged

fix(cypher): parse and apply the full multi-key ORDER BY list, keeping LIMIT (#1334)#1436
DeusData merged 2 commits into
mainfrom
fix/1334-multikey-orderby-limit

Conversation

@DeusData

@DeusData DeusData commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Fixes #1334.

Root cause

The Cypher request model stored a single order_by expression. On ORDER BY key1 DESC, key2 ASC LIMIT n the parser consumed only key1 DESC, left , key2 … LIMIT n unparsed, and the query silently returned the entire result set — 6,326 rows / 117 KB instead of 5 on the reporter's graph, a token flood straight into agent context.

Fix

  • The return clause models up to 8 sort keys with per-key direction (Cypher semantics); the parser consumes the whole comma-separated list, so the trailing LIMIT parses again.
  • Both sort sites — rb_apply_order_by (RETURN) and sort_bindings (WITH pipeline) — compare key-by-key, later keys breaking ties.
  • More keys than the modeled maximum is a loud parse error, never a silently dropped remainder.
  • The no-ORDER-BY projection fast path is preserved (order_key_count == 0).

Verification

  • 5 new tests: parse-level (2 keys + per-key direction + LIMIT consumed; 9-key over-cap rejected) and exec-level (RETURN limit kept, tiebreak ordering with mixed ASC/DESC, WITH-pipeline limit kept).
  • RED on main (row_count == 4, expected 2 ×3), GREEN with the fix, RED again on revert (production code reverted to origin/main with the fix committed, field-dependent tests excluded for compile).
  • cypher 175 passed · mcp 189 passed / 2 skipped (pre-existing) · make -f Makefile.cbm lint-ci clean.

Recorded (pre-existing, unchanged)

An ORDER BY key that is not part of the projection is silently skipped — single-key main behaves the same (the reporter's case A sorted by nothing, correctly capped). Sorting by unprojected properties needs hidden-column projection; separate issue.

…g LIMIT (#1334)

The Cypher request model stored a single order_by expression; on
ORDER BY key1 DESC, key2 ASC LIMIT n the parser consumed only key1,
left ', key2 ... LIMIT n' unparsed, and the query silently returned the
entire result set (6326 rows / 117 KB instead of 5 on the reporter's
graph - a token flood straight into agent context).

The return clause now models up to CBM_CYPHER_ORDER_KEYS_MAX (8) sort
keys with per-key direction (Cypher semantics). Both sort sites -
rb_apply_order_by for RETURN and sort_bindings for the WITH pipeline -
compare key-by-key with later keys breaking ties. More keys than the
modeled maximum is a loud parse error, never a silently dropped
remainder. The no-ORDER-BY projection fast path is preserved via
order_key_count == 0.

Tests: parse-level (2 keys, per-key direction, LIMIT consumed;
9-key over-cap rejected), exec-level RETURN (limit kept, tiebreak
ordering, per-key direction), and exec-level WITH pipeline (limit kept).
All RED before the fix (row_count 4 instead of 2), GREEN after.

Recorded, pre-existing and unchanged: an ORDER BY key that is not part
of the projection is silently skipped (single-key main behaves the
same); sorting by unprojected properties needs hidden-column projection
and is a separate issue.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
@DeusData
DeusData enabled auto-merge August 4, 2026 16:23
The over-cap ORDER BY rejection path (and the two sibling error paths
in parse_return_or_with) freed the items array but not the strings
inside it - ASan flagged 7 leaked bytes on the diag and Linux legs the
moment the new over-cap test exercised the path. Route all three error
paths through free_return_clause(), which already releases item
strings, CASE expressions, args and the ORDER BY key list.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
@DeusData
DeusData merged commit 4bbe098 into main Aug 5, 2026
33 checks 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.

query_graph: multi-key ORDER BY silently drops LIMIT (6326 rows / 117 KB instead of 5) on v0.9.1-rc.1

1 participant