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

Commit 58b4cb3

Browse files
committed
Redesign pageinspect function printing infomask bits
After more discussion, the new function added by ddbd5d8 could have been designed in a better way. Based on an idea from Álvaro, instead of returning one column which includes both the raw and combined flags, use two columns, with one for the raw flags and one for the combined flags. This also takes care of some issues with HEAP_LOCKED_UPGRADED and HEAP_XMAX_IS_LOCKED_ONLY which are not really combined flags as they depend on conditions defined by other raw bits, as mentioned by Amit. While on it, fix an extra issue with combined flags. A combined flag was returned if at least one of its bits was set, but all its bits need to be set to include it in the result. Author: Michael Paquier Reviewed-by: Álvaro Herrera, Amit Kapila Discussion: https://postgr.es/m/20190913114950.GA3824@alvherre.pgsql
1 parent 59354cc commit 58b4cb3

File tree

5 files changed

+153
-224
lines changed

5 files changed

+153
-224
lines changed

contrib/pageinspect/expected/page.out

+46-128
Original file line numberDiff line numberDiff line change
@@ -86,127 +86,55 @@ SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0));
8686
-- always be the same in all test runs. we show raw flags by
8787
-- default: HEAP_XMIN_COMMITTED and HEAP_XMIN_INVALID.
8888
VACUUM FREEZE test1;
89-
SELECT t_infomask, t_infomask2, flags
89+
SELECT t_infomask, t_infomask2, raw_flags, combined_flags
9090
FROM heap_page_items(get_raw_page('test1', 0)),
91-
LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) m(flags);
92-
t_infomask | t_infomask2 | flags
93-
------------+-------------+-----------------------------------------------------------
94-
2816 | 2 | {HEAP_XMAX_INVALID,HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID}
91+
LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2);
92+
t_infomask | t_infomask2 | raw_flags | combined_flags
93+
------------+-------------+-----------------------------------------------------------+--------------------
94+
2816 | 2 | {HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID,HEAP_XMAX_INVALID} | {HEAP_XMIN_FROZEN}
9595
(1 row)
9696

9797
-- output the decoded flag HEAP_XMIN_FROZEN instead
98-
SELECT t_infomask, t_infomask2, flags
98+
SELECT t_infomask, t_infomask2, raw_flags, combined_flags
9999
FROM heap_page_items(get_raw_page('test1', 0)),
100-
LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2, true) m(flags);
101-
t_infomask | t_infomask2 | flags
102-
------------+-------------+--------------------------------------
103-
2816 | 2 | {HEAP_XMAX_INVALID,HEAP_XMIN_FROZEN}
100+
LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2);
101+
t_infomask | t_infomask2 | raw_flags | combined_flags
102+
------------+-------------+-----------------------------------------------------------+--------------------
103+
2816 | 2 | {HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID,HEAP_XMAX_INVALID} | {HEAP_XMIN_FROZEN}
104104
(1 row)
105105

