Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a6ddb8a

Browse files
committed
amcheck: Support for different header sizes of short varlena datum
In the heap, tuples may contain short varlena datum with both 1B header and 4B headers. But the corresponding index tuple should always have such varlena's with 1B headers. So, for fingerprinting, we need to convert. Backpatch to all supported versions. Discussion: https://postgr.es/m/flat/7bdbe559-d61a-4ae4-a6e1-48abdf3024cc%40postgrespro.ru Author: Michael Zhilin Reviewed-by: Alexander Lakhin, Andrey Borodin, Jian He, Alexander Korotkov Backpatch-through: 12
1 parent 14e991d commit a6ddb8a

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

contrib/amcheck/expected/check_btree.out

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,18 @@ SELECT bt_index_check('bttest_a_expr_idx', true);
199199

200200
(1 row)
201201

202+
-- Check support of both 1B and 4B header sizes of short varlena datum
203+
CREATE TABLE varlena_bug (v text);
204+
ALTER TABLE varlena_bug ALTER column v SET storage plain;
205+
INSERT INTO varlena_bug VALUES ('x');
206+
COPY varlena_bug from stdin;
207+
CREATE INDEX varlena_bug_idx on varlena_bug(v);
208+
SELECT bt_index_check('varlena_bug_idx', true);
209+
bt_index_check
210+
----------------
211+
212+
(1 row)
213+
202214
-- cleanup
203215
DROP TABLE bttest_a;
204216
DROP TABLE bttest_b;
@@ -208,3 +220,4 @@ DROP TABLE toast_bug;
208220
DROP FUNCTION ifun(int8);
209221
DROP OWNED BY regress_bttest_role; -- permissions
210222
DROP ROLE regress_bttest_role;
223+
DROP TABLE varlena_bug;

contrib/amcheck/sql/check_btree.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ CREATE INDEX bttest_a_expr_idx ON bttest_a ((ifun(id) + ifun(0)))
135135

136136
SELECT bt_index_check('bttest_a_expr_idx', true);
137137

138+
-- Check support of both 1B and 4B header sizes of short varlena datum
139+
CREATE TABLE varlena_bug (v text);
140+
ALTER TABLE varlena_bug ALTER column v SET storage plain;
141+
INSERT INTO varlena_bug VALUES ('x');
142+
COPY varlena_bug from stdin;
143+
x
144+
\.
145+
CREATE INDEX varlena_bug_idx on varlena_bug(v);
146+
SELECT bt_index_check('varlena_bug_idx', true);
147+
138148
-- cleanup
139149
DROP TABLE bttest_a;
140150
DROP TABLE bttest_b;
@@ -144,3 +154,4 @@ DROP TABLE toast_bug;
144154
DROP FUNCTION ifun(int8);
145155
DROP OWNED BY regress_bttest_role; -- permissions
146156
DROP ROLE regress_bttest_role;
157+
DROP TABLE varlena_bug;

contrib/amcheck/verify_nbtree.c

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2642,7 +2642,7 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
26422642
TupleDesc tupleDescriptor = RelationGetDescr(state->rel);
26432643
Datum normalized[INDEX_MAX_KEYS];
26442644
bool isnull[INDEX_MAX_KEYS];
2645-
bool toast_free[INDEX_MAX_KEYS];
2645+
bool need_free[INDEX_MAX_KEYS];
26462646
bool formnewtup = false;
26472647
IndexTuple reformed;
26482648
int i;
@@ -2661,7 +2661,7 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
26612661
att = TupleDescAttr(tupleDescriptor, i);
26622662

26632663
/* Assume untoasted/already normalized datum initially */
2664-
toast_free[i] = false;
2664+
need_free[i] = false;
26652665
normalized[i] = index_getattr(itup, att->attnum,
26662666
tupleDescriptor,
26672667
&isnull[i]);
@@ -2684,11 +2684,32 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
26842684
{
26852685
formnewtup = true;
26862686
normalized[i] = PointerGetDatum(PG_DETOAST_DATUM(normalized[i]));
2687-
toast_free[i] = true;
2687+
need_free[i] = true;
2688+
}
2689+
2690+
/*
2691+
* Short tuples may have 1B or 4B header. Convert 4B header of short
2692+
* tuples to 1B
2693+
*/
2694+
else if (VARATT_CAN_MAKE_SHORT(DatumGetPointer(normalized[i])))
2695+
{
2696+
/* convert to short varlena */
2697+
Size len = VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(normalized[i]));
2698+
char *data = palloc(len);
2699+
2700+
SET_VARSIZE_SHORT(data, len);
2701+
memcpy(data + 1, VARDATA(DatumGetPointer(normalized[i])), len - 1);
2702+
2703+
formnewtup = true;
2704+
normalized[i] = PointerGetDatum(data);
2705+
need_free[i] = true;
26882706
}
26892707
}
26902708

2691-
/* Easier case: Tuple has varlena datums, none of which are compressed */
2709+
/*
2710+
* Easier case: Tuple has varlena datums, none of which are compressed or
2711+
* short with 4B header
2712+
*/
26922713
if (!formnewtup)
26932714
return itup;
26942715

@@ -2698,6 +2719,11 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
26982719
* (normalized input datums). This is rather naive, but shouldn't be
26992720
* necessary too often.
27002721
*
2722+
* In the heap, tuples may contain short varlena datums with both 1B
2723+
* header and 4B headers. But the corresponding index tuple should always
2724+
* have such varlena's with 1B headers. So, if there is a short varlena
2725+
* with 4B header, we need to convert it for for fingerprinting.
2726+
*
27012727
* Note that we rely on deterministic index_form_tuple() TOAST compression
27022728
* of normalized input.
27032729
*/
@@ -2706,7 +2732,7 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
27062732

27072733
/* Cannot leak memory here */
27082734
for (i = 0; i < tupleDescriptor->natts; i++)
2709-
if (toast_free[i])
2735+
if (need_free[i])
27102736
pfree(DatumGetPointer(normalized[i]));
27112737

27122738
return reformed;

0 commit comments

Comments
 (0)