fix(cypher): reject a non-numeric SKIP/LIMIT operand instead of dropping it

expect() fills p->error and returns NULL when the token after SKIP or LIMIT
is not a number, but both call sites only tested `if (num)` and then fell
through to `*out = r; return 0;`. r->limit kept the -1 "unset" initialiser,
which execution reads as "no LIMIT":

    rb_apply_skip_limit(rb, ret->skip, ret->limit >= 0 ? ret->limit : max_rows);

So `RETURN n.name LIMIT $limit` ran unbounded and answered isError:false with
the whole result set. `SKIP $offset LIMIT 10` lost both clauses at once,
because the orphaned operand also blocked the following match(p, TOK_LIMIT).

Propagate the failure the way the ORDER BY branch directly above already
does. This is the failure mode #1334 banned, reached by a different route.

Fixes #1994

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: metehanulusoy <ulusoy.metehan03@gmail.com>
This commit is contained in:
metehanulusoy
2026-09-02 12:06:45 +03:00
co-authored by Claude Opus 5
parent 5fbab7bb73
commit 3d9a6cf5cb
2 changed files with 64 additions and 6 deletions
+13 -6
View File
@@ -1817,20 +1817,27 @@ tail:
}
}
/* Optional SKIP */
/* Optional SKIP. A non-numeric operand is a loud parse error: expect() has
* already filled p->error, and dropping the clause instead would leave
* r->skip at its "none" default while the query still reports success. */
if (match(p, TOK_SKIP)) {
const cbm_token_t *num = expect(p, TOK_NUMBER);
if (num) {
r->skip = (int)strtol(num->text, NULL, CBM_DECIMAL_BASE);
if (!num) {
free_return_clause(r);
return CBM_NOT_FOUND;
}
r->skip = (int)strtol(num->text, NULL, CBM_DECIMAL_BASE);
}
/* Optional LIMIT */
/* Optional LIMIT. Same rule: a dropped LIMIT is the failure mode #1334
* banned - the caller would silently receive the whole result set. */
if (match(p, TOK_LIMIT)) {
const cbm_token_t *num = expect(p, TOK_NUMBER);
if (num) {
r->limit = (int)strtol(num->text, NULL, CBM_DECIMAL_BASE);
if (!num) {
free_return_clause(r);
return CBM_NOT_FOUND;
}
r->limit = (int)strtol(num->text, NULL, CBM_DECIMAL_BASE);
}
*out = r;