Skip to content

Fix wrong-result and crash bugs in summary build, maintenance and pruning (0.1.2) - #4

Merged
bitner merged 1 commit into
mainfrom
fix-pruning-correctness
Oct 21, 2026
Merged

bitner merged 1 commit into
mainfrom
fix-pruning-correctness

Conversation

@bitner

@bitner bitner commented Oct 21, 2026

Copy link
Copy Markdown
Owner

Correctness release (0.1.2). 0.1.1 can return wrong results (missing rows) and can crash the cluster. Every case below was reproduced against 0.1.1 and is covered by a test here. Full list in CHANGELOG.md.

Crashes

  • Any planning-time ERROR (e.g. SELECT 1/0) in a backend that had loaded the extension aborted the backend, so the whole cluster restarted. The planner hooks are now #[pg_guard]ed.
  • REINDEX of a table_range index crashed the same way: the SPI build planned SQL over a heap whose index was being reindexed.

Wrong results

  • Cached plans (PREPARE, PL/pgSQL) kept pruning after an insert widened a summary. Widening now invalidates the heap's relcache entry, not just the index's.
  • The per-transaction dedup of invalidations lost them across statements and rolled-back savepoints. Removed: PostgreSQL already coalesces them per command.
  • Concurrent inserts could overwrite each other's widening. Now a compare-and-swap under the buffer lock.
  • Failed widenings were swallowed. They now raise, or mark the column unbounded (e.g. a value too large for the metapage).
  • Partial indexes are now rejected.
  • Builds used an MVCC snapshot via SPI. They now use the table AM's index-build scan, which covers rows committed after a REPEATABLE READ snapshot and rows still visible to older snapshots.
  • Bounds depended on DateStyle/extra_float_digits. These are now pinned while bounds are written and read.
  • Cross-type constants were re-parsed as the column type. Now compared via the operator family's cross-type proc.
  • Comparisons under a different collation from the summary's were pruned. They are now kept.

Other

  • Builds report the real heap_tuples (0.1.1 set reltuples to 0).
  • uuid/boolean columns now build: min()/max() aggregates are no longer used.
  • All extension SQL is schema-qualified. This lets geometry builds run under PG17+'s restricted search_path and stops a caller's search_path from substituting functions.
  • amsummarizing = true, so updates of indexed columns can stay HOT.
  • On-page format v2. v1 summaries are ignored until REINDEX. sql/pg_table_range--0.1.1--0.1.2.sql warns how many indexes need it.

Upgrade

Install, restart PostgreSQL (a backend still running 0.1.1 cannot read v2 summaries and would skip widening them), then ALTER EXTENSION pg_table_range UPDATE, then REINDEX each table_range index.

Testing

  • cargo pgrx test: 43/43 on PG18, and on PG16 with PostGIS installed. Not run locally on PG17.
  • New tests/multisession.sh (cross-backend invalidation, REPEATABLE READ build, concurrent widening) passes on 0.1.2 and fails on 0.1.1. It is wired into CI; that step has not run on GitHub yet.
  • README benchmarks re-run (PG 18.4, release build). table_range planning is within noise of the no-pruning baseline and faster than CHECK constraint exclusion. Insert latency and WAL are unchanged.

Known limits (marked shortcut: in code)

  • A widening insert still writes a full-page WAL image (~8 KB).
  • Bounds are stored as text.
  • Geometry extents go through SQL.
  • Under READ COMMITTED, a widening that commits between planning and execution can be missed by that one execution.

🤖 Generated with Claude Code

@bitner
bitner merged commit fd5a3cd into main Oct 21, 2026
6 checks passed
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.

1 participant