PG Review v2: CF60/6654 — pg_dump extension config table data before user objects

code-review · generated from canonical Markdown

Type
code-review
Source
postgresql-master
Slug
commitfest-6654-review
Tags
binary-upgradecode-reviewcommitfest-60coveragepatch-reviewpg-dumppostgresqlreview-report-v2
Updated
2026-08-02T11:57:05.307684+00:00
Verdict / Summarywaiting-on-author
Front matter
schema: review-report-v2
target: CommitFest 60 / Patch 6654
head: 7cb9060dcde08ca63df1f0d701b0674e0e8ae811
repo: postgresql-master
review_date: 2026-08-02
verdict: waiting-on-author
verification: verified/cannot-verify findings documented below
repair_validation: passed/partial/waived as documented below
coverage_status: coverage-complete
line_numbers: verified at 7cb9060dcde08ca63df1f0d701b0674e0e8ae811

PG Review v2 — CommitFest 60, Patch 6654

Patch: pg_dump: Restore extension config table data before user objects during pg_upgrade Author: Jimmy Angelakos Source: postgresql-master (worktree cf-45ce650c1e17b9d9, READ-ONLY) HEAD SHA: 7cb9060dcde08ca63df1f0d701b0674e0e8ae811 Base: HEAD (uncommitted working-tree edits = v1 of the patch) Diff SHA: c3193e900241e96f02d3910f59b046c8d4e484ea251544efcce03fbcc1d73527 Diff stat: 4 files changed, 117 insertions(+), 2 deletions(-) Files: src/bin/pg_dump/pg_backup_archiver.c (+2), src/bin/pg_dump/pg_dump.c (+109,-2), src/bin/pg_dump/pg_dump.h (+1), src/bin/pg_dump/pg_dump_sort.c (+7) Reviewer tool: pg-review-harness (glm-5.2:cloud) Artifact schema: pg-review-artifact-v2 (validated) Thread: 640803 (4 messages, 2026-03-20 to 2026-07-27); related 632035 (user_catalog_table alternative)

Scope reviewed

v1 = standalone dumpExtensionData() / makeExtensionDataInfo(). v2 (posted to list, NOT applied) folds into dumpTableData() and adds tests. This review covers v1 in the prepared worktree.

New functions: dumpExtensionData() (pg_dump.c:2948), makeExtensionDataInfo() (pg_dump.c:3135). Modified: _tocEntryRequired() (pg_backup_archiver.c), dumpDumpableObject() / processExtensionTables() / addBoundaryDependencies() (pg_dump.c), describeDumpableObject() (pg_dump_sort.c). New enum: DO_EXTENSION_DATA (pg_dump.h); new priority PRIO_EXTENSION_DATA (pg_dump_sort.c).

Goal

pg_upgrade uses pg_dump --schema-only --binary-upgrade, which strips extension config table data. In the new cluster, binary_upgrade_create_empty_extension() creates extensions without populating config tables, so any CREATE TABLE requiring validation against that data (e.g. PostGIS spatial_ref_sys SRID validation) fails. The patch adds DO_EXTENSION_DATA that emits config table COPY data in SECTION_PRE_DATA during --binary-upgrade only, restoring it before user DDL.

Deterministic verdict

PG verdict: waiting-on-author Generic verdict: changes-requested Blockers: 0 BLOCKER (0 verified, 0 unverified) Rationale: Three MAJOR findings (F1 missing tests, F2 code duplication, F3 unresolved architectural objection) are verified by static analysis and corroborated by committer review on the pgsql-hackers thread. No BLOCKER-severity findings. F3 is a live architectural objection from pg_dump maintainer Peter Eisentraut (thread 632035) with no consensus — any live committer objection forces waiting-on-author. F1 and F2 are acknowledged by the author and addressed in v2 (posted but not applied to this worktree). Two MINOR findings (F4, F6) have concrete verified repairs validated in disposable scratch.

Findings

F1

