Skip to content

Fix projection declarations after column rename - #888

Merged
jdatcmd merged 2 commits into
commandprompt:mainfrom
linuxhikerpm:audit/projection-rename-restore
Sep 9, 2026
Merged

Fix projection declarations after column rename#888
jdatcmd merged 2 commits into
commandprompt:mainfrom
linuxhikerpm:audit/projection-rename-restore

Conversation

@linuxhikerpm

Copy link
Copy Markdown

Problem

Projection storage records column attnums, so a live projection follows ALTER TABLE ... RENAME COLUMN. Its dumpable declaration records column names, but the rename hook did not update those arrays. After backup/restore, pgcolumnar.rebuild_projections() therefore failed with column \"<old name>\" does not exist and the projection could not be recovered.

Fix

Carry each column rename through both columns and sort_key in every declaration for the relation, including inherited/partition descendants already traversed by the rename hook.

Verification

  • New public-boundary regression: create projection, rename column, pg_dump, restore, rebuild, and read all 2,000 rows.
  • Relevant suites: sorted_mark_rename, pg_dump_roundtrip, projections.
  • Full PG18 matrix: 243 passed, 0 failed, 0 incomplete; 2 PG19-only skips (native_repack, pg19_vacuum_options).

Made with Cursor

Co-authored-by: Cursor <cursoragent@cursor.com>

@OffgridwithJD OffgridwithJD 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.

Reviewed at 697a410 on pgcolumnar-audit, PG 18.4 assert build (/usr/local/pg18a). I ran your
suite on both trees rather than reading it, and I probed the fix with fixtures your suite does not
have. The fix is right and I could not break it. One coverage gap, proven by mutation, and I
would want an arm for it before this is approved.

Nothing here blocks on correctness. Also note up front: CI has never run on this PR — see the
bottom.

Your premise and your suite both hold

Same suite, same fixtures, two trees, source-asserted each time rather than trusted:

tree .so result
main 9628414 3e37c0af7b85 3 passed, 2 failed
your 697a410 15f926abd167 5 passed, 0 failed

The red arm fails for exactly the reason you describe: ERROR: column "sort_key" does not exist
out of rebuild_projections() after restore.

Seven adversarial fixtures, all correct

probe result
column in columns only, never in sort_key {a,b} -> {a,b2}, sort_key untouched
two projections on one table, both naming it both declarations moved
a different table with a column of the same name untouched — correctly keyed by relid
rename through a partitioned parent onto a columnar child child follows
renaming a column no declaration mentions byte-identical
rename, then rename back round-trips to {a,b}
rebuild_projections + read after each 0 rebuilt, 100 rows read — correct, the live projections were never lost, only the declaration was stale

The gap: nothing in the tree tests the inheritor walk

Your fixture prr is a single table, so kid and relid are the same oid for it and the walk is
exercised trivially. I mutated the call to use the named relation instead of each descendant —
one token, asserted present in the source before building:

PgColumnarRenameProjectionDeclarationColumn(relid, /*MUT888*/ rs->subname, rs->newname);
your suite, walk defeated (.so 1c12605d1905):  5 passed, 0 failed   <- cannot see it
my partitioned-child probe:                     child after: cols={a,b}   <- rename never arrives

So the walk is correct and unprotected: a later refactor that dropped it would keep your suite
green. The #778 block above your call walks find_all_inheritors for a reason its comment argues
at length, and that argument now covers your line too. A partitioned-child arm would close it —
mine is four statements and you are welcome to lift it verbatim.

Two code notes, neither blocking

rename_projection_declaration_array rebuilds with construct_array(elems, nelems, TEXTOID, -1, false, TYPALIGN_INT), which takes no nulls array. The loop continues on nulls[i], so a NULL
element would be reconstructed from an untouched elems[i]. Unreachable today: resolve_columns
rejects a NULL element before PgColumnarRecordProjectionDeclaration ever writes the row, so no
declaration can contain one. Worth a line saying that is why, since the reconstruction reads unsafe
on its own.

CatalogTupleUpdate inside systable_beginscan over the same relation can re-encounter the updated
tuple, because indexOk is false and this is a seqscan. It is safe here only because the second
visit finds no oldName, leaves changed false, and continues — the idempotence is doing load-
bearing work that nothing states. One sentence would keep a later reader from breaking it.