106106
-- tests for decoding of combined flags
107107
-- HEAP_XMAX_SHR_LOCK = (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
108-
SELECT heap_tuple_infomask_flags(x'0050'::int, 0, true);
109-
heap_tuple_infomask_flags
110-
---------------------------
111-
{HEAP_XMAX_SHR_LOCK}
112-
(1 row)
113-
114-
SELECT heap_tuple_infomask_flags(x'0050'::int, 0, false);
115-
heap_tuple_infomask_flags
116-
---------------------------------------------
117-
{HEAP_XMAX_EXCL_LOCK,HEAP_XMAX_KEYSHR_LOCK}
108+
SELECT * FROM heap_tuple_infomask_flags(x'0050'::int, 0);
109+
raw_flags | combined_flags
110+
---------------------------------------------+----------------------
111+
{HEAP_XMAX_KEYSHR_LOCK,HEAP_XMAX_EXCL_LOCK} | {HEAP_XMAX_SHR_LOCK}
118112
(1 row)
119113

120114
-- HEAP_XMIN_FROZEN = (HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID)
121-
SELECT heap_tuple_infomask_flags(x'0300'::int, 0, true);
122-
heap_tuple_infomask_flags
123-
---------------------------
124-
{HEAP_XMIN_FROZEN}
125-
(1 row)
126-
127-
SELECT heap_tuple_infomask_flags(x'0300'::int, 0, false);
128-
heap_tuple_infomask_flags
129-
-----------------------------------------
130-
{HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID}
115+
SELECT * FROM heap_tuple_infomask_flags(x'0300'::int, 0);
116+
raw_flags | combined_flags
117+
-----------------------------------------+--------------------
118+
{HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID} | {HEAP_XMIN_FROZEN}
131119
(1 row)
132120

133121
-- HEAP_MOVED = (HEAP_MOVED_IN | HEAP_MOVED_OFF)
134-
SELECT heap_tuple_infomask_flags(x'C000'::int, 0, true);
135-
heap_tuple_infomask_flags
136-
---------------------------
137-
{HEAP_MOVED}
122+
SELECT * FROM heap_tuple_infomask_flags(x'C000'::int, 0);
123+
raw_flags | combined_flags
124+
--------------------------------+----------------
125+
{HEAP_MOVED_OFF,HEAP_MOVED_IN} | {HEAP_MOVED}
138126
(1 row)
139127

140-
SELECT heap_tuple_infomask_flags(x'C000'::int, 0, false);
141-
heap_tuple_infomask_flags
142-
--------------------------------
143-
{HEAP_MOVED_IN,HEAP_MOVED_OFF}
144-
(1 row)
145-
146-
-- HEAP_LOCKED_UPGRADED = (HEAP_XMAX_IS_MULTI | HEAP_XMAX_LOCK_ONLY)
147-
SELECT heap_tuple_infomask_flags(x'1080'::int, 0, true);
148-
heap_tuple_infomask_flags
149-
---------------------------
150-
{HEAP_LOCKED_UPGRADED}
151-
(1 row)
152-
153-
SELECT heap_tuple_infomask_flags(x'1080'::int, 0, false);
154-
heap_tuple_infomask_flags
155-
------------------------------------------
156-
{HEAP_XMAX_LOCK_ONLY,HEAP_XMAX_IS_MULTI}
128+
SELECT * FROM heap_tuple_infomask_flags(x'C000'::int, 0);
129+
raw_flags | combined_flags
130+
--------------------------------+----------------
131+
{HEAP_MOVED_OFF,HEAP_MOVED_IN} | {HEAP_MOVED}
157132
(1 row)
158133

159134
-- test all flags of t_infomask and t_infomask2
160-
SELECT unnest(heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int, false))
161-
AS flags ORDER BY 1;
162-
flags
163-
-----------------------
164-
HEAP_COMBOCID
165-
HEAP_HASEXTERNAL
166-
HEAP_HASNULL
167-
HEAP_HASOID_OLD
168-
HEAP_HASVARWIDTH
169-
HEAP_HOT_UPDATED
170-
HEAP_KEYS_UPDATED
171-
HEAP_MOVED_IN
172-
HEAP_MOVED_OFF
173-
HEAP_ONLY_TUPLE
174-
HEAP_UPDATED
175-
HEAP_XMAX_COMMITTED
176-
HEAP_XMAX_EXCL_LOCK
177-
HEAP_XMAX_INVALID
178-
HEAP_XMAX_IS_MULTI
179-
HEAP_XMAX_KEYSHR_LOCK
180-
HEAP_XMAX_LOCK_ONLY
181-
HEAP_XMIN_COMMITTED
182-
HEAP_XMIN_INVALID
183-
(19 rows)
184-
185-
SELECT unnest(heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int, true))
186-
AS flags ORDER BY 1;
187-
flags
188-
---------------------
189-
HEAP_COMBOCID
190-
HEAP_HASEXTERNAL
191-
HEAP_HASNULL
192-
HEAP_HASOID_OLD
193-
HEAP_HASVARWIDTH
194-
HEAP_HOT_UPDATED
195-
HEAP_KEYS_UPDATED
196-
HEAP_MOVED
197-
HEAP_ONLY_TUPLE
198-
HEAP_UPDATED
199-
HEAP_XMAX_COMMITTED
200-
HEAP_XMAX_INVALID
201-
HEAP_XMAX_IS_MULTI
202-
HEAP_XMAX_LOCK_ONLY
203-
HEAP_XMAX_SHR_LOCK
204-
HEAP_XMIN_FROZEN
205-
(16 rows)
206-
207-
SELECT unnest(heap_tuple_infomask_flags(-1, -1, false))
208-
AS flags ORDER BY 1;
209-
flags
135+
SELECT unnest(raw_flags)
136+
FROM heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int) ORDER BY 1;
137+
unnest
210138
-----------------------
211139
HEAP_COMBOCID
212140
HEAP_HASEXTERNAL
@@ -229,38 +157,28 @@ SELECT unnest(heap_tuple_infomask_flags(-1, -1, false))
229157
HEAP_XMIN_INVALID
230158
(19 rows)
231159

