Skip to content

fix(query-result): correct row classification and stabilize result table UI - #175

Merged
Blankll merged 5 commits into
masterfrom
fix/query-result-display
Oct 10, 2026
Merged

Blankll merged 5 commits into
masterfrom
fix/query-result-display

Conversation

@Blankll

@Blankll Blankll commented Oct 9, 2026

Copy link
Copy Markdown
Member

Summary

Fixes two defects in the query result experience:

  1. SELECT queries preceded by SQL comments returned no data — only N row(s) affected.
  2. Result table Actions column / copy-export buttons were unreliable — the Actions header vanished on wide results and copy/export buttons disappeared entirely when there was nothing to copy.

Root cause & fixes

1. Row classification (src-tauri/src/database/*)

Statement routing used a naive first-keyword prefix check (trim().to_uppercase().starts_with("SELECT")). A SELECT preceded by a -- comment line fell through to the execute path, where driver-level execute() discards rows and only the command-tag count survives (SELECT 2 → "2 row(s) affected").

  • New shared module src-tauri/src/database/sql_classification.rs: strips leading comments/whitespace for a fast keyword scan, then falls back to dialect-aware sqlparser parsing for a single Query or RETURNING DML. Inconclusive cases stay conservative on the execute path.
  • Wired into the postgres, mysql, and sqlite adapters; their keyword lists are unchanged (postgres additionally accepts TABLE).

2. Result table UI (DataGrid.vue, QueryResultPanel.vue)

  • The Actions column header lived outside the rows scroll container, so its sticky never applied and it did not track horizontal scroll — on wide results the Actions column visually disappeared from the right edge. The header viewport now mirrors the rows' scrollLeft, keeping the sticky header pinned at the visible right edge, aligned with the sticky row cells.
  • Copy/export buttons were v-if-hidden when there were no rows; they now always render and are disabled (grayed out) instead, matching the tab buttons in the same panel.

Test evidence

  • cargo build ✅, cargo test --lib sql_classification — 11 new unit tests (comment prefixes, block comments, unterminated comments, DML ± RETURNING, multi-statement, parenthesized query, VALUES, TABLE) ✅
  • cargo test --lib database:: — 242 passed ✅
  • npm run build (vue-tsc + vite) ✅
  • npm test — 34 suites / 611 tests passed ✅

Notes

Statement classification used a naive first-keyword prefix check, so a
SELECT preceded by SQL comments (or a parenthesized query, VALUES, TABLE,
or DML with RETURNING) fell through to the execute path, where rows are
discarded and only the command-tag count surfaces — the UI then showed
'N row(s) affected' with an empty result table.

Add a shared sql_classification module: strip leading comments/whitespace
for the fast keyword scan, then fall back to sqlparser (dialect-aware) for
a single parsed Query or RETURNING DML. Wire it into the postgres, mysql,
and sqlite adapters; their keyword lists are unchanged.
…isible

Result table: the Actions header lived outside the rows scroll container,
so its sticky positioning never applied and the header did not track
horizontal scroll — the Actions column visually vanished from the right
edge on wide results. Mirror the rows' scrollLeft onto an overflow-hidden
header viewport so the sticky header stays pinned at the visible right
edge, aligned with the sticky row cells.

Copy/export buttons were v-if-hidden when there were no rows; show them
always and disable (gray out) instead, matching the tab buttons in the
same panel.
…overflow

Sticky positioning only pins during horizontal overflow; with few result
columns the Actions header and cells sat right after the last column,
leaving dead space to the right. Stretch the header row and virtual rows
to the container width (min-w-full) and push the Actions cells right with
ml-auto, so the column hugs the visible right edge in both cases.
…idth

Data columns were fixed at 150px with truncation regardless of how much
space the grid had — a single-column result truncated its value while most
of the panel sat empty. Give data columns a proportional flex-grow with
the existing width as flex-basis: spare width now stretches columns (more
content visible), while dense results keep the fixed basis, truncation,
and horizontal scroll. min-w-0 keeps long values from forcing their
min-content width onto the layout.
Freshly published advisories (vue XSS GHSA-g2v6-rqmx-r4w6,
brace-expansion DoS family) broke the CI audit gate on the master
baseline. Semver-compatible lockfile refresh; 22 moderate advisories
remain, below the critical threshold.
@Blankll
Blankll merged commit 669ca39 into master Oct 10, 2026
5 of 6 checks passed
@Blankll
Blankll deleted the fix/query-result-display branch October 10, 2026 02:20
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