Guides

Inspect query plans

Request a vendor-specific plan, with analysis limited to read queries.

Use an adapter that supports ExplainableQueryAdapter. For example, with the PostgreSQL adapter from Execute queries:

import { from, integer, qubu, select, table } from "qubu"
import { pgAdapter } from "@qubu/adapter-pg"
import { Pool } from "pg"

const db = qubu(pgAdapter(new Pool()))
const users = table("users", { id: integer() })
const readQuery = select({ id: users.id }, from(users))

const plan = await db.explain(readQuery, { analyze: true, verbose: true })
// plan.rows has the pg adapter's vendor-specific plan-row type.

The standalone equivalent is explain(readQuery, db.adapter, options). Qubu calls the adapter's explain() method rather than execute().

Qubu keeps ExplainResult.rows in the adapter's vendor-specific shape. It does not normalize PostgreSQL, SQLite, or MySQL plans into one tree. The adapter owns parameter binding, plan-row decoding, connections, transactions, and cancellation. ExplainRequest carries the rendered statement, ordered raw parameters, query kind, and optional abort signal just like an ordinary execution request.

The first-party policies accept these options:

Dialect Plan options Restrictions
PostgreSQL analyze, verbose, buffers, and format: 'text' | 'xml' | 'json' | 'yaml' buffers requires analyze; analysis requires a read query kind
SQLite format: 'query-plan' | 'bytecode' or queryPlan analyze, verbose, and buffers are unsupported
MySQL analyze or format: 'traditional' | 'json' | 'tree' analyze cannot be combined with format; requires a read query kind

All supported queries can be explained, including INSERT, UPDATE, and DELETE. Mutation EXPLAIN is always plan-only. The type and runtime boundaries reject analyze for mutation query kinds. Analysis executes the read statement; Qubu does not parse SQL or rule out side effects from routines, custom fragments, or data-modifying SQL hidden inside it. Unsupported options and invalid combinations raise a structured QueryValidationError before the adapter is called.