232-
SELECT unnest(heap_tuple_infomask_flags(-1, -1, true))
233-
AS flags ORDER BY 1;
234-
flags
235-
---------------------
236-
HEAP_COMBOCID
237-
HEAP_HASEXTERNAL
238-
HEAP_HASNULL
239-
HEAP_HASOID_OLD
240-
HEAP_HASVARWIDTH
241-
HEAP_HOT_UPDATED
242-
HEAP_KEYS_UPDATED
160+
SELECT unnest(combined_flags)
161+
FROM heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int) ORDER BY 1;
162+
unnest
163+
--------------------
243164
HEAP_MOVED
244-
HEAP_ONLY_TUPLE
245-
HEAP_UPDATED
246-
HEAP_XMAX_COMMITTED
247-
HEAP_XMAX_INVALID
248-
HEAP_XMAX_IS_MULTI
249-
HEAP_XMAX_LOCK_ONLY
250165
HEAP_XMAX_SHR_LOCK
251166
HEAP_XMIN_FROZEN
252-
(16 rows)
167+
(3 rows)
253168

254-
-- no flags
255-
SELECT unnest(heap_tuple_infomask_flags(0, 0, false));
256-
unnest
257-
--------
258-
(0 rows)
169+
-- no flags at all
170+
SELECT * FROM heap_tuple_infomask_flags(0, 0);
171+
raw_flags | combined_flags
172+
-----------+----------------
173+
{} | {}
174+
(1 row)
259175

260-
SELECT unnest(heap_tuple_infomask_flags(0, 0, true));
261-
unnest
262-
--------
263-
(0 rows)
176+
-- no combined flags
177+
SELECT * FROM heap_tuple_infomask_flags(x'0010'::int, 0);
178+
raw_flags | combined_flags
179+
-------------------------+----------------
180+
{HEAP_XMAX_KEYSHR_LOCK} | {}
181+
(1 row)
264182

265183
DROP TABLE test1;
266184
-- check that using any of these functions with a partitioned table or index

contrib/pageinspect/heapfuncs.c

+78-60
Original file line numberDiff line numberDiff line change
@@ -507,99 +507,117 @@ PG_FUNCTION_INFO_V1(heap_tuple_infomask_flags);
507507
Datum
508508
heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
509509
{
510+
#define HEAP_TUPLE_INFOMASK_COLS 2
511+
Datum values[HEAP_TUPLE_INFOMASK_COLS];
512+
bool nulls[HEAP_TUPLE_INFOMASK_COLS];
510513
uint16 t_infomask = PG_GETARG_INT16(0);
511514
uint16 t_infomask2 = PG_GETARG_INT16(1);
512-
bool decode_combined = PG_GETARG_BOOL(2);
513515
int cnt = 0;
514516
ArrayType *a;
515517
int bitcnt;
516-
Datum *d;
518+
Datum *flags;
519+
TupleDesc tupdesc;
520+
HeapTuple tuple;
517521

518522
if (!superuser())
519523
ereport(ERROR,
520524
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
521525
errmsg("must be superuser to use raw page functions")));
522526

527+
/* Build a tuple descriptor for our result type */
528+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
529+
elog(ERROR, "return type must be a row type");
530+
523531
bitcnt = pg_popcount((const char *) &t_infomask, sizeof(uint16)) +
524532
pg_popcount((const char *) &t_infomask2, sizeof(uint16));
525533

526-
/* If no flags, return an empty array */
534+
/* Initialize values and NULL flags arrays */
535+
MemSet(values, 0, sizeof(values));
536+
MemSet(nulls, 0, sizeof(nulls));
537+
538+
/* If no flags, return a set of empty arrays */
527539
if (bitcnt <= 0)
528-
PG_RETURN_POINTER(construct_empty_array(TEXTOID));
540+
{
541+
values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
542+
values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
543+
tuple = heap_form_tuple(tupdesc, values, nulls);
544+
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
545+
}
529546

