CHANGELOG
1.0.3
- perf: stripe-level min/max pruning for colcompress scans — before reading
any stripe, the scan aggregates the per-column min/max statistics from
engine.chunkacross all chunks of the stripe and tests the resulting stripe-wide ranges against the query’s WHERE predicates usingpredicate_refuted_by. Any stripe whose range is provably disjoint from the predicate is skipped entirely — no decompression, no I/O. The pruned count is shown inEXPLAIN:
Engine Stripes Removed by Pruning: N
Pruning applies to both the serial scan path and the parallel DSM path
(parallel workers only receive stripe IDs that survive the filter).
Effectiveness scales directly with data sortedness; combine with
engine.colcompress_merge() and the orderby table option to maximise it.
1.0.2
- fix: index corruption during
COPYinto colcompress tables —engine_multi_insertwas callingExecInsertIndexTuples()internally, while COPY’sCopyMultiInsertBufferFlushalso calls it aftertable_multi_insertreturns. The double insertion corrupted every B-tree index on tables loaded viaCOPY. Fixed by removing all executor infrastructure from the per-tuple loop; index insertion is the caller’s responsibility, matchingheap_multi_insertsemantics. - fix: index corruption when
orderbyand indexes coexist — when sort-on-write is active,ColumnarWriteRow()buffers rows and returnsCOLUMNAR_FIRST_ROW_NUMBER(= 1) as a placeholder for every row. The executor then indexed all rows with TID(0,1), making every index lookup return the first row. Fixed inengine_init_write_state(): sort-on-write is disabled when the target relation hasrelhasindex = true. Tables with indexes already have fast key access; sort ordering is redundant and was silently lethal. - perf: fast
ANALYZEvia chunk-group stride sampling — samples at mostN / stridechunk groups (stride = max(1, nchunks / 300)) instead of reading the entire table, makingANALYZEon large colcompress tables milliseconds instead of minutes.
Migration note (1.0.1 → 1.0.2): any colcompress table that has indexes and was written with
COPYorcolcompress_mergeusing a prior version must be rebuilt:REINDEX TABLE CONCURRENTLY <table>;
1.0.1
- fix:
multi_insertnow setstts_tidbefore opening indexes, and explicitly callsExecInsertIndexTuples()— previously B-tree entries received garbage TIDs duringINSERT INTO ... SELECT, causing index scans to return wrong rows. Tables populated before this fix requireREINDEX TABLE CONCURRENTLY. - fix:
orderbysyntax is now validated atALTER TABLE SET (orderby=...)time instead of at merge time, giving an immediate error on bad input. - fix: CustomScan node names renamed to avoid symbol collision with
columnar.sowhen both extensions are loaded simultaneously. - fix: corrected SQL function names for
se_alter_engine_table_set/se_alter_engine_table_reset(C symbols were mismatched). - fix: added
safeclibsymlink undervendor/somemcpy_sresolves correctly at link time. - add:
META.jsonfor PGXN publication.
1.0.0
Initial release of storage_engine — a PostgreSQL table access method extension derived from Hydra Columnar and extended with two independent access methods:
- colcompress — column-oriented storage with vectorized execution, parallel
DSM scan, chunk pruning, and a MergeTree-style per-table sort key (
orderby). - rowcompress — row-compressed batch storage with parallel work-stealing scan and full DELETE/UPDATE support via a row-level mask.
Additional features added beyond the upstream:
- per-table
index_scanoption (GUCstorage_engine.enable_index_scan) - full DELETE/UPDATE support for colcompress via row mask
- parallel columnar scan wired through DSM
- GUCs under the
storage_engine.*namespace - support for PostgreSQL 16, 17, and 18