MP108warningneeds databasepg_partman

warn-partman-managed-parent

Manual partition DDL on a parent table managed by pg_partman.

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

What triggers it

Either a CreateStmt that has a partbound and names a parent in inhRelations[0].RangeVar.relname, or an AlterTableStmt carrying an AT_AttachPartition or AT_DetachPartition subcommand whose parent is relation.relname — where that parent resolves through lookupTableExtensions() to a TableExtensionInfo with isPartmanParent true, meaning it appears in pg_partman's part_config.

What does not

Every run without --database-url: part_config is the only thing that says a parent is managed, so without it a CREATE TABLE ... PARTITION OF reads as ordinary partition DDL (requiresDatabaseUrl is set). A CreateStmt with no partbound, or one with no inhRelations entry to name the parent. Parents absent from part_config. Every other statement shape, including a DROP TABLE on a child partman believes it owns.

Where it applies

Applies to every PostgreSQL version MigrationPilot targets. It only fires on tables managed by pg_partman. It needs --database-url: without a connection it has nothing to read and stays silent.

The lock, and what it blocks

No lock claim. ATTACH PARTITION takes SHARE UPDATE EXCLUSIVE on the parent and ACCESS EXCLUSIVE on the table being attached, and a non-concurrent DETACH takes ACCESS EXCLUSIVE on the parent — but none of that is what the rule reports. The finding is a bookkeeping divergence: part_config will not record the partition, and the collision surfaces later on a run_maintenance run rather than during the migration.

Why it matters

pg_partman decides which children exist, from what part_config says: run_maintenance pre-creates the next few partitions according to premake and drops old ones according to retention, on its own schedule. A partition created, attached, or detached by hand is not recorded there, so the next maintenance run can try to create a partition whose range you have already covered — which fails — or drop one it believes it owns. Nothing goes wrong at migration time; it surfaces later on a scheduled run nobody is watching.

Unsafe, and safe

Flagged

-- events is managed by pg_partman (interval 1 day, premake 4, retention 90 days)
CREATE TABLE events_p2024_01 PARTITION OF events
  FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');

Safe alternative

-- Check what partman thinks it owns, then let it make the partitions
-- by widening how far ahead it pre-creates.
SELECT parent_table, control, partition_interval, premake, retention
FROM part_config WHERE parent_table LIKE '%events';

What it assumes

The rule cannot compare your partition's range against what partman is about to pre-create, so it cannot distinguish a genuine collision from a manual partition sitting harmlessly outside the premake window — every hand-written partition on a managed parent is reported. Parents are matched by bare relation name against what was read from part_config, so the same parent name in two schemas is ambiguous. The configuration quoted in the message (control column, interval, premake, retention) is each optional and is used for wording only, never for a decision, so a partly-readable part_config still produces the same finding.

This rule reads live catalogue state, so it says nothing at all without --database-url. That is the trade: no connection, no guess.

What the CLI prints

migrationpilot analyze migration.sql --database-url $DATABASE_URL
⚠ [MP108] WARNING (line 2)
  CREATE TABLE events_p2024_01 PARTITION OF on "events", which pg_partman manages (control column "created_at", interval 1 day, premake 4, retention 90 days). partman creates and removes children from part_config on its own schedule; a partition changed by hand is not recorded there, so the next run_maintenance can collide with it. Its retention policy is 90 days, so partman will drop children on that schedule whether or not this migration made them.

  Safe alternative:
  -- Check what partman thinks it owns before changing anything:
  SELECT parent_table, control, partition_interval, premake, retention, automatic_maintenance
  FROM part_config WHERE parent_table LIKE '%events';
  
  -- Let partman make the partitions, by widening how far ahead it pre-creates:
  UPDATE part_config SET premake = 8 WHERE parent_table = 'public.events';
  CALL run_maintenance_proc();
  
  -- To move existing rows into the partition set, use partman's own procedure so
  -- it commits in batches instead of one long transaction:
  CALL partition_data_proc('public.events');
  
  -- If the partition set really should be managed by hand from now on, take it out
  -- of partman first: DELETE FROM part_config WHERE parent_table = '...';

  Why: pg_partman decides which children exist from part_config: run_maintenance pre-creates the next few partitions and applies the retention policy. A partition created, attached, or detached by hand is invisible to that bookkeeping, so the next maintenance run can try to create a partition whose range you already covered, which fails, or drop one it believes it owns. The two systems disagree quietly and the failure surfaces later, on a maintenance run nobody was watching.
  Docs: https://migrationpilot.dev/rules/mp108

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. The catalogue figures come from the production context this rule documents.

Turning it off

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

-- migrationpilot-disable MP108
CREATE TABLE events_p2024_01 PARTITION OF events

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

.migrationpilotrc.yml
rules:
  MP108: false

# or keep it, and downgrade it
rules:
  MP108:
    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 MP108 in the playground

Related rules