Skip to content

feat: add pgjson format support for EXPLAIN ANALYZE#21767

Draft
adriangb wants to merge 1 commit intoapache:mainfrom
pydantic:explain-analyze-pgjson
Draft

feat: add pgjson format support for EXPLAIN ANALYZE#21767
adriangb wants to merge 1 commit intoapache:mainfrom
pydantic:explain-analyze-pgjson

Conversation

@adriangb
Copy link
Copy Markdown
Contributor

Which issue does this PR close?

  • Closes #.

Rationale for this change

DataFusion already emits PostgreSQL JSON (pgjson) for logical plans via EXPLAIN (FORMAT pgjson) .... This PR extends that support to EXPLAIN ANALYZE so the physical plan, along with live execution metrics, can be fed into pgjson visualizers such as Dalibo and PEV2.

Today, EXPLAIN ANALYZE FORMAT pgjson is explicitly rejected in the planner with "EXPLAIN ANALYZE with FORMAT is not supported". With this PR the restriction is lifted for pgjson.

What changes are included in this PR?

  • Add a format: ExplainFormat field to the logical Analyze node and the physical AnalyzeExec operator, threaded through SQL parsing, logical planning, and physical planning.
  • Accept EXPLAIN ANALYZE FORMAT pgjson <stmt>. Tree and Graphviz with ANALYZE still error with a clear message (out of scope for this PR).
  • Add DisplayableExecutionPlan::pgjson() and a new PgJsonExecutionPlanVisitor that mirror the logical-plan PgJsonVisitor. Per-node output includes:
    • Node TypeExecutionPlan::name()
    • Details — the one-line DisplayAs::Default rendering
    • Actual Rows / Actual Total Time — PG-canonical metric keys populated from output_rows / elapsed_compute (emitted as float milliseconds; note DataFusion records compute time, not wall time)
    • Extras — remaining DataFusion metrics keyed by their native name
    • Plans — child nodes
  • Add an optional set_summary() builder so AnalyzeExec can attach Total Rows and Duration at the root in verbose mode.
  • Honor existing analyze_level / analyze_categories config exactly as indent() does.

Are these changes tested?

  • Unit tests in datafusion/physical-plan/src/display.rs:
    • pgjson_renders_plan_without_metrics
    • pgjson_includes_summary_when_set
    • pgjson_snapshot_of_sample_plan (insta snapshot)
  • sqllogictest coverage in datafusion/sqllogictest/test_files/explain_analyze.slt:
    • Structural golden for EXPLAIN ANALYZE FORMAT pgjson with analyze_categories = 'none'
    • Negative tests for EXPLAIN ANALYZE FORMAT tree and EXPLAIN ANALYZE FORMAT graphviz
  • cargo clippy --all-targets --all-features -- -D warnings clean on the touched crates; cargo fmt --all clean.

Are there any user-facing changes?

Yes — new syntax is accepted:

EXPLAIN ANALYZE FORMAT pgjson SELECT count(*) FROM t;

No existing behavior changes: the default (EXPLAIN ANALYZE ... with no FORMAT) still emits the indent-format plan with metrics, and EXPLAIN (FORMAT pgjson) ... on the logical plan is unchanged.

🤖 Generated with Claude Code

@github-actions github-actions Bot added sql SQL Planner logical-expr Logical plan and expressions core Core DataFusion crate sqllogictest SQL Logic Tests (.slt) physical-plan Changes to the physical-plan crate labels Apr 21, 2026
@adriangb adriangb force-pushed the explain-analyze-pgjson branch from af1be1a to b4c739f Compare April 21, 2026 19:49
Extend the existing `FORMAT pgjson` option so that it also renders
`EXPLAIN ANALYZE` output as PostgreSQL-style JSON, suitable for
visualizers such as Dalibo and PEV2.

Each physical operator becomes a JSON object carrying:
  - `Node Type` — `ExecutionPlan::name()`
  - `Details` — the one-line `DisplayAs::Default` rendering
  - `Actual Rows` / `Actual Total Time` — PG-canonical metric keys
    populated from `output_rows` / `elapsed_compute`
  - `Extras` — remaining DataFusion metrics keyed by their native name
  - `Plans` — child nodes

The existing logical-plan pgjson path, metric filtering config
(`analyze_categories`), and indent-format behavior are unchanged.
`Tree` and `Graphviz` with `ANALYZE` remain unsupported with a clear
error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@adriangb adriangb force-pushed the explain-analyze-pgjson branch from b4c739f to 5fc8a84 Compare April 21, 2026 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Core DataFusion crate logical-expr Logical plan and expressions physical-plan Changes to the physical-plan crate sql SQL Planner sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant