Skip to content

Explain why utility statements have no query plan - #414

Closed
dpage wants to merge 1 commit into
mainfrom
fix/issue-368-non-explainable-statements
Closed

Explain why utility statements have no query plan#414
dpage wants to merge 1 commit into
mainfrom
fix/issue-368-non-explainable-statements

Conversation

@dpage

@dpage dpage commented Aug 12, 2026

Copy link
Copy Markdown
Member

Summary

The Query Plan panel built its request by concatenating EXPLAIN with
the captured statement text, and because pg_stat_statements records
utility and DDL commands alongside DML, a Top Queries row can hold bare
VACUUM, ANALYZE, REINDEX ... or CLUSTER ... text; wrapping any
of those in EXPLAIN is invalid SQL, so the panel surfaced a raw
syntax error at or near "VACUUM" back at the user.

This change adds client/src/utils/sqlHelpers.ts, which classifies a
statement from its leading keyword after skipping leading whitespace,
line and block comments, and opening parentheses. useQueryPlan now
checks that classification before building the request and reports the
statement type through a new notExplainable field instead of firing a
request that can only fail, whilst QueryPlanPanel renders a friendly
informational alert naming the statement type in place of the Postgres
error.

The explainable set is SELECT, INSERT, UPDATE, DELETE, MERGE, VALUES,
EXECUTE, DECLARE, WITH, TABLE, CREATE TABLE AS and CREATE MATERIALIZED
VIEW, plus REFRESH MATERIALIZED VIEW, which the EXPLAIN grammar accepts
even though the documentation omits it. Every case in the test tables
was verified empirically against PostgreSQL 18.4 rather than assumed.

Test plan

  • New sqlHelpers unit tests cover keyword extraction, comment and
    parenthesis stripping, and eighteen explainable and twenty-three
    non-explainable statements; the file reports 100% line, branch and
    function coverage.
  • New useQueryPlan tests assert that VACUUM, ANALYZE, REINDEX,
    CLUSTER, CREATE INDEX and TRUNCATE issue no API call at all, that the
    detected keyword is reported, and that the flag clears when a
    plannable query follows; the hook reports 98.68% line coverage.
  • New QueryPlanPanel tests assert the friendly message renders, that
    the plan tabs stay hidden, and that the notice takes precedence over
    a stale error; the component reports 100% line coverage.
  • npm run lint reports 0 errors, and npm run build succeeds.

Closes #368

The Query Plan panel built its request by concatenating EXPLAIN with
the captured statement text, but pg_stat_statements records utility
and DDL commands as well as DML, so a Top Queries row can hold bare
VACUUM, ANALYZE, REINDEX or CLUSTER text. PostgreSQL's EXPLAIN accepts
only SELECT, INSERT, UPDATE, DELETE, MERGE, VALUES, EXECUTE, DECLARE,
CREATE TABLE AS and CREATE MATERIALIZED VIEW (the grammar additionally
accepts REFRESH MATERIALIZED VIEW), so those requests could only ever
fail, and the panel rendered the raw syntax error back at the user.

The new sqlHelpers module classifies a statement from its leading
keyword, ignoring leading whitespace, comments and parentheses, and
useQueryPlan now reports the statement type through notExplainable
rather than issuing a doomed request; the panel renders a friendly
informational message naming the statement type instead of a Postgres
syntax error. The classification was verified against PostgreSQL 18.

Closes #368
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 51 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bee25a78-3cfc-44b1-a601-4f741e5f5505

📥 Commits

Reviewing files that changed from the base of the PR and between 19c645d and 8c11855.

📒 Files selected for processing (6)
  • client/src/components/Dashboard/ObjectDashboard/QueryPlanPanel.tsx
  • client/src/components/Dashboard/ObjectDashboard/__tests__/QueryPlanPanel.test.tsx
  • client/src/hooks/__tests__/useQueryPlan.test.ts
  • client/src/hooks/useQueryPlan.ts
  • client/src/utils/__tests__/sqlHelpers.test.ts
  • client/src/utils/sqlHelpers.ts

Comment @coderabbitai help to get the list of available commands.

@codacy-production

codacy-production Bot commented Aug 12, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 3 high

Alerts:

⚠ 1 issue (≤ 0 issues of at least minor severity)

Results:
3 new issues

Category Results
ErrorProne 2 high (2 false positives)
Security 1 high

View in Codacy

🟢 Metrics 45 complexity

Metric Results
Complexity 45

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@dpage

dpage commented Aug 12, 2026

Copy link
Copy Markdown
Member Author

Closing in favour of #385, which fixes the same issue more correctly.

Verified against PostgreSQL 18.4: EXPLAIN REFRESH MATERIALIZED VIEW mv is accepted by the parser and returns "Utility statements have no plan structure", with FORMAT JSON returning ["Utility Statement"]. This branch classifies that statement as explainable, so it still issues the request and then hands the plan renderer a JSON array containing a bare string, replacing one failure mode with another. #385 models three states (plan, planless, unsupported) and hardens extractJsonPlan against non-plan shapes, so it handles the case correctly; its CTAS pattern is also tighter, and it updates the changelog.

The sqlHelpers extraction and the dedicated notExplainable field here are a reasonable follow-up on top of a merged #385, but are not a reason to keep this branch open.

@dpage dpage closed this Aug 12, 2026
@dpage
dpage deleted the fix/issue-368-non-explainable-statements branch August 12, 2026 12:11
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.

Query Plan panel shows raw syntax error for non-explainable statements (VACUUM, ANALYZE, etc.)

1 participant