— MAJOR — no tests included in v1 (verified, static-check)

  • Location: src/test/modules/test_pg_dump/ (no changes in v1 diff)
  • Mechanism: Andrew Dunstan (committer) explicitly requested tests in test_pg_dump (msg dafc934b-...@dunslane.net, 2026-03-29). v1 contains zero test changes. v2 (msg CAA0-ca3T3Lq..., 2026-04-06) adds a test_pg_dump test but is NOT applied here.
  • Verification: verified by static-check — amauta_tests_for on all changed symbols returned empty; diff confirms zero changes under src/test/modules/test_pg_dump/.
  • Repair intent: Apply v2 test additions (insert row into regress_table_dumpable; add TAP block asserting COPY public.regress_table_dumpable (col1) appears in binary_upgrade => section_pre_data and is unlike for plain dumps).
  • Repair patch: waived (design-choice) — the test belongs with the v2 refactor (F2); a v1-only test would test dumpExtensionData() that v2 deletes.
  • Test example: provided (TAP, src/test/modules/test_pg_dump/t/001_base.pl).
  • Validation: partial — functional behavior verified via coverage test harness (EXTENSION DATA appears in TOC dumpId 3433); no committed regression test.
F2

— MAJOR — code duplication between dumpExtensionData() and dumpTableData() (verified, static-check)

  • Location: src/bin/pg_dump/pg_dump.c:2940-2980
  • Mechanism: dumpExtensionData() is a near-verbatim copy of the COPY-building half of dumpTableData() (pg_dump.c:2830-2936). Andrew Dunstan flagged this directly: *"There appears to be a lot of code duplication ... It might be better to refactor that, perhaps by supplying an extra flag to dumpTableData()."* v2 folds the DO_EXTENSION_DATA case into dumpTableData() and deletes dumpExtensionData().
  • Verification: verified by static-check — diff confirms duplication; thread msg 2 flags it; thread msg 3 (v2) refactors.
  • Repair intent: Delete dumpExtensionData(); branch on tdinfo->dobj.objType == DO_EXTENSION_DATA in dumpTableData() to set .description = "EXTENSION DATA" and .section = SECTION_PRE_DATA.
  • Repair patch: waived (design-choice) — the full refactor touches shared dumpTableData(); author's v2 is canonical.
  • Test example: provided (TAP — same as F1 validates the refactored branch).
  • Validation: partial — duplication confirmed by code read; coverage on v1 confirms dumpExtensionData() exercised (7 calls, 100% line coverage).
F3

— MAJOR — unresolved architectural objection (cannot-verify, static-check)

  • Location: design-level, src/bin/pg_dump/pg_dump.h:43
  • Mechanism: Peter Eisentraut (pg_dump maintainer) proposed on 2026-03-13 (msg 5835b04f-...@eisentraut.org, thread 632035) a competing "more principled" approach: PostGIS should mark spatial_ref_sys with user_catalog_table and pg_dump should dump user-catalog-table contents before other DDL. Paul Ramsey (PostGIS) questioned the side effects. The author's 2026-07-27 ping went unanswered. No consensus.
  • Verification: cannot-verify (design/process finding, not a code defect).
  • Repair: re-engage on pgsql-hackers; get explicit ack/rejection from Peter before pushing for commit. All repair fields waived (design-choice).
F4

— MINOR — filtercond bypass broader than DO_EXTENSION_DATA path (verified, targeted-test)

  • Location: src/bin/pg_dump/pg_dump.c:20235
  • Mechanism: !dopt->binary_upgrade skips the extension's WHERE filter for ALL extension config tables in binary-upgrade, not only RELKIND_RELATION ones routed to makeExtensionDataInfo(). For non-plain-relation config tables still going through makeTableDataInfo(), the filter is also dropped with no stated justification.
  • Verification: verified by targeted-test — applied repair patch (hash 62aa0416...) in disposable scratch; compiled (exit 0); pg_dump --binary-upgrade --schema-only produces correct EXTENSION DATA; pg_dump --data-only (non-bu) produces correct COPY.
  • Repair patch (provided, HEAD-bound):
  • head: 7cb9060dcde08ca63df1f0d701b0674e0e8ae811
  • hash: 62aa04166001ef7d5138c3721e8a8c4508fcb19c625e4fdd561ba1411e3e9772
  • Introduces bool earlyData = (dopt->binary_upgrade && configtbl->relkind == RELKIND_RELATION); and gates the filtercond skip on !earlyData.
  • Validation: passed — git apply (exit 0); make (exit 0); dump tests pass; no regressions.
F5

— MINOR — only RELKIND_RELATION config tables get early-restore (cannot-verify, static-check)

  • Location: src/bin/pg_dump/pg_dump.c:20222
  • Mechanism: makeExtensionDataInfo() gated on RELKIND_RELATION; partitioned/foreign/matview config tables fall through to makeTableDataInfo() → DO_TABLE_DATA in SECTION_DATA, masked out of --schema-only restores. Also drops all makeTableDataInfo() guards.
  • Verification: cannot-verify (design decision on relkind scope).
  • Repair: document the limitation or broaden with lifted guards (design-choice; needs committer input).
