Skip to content

Derive pagination LIMIT/OFFSET from a SQL parser#286

Open
debba wants to merge 3 commits into
mainfrom
feat/pagination-sql-parser
Open

Derive pagination LIMIT/OFFSET from a SQL parser#286
debba wants to merge 3 commits into
mainfrom
feat/pagination-sql-parser

Conversation

@debba
Copy link
Copy Markdown
Collaborator

@debba debba commented Jun 4, 2026

Builds on #275.

Background

PR #275 fixed the grid pagination rewriter to fold the user's OFFSET into the
per-page offset, but it did so by extending the hand-rolled token scanner in
src-tauri/src/drivers/common/query.rs, which only recognises the trailing
… LIMIT <n> OFFSET <n> shape.

That heuristic is fragile. It does not understand:

  • MySQL's LIMIT <offset>, <count> syntax
  • OFFSET before LIMIT (valid in Postgres)
  • numeric expressions / placeholders

In those cases the values are read wrong (or dropped) and the stripped base can be
inconsistent with what was extracted, producing a malformed appended query.

The change

  • Add the sqlparser crate (v0.62) and read Query.limit_clause from the AST,
    parsed with the correct per-driver dialect (PaginationDialect::{MySql,Postgres,Sqlite}
    threaded through build_paginated_query). MySQL's LIMIT <offset>, <count> is
    normalised to the same (limit, offset) shape.
  • Strip the trailing clause at its LIMIT/OFFSET keyword (reusing the existing
    position-aware tokenizer, which collapses parenthesised subqueries so inner
    LIMITs are never touched), consistent with what the parser saw.
  • Render the new pagination clause from a LimitClause AST node and concatenate it
    to the verbatim sliced base, so leading comments, inline /*+ hints */, and
    the body's formatting are preserved (no full-query reserialization).
  • Keep the original token scanner as a fallback for inputs the parser rejects,
    so behaviour never regresses. FETCH FIRST … ROWS is out of scope and defers to
    the fallback.

Tests

Existing build_paginated_query tests updated to pass a dialect; new cases added for
the MySQL comma form (pages 1 & 2), OFFSET before LIMIT, backtick identifiers,
inline-hint preservation, and the parse-error fallback. cargo test drivers::common
— 63 passed.

debba added 3 commits June 4, 2026 14:18
The grid pagination rewriter read the user's LIMIT/OFFSET with a
hand-rolled token scanner that only recognised the trailing
`LIMIT <n> OFFSET <n>` shape. It mis-handled MySQL's
`LIMIT <offset>, <count>`, `OFFSET` before `LIMIT`, and numeric
expressions, producing wrong values or a malformed appended query.

Parse the query with sqlparser using the driver's dialect and read
LIMIT/OFFSET from the AST instead, normalising the MySQL comma form.
The trailing clause is stripped at its keyword (consistent with what
the parser saw) and the new pagination clause is rendered from a
LimitClause AST node, then concatenated to the verbatim sliced base so
leading comments, inline hints, and formatting are preserved. The
token scanner is kept as a fallback for inputs the parser rejects, so
behaviour never regresses. FETCH FIRST ... ROWS is out of scope and
defers to the fallback.

Builds on #275.
@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot Bot commented Jun 4, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (21 files)
  • src-tauri/Cargo.lock - dependency additions (sqlparser, recursive, stacker, etc.) and version bump to 0.13.0
  • src-tauri/Cargo.toml - adds sqlparser = "0.62" dependency
  • src-tauri/src/drivers/common.rs - re-exports new symbols
  • src-tauri/src/drivers/common/query.rs - AST-based pagination rewriter with dialect-aware parsing and fallback heuristics
  • src-tauri/src/drivers/common/tests.rs - updated existing tests + new coverage for MySQL comma syntax, offset-before-limit, backticks, hints, and parse-error fallback
  • src-tauri/src/drivers/mysql/mod.rs - wires MySQL dialect and error annotation
  • src-tauri/src/drivers/postgres/mod.rs - wires Postgres dialect and error annotation
  • src-tauri/src/drivers/sqlite/mod.rs - wires SQLite dialect and error annotation
  • src/components/notebook/SqlCell.tsx - passes originalQuery to result component
  • src/components/notebook/SqlCellResult.tsx - accepts and forwards originalQuery
  • src/components/ui/ErrorDisplay.tsx - displays original/executed query via collapsible panels
  • src/components/ui/ResultEntryContent.tsx - passes entry.query to ErrorDisplay
  • src/pages/Editor.tsx - passes activeTab.query to ErrorDisplay
  • src/i18n/locales/{de,en,es,fr,it,ja,ru,zh}.json - adds show/hide query translation keys

Reviewed by kimi-k2.6-20260420 · 894,987 tokens

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