Skip to content

feat(planner): refuse retyping or dropping a column a view reads - #223

Merged
aparajon merged 15 commits into
mainfrom
armand/dependent-view-refusal
Oct 20, 2026
Merged

aparajon merged 15 commits into
mainfrom
armand/dependent-view-refusal

Conversation

@aparajon

Copy link
Copy Markdown
Collaborator

Why

PostgreSQL refuses ALTER COLUMN TYPE and DROP COLUMN on a column a view or materialized view reads, even for a type change it would otherwise relabel without a rewrite. The planner classified both as native, so the dry-run said "runs as written" and the real run then failed at the server with an untyped error that did not say which views were in the way. Copy-and-swap already refuses tables with dependent views, but only by count, and the native path never checked at all.

What

  • Both front doors (migrate and the declarative diff) read, from pg_depend, which views and materialized views read each column of the target table (preflight.ColumnDependentViews).
  • The planner refuses a type change or drop of such a column with a new dependent-view reason. The decision names the views in a new dependent_views field, and the refusal detail and dry-run text name them and say to drop or redefine them first.
  • A rename is still allowed, since a view follows the column. The server's own refusal stays the backstop for a view created after planning.
  • The new reason and field are contract changes: the plan report moves to format_version 10, and the lint report, which embeds the reasons, to 4. The linter has no live facts and never reports the reason.
  • Integration tests cover the catalog read, both front doors, and the cases that must still run.

Stacked on #222, since both bump the lint format_version.

An apply widens app.users.email from varchar(50) to varchar(100) while app.active_users and app.mail_report select it.

Before                                   After

┌───────────────────────────────┐        ┌───────────────────────────────┐
│ dry-run                       │        │ dry-run                       │
│ binary-coercible, native      │        │ dependent-view, refused       │
│ "runs as written"             │ ✗      │ names both views              │
└───────────────┬───────────────┘        └───────────────┬───────────────┘
                │ run                                    │ run
                ▼                                        ▼
┌───────────────────────────────┐        ┌───────────────────────────────┐
│ server refuses: SQLSTATE 0A000│        │ refused at plan time          │
│ execution-failed, no reason,  │ ✗      │ nothing sent to the server;   │
│ views not named               │        │ detail names both views       │
└───────────────────────────────┘        └───────────────────────────────┘
Dry-run, before
statement 1:
  ALTER TABLE app.users ALTER COLUMN email TYPE varchar(100);

note[binary-coercible]:
  ALTER COLUMN email TYPE varchar(100) — PostgreSQL relabels the type in
  place; no table rewrite

note:
  runs as written

plan:
  app.users (PostgreSQL 16.15) — 1 statement, 1 step to run, 0 refused

The run then failed:

failed (execution-failed)
  table:     app.users
  statement: ALTER TABLE app.users ALTER COLUMN email TYPE varchar(100)
  detail:    sequence step 1 of 1 failed; no earlier steps had committed — Code names the outcome and any state the failed step itself left
  failed at: step 1: ALTER TABLE app.users ALTER COLUMN email TYPE varchar(100)
Dry-run, after
statement 1:
  ALTER TABLE app.users ALTER COLUMN email TYPE varchar(100);

error[unsupported-statement]:
  refused — ALTER COLUMN email TYPE varchar(100) changes a column read by
  "app"."active_users", "app"."mail_report", and PostgreSQL refuses to
  retype or drop a column while a view reads it

note:
  refusal class: capability-boundary

note[dependent-view]:
  ALTER COLUMN email TYPE varchar(100) — changes a column a view reads;
  PostgreSQL refuses this until the view is dropped or redefined

help:
  drop or redefine those views first, then re-plan

plan:
  app.users (PostgreSQL 16.15) — 1 statement, 0 steps to run, 1 refused

The run is refused the same way:

refused (unsupported-statement)
  table:     app.users
  class:     capability-boundary
  statement: ALTER TABLE app.users ALTER COLUMN email TYPE varchar(100)
  detail:    ALTER COLUMN email TYPE varchar(100) changes a column read by "app"."active_users", "app"."mail_report", and PostgreSQL refuses to retype or drop a column while a view reads it; drop or redefine those views first, then re-plan

🤖 Generated with Claude Code