F6

— MINOR — first EXTENSION DATA whitelist is dead code (verified, targeted-test)

  • Location: src/bin/pg_dump/pg_backup_archiver.c:3303
  • Mechanism: The first whitelist (line 3301-3310) is inside if (!te->hadDumper). EXTENSION DATA entries always have .dumpFn = dumpTableData_copy → hadDumper=true, so this block is never entered for them. Coverage confirms: line 3303 strcmp executed 357 times but == 0 branch never true (0%). The second whitelist (line 3345) is the live path — executed 184 times, branch taken 3%.
  • Verification: verified by targeted-test + coverage — repair patch (hash b79faa44...) applied (exit 0); compiled (exit 0); pg_dump --binary-upgrade -F c + pg_restore -l still shows EXTENSION DATA (live path at 3345 preserved).
  • Repair patch (provided, HEAD-bound):
  • head: 7cb9060dcde08ca63df1f0d701b0674e0e8ae811
  • hash: b79faa44aa9728bb727f459d21196e2c79880fe8a4446503dcc61aeaf9e8e9a7
  • Removes the single dead-code line at 3303.
  • Validation: passed — git apply (exit 0); make (exit 0); EXTENSION DATA still appears in TOC.
F7

— NOTE — pgindent / comment-style drift (verified, static-check)

  • Location: src/bin/pg_dump/pg_dump.c:2940-2980
  • Mechanism: ARCHIVE_OPTS alignment and comment phrasing diverge from dumpTableData(). Moot if F2 adopted.
  • Repair: run pgindent before submission (design-choice; pgindent is canonical).
F8

— NOTE — feature-vs-bugfix classification unresolved (cannot-verify, static-check)

  • Location: submission-level
  • Mechanism: Andrew Dunstan classified as feature → PG20, no backpatch. Author argues bugfix. Committer call.
  • Repair: get committer ruling (design-choice).
F9

— NOTE — --data-only --binary-upgrade does not get the fix (verified, static-check)

  • Location: src/bin/pg_dump/pg_dump.c:1095 (interaction with getTableData)
  • Mechanism: In --data-only binary-upgrade, getTableData() runs first, makeExtensionDataInfo() no-ops via if (tbinfo->dataObj != NULL) return;. Early-restore only triggers for --schema-only --binary-upgrade (pg_upgrade path). Coverage confirms makeExtensionDataInfo line 3140 branch taken 0% (fallthrough 100%).
  • Repair: add comment documenting the limitation (design-choice).

SEC-M1 — MINOR — Assert-only guard on tbinfo->interesting (verified, static-check, non-finding)

SEC-M2 — MINOR — filtercond skip scope (security angle) (verified, static-check)

Verification Summary

Per-finding verification evidence is recorded in the combined summary below.

Repair Validation Summary

Per-finding repair-validation status and evidence are recorded in the combined summary below.

FindingSeverityVerificationRepair patchValidation
F1MAJORverified (static-check)waived (design-choice)partial
F2MAJORverified (static-check)waived (design-choice)partial
F3MAJORcannot-verify (static-check)waived (design-choice)waived
F4MINORverified (targeted-test)provided (62aa0416)passed
F5MINORcannot-verify (static-check)waived (design-choice)not-run
F6MINORverified (targeted-test)provided (b79faa44)passed
F7NOTEverified (static-check)waived (design-choice)not-run
F8NOTEcannot-verify (static-check)waived (design-choice)waived
F9NOTEverified (static-check)waived (design-choice)not-run
SEC-M1MINORverified (static-check)waived (design-choice)waived
SEC-M2MINORverified (static-check)provided (62aa0416)passed

Verified findings: 8 (F1, F2, F4, F6, F7, F9, SEC-M1, SEC-M2) Cannot-verify findings: 3 (F3, F5, F8) — UNVERIFIED Refuted findings: 0 Repairs validated (passed): 3 (F4, F6, SEC-M2 — all share 2 distinct patches)

Changed-Code Coverage

Coverage requirement: required (changed instrumentable implementation in 3 files) Status: measured Coverage epoch: fresh-epoch-1 (disposable scratch, review worktree untouched) Compiler: gcc 15.2.0 (-O0 -g, -fprofile-arcs -ftest-coverage) Build: disposable scratch; review worktree never modified

