Skip to content

Hint at quoting when an unquoted path is used as a table name - #966

Merged
thekevinscott merged 4 commits into
mainfrom
claude/issue-951-0eease
Aug 20, 2026
Merged

thekevinscott merged 4 commits into
mainfrom
claude/issue-951-0eease

Conversation

@thekevinbot

@thekevinbot thekevinbot commented Aug 20, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #951

dirsql 'SELECT * FROM ./' died on SQLite's raw syntax error, which says nothing about the missing quotes:

dirsql query: SQLite error: near ".": syntax error in SELECT * FROM ./ at offset 14

./ is punctuation to SQLite's parser, so the statement dies at prepare time and never reaches the no such table error the whole path-table fallback rides on — which is why none of the existing path-table hints could fire either.

Now:

dirsql query: SQLite error: near ".": syntax error in SELECT * FROM ./ at offset 14
hint: paths used as table names must be quoted; did you mean "./"?

How it works

All of it lands in the shared Rust core (packages/rust/src/db.rs), so both bindings and the CLI inherit it with no per-binding surface and no SDK signature changes.

  • rusqlite surfaces a prepare failure as Error::SqlInputError { sql, offset, .. }, where offset is the byte offset of the token SQLite rejected.
  • path_token_at(sql, offset) widens over path characters in both directions. This matters both ways: FROM ./ rejects the leading ., while FROM src/main.rs rejects the / in the middle — the same token comes back either way.
  • The hint fires only when the recovered token contains a /, per the issue's "detection can be conservative".
  • Wired at the one return Err(error) arm of query's prepare loop, reusing the existing DbError::PathTable variant — no new public enum variant. Gated on path_table_root being set, since without a root a quoted path would fail too and the hint would be a dead end.

Red → green

  • 62afc68 pushed the failing tests alone. Rust CI went red on exactly the new assertion — expected the quoting hint, got: dirsql query: SQLite error: near ".": syntax error in SELECT * FROM ./ at offset 14 — with the negative controls green in the same run.
  • a4c7c1d added the implementation; Rust CI flipped to green.

Tests added: 3 integration (tests/path_table_query.rs), 2 e2e (tests/path_table_cli_e2e.rs), 13 colocated unit (src/db.rs). Two of them are negative controls pinning the conservative side.

Manual verification

Built target/debug/dirsql and ran it against a real temp directory:

Command Observed
SELECT * FROM ./ syntax error + did you mean "./"?
SELECT basename FROM "./" [{"basename":"a.md"},…], exit 0 — the fix the hint names works
SELECT * FROM docs/a.md did you mean "docs/a.md"? (mid-path offset widened)
SELECT * FROM ../ / ~/notes / /var/log/*.log hinted
SELECT * FROM bare incomplete input, no hint
SELECT * FROM usrs bare no such table: usrs, no hint
SELECT size/1024 FROM "./" WHER size > 0 no hint — division untouched
SELECT (size/1024 FROM "./" no hint

Also exercised through both bindings, which return the identical two-line message:

  • Python (PyO3): await db.query('SELECT * FROM ./') → RuntimeError: SQLite error: near ".": syntax error … / hint: paths used as table names must be quoted; did you mean "./"?
  • TypeScript (napi): same message via new DirSQL({root}).query("SELECT * FROM ./")

One accepted false positive: a contrived, already-broken query such as SELECT * FROM "./" GROUP a/b hints on a/b. The original error is still shown in full and the hint is additive.

E2E Verification

  • Ran e2e suites locally for every affected SDK
  • Python SDK e2e: pass (29 passed)
  • TypeScript SDK e2e: pass (13 passed, 4 files)
  • Rust core e2e (if applicable): pass (cargo test --workspace --features cli; see note below)
  • packages/python e2e attestation refreshed (5e319db)
  • packages/ts e2e attestation refreshed (63b83d3) — a packages/rust/src change stales both
  • Command(s) run:
    • cargo test --workspace --features cli
    • cd packages/python && uv run python -m pytest tests/e2e/ -x -q
    • cd packages/ts && pnpm test:e2e
    • cargo clippy --workspace -- -D warnings, cargo fmt --all -- --check
    • npx -y testing-conventions unit colocated-test|unit lint --language rust … packages/rust
    • npx -y testing-conventions unit coverage --language rust packages/rust/src (on nightly)
  • Result summary: all green, with one pre-existing, environment-caused failure: tests/vtab.rs::unreadable_file_yields_null_content_without_erroring_the_row chmods a fixture 0o000 and expects the read to fail, but the sandbox runs as uid 0, which bypasses file permissions. Confirmed pre-existing by stashing this branch's source change and re-running; it passes in CI.

Changelog / Migrations

  • Changelog fragment added: packages/rust/changelog.d/2026-08-20-unquoted-path-table-hint.md
  • Migration fragment not required — purely additive diagnostic. A query that failed before still fails, with strictly more information appended; SQLite's original message is preserved verbatim as the prefix.

Parity

PARITY.md updated with an "Unquoted-path hint (#951)" entry. Not drift — the change is in the shared core, so all three SDKs and the CLI receive the identical message simultaneously. Verified empirically across the PyO3 and napi boundaries (above), so no follow-up issues are needed.

claude added 4 commits August 20, 2026 17:28
`dirsql 'SELECT * FROM ./'` fails with SQLite's raw syntax error, which
says nothing about the missing quotes. Pin the hint that should carry the
fix, plus the negative control that an ordinary syntax error stays bare.

Refs #951

skip-changelog: red tests only; no source change yet

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QmQHSMTjNCmjKzhyfuHXdL
`SELECT * FROM ./` dies in SQLite's parser -- `./` is punctuation, not an
identifier -- so it never reaches the `no such table` error the path-table
fallback rides on, and the user sees only `near ".": syntax error`.

`query()` now widens SQLite's reported error offset over the surrounding
path characters and appends the quoting hint when the recovered token holds
a `/`. Widening matters in both directions: `FROM ./` rejects the leading
`.` while `FROM src/main.rs` rejects the `/` in the middle, and the same
token comes back either way.

Detection stays conservative -- a token with no `/`, an error SQLite reports
without a token offset, and an index with no path-table root (where quoting
would fail too) are all left exactly as they were.

Fixes #951

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QmQHSMTjNCmjKzhyfuHXdL
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.

Clearer error when an unquoted path is used as a table name

3 participants