PostgreSQL refuses every CONCURRENTLY form inside an explicit block, so
a script that wraps one in BEGIN ... COMMIT fails at that statement and
rolls back. Lint now tracks the block a script opens and reports the
operation as concurrent-in-transaction, an error, with how to fix it.
statement.TransactionControlOf reads BEGIN, COMMIT, and their variants
from the parse tree. The lint report moves to format_version 3.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Dependency discovery misses affected descendants, and the classifier incorrectly refuses explicit CASCADE drops.

2 open issues
What changed in this PR

Adds live view-dependency checks so pg-sprite can refuse blocked column changes during planning and name the affected views.

Changes:

  • Reads column dependencies for imperative and declarative planning.
  • Adds dependent-view diagnostics and the dependent_views decision field.
  • Updates tests, documentation, and plan/lint contract versions.
File Description
README.md Summarizes the new refusal.
pkg/​preflight/​dependent_views.go Reads column-to-view dependencies.
pkg/​preflight/​dependent_views_integration_test.go Tests catalog dependency discovery.
pkg/​planner/​planner.go Adds dependency facts and refusal classification.
pkg/​planner/​planner_test.go Tests refusal and unaffected operations.
pkg/​plan/​plan.go Bumps plan format to 10.
pkg/​plan/​plan_test.go Updates contract assertions.
pkg/​migrate/​verdicts.go Names views in refusal details.
pkg/​migrate/​facts.go Loads dependencies for imperative planning.
pkg/​migrate/​dependent_view_integration_test.go Tests imperative refusal and allowed changes.
pkg/​lint/​lint.go Bumps lint format to 4.
pkg/​lint/​lint_test.go Updates JSON version assertions.
pkg/​diffplan/​diffplan.go Loads dependencies for declarative planning.
pkg/​diffplan/​dependent_view_integration_test.go Tests declarative refusal.
pkg/​capabilities/​capabilities.yaml Records dependency-related restrictions.
internal/​cli/​dryrun_text.go Renders view names and remediation.
internal/​cli/​dryrun_text_test.go Tests refusal rendering.
docs/​postgres-online-ddl-reference.md Explains the new reason.
docs/​plan-report.md Documents the version and field.
docs/​optimistic-attempt.md Records plan-time refusal behavior.
docs/​lint-report.md Documents the vocabulary version change.
docs/​limitations.md Describes dependency restrictions.
docs/​cli-output-examples.md Updates JSON versions.
docs/​capabilities.md Updates column-change capabilities.
docs/​binary-coercible-type-changes.md Explains early dependency refusal.
demo/​tour.sh Updates contract-version checks.

Review effort: Balanced

Comment thread pkg/planner/planner.go Resolved
Comment thread pkg/preflight/dependent_views.go Resolved
aparajon and others added 3 commits October 17, 2026 11:46
REINDEX (CONCURRENTLY false) and (CONCURRENTLY 0) rebuild with the
blocking lock, which PostgreSQL runs inside a transaction block, but the
parser counted any CONCURRENTLY option as concurrent. Lint flagged them
as concurrent-in-transaction, and the concurrent rewrite appended a
second CONCURRENTLY option the server refuses as conflicting.

The option's value is now read as the server's defGetBoolean reads it,
through one helper that replaces the duplicate in ops.go, and the
rewrite replaces a disabled option instead of adding one.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
PostgreSQL refuses ALTER COLUMN TYPE and DROP COLUMN on a column that a
view or materialized view reads, even for a type change it would
otherwise relabel without a rewrite. The planner classified both as
native, so the statement reached the server and failed there with an
untyped error that did not say which views were in the way.

Both front doors now read, for the target table, which views and
materialized views pg_depend records as reading each column, and the
planner refuses a type change or drop of such a column with the new
dependent-view reason. The decision names the views in a new
dependent_views field, and the refusal detail and dry-run text tell the
operator to drop or redefine them first. A rename is still allowed,
since a view follows the column. The server's own refusal remains the
backstop for a view created after planning.

The new reason grows the closed Reasons vocabulary and the decision
gains a field, so the plan report moves to format version 10 and the
lint report, which embeds the reasons, to version 4. The linter has no
live facts and never reports the reason.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A DROP COLUMN ... CASCADE drops the views that read the column, which
the server accepts, so it is no longer refused; it stays destructive.
The parser records CASCADE on the operation.