Test commands executed (host-disposable lane, port 55432, test_pg_dump extension)

  1. pg_dump --schema-only --binary-upgrade (plain SQL)
  2. pg_dump --schema-only (non-bu, negative)
  3. pg_dump --binary-upgrade (full)
  4. pg_dump --schema-only --binary-upgrade --section=pre-data
  5. pg_dump --data-only --binary-upgrade
  6. pg_dump --schema-only --binary-upgrade --inserts
  7. pg_dump --schema-only --binary-upgrade -F c (custom) + pg_restore -l
  8. pg_restore --schema-only (restore planning, _tocEntryRequired)
  9. pg_dump --schema-only --binary-upgrade -F d (directory)
  10. pg_dump (plain full, non-bu)
  11. pg_dump --schema-only --binary-upgrade --no-security-labels --no-privileges
  12. pg_dump -v --schema-only --binary-upgrade

Execution lane

Raw metrics

MetricValue
Changed executable lines57
Changed lines covered52
Changed lines uncovered5
Changed-line coverage91.2%

New function coverage

FunctionFileCallsLine coverageBranch coverage
dumpExtensionDatapg_dump.c7100.0%93.0%
makeExtensionDataInfopg_dump.c794.1%86.0%

Uncovered changed lines (all non-actionable)

File:LineFunctionCoverabilityReason
pg_dump.c:3141makeExtensionDataInfoinfeasible-with-reasonDefensive early-return guard; branch taken 0% by construction (dataObj always NULL in schema-only pg_upgrade path)
pg_dump.c:20236processExtensionTablesrequires-special-harness-or-injection-pointfiltercond assignment requires extension with non-empty pg_extension_config_dump condition; test_pg_dump uses ''
pg_dump_sort.c:1529describeDumpableObjectinfeasible-with-reasonDiagnostic-only path; only called on unresolvable dependency-loop warning
pg_dump_sort.c:1530describeDumpableObjectinfeasible-with-reasonSame — diagnostic-only path
pg_dump_sort.c:1531describeDumpableObjectinfeasible-with-reasonSame — diagnostic-only path

Uncovered branches (changed regions)

File:LineFunctionBranchCoverabilityReason
pg_dump.c:2955dumpExtensionDataAssert branch 0infeasible-with-reasonAssert failure branch; invariant by construction
pg_dump.c:2963dumpExtensionDataDUMP_COMPONENT_DATA == 0requires-special-harnessRequires selectively-excluded config table
pg_backup_archiver.c:3303_tocEntryRequiredEXTENSION DATA == 0 (true)infeasible-with-reasonDead code (F6); hadDumper always true; branch taken 0% across 357 executions

Touched functions

FunctionFileCoveredCalls
dumpExtensionDatapg_dump.cyes7
makeExtensionDataInfopg_dump.cyes7
processExtensionTablespg_dump.cyes8
_tocEntryRequiredpg_backup_archiver.cyes464
dumpDumpableObjectpg_dump.cyes28867
addBoundaryDependenciespg_dump.cyes8
describeDumpableObjectpg_dump_sort.cno0 (diagnostic-only)

Non-instrumentable changes

Residual limitations

pgsql-hackers thread ledger

Ledger report: commitfest-6654-thread-ledger (persisted, read back) Schema: pg-review-thread-ledger/v1 Status: reconciled Thread 640803: 4 messages (v1 → committer review → v2 → unanswered ping) Thread 632035: Peter Eisentraut's user_catalog_table alternative (live architectural objection)

Live objections

Aggregated Test Plan

TestVehicleStatusCovers
test_pg_dump TAP: COPY in binary_upgrade pre-dataTAPproposed (v2 has it)F1, F2, F6
F4 test: non-earlyData config table retains filterTAPproposedF4, SEC-M2
filtercond test: extension with non-empty conditionTAPproposedF9 coverage gap

Verified clean / non-findings

Maintainers (top-3 per changed file, 3y window)

Provenance / model routes

Residual risk

The patch functionally fixes the PostGIS SRID validation pg_upgrade failure (verified by coverage). The primary blockers are process-level (F3 architectural consensus, F1/F2 addressed in unapplied v2). The F4 and F6 repairs are verified and low-risk. The design contest (F3) is the dominant risk: a committer is unlikely to commit over a live objection from the file's maintainer.

v2 artifact validation

pg-review-artifact-v2 artifact validated by validate-pg-review-artifact — PASSED (zero exit).