530-
d = (Datum *) palloc0(sizeof(Datum) * bitcnt);
547+
/* build set of raw flags */
548+
flags = (Datum *) palloc0(sizeof(Datum) * bitcnt);
531549

532550
/* decode t_infomask */
533551
if ((t_infomask & HEAP_HASNULL) != 0)
534-
d[cnt++] = CStringGetTextDatum("HEAP_HASNULL");
552+
flags[cnt++] = CStringGetTextDatum("HEAP_HASNULL");
535553
if ((t_infomask & HEAP_HASVARWIDTH) != 0)
536-
d[cnt++] = CStringGetTextDatum("HEAP_HASVARWIDTH");
554+
flags[cnt++] = CStringGetTextDatum("HEAP_HASVARWIDTH");
537555
if ((t_infomask & HEAP_HASEXTERNAL) != 0)
538-
d[cnt++] = CStringGetTextDatum("HEAP_HASEXTERNAL");
556+
flags[cnt++] = CStringGetTextDatum("HEAP_HASEXTERNAL");
539557
if ((t_infomask & HEAP_HASOID_OLD) != 0)
540-
d[cnt++] = CStringGetTextDatum("HEAP_HASOID_OLD");
558+
flags[cnt++] = CStringGetTextDatum("HEAP_HASOID_OLD");
559+
if ((t_infomask & HEAP_XMAX_KEYSHR_LOCK) != 0)
560+
flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_KEYSHR_LOCK");
541561
if ((t_infomask & HEAP_COMBOCID) != 0)
542-
d[cnt++] = CStringGetTextDatum("HEAP_COMBOCID");
562+
flags[cnt++] = CStringGetTextDatum("HEAP_COMBOCID");
563+
if ((t_infomask & HEAP_XMAX_EXCL_LOCK) != 0)
564+
flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_EXCL_LOCK");
565+
if ((t_infomask & HEAP_XMAX_LOCK_ONLY) != 0)
566+
flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_LOCK_ONLY");
567+
if ((t_infomask & HEAP_XMIN_COMMITTED) != 0)
568+
flags[cnt++] = CStringGetTextDatum("HEAP_XMIN_COMMITTED");
569+
if ((t_infomask & HEAP_XMIN_INVALID) != 0)
570+
flags[cnt++] = CStringGetTextDatum("HEAP_XMIN_INVALID");
543571
if ((t_infomask & HEAP_XMAX_COMMITTED) != 0)
544-
d[cnt++] = CStringGetTextDatum("HEAP_XMAX_COMMITTED");
572+
flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_COMMITTED");
545573
if ((t_infomask & HEAP_XMAX_INVALID) != 0)
546-
d[cnt++] = CStringGetTextDatum("HEAP_XMAX_INVALID");
574+
flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_INVALID");
575+
if ((t_infomask & HEAP_XMAX_IS_MULTI) != 0)
576+
flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_IS_MULTI");
547577
if ((t_infomask & HEAP_UPDATED) != 0)
548-
d[cnt++] = CStringGetTextDatum("HEAP_UPDATED");
549-
550-
/* decode combined masks of t_infomaks */
551-
if (decode_combined && (t_infomask & HEAP_XMAX_SHR_LOCK) != 0)
552-
d[cnt++] = CStringGetTextDatum("HEAP_XMAX_SHR_LOCK");
553-
else
554-
{
555-
if ((t_infomask & HEAP_XMAX_EXCL_LOCK) != 0)
556-
d[cnt++] = CStringGetTextDatum("HEAP_XMAX_EXCL_LOCK");
557-
if ((t_infomask & HEAP_XMAX_KEYSHR_LOCK) != 0)
558-
d[cnt++] = CStringGetTextDatum("HEAP_XMAX_KEYSHR_LOCK");
559-
}
560-
561-
if (decode_combined && (t_infomask & HEAP_XMIN_FROZEN) != 0)
562-
d[cnt++] = CStringGetTextDatum("HEAP_XMIN_FROZEN");
563-
else
564-
{
565-
if ((t_infomask & HEAP_XMIN_COMMITTED) != 0)
566-
d[cnt++] = CStringGetTextDatum("HEAP_XMIN_COMMITTED");
567-
if ((t_infomask & HEAP_XMIN_INVALID) != 0)
568-
d[cnt++] = CStringGetTextDatum("HEAP_XMIN_INVALID");
569-
}
570-
571-
if (decode_combined && (t_infomask & HEAP_MOVED) != 0)
572-
d[cnt++] = CStringGetTextDatum("HEAP_MOVED");
573-
else
574-
{
575-
if ((t_infomask & HEAP_MOVED_IN) != 0)
576-
d[cnt++] = CStringGetTextDatum("HEAP_MOVED_IN");
577-
if ((t_infomask & HEAP_MOVED_OFF) != 0)
578-
d[cnt++] = CStringGetTextDatum("HEAP_MOVED_OFF");
579-
}
580-
581-
if (decode_combined && HEAP_LOCKED_UPGRADED(t_infomask))
582-
d[cnt++] = CStringGetTextDatum("HEAP_LOCKED_UPGRADED");
583-
else
584-
{
585-
if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
586-
d[cnt++] = CStringGetTextDatum("HEAP_XMAX_LOCK_ONLY");
587-
if ((t_infomask & HEAP_XMAX_IS_MULTI) != 0)
588-
d[cnt++] = CStringGetTextDatum("HEAP_XMAX_IS_MULTI");
589-
}
578+
flags[cnt++] = CStringGetTextDatum("HEAP_UPDATED");
579+
if ((t_infomask & HEAP_MOVED_OFF) != 0)
580+
flags[cnt++] = CStringGetTextDatum("HEAP_MOVED_OFF");
581+
if ((t_infomask & HEAP_MOVED_IN) != 0)
582+
flags[cnt++] = CStringGetTextDatum("HEAP_MOVED_IN");
590583