A change without ONLY reaches the column on every partition and
inheritance child, so a view on one of them blocks it too. The lookup
now walks the inheritance tree and reports, per column of the table, the
views on the whole tree and on the table alone; a change under ONLY is
judged by the table's own.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@aparajon
aparajon force-pushed the armand/dependent-view-refusal branch from d52166f to 7f5473a Compare October 17, 2026 15:53
@aparajon
aparajon marked this pull request as ready for review October 17, 2026 16:13
…t-in-transaction

# Conflicts:
#	pkg/lint/lint.go
#	pkg/lint/lint_test.go
#	pkg/statement/rewrite.go
…ction' into armand/dependent-view-refusal

# Conflicts:
#	pkg/migrate/facts.go
#	pkg/planner/planner.go
@Kiran01bm

Copy link
Copy Markdown
Collaborator

🤖 Review findings - created by Kiran's code review agent - for pg-sprite/pull/223, e35b869.

Verdict: 6 findings — 0 blocking, 2 non-blocking (a recursive DROP COLUMN is wrongly refused when a child's column survives the drop), 4 suggestions.

Non-blocking

  1. A recursive DROP COLUMN is refused over views on child columns that PostgreSQL would keep. See pkg/preflight/dependent_views.go:40-42. The tree query (JOIN pg_catalog.pg_inherits i ON i.inhparent = tree.oid) counts every child's same-named column and never checks attislocal or attinhcount. PostgreSQL's ATExecDropColumn only drops a child's copy when attinhcount == 1 && !attislocal; otherwise it keeps the column. Example: CREATE TABLE admins (email text, level int) INHERITS (users) with a view admin_mail reading admins.email. Then ALTER TABLE users DROP COLUMN email succeeds on the server, but viewsReadingColumn returns Tree["email"] and the planner refuses it with ReasonDependentView.

    • This fails closed: it is a false refusal, not an unsafe run, and ONLY works around it.
    • Partitions are not affected, because their columns are never local.
    • ALTER COLUMN TYPE is not affected, because it always recurses.
  2. The docs and tests say the drop reaches every child, which is wrong for merged or multiply-inherited children. The function comment at pkg/preflight/dependent_views.go:29-30 says "A recursive change reaches the column on every table below". docs/limitations.md:21 and plan-report.md say the same. Both are wrong for DROP COLUMN on a child that declares the column locally, attaches later with ALTER TABLE ... INHERIT, or inherits it from two parents. TestRunRefusesChangingAColumnAChildsViewReads only covers a child that inherits email without declaring it, so no test pins the false-refusal case.

General suggestions

  1. Dry-run can name a different refusal cause than the real run. See internal/cli/dryrun_text.go:340. if d, ok := dependentViewRefusal(ps); ok { picks a dependent-view decision wherever it sits in the statement. The run path's routeRefusalVerdict (pkg/migrate/verdicts.go:151-165) reports the first refused decision and breaks. Example: for ALTER TABLE t DROP COLUMN ref, DROP COLUMN email (ref in the replica identity index, a view reading email), the run reports replica identity but dry-run leads with the view. That contradicts the "mirroring the run path" doc comment. Every diagnostic still prints, so only the leading sentence differs.

  2. The Facts doc still promises that missing facts are always more conservative. pkg/planner/planner.go:265-267 still says the zero value "classifies strictly more conservatively". A nil DependentViews map (pkg/planner/planner.go:282-287) instead lets a retype or drop of a column a view reads classify as native or destructive. Possible rewording: "missing facts never make an unsafe change succeed; some only defer a refusal to the server".

  3. The dependent-view query runs for every ALTER TABLE, even ones that never use it. See pkg/migrate/facts.go:79. if st.Kind() == statement.KindAlterTable { runs the recursive catalog query for every ALTER TABLE, including ADD COLUMN, SET NOT NULL and ADD CONSTRAINT, where viewsReadingColumn returns nil. The neighbouring fact reads are gated on the ops that need them (addsColumn, addsUnnamedValidatableConstraint). pkg/diffplan/diffplan.go:102 has the same issue. A timeout on this unused query aborts the plan.

  4. On the run path, the dependent views appear only in prose. See pkg/migrate/verdicts.go:161. The migrate.Run refusal is the generic CapabilityBoundary(ReasonUnsupportedStatement), and the view names go only into v.Detail; the typed dependent_views field exists only in the plan report. AGENTS.md asks for a typed field before behaviour shows only in prose, and the new integration tests assert on Detail wording. This follows the existing replica-identity precedent.

The one thing that could have broken, verified

Could --force, or an op the check exempts, let a retype or drop of a column a view reads reach execution?

  • No. DispositionRefuse ignores --force (pkg/migrate/migrate.go:292-296).
  • viewsReadingColumn exempts only DROP COLUMN ... CASCADE and RENAME. RESTRICT parses as Cascade=false, and ops_test covers it.
  • ONLY switches the check to the table's own views rather than skipping it.
  • The remaining gaps (missing facts, a view created after planning) leave the server's own refusal as the backstop.

Verified correct

  • Every site that handles ReasonReplicaIdentity also handles ReasonDependentView: Reasons(), impactText, the routeRefusalVerdict detail, and the pinned vocabulary test.
  • The dependent-view check runs after the replica-identity check and before the per-kind switch, so a refused decision keeps the Destructive flag from destructiveOp.
  • Child columns are matched by name, not attnum, so partitions with different attnums are handled.
  • The relkind IN ('v','m') filter excludes rules on ordinary tables, and v.oid <> d.refobjid excludes self-references.
  • ORDER BY sorts on name-typed columns (C collation), so the order is bytewise and matches the sortedQualified test helper.
  • View names go through pgx.Identifier.Sanitize, as the repo convention requires.
  • A missing table gives a NULL from to_regclass and no rows, and LiveFacts returns earlier on ErrTableNotFound anyway.
  • The removed and changed lines are only format-version literals, doc wording, and the OpDropColumn construction, which now also records Cascade.

No local builds or tests were run; this review is source inspection only. CI at this head is fully green (16/16).

This review was generated by Claude Code (claude-opus-5-5).

@Kiran01bm Kiran01bm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Approved on Kiran's (@kmuddukrishna) behalf by the scheduled review agent — no blocking findings at e35b869. See the review comment above; non-blocking findings and suggestions, if any, are not merge gates.

aparajon and others added 2 commits October 19, 2026 00:31
A recursive DROP COLUMN drops a child's copy only when the child inherits
the column from this one parent alone and does not declare it, so a view
reading a child's own copy no longer refuses the drop. The preflight read
now returns Drop reach alongside Tree and Own, the read runs only for a
statement that retypes or drops a column, the dry-run text names views
only when the first refusal is a dependent view, and the verdict carries
the view list as dependent_views.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@aparajon

Copy link
Copy Markdown
Collaborator Author

🤖 Thanks, all six are addressed in 48ce870.

  1. False refusal on a recursive drop. ColumnDependentViews now also returns Drop, the views on the column copies a recursive DROP COLUMN actually drops. A recursive CTE starts from the root's columns and descends only through children whose copy has attinhcount = 1 AND NOT attislocal, which is what ATExecDropColumn does. viewsReadingColumn reads DropDependentViews for a recursive drop, Own for ONLY, and Tree for a type change. Your admins example now runs. TestRunDropsAColumnAChildDeclaresWhileAViewReadsTheChildsCopy pins it, and a mutation that reads Tree for the drop fails that test.
  2. Docs and tests on drop reach. The function comment, limitations.md, plan-report.md and the online DDL reference now say that a type change reaches every table below, while a drop skips a child that declared the column, merged it on INHERIT, or inherits it from a second parent. TestColumnDependentViewsForADrop uses the server as the oracle: inherited, declared, attached, two-parent and partition children, plus a grandchild under each of the first two. It asserts Drop holds exactly the views a real DROP COLUMN ... CASCADE removes.
  3. Dry-run cause. refuseText now leads with the first refused decision (firstRefusal), the same one routeRefusalVerdict reports, and names views only when that decision is the dependent-view one. TestDryRunTextRefusalLeadsWithTheFirstRefusedOperation covers your replica identity plus view example.
  4. Facts doc. It now reads: "Missing facts never let an unsafe change succeed: the zero value is valid, routes every type change to copy-and-swap, and only defers some refusals, such as a column a view reads, to the server's own refusal at execution."
  5. Unused query. Both migrate and diffplan now read dependent views only when the statement retypes or drops a column (retypesOrDropsColumn). TestLiveFactsReadsDependentViewsOnlyForARetypeOrDrop pins the gate.
  6. Typed field on the run path. The verdict now carries dependent_views, the same sorted, quoted list as the plan report's decision. The integration tests assert on that field instead of the Detail wording, and the renderer parity fixture covers it.

Addressed by Claude Code

@JashLal

JashLal commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

🤖 Reviewed at head 48ce870607aadc32a78677e2b9910b652d9c13fd on Jash's behalf, scoped to the delta above #222.

Verdict: one correctness gap remains in recursive DROP COLUMN dependency discovery. PostgreSQL still rejects the unsafe drop; the gap makes the dry-run miss a blocker that this change intends to identify.

1. [P2, blocker] Account for multiple inheritance paths from the same dropped ancestor. In pkg/preflight/dependent_views.go:68–69, dropped excludes every child whose initial attinhcount exceeds one. Consider root(email text), two children branch_a and branch_b inheriting root, and leaf inheriting both branches without declaring email locally. A view selecting leaf.email blocks ALTER TABLE root DROP COLUMN email: PostgreSQL's ATExecDropColumn decrements leaf's inheritance count through the first branch, then schedules its column for deletion through the second. This query sees the original count of two and omits the view from Drop, so the planner reports a native drop instead of dependent-view. The existing two-parent fixture has an independent surviving parent and therefore does not exercise this case. This touches core preflight; the observed risk is a missed planning refusal and subsequent server error, not data corruption.

Action item

  1. Model whether all inherited sources of a nonlocal column are removed by the recursive drop, including converging paths. Add a diamond-inheritance regression with a dependent view, asserting both its inclusion in Drop and PostgreSQL's refusal; update the documentation's blanket claim that a second parent always preserves the column.

OSS and integration: naming the blocking views and explaining the remedy improves standalone usability. Both front doors populate the same typed facts, the verdict now exposes dependent_views, and plan/lint versions 10/4 make the contract change explicit for consumers. No orchestrator-specific dependency is introduced.

Validation: inspected the full delta and exact-head surrounding source, including classification, both fact-loading paths, renderers, tests, and the PostgreSQL deletion algorithm. The previous review's local-column, redundant-query, first-refusal, and typed-verdict concerns are addressed. CI is successful across the reported checks, including PostgreSQL 14–18. I did not run local builds or database tests; the diamond finding is source-derived and needs the regression above.

Review generated by Codex.

@JashLal JashLal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Approved by Jash’s AI agent (Codex) under the authorized review workflow. The accompanying review records any blockers and validation limits; this approval does not negate them.

…e drop

A recursive DROP COLUMN lowers a child's inheritance count once per
dropped parent and drops the child's copy on the last one, so a child
that inherits the column along two paths from the dropped table loses
it. Drop reach is now a replay of that walk over the catalog facts
instead of an attinhcount = 1 filter, which left a view on such a child
out of the plan.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@aparajon

Copy link
Copy Markdown
Collaborator Author

🤖 Thanks, you're right about the diamond. Fixed in 50c24fd.

  • Fix: the attinhcount = 1 filter is gone. ColumnDependentViews now reads every table in the hierarchy in one statement: each table's parents, and each column's attislocal, attinhcount and the views that read it. droppedCopies then replays ATExecDropColumn's walk. Each dropped table visits its children, and a child's copy is dropped on the visit that brings its count to its last parent, unless the child declares the column. Otherwise the visit only lowers the count. Since the recursive CTE can't ask whether every parent was dropped, this decision now lives in Go.
  • Regression test: TestColumnDependentViewsForADrop adds your diamond (branch_a, branch_b, diamond) and an uneven one, where uneven inherits from below_inherited (two levels down) and from branch_b. It asserts that v_diamond and v_uneven are in Drop. The server is the oracle: the real DROP COLUMN succeeds once every view in Drop is removed, and keeping any single one, v_diamond included, fails with 2BP01. Swapping the replay back to the one-parent rule makes the test fail on v_diamond.
  • Docs: the function comment, limitations.md, plan-report.md, the online DDL reference and the DropDependentViews doc no longer say a second parent always preserves the column. They now say a child keeps its copy when it declares the column or also inherits it from a table outside the drop, and loses it when it inherits along two paths from the dropped table.

Addressed by Claude Code

Base automatically changed from armand/lint-concurrent-in-transaction to main October 19, 2026 18:05
aparajon and others added 4 commits October 19, 2026 14:15
…-refusal

# Conflicts:
#	demo/tour.sh
#	docs/cli-output-examples.md
#	docs/lint-report.md
#	pkg/lint/lint.go
#	pkg/lint/lint_test.go
…-refusal

# Conflicts:
#	docs/capabilities.md
@aparajon
aparajon merged commit 0c68de2 into main Oct 20, 2026
16 checks passed
@aparajon
aparajon deleted the armand/dependent-view-refusal branch October 20, 2026 19:00
Kiran01bm added a commit that referenced this pull request Oct 21, 2026
…-marker-absent-row

* origin/main: (37 commits)
  executor: qualify the create-owner check and two reads with pg_catalog (#204)
  docs: renames never reach copy-and-swap (#231)
  executor: type a lost bounded-attempt commit as outcome-unknown (#200)
  dbconn: refuse session timeouts below one millisecond (#201)
  preflight: qualify every decision read with pg_catalog (#202)
  feat(planner): refuse retyping or dropping a column a view reads (#223)
  copier: lock the shadow for writing before confirming the table lock (#193)
  router: run a type rewrite through copy-and-swap (#184)
  schemachange: qualify shadow, swap-inspection, fence, and name reads (#209)
  executor: warm the parser before timing the lock-budget test (#212)
  test(migrate): prove every native capability row runs without a rewrite (#221)
  feat(lint): flag a CONCURRENTLY operation inside a transaction block (#222)
  schemachange: enable the write fence always and check it at swap (#187)
  planner: refuse the relabel route for type shapes it cannot fully read (#220)
  planner: name an unnamed CHECK or FOREIGN KEY so its online sequence can be built (#219)
  progress: detach and bound the build progress read from its observer (#199)
  statement: refuse accepted-blocking DROP INDEX ... CASCADE (#189)
  checksum: hold the catch-up's flushes in Go while a live repair recopies (#191)
  capabilities: mark rows migrate refuses as refused (#188)
  fix(migrate): report a desired-state run executed only when a fresh plan is empty (#217)
  ...

# Conflicts:
#	SAFETY.md
#	pkg/applier/catchup.go
#	pkg/applier/doc.go
Kiran01bm added a commit that referenced this pull request Oct 21, 2026
…ge-exit-code

* origin/main: (37 commits)
  executor: qualify the create-owner check and two reads with pg_catalog (#204)
  docs: renames never reach copy-and-swap (#231)
  executor: type a lost bounded-attempt commit as outcome-unknown (#200)
  dbconn: refuse session timeouts below one millisecond (#201)
  preflight: qualify every decision read with pg_catalog (#202)
  feat(planner): refuse retyping or dropping a column a view reads (#223)
  copier: lock the shadow for writing before confirming the table lock (#193)
  router: run a type rewrite through copy-and-swap (#184)
  schemachange: qualify shadow, swap-inspection, fence, and name reads (#209)
  executor: warm the parser before timing the lock-budget test (#212)
  test(migrate): prove every native capability row runs without a rewrite (#221)
  feat(lint): flag a CONCURRENTLY operation inside a transaction block (#222)
  schemachange: enable the write fence always and check it at swap (#187)
  planner: refuse the relabel route for type shapes it cannot fully read (#220)
  planner: name an unnamed CHECK or FOREIGN KEY so its online sequence can be built (#219)
  progress: detach and bound the build progress read from its observer (#199)
  statement: refuse accepted-blocking DROP INDEX ... CASCADE (#189)
  checksum: hold the catch-up's flushes in Go while a live repair recopies (#191)
  capabilities: mark rows migrate refuses as refused (#188)
  fix(migrate): report a desired-state run executed only when a fresh plan is empty (#217)
  ...

# Conflicts:
#	README.md
Kiran01bm added a commit that referenced this pull request Oct 21, 2026
…nts-qualified-reads

* origin/main:
  cli: exit 1 and write usage errors to stderr (#206)
  applier: hold an unmoved marker image whose shadow row is absent (#203)
  executor: qualify the create-owner check and two reads with pg_catalog (#204)
  docs: renames never reach copy-and-swap (#231)
  executor: type a lost bounded-attempt commit as outcome-unknown (#200)
  dbconn: refuse session timeouts below one millisecond (#201)
  preflight: qualify every decision read with pg_catalog (#202)
  feat(planner): refuse retyping or dropping a column a view reads (#223)
  copier: lock the shadow for writing before confirming the table lock (#193)
Kiran01bm added a commit that referenced this pull request Oct 21, 2026
…accessor

* origin/main: (26 commits)
  cli: exit 1 and write usage errors to stderr (#206)
  applier: hold an unmoved marker image whose shadow row is absent (#203)
  executor: qualify the create-owner check and two reads with pg_catalog (#204)
  docs: renames never reach copy-and-swap (#231)
  executor: type a lost bounded-attempt commit as outcome-unknown (#200)
  dbconn: refuse session timeouts below one millisecond (#201)
  preflight: qualify every decision read with pg_catalog (#202)
  feat(planner): refuse retyping or dropping a column a view reads (#223)
  copier: lock the shadow for writing before confirming the table lock (#193)
  router: run a type rewrite through copy-and-swap (#184)
  schemachange: qualify shadow, swap-inspection, fence, and name reads (#209)
  executor: warm the parser before timing the lock-budget test (#212)
  test(migrate): prove every native capability row runs without a rewrite (#221)
  feat(lint): flag a CONCURRENTLY operation inside a transaction block (#222)
  schemachange: enable the write fence always and check it at swap (#187)
  planner: refuse the relabel route for type shapes it cannot fully read (#220)
  planner: name an unnamed CHECK or FOREIGN KEY so its online sequence can be built (#219)
  progress: detach and bound the build progress read from its observer (#199)
  statement: refuse accepted-blocking DROP INDEX ... CASCADE (#189)
  checksum: hold the catch-up's flushes in Go while a live repair recopies (#191)
  ...

# Conflicts:
#	docs/copy-and-swap-design.md
#	docs/invariants.md
Kiran01bm added a commit that referenced this pull request Oct 22, 2026
…-qualified-reads

* origin/main: (40 commits)
  schemachange: qualify the dependent catalog reads with pg_catalog (#210)
  cli: exit 1 and write usage errors to stderr (#206)
  applier: hold an unmoved marker image whose shadow row is absent (#203)
  executor: qualify the create-owner check and two reads with pg_catalog (#204)
  docs: renames never reach copy-and-swap (#231)
  executor: type a lost bounded-attempt commit as outcome-unknown (#200)
  dbconn: refuse session timeouts below one millisecond (#201)
  preflight: qualify every decision read with pg_catalog (#202)
  feat(planner): refuse retyping or dropping a column a view reads (#223)
  copier: lock the shadow for writing before confirming the table lock (#193)
  router: run a type rewrite through copy-and-swap (#184)
  schemachange: qualify shadow, swap-inspection, fence, and name reads (#209)
  executor: warm the parser before timing the lock-budget test (#212)
  test(migrate): prove every native capability row runs without a rewrite (#221)
  feat(lint): flag a CONCURRENTLY operation inside a transaction block (#222)
  schemachange: enable the write fence always and check it at swap (#187)
  planner: refuse the relabel route for type shapes it cannot fully read (#220)
  planner: name an unnamed CHECK or FOREIGN KEY so its online sequence can be built (#219)
  progress: detach and bound the build progress read from its observer (#199)
  statement: refuse accepted-blocking DROP INDEX ... CASCADE (#189)
  ...
Kiran01bm added a commit that referenced this pull request Oct 22, 2026
…esume-restart

* origin/main:
  migrate: qualify the target resolve and accept-blocking reads (#205)
  decode: make an absent column's value unreadable (#218)
  schemachange: qualify the dependent catalog reads with pg_catalog (#210)
  cli: exit 1 and write usage errors to stderr (#206)
  applier: hold an unmoved marker image whose shadow row is absent (#203)
  executor: qualify the create-owner check and two reads with pg_catalog (#204)
  docs: renames never reach copy-and-swap (#231)
  executor: type a lost bounded-attempt commit as outcome-unknown (#200)
  dbconn: refuse session timeouts below one millisecond (#201)
  preflight: qualify every decision read with pg_catalog (#202)
  feat(planner): refuse retyping or dropping a column a view reads (#223)
  copier: lock the shadow for writing before confirming the table lock (#193)

# Conflicts:
#	cmd/pg-sprite/main.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants