Skip to content

fix(parser): preserve T-SQL OFFSET/FETCH across parse→generate roundtrip (CR-010)#16

Merged
yigalrozenberg merged 1 commit into
masterfrom
fix/cr-010-tsql-offset-fetch-roundtrip
May 28, 2026
Merged

fix(parser): preserve T-SQL OFFSET/FETCH across parse→generate roundtrip (CR-010)#16
yigalrozenberg merged 1 commit into
masterfrom
fix/cr-010-tsql-offset-fetch-roundtrip

Conversation

@yigalrozenberg

Copy link
Copy Markdown
Collaborator

Summary

Fixes CR-010 / PSQ-2420: T-SQL FETCH NEXT m ROWS ONLY was silently dropped during parse → generate roundtrips, causing data over-exposure in the Secure Query Gateway whenever an ABAC policy was active on a LIMIT/OFFSET query.

Root cause

The defect is in the parser, not the generator. After parsing OFFSET <expr>, the parser did not consume the trailing ROWS/ROW keyword. So for input like:

```
ORDER BY col OFFSET 2 ROWS FETCH NEXT 5 ROWS ONLY
```

the next `match_token(Fetch)` saw `ROWS` and returned `false`, leaving `fetch_first = None`. The generator already emits `OFFSET n ROWS FETCH NEXT m ROWS ONLY` correctly for T-SQL/Fabric when `fetch_first` is set, which is why direct transpile worked but re-parsing the transpiled SQL did not.

Fix

Two-line change in `src/parser/sql_parser.rs`: after parsing the OFFSET expression, consume the optional `ROWS`/`ROW` keyword (ANSI SQL:2008 / T-SQL form).

Tests

Added 4 tests in `tests/test_dialects.rs`:

  • `test_tsql_offset_fetch_roundtrip_preserved`
  • `test_tsql_offset_fetch_with_subquery_order_roundtrip`
  • `test_tsql_offset_only_no_fetch_roundtrip` (regression guard — OFFSET without FETCH must NOT add FETCH)
  • `test_pg_limit_offset_transpile_then_tsql_roundtrip` (end-to-end ABAC pipeline scenario)

All previously passing tests continue to pass (zero regressions across the full suite).

Validation

  • `cargo test` — all suites green
  • `cargo fmt --all` clean
  • `cargo clippy` — no new warnings on changed lines

Refs: PSQ-2420

…p (CR-010)

The T-SQL parser failed to consume the trailing ROWS keyword after
'OFFSET <expr>'. As a result, when re-parsing T-SQL like
  ORDER BY col OFFSET 2 ROWS FETCH NEXT 5 ROWS ONLY
the subsequent match_token(Fetch) saw ROWS on the stream, returned false,
and the FETCH clause was silently dropped. The generator already emits
OFFSET/FETCH correctly when fetch_first is set, so transpile worked but
parse->generate roundtrips lost the page-size limit.

Fix: after parsing the OFFSET expression, consume the optional ROWS/ROW
keyword (ANSI SQL:2008 / T-SQL form).

Tests (tests/test_dialects.rs):
- tsql_offset_fetch_roundtrip_preserved
- tsql_offset_fetch_with_subquery_order_roundtrip
- tsql_offset_only_no_fetch_roundtrip
- pg_limit_offset_transpile_then_tsql_roundtrip (end-to-end ABAC scenario)

Refs: PSQ-2420
@yigalrozenberg yigalrozenberg merged commit 477aac4 into master May 28, 2026
2 of 3 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.

1 participant