postgresql/src/include/access
Tomas Vondra d78a66d92c Fix handling of empty ranges and NULLs in BRIN
BRIN indexes did not properly distinguish between summaries for empty
(no rows) and all-NULL ranges, treating them as essentially the same
thing. Summaries were initialized with allnulls=true, and opclasses
simply reset allnulls to false when processing the first non-NULL value.
This however produces incorrect results if the range starts with a NULL
value (or a sequence of NULL values), in which case we forget the range
contains NULL values when adding the first non-NULL value.

This happens because the allnulls flag is used for two separate
purposes - to mark empty ranges (not representing any rows yet) and
ranges containing only NULL values.

Opclasses don't know which of these cases it is, and so don't know
whether to set hasnulls=true. Setting the flag in both cases would make
it correct, but it would also make BRIN indexes useless for queries with
IS NULL clauses. All ranges start empty (and thus allnulls=true), so all
ranges would end up with either allnulls=true or hasnulls=true.

The severity of the issue is somewhat reduced by the fact that it only
happens when adding values to an existing summary with allnulls=true.
This can happen e.g. for small tables (because a summary for the first
range exists for all BRIN indexes), or for tables with large fraction of
NULL values in the indexed columns.

Bulk summarization (e.g. during CREATE INDEX or automatic summarization)
that processes all values at once is not affected by this issue. In this
case the flags were updated in a slightly different way, not forgetting
the NULL values.

To identify empty ranges we use a new flag, stored in an unused bit in
the BRIN tuple header so the on-disk format remains the same. A matching
flag is added to BrinMemTuple, into a 3B gap after bt_placeholder.
That means there's no risk of ABI breakage, although we don't actually
pass the BrinMemTuple to any public API.

We could also skip storing index tuples for empty summaries, but then
we'd have to always process such ranges - even if there are no rows in
large parts of the table (e.g. after a bulk DELETE), it would still
require reading the pages etc. So we store them, but ignore them when
building the bitmap.

Backpatch to 11. The issue exists since BRIN indexes were introduced in
9.5, but older releases are already EOL.

Backpatch-through: 11
Reviewed-by: Justin Pryzby, Matthias van de Meent, Alvaro Herrera
Discussion: https://postgr.es/m/402430e4-7d9d-6cf1-09ef-464d80afff3b@enterprisedb.com
2023-05-19 00:16:13 +02:00
..
amapi.h Initial pgindent run for v12. 2019-05-22 12:55:34 -04:00
amvalidate.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
attnum.h Fix many typos and inconsistencies 2019-07-01 10:00:23 +09:00
brin.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
brin_internal.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
brin_page.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
brin_pageops.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
brin_revmap.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
brin_tuple.h Fix handling of empty ranges and NULLs in BRIN 2023-05-19 00:16:13 +02:00
brin_xlog.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
bufmask.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
clog.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
commit_ts.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
genam.h Improve handling of NULLs in KNN-GiST and KNN-SP-GiST 2019-09-19 21:49:07 +03:00
generic_xlog.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
gin.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
gin_private.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
ginblock.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
ginxlog.h Generate less WAL during GiST, GIN and SP-GiST index build. 2019-04-03 17:03:15 +03:00
gist.h Use full 64-bit XID for checking if a deleted GiST page is old enough. 2019-07-24 20:25:22 +03:00
gist_private.h Revert "Skip WAL for new relfilenodes, under wal_level=minimal." 2020-03-22 09:24:13 -07:00
gistscan.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
gistxlog.h Revert "Skip WAL for new relfilenodes, under wal_level=minimal." 2020-03-22 09:24:13 -07:00
hash.h Get rid of trailing semicolons in C macro definitions. 2020-05-01 17:28:00 -04:00
hash_xlog.h Compute XID horizon for page level index vacuum on primary. 2019-03-26 16:52:54 -07:00
heapam.h Prevent access to no-longer-pinned buffer in heapam_tuple_lock(). 2022-04-13 13:35:02 -04:00
heapam_xlog.h C comment: remove mention of use of t_hoff WAL structure member 2020-08-31 17:51:31 -04:00
hio.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
htup.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
htup_details.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
itup.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
multixact.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
nbtree.h Get rid of trailing semicolons in C macro definitions. 2020-05-01 17:28:00 -04:00
nbtxlog.h Fix nbtree page split rmgr desc routine. 2019-09-12 15:45:07 -07:00
parallel.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
printsimple.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
printtup.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
relation.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
reloptions.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
relscan.h Initial pgindent run for v12. 2019-05-22 12:55:34 -04:00
rewriteheap.h Revert "Skip WAL for new relfilenodes, under wal_level=minimal." 2020-03-22 09:24:13 -07:00
rmgr.h Phase 2 of pgindent updates. 2017-06-21 15:19:25 -04:00
rmgrlist.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
sdir.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
session.h Fix typo. 2020-01-13 14:52:59 +05:30
skey.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
slru.h Prevent excess SimpleLruTruncate() deletion. 2021-01-16 12:21:39 -08:00
spgist.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
spgist_private.h Improve handling of NULLs in KNN-GiST and KNN-SP-GiST 2019-09-19 21:49:07 +03:00
spgxlog.h Initial pgindent run for v12. 2019-05-22 12:55:34 -04:00
stratnum.h Move hash_any prototype from access/hash.h to utils/hashutils.h 2019-03-11 13:17:50 -03:00
subtrans.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
sysattr.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
table.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
tableam.h Fix comments related to table AMs 2020-07-14 13:17:34 +09:00
timeline.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
transam.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
tsmapi.h tableam: sample scan. 2019-03-31 18:37:57 -07:00
tupconvert.h Fix permission checks on constraint violation errors on partitions. 2021-02-08 11:01:55 +02:00
tupdesc.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
tupdesc_details.h Make naming of tupdesc related structs more consistent with the rest of PG. 2019-01-14 16:25:50 -08:00
tupmacs.h Improve comment for att_isnull. 2019-05-13 13:13:24 -04:00
tuptoaster.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
twophase.h Fix CREATE INDEX CONCURRENTLY for the newest prepared transactions. 2021-10-23 18:36:42 -07:00
twophase_rmgr.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
valid.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
visibilitymap.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
xact.h Rethink handling of [Prevent|Is]InTransactionBlock in pipeline mode. 2022-12-13 14:23:59 -05:00
xlog.h Revert "Avoid creating archive status ".ready" files too early" 2021-09-04 12:14:30 -04:00
xlog_internal.h Fix WAL replay in presence of an incomplete record 2021-09-29 11:21:51 -03:00
xlogdefs.h Revert "Avoid creating archive status ".ready" files too early" 2021-09-04 12:14:30 -04:00
xloginsert.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00
xlogreader.h Fix WAL replay in presence of an incomplete record 2021-09-29 11:21:51 -03:00
xlogrecord.h Update copyright for 2019 2019-01-02 12:44:25 -05:00
xlogutils.h Phase 2 pgindent run for v12. 2019-05-22 13:04:48 -04:00