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

Commit 50f8611

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 82c2192 commit 50f8611

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
@@ -190,6 +190,18 @@ SELECT bt_index_check('bttest_a_expr_idx', true);
190190

191191
(1 row)
192192

193+
-- Check support of both 1B and 4B header sizes of short varlena datum
194+
CREATE TABLE varlena_bug (v text);
195+
ALTER TABLE varlena_bug ALTER column v SET storage plain;
196+
INSERT INTO varlena_bug VALUES ('x');
197+
COPY varlena_bug from stdin;
198+
CREATE INDEX varlena_bug_idx on varlena_bug(v);
199+
SELECT bt_index_check('varlena_bug_idx', true);
200+
bt_index_check
201+
----------------
202+
203+
(1 row)
204+
193205
-- cleanup
194206
DROP TABLE bttest_a;
195207
DROP TABLE bttest_b;
@@ -199,3 +211,4 @@ DROP TABLE toast_bug;
199211
DROP FUNCTION ifun(int8);
200212
DROP OWNED BY regress_bttest_role; -- permissions
201213
DROP ROLE regress_bttest_role;
214+
DROP TABLE varlena_bug;

contrib/amcheck/sql/check_btree.sql

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

131131
SELECT bt_index_check('bttest_a_expr_idx', true);
132132

133+
-- Check support of both 1B and 4B header sizes of short varlena datum
134+
CREATE TABLE varlena_bug (v text);
135+
ALTER TABLE varlena_bug ALTER column v SET storage plain;
136+
INSERT INTO varlena_bug VALUES ('x');
137+
COPY varlena_bug from stdin;
138+
x
139+
\.
140+
CREATE INDEX varlena_bug_idx on varlena_bug(v);
141+
SELECT bt_index_check('varlena_bug_idx', true);
142+
133143
-- cleanup
134144
DROP TABLE bttest_a;
135145
DROP TABLE bttest_b;
@@ -139,3 +149,4 @@ DROP TABLE toast_bug;
139149
DROP FUNCTION ifun(int8);
140150
DROP OWNED BY regress_bttest_role; -- permissions
141151
DROP ROLE regress_bttest_role;
152+
DROP TABLE varlena_bug;

contrib/amcheck/verify_nbtree.c

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2058,7 +2058,7 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
20582058
TupleDesc tupleDescriptor = RelationGetDescr(state->rel);
20592059
Datum normalized[INDEX_MAX_KEYS];
20602060
bool isnull[INDEX_MAX_KEYS];
2061-
bool toast_free[INDEX_MAX_KEYS];
2061+
bool need_free[INDEX_MAX_KEYS];
20622062
bool formnewtup = false;
20632063
IndexTuple reformed;
20642064
int i;
@@ -2074,7 +2074,7 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
20742074
att = TupleDescAttr(tupleDescriptor, i);
20752075

20762076
/* Assume untoasted/already normalized datum initially */
2077-
toast_free[i] = false;
2077+
need_free[i] = false;
20782078
normalized[i] = index_getattr(itup, att->attnum,
20792079
tupleDescriptor,
20802080
&isnull[i]);
@@ -2097,11 +2097,32 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
20972097
{
20982098
formnewtup = true;
20992099
normalized[i] = PointerGetDatum(PG_DETOAST_DATUM(normalized[i]));
2100-
toast_free[i] = true;
2100+
need_free[i] = true;
2101+
}
2102+
2103+
/*
2104+
* Short tuples may have 1B or 4B header. Convert 4B header of short
2105+
* tuples to 1B
2106+
*/
2107+
else if (VARATT_CAN_MAKE_SHORT(DatumGetPointer(normalized[i])))
2108+
{
2109+
/* convert to short varlena */
2110+
Size len = VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(normalized[i]));
2111+
char *data = palloc(len);
2112+
2113+
SET_VARSIZE_SHORT(data, len);
2114+
memcpy(data + 1, VARDATA(DatumGetPointer(normalized[i])), len - 1);
2115+
2116+
formnewtup = true;
2117+
normalized[i] = PointerGetDatum(data);
2118+
need_free[i] = true;
21012119
}
21022120
}
21032121

2104-
/* Easier case: Tuple has varlena datums, none of which are compressed */
2122+
/*
2123+
* Easier case: Tuple has varlena datums, none of which are compressed or
2124+
* short with 4B header
2125+
*/
21052126
if (!formnewtup)
21062127
return itup;
21072128

@@ -2111,6 +2132,11 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
21112132
* (normalized input datums). This is rather naive, but shouldn't be
21122133
* necessary too often.
21132134
*
2135+
* In the heap, tuples may contain short varlena datums with both 1B
2136+
* header and 4B headers. But the corresponding index tuple should always
2137+
* have such varlena's with 1B headers. So, if there is a short varlena
2138+
* with 4B header, we need to convert it for for fingerprinting.
2139+
*
21142140
* Note that we rely on deterministic index_form_tuple() TOAST compression
21152141
* of normalized input.
21162142
*/
@@ -2119,7 +2145,7 @@ bt_normalize_tuple(BtreeCheckState *state, IndexTuple itup)
21192145

21202146
/* Cannot leak memory here */
21212147
for (i = 0; i < tupleDescriptor->natts; i++)
2122-
if (toast_free[i])
2148+
if (need_free[i])
21232149
pfree(DatumGetPointer(normalized[i]));
21242150

21252151
return reformed;

0 commit comments

Comments
 (0)