amcheck: Normalize index tuples containing uncompressed varlena

It might happen that the varlena value wasn't compressed by index_form_tuple()
due to current storage parameters.  If compression is currently enabled, we
need to compress such values to match index tuple coming from the heap.

Backpatch to all supported versions.

Discussion: https://postgr.es/m/flat/7bdbe559-d61a-4ae4-a6e1-48abdf3024cc%40postgrespro.ru
Author: Andrey Borodin
Reviewed-by: Alexander Lakhin, Michael Zhilin, Jian He, Alexander Korotkov
Backpatch-through: 12
This commit is contained in:
Alexander Korotkov 2024-03-23 23:00:06 +02:00
parent e2c2414165
commit 5cc1f26263
3 changed files with 29 additions and 0 deletions

View File

@ -211,6 +211,16 @@ SELECT bt_index_check('varlena_bug_idx', true);
(1 row)
-- Also check that we compress varlena values, which were previously stored
-- uncompressed in index.
INSERT INTO varlena_bug VALUES (repeat('Test', 250));
ALTER TABLE varlena_bug ALTER COLUMN v SET STORAGE extended;
SELECT bt_index_check('varlena_bug_idx', true);
bt_index_check
----------------
(1 row)
-- cleanup
DROP TABLE bttest_a;
DROP TABLE bttest_b;

View File

@ -145,6 +145,12 @@ x
CREATE INDEX varlena_bug_idx on varlena_bug(v);
SELECT bt_index_check('varlena_bug_idx', true);
-- Also check that we compress varlena values, which were previously stored
-- uncompressed in index.
INSERT INTO varlena_bug VALUES (repeat('Test', 250));
ALTER TABLE varlena_bug ALTER COLUMN v SET STORAGE extended;
SELECT bt_index_check('varlena_bug_idx', true);
-- cleanup
DROP TABLE bttest_a;
DROP TABLE bttest_b;

View File

@ -23,6 +23,7 @@
*/
#include "postgres.h"
#include "access/heaptoast.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/table.h"
@ -2561,6 +2562,18 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
ItemPointerGetBlockNumber(&(itup->t_tid)),
ItemPointerGetOffsetNumber(&(itup->t_tid)),
RelationGetRelationName(state->rel))));
else if (!VARATT_IS_COMPRESSED(DatumGetPointer(normalized[i])) &&
VARSIZE(DatumGetPointer(normalized[i])) > TOAST_INDEX_TARGET &&
(att->attstorage == TYPSTORAGE_EXTENDED ||
att->attstorage == TYPSTORAGE_MAIN))
{
/*
* This value will be compressed by index_form_tuple() with the
* current storage settings. We may be here because this tuple
* was formed with different storage settings. So, force forming.
*/
formnewtup = true;
}
else if (VARATT_IS_COMPRESSED(DatumGetPointer(normalized[i])))
{
formnewtup = true;