One test-idiom note

check "pg_dump succeeds" "$?" "0" reads the status of whatever ran last. It is correct as written,
and it silently stops being correct if anyone inserts a line between the command and the check.
Capturing into a variable on the same line as the command is the form that cannot drift.

Separately: because by_sort names the renamed column in both columns and sort_key, the
suite reddens if either array is left behind but cannot say which. My first probe covers columns
alone if you want the distinction.

CI has not run, and that is not your doing

Both your PRs sit at completed/action_required. You are a first-time contributor pushing from
linuxhikerpm/pgcolumnar with read permission, so GitHub is holding the workflows for a
maintainer to approve. gh pr checks reports "no checks reported", which reads like "queued" and is
not. @jdatcmd — these need a click before either PR has a gate.

I am not approving yet, and CI is the reason, not the code. The bar on this repo is a green full
CI, not a green local run ([[approve-only-on-green-full-ci-not-local]] in my own notes, learned the
hard way). Add the partition arm, get the workflows approved, and take it out of draft, and I expect
to approve on the green.

One thing you should know because it lands on your work: I am implementing #887 on
src/columnar_tableam.c and src/columnar_projection.c, and my change reads the very arrays you are
fixing. On main today a rewrite silently loses a projection; with my change it re-records from the
declaration, and a declaration left stale by a rename made my repair raise inside an unrelated
ALTER TABLE
, rolling the user's type change back. I have made mine fail soft with a WARNING so it
survives a stale declaration either way, but your PR removes the cause rather than the symptom, and
I would rather land behind you than ahead of you. Say the word and I will rebase onto #888.

@jdatcmd

jdatcmd commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

CI is now released on this PR. The workflow run has moved from action_required to queued
and will produce a real result.

Worth stating plainly for the record, because the failure mode here is quiet: this PR had no
gate at all
until now, and the way that presents is misleading. gh pr checks reported

no checks reported on the '<branch>' branch

which reads like "not configured" or "queued" and actually meant "held pending a maintainer's
approval". A fork PR from an account with read permission does not run workflows until someone
with write releases them, and it must be released again on every push. So if you push a new
commit here, the gate goes back to held and needs another approval — ping @jdatcmd rather than
reading the absence of checks as a pass.

For what it is worth on the safety question, since running a contributor's code is the reason the
hold exists: .github/workflows/ci.yml triggers on pull_request rather than
pull_request_target, declares permissions: contents: read, references no secrets anywhere, and
uses only GitHub-hosted runners. So these runs execute in an ephemeral VM with a read-only token
and nothing to reach. That is why approving was routine rather than a judgement call about the
contributor.

Co-authored-by: Cursor <cursoragent@cursor.com>

@OffgridwithJD OffgridwithJD 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.

Re-reviewed at 2ba0f91. Your new arm does what I asked, and I proved it rather than reading it:
I re-ran the same mutation that left your previous suite fully green.

Two arms, same tree, same build directory so a fingerprint difference is a source difference, and the
mutation asserted present in the source before building and absent after:

their tree, UNMUTATED            .so 4fad9e322a10   8 passed, 0 failed
+ inheritor walk defeated        .so e44731f7d3c3   6 passed, 2 FAILED
   (PgColumnarRenameProjectionDeclarationColumn(kid,...) -> (relid,...))

FAIL  the descendant declaration follows the parent rename: got [] want [1]
FAIL  the rebuilt child projection contains every restored row: got [] want [99]

Your old suite stayed 5/5 green under that same one-token change. It now reddens two arms, and they
are the right two. The walk is protected.

All three of my non-blocking notes are addressed, and one is better than what I suggested:

  • construct_array became construct_md_array(elems, nulls, ...), so the null bitmap survives. I had
    only asked for a comment saying the path was unreachable. Preserving the bitmap and then saying
    why it is unreachable is the stronger answer, because it stays correct if a row ever arrives from
    outside add_projection.
  • The seqscan-updated-in-place idempotence is now stated at columnar_metadata.c:3652. That was
    load-bearing and undocumented; now a later reader cannot remove it by accident.
  • pg_dump and the restore capture into dump_rc=$? and restore_rc=$? on the same line as the
    command, so inserting a line between them cannot silently change what is being checked.

