Skip to content

postgres_scan: re-add the inheritance-parent member split with an explicit parent-only mode #735

Open

Description

@sfc-gh-dachristensen

Background

#653 originally included "split inheritance parents per member table too" (353f475). It treated a plain table with inheritance children (relkind = 'r' with relhassubclass) like a partitioned table: postgres_scan listed the parent and its descendants through pg_inherits and scanned each one with its own COPY (SELECT ... FROM ONLY <member>) TO STDOUT. Without it, an inheritance parent takes the plain-table path. That path is sized from the parent's own pages, which are usually 0, so the scan runs as a single task with a near-zero row estimate.

The commit was removed from #653 because it breaks callers that need the scan to read exactly the relation they named.

The conflict

A downstream logical-replication extension snapshots a source table through postgres_scan over a dedicated connection that uses an exported snapshot. On that connection a ProcessUtility hook fails closed. A top-level COPY ... TO has to name the single expected relation OID, and the hook clears RangeVar.inh so the copy reads ONLY that relation. Each inheritance member gets its own snapshot, so the parent copy must not pick up child rows.

With the member split, scanning the parent issues copies for the children over that connection. The hook rejects every one:

ERROR:  cannot restrict the snapshot copy of "parent" to its own rows
DETAIL:  The copy reads relation "child" instead.
STATEMENT:  COPY (SELECT "id", "value" FROM ONLY "<schema>"."child") TO STDOUT (FORMAT "binary");

The snapshot then never completes.

Proposal

Bring the inheritance-parent split back, plus an explicit way for a caller to ask for parent-only semantics, for example a postgres_scan named parameter or a session setting:

  • Default (no option): behavior stays as it is now. The parent and all of its descendants are read, either as one parent scan or split per member once the split is back.
  • Parent-only: do not enumerate pg_inherits members. Scan only the named relation, with FROM ONLY <relation> so child rows are excluded even on the plain path. Ctid-range parallelism within that one relation is still fine.

The replication extension would then set the option for its snapshot scans, and the hook's single-OID check can stay as strict as it is.

Partitioned tables (relkind = 'p') are not affected. The replication extension expands those to leaves itself and does not set the expected-OID restriction on them. It may still be worth defining what parent-only means for a partitioned root, either an error or a no-op.

Tests

  • An inheritance parent with rows in the parent and in two children, one of which is reachable through two parents: the default scan returns every row exactly once, and with the split back it runs as a per-member parallel scan.
  • The same tables with parent-only set: only the parent's own rows come back, and every issued COPY names the parent with ONLY. This can be checked from log_statement or with a hook or trigger that records the relations.
  • A regression test on the replication side that snapshots an inheritance parent through the hook with a postgres_scan that has the split enabled.

Related

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions