MP093warning

warn-default-partition-growth

A DEFAULT partition silently absorbs rows that belong to missing partitions, making later ATTACH operations expensive.

operation
Partitions
lock taken
no table lock
remediation
Manual rewrite
category
Partitioning

What triggers it

CREATE TABLE ... PARTITION OF ... DEFAULT — detected via partbound.is_default === true on the CreateStmt.

What does not

Non-CreateStmt statements. Bounded PARTITION OF ... FOR VALUES partitions and partitioned-parent declarations (PARTITION BY) don't set is_default, so they're left alone.

Where it applies

Applies to every PostgreSQL version MigrationPilot targets. It works on the SQL text alone — no database connection needed.

The lock, and what it blocks

None for the statement this rule flags — creating an empty default partition is fast. The lock lands later: attaching the partition those absorbed rows should have gone to forces PostgreSQL to prove none of them overlap the new bound, under ACCESS EXCLUSIVE on both the default partition and the parent, and that ATTACH fails outright if any row does overlap.

Why it matters

A default partition converts a loud failure into a silent one. Without it, inserting a row that matches no partition raises an error somebody notices the same day; with it, the row lands in the catch-all and nothing is logged. Miss a month of partition creation and the default partition quietly becomes the largest table in the database — and getting out is expensive in proportion to how long it went unnoticed, because attaching the partition those rows belong to scans the whole default partition under ACCESS EXCLUSIVE.

Unsafe, and safe

Flagged

CREATE TABLE events_default PARTITION OF events DEFAULT;
-- Silently absorbs every row with no home, forever

Safe alternative

-- Create partitions ahead of time so a gap fails loudly instead of silently
CREATE TABLE events_2026_01 PARTITION OF events
  FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE events_2026_02 PARTITION OF events
  FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');

What it assumes

Assumes creating a DEFAULT partition is risky regardless of how it's operated — a default partition that's actively monitored and kept near-empty, which the rule's own guidance treats as reasonable, is flagged the same as one nobody is watching, since the rule sees the DDL, not runtime row counts.

What the CLI prints

migrationpilot analyze migration.sql
⚠ [MP093] WARNING (line 1)
  "events_default" is a DEFAULT partition of "events". It will silently absorb every row that matches no other partition, and each later ATTACH PARTITION on "events" must scan it in full under ACCESS EXCLUSIVE.

  Safe alternative:
  -- Prefer creating partitions ahead of time so a missing one fails loudly:
  CREATE TABLE events_2026_01 PARTITION OF events
    FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
  
  -- If you keep the default partition, monitor it so it stays near-empty:
  SELECT count(*) FROM events_default;
  
  -- and drain it before attaching the partition its rows belong to, so the
  -- ATTACH scan has nothing to find.

  Why: The default partition turns a missing partition from a loud failure into a silent one. Without it, an insert with no matching partition raises an error somebody notices the same day; with it, the row lands in the catch-all and the gap goes unnoticed until the default partition is the largest table in the database. Getting out is the expensive part: attaching the partition those rows belonged to requires a full scan of the default partition under ACCESS EXCLUSIVE to prove no row overlaps the new bound, and if one does, the ATTACH fails and the rows have to be moved out by hand first.
  Docs: https://migrationpilot.dev/rules/mp093

Generated by running the CLI's own formatter over the flagged example above, so it is the text the tool actually produces. A real run also reports the other rules that fire on the same statement; those blocks are left out here.

Turning it off

For one statement, put a comment on the line before it:

-- migrationpilot-disable MP093
CREATE TABLE events_default PARTITION OF events DEFAULT;

For the whole project, in .migrationpilotrc.yml — by name or by id:

.migrationpilotrc.yml
rules:
  MP093: false

# or keep it, and downgrade it
rules:
  MP093:
    severity: warning

Try it

Open this rule's flagged example in the playground. It runs in your browser — edit it and watch the finding appear and disappear.

Run MP093 in the playground

Related rules