I am not approving yet, and it is not your code

Your CI is held again. Run 34288862406 on 2ba0f910 is completed/action_required, while the
previous head's run 34282722871 finished green. A fork PR from a read-permission account needs a
maintainer to release the workflows on every push, so the gate reverts to held each time you
address a review. gh pr checks reports "no checks reported" in that state, which reads like queued
and is not.

@jdatcmd has been asked to release it. Once it is green I will approve: the bar here is a green full
CI rather than a green local run, and I have only run PG18 locally.

One thing worth flagging since we are now both in this area. I have opened #892, which re-records
projections after a rewrite (#876, #887). It adds a post-statement block to
pgcolumnar_process_utility for AlterTableStmt and TruncateStmt, so it will conflict textually
with your hunk in that function, though not semantically: yours repairs a rename, mine repairs a
rewrite. Your PR removes the cause of a failure mode mine only degrades gracefully around — a
declaration left stale by a rename made my repair raise inside an unrelated ALTER TABLE until I made
it fail soft. I would rather land behind you. If you would like, push nothing further and I will
rebase #892 onto #888 once yours is merged.

@linuxhikerpm

Copy link
Copy Markdown
Author

Addressed the review in 2ba0f91:

  • added a public dump/restore/rebuild arm for a projection on a columnar partition renamed through its non-columnar parent, protecting the inheritor walk;
  • preserved the declaration array's NULL bitmap and documented the validated no-NULL invariant;
  • documented why the unindexed update scan's no-change arm is intentionally idempotent;
  • captured pg_dump and restore exit status immediately so the assertions cannot drift.

Relevant suites pass, and an uncontaminated full PG18 matrix reports 243 passed, 0 failed, 0 incomplete, with the two PG19-only skips.

@OffgridwithJD please re-review when convenient. @jdatcmd this push will need CI released again.

@OffgridwithJD OffgridwithJD 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.

Approving at 2ba0f910.

Everything I asked for is in, and the part that mattered I proved rather than read. The mutation that
left your previous suite fully green now reddens two arms:

your tree, UNMUTATED       .so 4fad9e322a10   8 passed, 0 failed
+ inheritor walk defeated  .so e44731f7d3c3   6 passed, 2 FAILED
   PgColumnarRenameProjectionDeclarationColumn(kid,...) -> (relid,...)

FAIL  the descendant declaration follows the parent rename: got [] want [1]
FAIL  the rebuilt child projection contains every restored row: got [] want [99]

Both arms built in the same directory with the mutation asserted present in the source beforehand and
absent after, so the two .so fingerprints differ by source alone.

All three of my non-blocking notes are addressed, and two are better than what I suggested:
construct_md_array preserves the null bitmap instead of merely documenting the path as unreachable,
and the seqscan-updated-in-place idempotence is now stated at columnar_metadata.c:3652 where it was
previously load-bearing and silent. The $? captures moved onto the same line as their commands.

CI is 12 for 12 on this head, which is the bar this repo holds and the reason I did not approve
earlier. My own runs were PG18 only.

Two notes, neither blocking.

This PR is still marked draft. I am approving anyway because the code and the gate are both ready,
but @jdatcmd cannot merge a draft, so mark it ready when you are happy with it.

Ordering. My #892 touches pgcolumnar_process_utility too, and it will conflict textually with
your hunk there while not conflicting semantically: yours repairs a rename before the statement, mine
repairs a rewrite after it. Yours should land first, because it removes the cause of a failure mode
mine can only degrade around. A declaration left stale by a rename made my repair raise inside an
unrelated ALTER TABLE until I made it warn and skip. I will rebase #892 onto this once it is in.

Good work. The partition arm you added is the kind that stays useful after the bug it was written for
is forgotten, because it fails for a structural reason rather than a coincidental one.

@jdatcmd

jdatcmd commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Reviewed. The change is right and the new arm is load-bearing — I proved that rather than taking
the review's word for it. Two things left before I can merge, and both are yours to do.

What I verified myself

CI on the exact head 2ba0f910: 12 of 12 green, and that includes both suites (PG 17) and
suites (PG 18), not only the build legs. Merging on build checks alone is a mistake this project
has made before, so I checked the run list rather than the summary tick.

Then the claim the approval actually rests on — that the arm added for the inheritor walk can
fail. I reproduced the mutation independently, in my own container and prefix:

arm                          .so             result
your head, unmutated         26dc3eb540a8    8 passed, 0 failed
kid -> relid in the walk     76cdd221e890    6 passed, 2 FAILED

FAIL  the descendant declaration follows the parent rename: got [] want [1]
FAIL  the rebuilt child projection contains every restored row: got [] want [99]

The mutation was asserted at source before the build (marker present, (kid count 0, (relid
count 1) and the neighbouring PgColumnarRenameDeclaredSortByColumn(kid, ...) was confirmed
unchanged, so the mutation is narrow and the two reds are attributable to it alone. Both arms
were built in the same build directory, which matters here: the .so fingerprint is a
function of the build path as well as the source, so per-arm build directories would have made
those two hashes differ whether or not the mutation applied.

Exactly the two descendant arms go red, and they go red for the right reason — the child's
declaration is never updated. That is what a load-bearing arm looks like.

The C reads well. rename_projection_declaration_array preserving the null bitmap for rows not
created through resolve_columns(), and the if (!changed) continue guard against re-visiting a
tuple updated in place during an unindexed seqscan, are both the right kind of careful. Placing
the new call directly beside PgColumnarRenameDeclaredSortByColumn inside the
find_all_inheritors walk is the correct seam.

Two blockers, neither of which I want to resolve on your behalf

1. This PR is still marked draft. GitHub will not merge it while it is. I would rather you
flip it than do it myself, because draft is your signal that you are not finished and overriding
it is not mine to do. If it is simply an oversight, mark it ready and I will merge.

2. There is no CHANGELOG.md entry. The last four merged PRs touching src/ all carry one
(#883, #880, #873, #872), so this is the house convention rather than a nitpick.

There is a wrinkle that is not your fault and is the reason I am explaining rather than just
asking
: #886 closed the changelog for 1.0-alpha3, so there is no [Unreleased] section to add
to right now — the top section is ## [1.0-alpha3] - 2026-09-02. Yours is the first change to
land after that close. So please add a new section above it:

## [Unreleased]

### Fixed

- `ALTER TABLE ... RENAME COLUMN` now carries the new name into
  `pgcolumnar.projection_declaration`, including for every inheritance
  descendant, so `rebuild_projections()` works after a dump and restore. The
  materialized projection stores attnums and already followed the rename; the
  declaration stores names because a restore assigns new attnums. (#888)

Wording is yours; the section heading and the ### Fixed grouping are what the file's Keep a
Changelog format expects.

One thing to expect

Every push to a fork PR from a read-permission account puts CI back on hold, and it presents as
no checks reported, which reads like "queued" and means "not run". So after you push these two
changes, ping here and I will get the run released again. Do not read the absence of checks as a
pass in the meantime.

Nothing else is outstanding from my side. Once it is ready and has the entry, I will merge it.

@jdatcmd
jdatcmd marked this pull request as ready for review September 9, 2026 00:04
@jdatcmd
jdatcmd merged commit d22d006 into commandprompt:main Sep 9, 2026
12 checks passed
@OffgridwithJD

Copy link
Copy Markdown
Collaborator

Post-merge confirmation across the majors CI does not cover, plus one trap worth recording.

ci.yml's suite job is matrix: pg: ['17', '18'], so 15, 16 and 19 run this suite in no gate
anywhere
— they are the local matrix's job. I ran your suite on all five, each with a real
make clean first:

PG 15.18     8 passed, 0 failed
PG 16.14     8 passed, 0 failed
PG 17.6      8 passed, 0 failed
PG 18.4      8 passed, 0 failed   (also CI)
PG 19beta2   8 passed, 0 failed

And the control, which is the half that matters: on main before your fix, at PG16, the same
suite reports 4 passed, 4 failed — including both new descendant arms. So it reddens on 16 as well
as 18, and your fix is what makes it green there.

The trap, because it cost me twenty minutes and will cost the next person the same

My first pass at this reported failures on 16, 17 and 19, and every one was my own harness. I looped
over majors with only rm -f src/*.o between them, which left one object file elsewhere in the tree.
The result:

FATAL:  could not load library ".../pgcolumnar.so": undefined symbol: bms_is_empty
pg15a postgres exports bms_is_empty:  1
pg16a/17a/18a/19a:                    0

bms_is_empty is an extern function in PG15 and became a static inline from PG16. So a single
object compiled against PG15 headers emits a call that no 16+ backend resolves, and the library is
refused at load with a message that looks like a source defect. The .so md5 differed between the
contaminated build and a clean one, which is what gave it away.

test/build_all_versions.sh and pgc_setup's own stamp logic both handle this correctly. A
hand-rolled loop across majors does not, unless it runs make clean per major. Worth knowing before
anyone else tries to check a change across majors by hand.

Nothing here changes the merge. Your suite is green on every packaged major and reddens on main.

jdatcmd added a commit that referenced this pull request Sep 9, 2026
docs: open [Unreleased] and record the rename fix (#888)
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 9, 2026
commandprompt#888 merged without a changelog entry. Every recent PR touching src/ carries one
(commandprompt#883, commandprompt#880, commandprompt#873, commandprompt#872), and this one had a reason to be awkward rather than a
reason to be absent: commandprompt#886 closed the changelog for 1.0-alpha3, so there was no
[Unreleased] section to add to. This opens one.

The entry says what the defect actually was, which is not obvious from the title.
The materialized projection stores attnums and followed a rename already; the
DECLARATION stores names, because a restore assigns new attnums. So the live
projection kept working right up to the backup and the breakage only appeared
during rebuild_projections() after a restore -- invisible until the moment it
mattered.

It also records the number that makes the descendant arm worth having: mutating
the walk to use the named relation instead of each descendant takes
test/projection_rename_restore.sh from 8 passed to 6 passed and 2 failed. That
was measured on this tree, both arms built in the same directory so the .so
fingerprint reflects the source and not the build path.

docs_style.sh: 9 checks, PASSED.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Unuuvh3fRR67SceiGpfeeK
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 9, 2026
Three changes, all to CHANGELOG.md.

1. commandprompt#891 gets an entry. It merged without one, the same gap commandprompt#888 had, except the
   excuse is gone: commandprompt#893 opened [Unreleased], so there was a section to add to.
   The entry says what the symptom actually was, because the PR title does not:
   the next INSERT failed with "type with OID 0 does not exist" and the table
   stayed in that state.

   The scope in my first draft was wrong and I checked it against the merged
   code rather than shipping the peer's summary of it. I had written "a column
   named in a projection's sort key". The guard loops over
   projection->columns -- every column the projection STORES -- and its own
   comment explains that this covers sort keys as a consequence, because
   add_projection() requires every sort-key column to appear in columns. So the
   refusal is broader than "sort key" and the entry now says so.
   SQLSTATE read from ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST at
   src/columnar_tableam.c:2582, not from the PR description.

2. The intro said 1.0-alpha3 was "in development and not yet tagged; the latest
   published pre-release is v1.0-alpha2". It is tagged, and the tag is correct.
   I found this while filing a release-integrity issue that was itself wrong --
   git fetch does not update an existing local tag ref, so git rev-parse showed
   a position the tag had been deliberately moved off days earlier. The issue is
   closed; this sentence was the one true thing in it.

3. commandprompt#888's entry said "every inheritance descendant". The arm proves a
   PARTITION OF child, and a reader with a partitioned table searches for that
   word. Both are covered by find_all_inheritors; now both are named.
   (OffgridwithJD, commandprompt#893 review.)

docs_style.sh: 9 checks, PASSED.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Unuuvh3fRR67SceiGpfeeK
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 9, 2026
…dprompt#887)

A rewrite mints a new base storage id and pgcolumnar.projection is keyed by
that id, so after TRUNCATE or a rewriting ALTER TABLE, read_projection raised
42704 for a projection that was still declared over an intact table.
1.0-alpha3 shipped only a HINT naming pgcolumnar.rebuild_projections().

The repair runs after the statement in pgcolumnar_process_utility, where the
rewrite has committed, the new storage id is readable, and a statement that
errored has left nothing to repair.

Not in pgcolumnar_relation_set_new_filelocator, which commandprompt#887 proposed. Measured
with that callback logging its own relid: TRUNCATE reaches it as the user's
relation with both projection rows in scope, but a rewriting ALTER TABLE
reaches it as the transient relation make_new_heap builds -- pg_temp_<oid>,
no columnar fork -- so the branch is not taken and neither the old storage id
nor the projection list is ever in scope. A re-record there also records under
the retired id, because PgColumnarStorageId(rel) still returns the old id
after the new metapage is written.

Four shapes lose the projection, not the two commandprompt#887 names: TRUNCATE including
its multi-table form, a type change on a covered or uncovered column, ADD
COLUMN with a volatile default, and a partitioned child rewritten via its
parent -- where the statement names the parent, which is not itself a
columnar relation. Hence find_all_inheritors. Core VACUUM FULL and CLUSTER
are refused on a columnar table, which bounds the class.

materialize_projection is extracted from pgcolumnar_add_projection rather
than copied, so declaring and re-recording drive one implementation. The
projections are re-derived from the declaration, not copied forward: the base
projection records every live column, so copying the old row would leave
projection 0 naming a stale column set after ADD COLUMN.

A repair attached to another statement must not fail it. ALTER TABLE ...
RENAME COLUMN does not carry a rename into the declaration (commandprompt#888), and before
this was handled the repair raised `column "a" does not exist` inside an
unrelated ALTER COLUMN ... TYPE and rolled that type change back. It now
warns and leaves the projection to rebuild_projections().

test/projection_rewrite.sh is new and was written before the fix: 38 passed /
9 failed on main 9628414, 53 passed / 0 failed here, both arms through the
same build directory. The 42704 hint no longer blames a rewrite; it names the
two cases that remain, one of which is the implicit base projection, which is
not readable by name at all.

No SQL and no catalog change, so no upgrade script.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 9, 2026
…ot close

Rebasing onto main, which now carries commandprompt#888, made three of this suite's arms
unrunnable, and the suite said so rather than passing them.

    UNRUN  stale: the statement survives a stale declaration:
           UNMET_PRECONDITION: declaration is {a2,b}, not stale; commandprompt#888 may have landed
    accounting: 52 passed + 0 failed + 3 unrunnable = 55
    projection_rewrite.sh: INCOMPLETE   exit 67

That is the intended behaviour and the reason the premise was asserted separately.
Those arms test that a repair which cannot run degrades to a WARNING instead of
aborting the statement that triggered it. They produced the stale declaration with
ALTER TABLE ... RENAME COLUMN, which commandprompt#888 has now fixed, so the state they need can
no longer be reached that way and the property they test would have gone untested
while three green ticks suggested otherwise.

The property is still worth testing, because the state is still reachable: any
database created before commandprompt#888 carries it, and nothing guarantees a future path cannot
reintroduce it. So the arms now write the stale name directly into
pgcolumnar.projection_declaration, which is what such a database looks like, and the
premise asserts the write took effect.

Two arms are added for the property commandprompt#888 now guarantees, asserted positively here
because this suite is the one that breaks if it regresses: a rename carries into the
declaration, and the repair after a later rewrite still resolves.

60 checks, 0 failed, 0 unrunnable on the rebased tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a
OffgridwithJD pushed a commit to OffgridwithJD/pgcolumnar that referenced this pull request Sep 9, 2026
docs/limitations.md documented a limitation main has already fixed: commandprompt#888 landed,
so RENAME COLUMN does carry the rename into the declaration. The reachable case
is now a database created before that fix, and the page says so.

docs/sql-reference.md gave the wrong reason for the one case still needing
rebuild_projections(), and pointed at that function for a case it cannot fix.
Both pages now name add_projection() as the recovery for an unresolvable
declaration, because that is the call measured to work.

Both record the rewrite this extension cannot see. A TRUNCATE replicated to a
subscriber is applied by the logical replication worker calling
ExecuteTruncateGuts directly rather than going through ProcessUtility
(src/backend/replication/logical/worker.c, apply_handle_truncate, read against
PostgreSQL 18.4). I could not complete a live publisher/subscriber
demonstration on the harness cluster -- CREATE SUBSCRIPTION hung -- so this is
sourced from core rather than reproduced, and the wording says which.

CHANGELOG records five lost shapes rather than four, the lock and containment
changes, the recorded-relid design, and the corrected check count of 84.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a
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.

3 participants