Skip to content

[P0][bug] EXPLAIN ANALYZE runs the actual query (UPDATE/INSERT/DELETE) with no confirmation, no production-safety, no read-only enforcement #412

Description

@EVWorth

Context

EXPLAIN ANALYZE in SQLPilot executes the underlying query to gather actual cost/timing data.

Problem

src/stores/resultStore.ts:118-136 (executeExplainAnalyze) runs api.executeQuery(connectionId, EXPLAIN ANALYZE ${sql}, database). EXPLAIN ANALYZE actually executes the query (it's EXPLAIN ANALYZE SELECT plus actual execution, returning actual time=…, rows=…, loops=…). For EXPLAIN ANALYZE DELETE FROM users WHERE 1=1, the DELETE runs. EXPLAIN (non-ANALYZE) is safe — only plans. But the UI doesn't distinguish; user clicks one button (Explain) and a dropdown (QueryToolbar.tsx:103-111) selects ANALYZE. No production-safety confirm dialog — DESTRUCTIVE_PATTERN is checked only by resultStore.executeQuery, not by executeExplain/executeExplainAnalyze. No read_only enforcement (admin F1 pattern). The user opens a query tab on production, types DELETE FROM important_table WHERE created_at < '2020-01-01', clicks EXPLAIN ANALYZE — table is wiped.

Files

  • src/stores/resultStore.ts:118-136 (executeExplainAnalyze)
  • src/components/editor/QueryToolbar.tsx:103-111 (dropdown)

Repro

  1. Connect to production DB
  2. Open query tab, type DELETE FROM users WHERE 1=1
  3. Click Explain → EXPLAIN ANALYZE
  4. The DELETE runs against the production database without confirmation

Expected

Clicking EXPLAIN ANALYZE on DELETE FROM users WHERE 1=1 shows a warning "EXPLAIN ANALYZE executes the query — falling back to EXPLAIN" and only plans, doesn't delete. Production connection always confirms. Read-only profile rejects.

Proposed fix

(1) Detect destructive SQL (UPDATE|INSERT|DELETE|REPLACE|TRUNCATE|DROP|ALTER — extended beyond editor's current DESTRUCTIVE_PATTERN) in executeExplainAnalyze. If detected, refuse to run ANALYZE and fall back to plain EXPLAIN, with a warning. (2) Apply production-safety check (isProductionConnection + confirm dialog) regardless of destructive pattern. (3) Apply read_only profile check via a new explain_query Tauri command (F11). (4) Update the QueryToolbar dropdown label to "Run EXPLAIN ANALYZE (executes the query)" so the user knows the cost. Scope: M.

Acceptance

Clicking EXPLAIN ANALYZE on DELETE FROM users WHERE 1=1 shows a warning "EXPLAIN ANALYZE executes the query — falling back to EXPLAIN" and only plans, doesn't delete. Production connection always confirms. Read-only profile rejects.

Needs human verify

yes

Doc drift

partial — DESIGN_REQUIREMENTS FR-2.2.5 doesn't address EXPLAIN ANALYZE safety

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/explainAudit areaauditTracks a feature-by-feature codebase audit findingkind/bugAudit finding categoryseverity/p0Audit finding severity

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions