Skip to content

fix: attnum drift causes index mismatch with inheritance/hypertables (#288)#289

Merged
tjgreen42 merged 2 commits intomainfrom
fix/attnum-drift-inheritance
Mar 18, 2026
Merged

fix: attnum drift causes index mismatch with inheritance/hypertables (#288)#289
tjgreen42 merged 2 commits intomainfrom
fix/attnum-drift-inheritance

Conversation

@tjgreen42
Copy link
Copy Markdown
Collaborator

Summary

Fixes #288.

When a parent table has dropped columns, child tables created afterward
don't inherit the dropped-column slot. This causes the same logical column
to have different physical attnum values in parent vs child. Two code
paths compared raw attnums and rejected valid parent/child BM25 index pairs:

  • indexes_match_by_attribute() in src/am/scan.c — the index scan
    validation path. Failed with ERROR: tpquery index mismatch.
  • find_first_child_bm25_index() in src/types/query.c — the scoring
    fallback path. Silently returned no matching child index.

Both now resolve attnums to column names via get_attname() and compare
those instead. This handles TimescaleDB hypertables, plain INHERITS
tables, and any other case where dropped columns cause attnum divergence.

Reproduces without TimescaleDB using plain inheritance:

CREATE TABLE parent (id serial, extra text, content text);
INSERT INTO parent (extra, content) VALUES ('x', 'some document');
ALTER TABLE parent DROP COLUMN extra;
CREATE TABLE child () INHERITS (parent);
INSERT INTO child (content) VALUES ('another document');
CREATE INDEX p_bm25 ON parent USING bm25 (content) WITH (text_config='english');
CREATE INDEX c_bm25 ON child USING bm25 (content) WITH (text_config='english');
-- Before fix: ERROR: tpquery index mismatch
-- After fix: works
SET enable_seqscan = off;
SELECT content <@> 'document' FROM parent ORDER BY content <@> 'document' LIMIT 5;

Testing

  • Added regression tests to test/sql/inheritance.sql (Test 4a and 4b)
    covering both the index scan path and the scoring fallback path
  • All 52 regression tests pass

…288)

When a parent table has dropped columns, child tables created after
the drop get different physical attnums for the same logical column.
Compare indexed column names instead of raw attnums when matching
parent/child BM25 indexes.
@tjgreen42 tjgreen42 marked this pull request as ready for review March 18, 2026 01:40
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

LGTM — the column-name comparison approach is correct and well-tested; the two inline nits are low-impact and only reachable under catalog corruption.

Extended reasoning...

Overview

This PR modifies two code paths in src/am/scan.c (indexes_match_by_attribute) and src/types/query.c (find_first_child_bm25_index, bm25_text_bm25query_score) to compare column names instead of raw attribute numbers when matching parent/child BM25 indexes. Regression tests covering both paths are added to test/sql/inheritance.sql and test/expected/inheritance.out.

Security risks

None. The change is a catalog lookup substitution; no auth, crypto, or permission logic is touched.

Level of scrutiny

Moderate. The change is a targeted bug fix with a clear root cause (attnum drift after ALTER TABLE DROP COLUMN). The logic—resolve attnum → column name, compare names—is sound and mirrors the already-correct pattern used in find_first_child_bm25_index at query.c:493. Regression output confirms the tests pass and attnum drift is demonstrably present and handled.

Other factors

The two bugs flagged by the inline comments (both missing_ok=false instead of true) are real but minor: one causes dead NULL-guard code in scan.c with no incorrect behavior; the other creates a theoretical index_rel leak in query.c that only fires under catalog corruption and is reclaimed by PostgreSQL's ResourceOwner at transaction abort regardless. Neither is a regression introduced by this PR relative to the pre-fix behavior, and both could be cleaned up in a small follow-on. The core fix is correct and the test coverage is solid.

Address code review: get_attname with missing_ok=false would
ereport(ERROR) instead of returning NULL, making the NULL guards
dead code. Use missing_ok=true to match the pattern in
find_first_child_bm25_index and allow graceful fallback.
@tjgreen42 tjgreen42 merged commit 81b891e into main Mar 18, 2026
19 checks passed
@tjgreen42 tjgreen42 deleted the fix/attnum-drift-inheritance branch March 18, 2026 05:09
@creatorrr
Copy link
Copy Markdown

@tjgreen42 any rough expected timeline for a v0.6.2 patch release landing this change and ideally #292 ? or should i build from main branch directly?

@tjgreen42
Copy link
Copy Markdown
Collaborator Author

@tjgreen42 any rough expected timeline for a v0.6.2 patch release landing this change and ideally #292 ? or should i build from main branch directly?

@creatorrr I'm planning to cut the v1.0.0 release later this week, so you can either wait for that, or build from main directly for now.

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.

Timescale hypertable BM25 scans fail when parent/chunk indexed-column attnums drift

2 participants