591584
/* decode t_infomask2 */
592585
if ((t_infomask2 & HEAP_KEYS_UPDATED) != 0)
593-
d[cnt++] = CStringGetTextDatum("HEAP_KEYS_UPDATED");
586+
flags[cnt++] = CStringGetTextDatum("HEAP_KEYS_UPDATED");
594587
if ((t_infomask2 & HEAP_HOT_UPDATED) != 0)
595-
d[cnt++] = CStringGetTextDatum("HEAP_HOT_UPDATED");
588+
flags[cnt++] = CStringGetTextDatum("HEAP_HOT_UPDATED");
596589
if ((t_infomask2 & HEAP_ONLY_TUPLE) != 0)
597-
d[cnt++] = CStringGetTextDatum("HEAP_ONLY_TUPLE");
590+
flags[cnt++] = CStringGetTextDatum("HEAP_ONLY_TUPLE");
598591

592+
/* build value */
599593
Assert(cnt <= bitcnt);
600-
a = construct_array(d, cnt, TEXTOID, -1, false, 'i');
594+
a = construct_array(flags, cnt, TEXTOID, -1, false, 'i');
595+
values[0] = PointerGetDatum(a);
601596

602-
pfree(d);
597+
/*
598+
* Build set of combined flags. Use the same array as previously, this
599+
* keeps the code simple.
600+
*/
601+
cnt = 0;
602+
MemSet(flags, 0, sizeof(Datum) * bitcnt);
603+
604+
/* decode combined masks of t_infomask */
605+
if ((t_infomask & HEAP_XMAX_SHR_LOCK) == HEAP_XMAX_SHR_LOCK)
606+
flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_SHR_LOCK");
607+
if ((t_infomask & HEAP_XMIN_FROZEN) == HEAP_XMIN_FROZEN)
608+
flags[cnt++] = CStringGetTextDatum("HEAP_XMIN_FROZEN");
609+
if ((t_infomask & HEAP_MOVED) == HEAP_MOVED)
610+
flags[cnt++] = CStringGetTextDatum("HEAP_MOVED");
611+
612+
/* Build an empty array if there are no combined flags */
613+
if (cnt == 0)
614+
a = construct_empty_array(TEXTOID);
615+
else
616+
a = construct_array(flags, cnt, TEXTOID, -1, false, 'i');
617+
pfree(flags);
618+
values[1] = PointerGetDatum(a);
603619

604-
PG_RETURN_POINTER(a);
620+
/* Returns the record as Datum */
621+
tuple = heap_form_tuple(tupdesc, values, nulls);
622+
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
605623
}

0 commit comments

Comments
 (0)