During a stress test of an experimental patch (which implements a new technique for managing B-Tree index bloat caused by non-HOT updates), I noticed a minor bug in _bt_truncate(). The issue affects Postgres 12 + master.
The problem is that INCLUDE indexes don't have their non-key attributes physically truncated away in a small minority of cases. I say "physically" because we nevertheless encode the number of remaining key attributes in the tuple correctly in all cases (we also correctly encode the presence or absence of the special pivot tuple heap TID representation in all cases). That is, we don't consistently avoid non-key attribute space overhead in the new high key, even though _bt_truncate() is clearly supposed to consistently avoid said overhead. Even when it must add a heap TID to the high key using the special pivot representation of heap TID, it shouldn't have to keep around the non-key attributes. This only happens when we cannot truncate away any key columns (and must therefore include a heap TID in the new leaf high key) in an INCLUDE index. This condition is rare because in general nbtsplitloc.c goes out of its way to at least avoid having to include a heap TID in new leaf page high keys. It's also rare because INCLUDE indexes are generally only used with unique constraints/indexes, which makes it particularly likely that nbtsplitloc.c will be able to avoid including a heap TID in the final high key (unique indexes seldom have enough duplicates to make nbtsplitloc.c ever use its "single value" strategy). Attached patch fixes the issue. Barring objections, I'll push this to v12 + master branches early next week. The bug is low severity, but then the fix is very low risk. -- Peter Geoghegan
v1-0001-Consistently-truncate-non-key-suffix-columns.patch
Description: Binary data