Fix Heap rmgr's desc output for infobits arrays.
[pgsql.git] / src / backend / access / rmgrdesc / heapdesc.c
blobd182d8048b61e00b4e0240c360f7d3ee90ded1b4
1 /*-------------------------------------------------------------------------
3 * heapdesc.c
4 * rmgr descriptor routines for access/heap/heapam.c
6 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/access/rmgrdesc/heapdesc.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include "access/heapam_xlog.h"
18 #include "access/rmgrdesc_utils.h"
21 * NOTE: "keyname" argument cannot have trailing spaces or punctuation
22 * characters
24 static void
25 infobits_desc(StringInfo buf, uint8 infobits, const char *keyname)
27 appendStringInfo(buf, "%s: [", keyname);
29 Assert(buf->data[buf->len - 1] != ' ');
31 if (infobits & XLHL_XMAX_IS_MULTI)
32 appendStringInfoString(buf, "IS_MULTI, ");
33 if (infobits & XLHL_XMAX_LOCK_ONLY)
34 appendStringInfoString(buf, "LOCK_ONLY, ");
35 if (infobits & XLHL_XMAX_EXCL_LOCK)
36 appendStringInfoString(buf, "EXCL_LOCK, ");
37 if (infobits & XLHL_XMAX_KEYSHR_LOCK)
38 appendStringInfoString(buf, "KEYSHR_LOCK, ");
39 if (infobits & XLHL_KEYS_UPDATED)
40 appendStringInfoString(buf, "KEYS_UPDATED, ");
42 if (buf->data[buf->len - 1] == ' ')
44 /* Truncate-away final unneeded ", " */
45 Assert(buf->data[buf->len - 2] == ',');
46 buf->len -= 2;
47 buf->data[buf->len] = '\0';
50 appendStringInfoString(buf, "]");
53 static void
54 truncate_flags_desc(StringInfo buf, uint8 flags)
56 appendStringInfoString(buf, "flags: [");
58 if (flags & XLH_TRUNCATE_CASCADE)
59 appendStringInfoString(buf, "CASCADE, ");
60 if (flags & XLH_TRUNCATE_RESTART_SEQS)
61 appendStringInfoString(buf, "RESTART_SEQS, ");
63 if (buf->data[buf->len - 1] == ' ')
65 /* Truncate-away final unneeded ", " */
66 Assert(buf->data[buf->len - 2] == ',');
67 buf->len -= 2;
68 buf->data[buf->len] = '\0';
71 appendStringInfoString(buf, "]");
74 static void
75 plan_elem_desc(StringInfo buf, void *plan, void *data)
77 xl_heap_freeze_plan *new_plan = (xl_heap_freeze_plan *) plan;
78 OffsetNumber **offsets = data;
80 appendStringInfo(buf, "{ xmax: %u, infomask: %u, infomask2: %u, ntuples: %u",
81 new_plan->xmax,
82 new_plan->t_infomask, new_plan->t_infomask2,
83 new_plan->ntuples);
85 appendStringInfoString(buf, ", offsets:");
86 array_desc(buf, *offsets, sizeof(OffsetNumber), new_plan->ntuples,
87 &offset_elem_desc, NULL);
89 *offsets += new_plan->ntuples;
91 appendStringInfo(buf, " }");
94 void
95 heap_desc(StringInfo buf, XLogReaderState *record)
97 char *rec = XLogRecGetData(record);
98 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
100 info &= XLOG_HEAP_OPMASK;
101 if (info == XLOG_HEAP_INSERT)
103 xl_heap_insert *xlrec = (xl_heap_insert *) rec;
105 appendStringInfo(buf, "off: %u, flags: 0x%02X",
106 xlrec->offnum,
107 xlrec->flags);
109 else if (info == XLOG_HEAP_DELETE)
111 xl_heap_delete *xlrec = (xl_heap_delete *) rec;
113 appendStringInfo(buf, "xmax: %u, off: %u, ",
114 xlrec->xmax, xlrec->offnum);
115 infobits_desc(buf, xlrec->infobits_set, "infobits");
116 appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
118 else if (info == XLOG_HEAP_UPDATE)
120 xl_heap_update *xlrec = (xl_heap_update *) rec;
122 appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
123 xlrec->old_xmax, xlrec->old_offnum);
124 infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
125 appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
126 xlrec->flags, xlrec->new_xmax, xlrec->new_offnum);
128 else if (info == XLOG_HEAP_HOT_UPDATE)
130 xl_heap_update *xlrec = (xl_heap_update *) rec;
132 appendStringInfo(buf, "old_xmax: %u, old_off: %u, ",
133 xlrec->old_xmax, xlrec->old_offnum);
134 infobits_desc(buf, xlrec->old_infobits_set, "old_infobits");
135 appendStringInfo(buf, ", flags: 0x%02X, new_xmax: %u, new_off: %u",
136 xlrec->flags, xlrec->new_xmax, xlrec->new_offnum);
138 else if (info == XLOG_HEAP_TRUNCATE)
140 xl_heap_truncate *xlrec = (xl_heap_truncate *) rec;
142 truncate_flags_desc(buf, xlrec->flags);
143 appendStringInfo(buf, ", nrelids: %u", xlrec->nrelids);
144 appendStringInfoString(buf, ", relids:");
145 array_desc(buf, xlrec->relids, sizeof(Oid), xlrec->nrelids,
146 &oid_elem_desc, NULL);
148 else if (info == XLOG_HEAP_CONFIRM)
150 xl_heap_confirm *xlrec = (xl_heap_confirm *) rec;
152 appendStringInfo(buf, "off: %u", xlrec->offnum);
154 else if (info == XLOG_HEAP_LOCK)
156 xl_heap_lock *xlrec = (xl_heap_lock *) rec;
158 appendStringInfo(buf, "xmax: %u, off: %u, ",
159 xlrec->xmax, xlrec->offnum);
160 infobits_desc(buf, xlrec->infobits_set, "infobits");
161 appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
163 else if (info == XLOG_HEAP_INPLACE)
165 xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
167 appendStringInfo(buf, "off: %u", xlrec->offnum);
171 void
172 heap2_desc(StringInfo buf, XLogReaderState *record)
174 char *rec = XLogRecGetData(record);
175 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
177 info &= XLOG_HEAP_OPMASK;
178 if (info == XLOG_HEAP2_PRUNE)
180 xl_heap_prune *xlrec = (xl_heap_prune *) rec;
182 appendStringInfo(buf, "snapshotConflictHorizon: %u, nredirected: %u, ndead: %u",
183 xlrec->snapshotConflictHorizon,
184 xlrec->nredirected,
185 xlrec->ndead);
187 if (!XLogRecHasBlockImage(record, 0))
189 OffsetNumber *end;
190 OffsetNumber *redirected;
191 OffsetNumber *nowdead;
192 OffsetNumber *nowunused;
193 int nredirected;
194 int nunused;
195 Size datalen;
197 redirected = (OffsetNumber *) XLogRecGetBlockData(record, 0,
198 &datalen);
200 nredirected = xlrec->nredirected;
201 end = (OffsetNumber *) ((char *) redirected + datalen);
202 nowdead = redirected + (nredirected * 2);
203 nowunused = nowdead + xlrec->ndead;
204 nunused = (end - nowunused);
205 Assert(nunused >= 0);
207 appendStringInfo(buf, ", nunused: %u", nunused);
209 appendStringInfoString(buf, ", redirected:");
210 array_desc(buf, redirected, sizeof(OffsetNumber) * 2,
211 nredirected, &redirect_elem_desc, NULL);
212 appendStringInfoString(buf, ", dead:");
213 array_desc(buf, nowdead, sizeof(OffsetNumber), xlrec->ndead,
214 &offset_elem_desc, NULL);
215 appendStringInfoString(buf, ", unused:");
216 array_desc(buf, nowunused, sizeof(OffsetNumber), nunused,
217 &offset_elem_desc, NULL);
220 else if (info == XLOG_HEAP2_VACUUM)
222 xl_heap_vacuum *xlrec = (xl_heap_vacuum *) rec;
224 appendStringInfo(buf, "nunused: %u", xlrec->nunused);
226 if (!XLogRecHasBlockImage(record, 0))
228 OffsetNumber *nowunused;
230 nowunused = (OffsetNumber *) XLogRecGetBlockData(record, 0, NULL);
232 appendStringInfoString(buf, ", unused:");
233 array_desc(buf, nowunused, sizeof(OffsetNumber), xlrec->nunused,
234 &offset_elem_desc, NULL);
237 else if (info == XLOG_HEAP2_FREEZE_PAGE)
239 xl_heap_freeze_page *xlrec = (xl_heap_freeze_page *) rec;
241 appendStringInfo(buf, "snapshotConflictHorizon: %u, nplans: %u",
242 xlrec->snapshotConflictHorizon, xlrec->nplans);
244 if (!XLogRecHasBlockImage(record, 0))
246 xl_heap_freeze_plan *plans;
247 OffsetNumber *offsets;
249 plans = (xl_heap_freeze_plan *) XLogRecGetBlockData(record, 0, NULL);
250 offsets = (OffsetNumber *) ((char *) plans +
251 (xlrec->nplans *
252 sizeof(xl_heap_freeze_plan)));
253 appendStringInfoString(buf, ", plans:");
254 array_desc(buf, plans, sizeof(xl_heap_freeze_plan), xlrec->nplans,
255 &plan_elem_desc, &offsets);
258 else if (info == XLOG_HEAP2_VISIBLE)
260 xl_heap_visible *xlrec = (xl_heap_visible *) rec;
262 appendStringInfo(buf, "snapshotConflictHorizon: %u, flags: 0x%02X",
263 xlrec->snapshotConflictHorizon, xlrec->flags);
265 else if (info == XLOG_HEAP2_MULTI_INSERT)
267 xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
268 bool isinit = (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE) != 0;
270 appendStringInfo(buf, "ntuples: %d, flags: 0x%02X", xlrec->ntuples,
271 xlrec->flags);
273 if (!XLogRecHasBlockImage(record, 0) && !isinit)
275 appendStringInfoString(buf, ", offsets:");
276 array_desc(buf, xlrec->offsets, sizeof(OffsetNumber),
277 xlrec->ntuples, &offset_elem_desc, NULL);
280 else if (info == XLOG_HEAP2_LOCK_UPDATED)
282 xl_heap_lock_updated *xlrec = (xl_heap_lock_updated *) rec;
284 appendStringInfo(buf, "xmax: %u, off: %u, ",
285 xlrec->xmax, xlrec->offnum);
286 infobits_desc(buf, xlrec->infobits_set, "infobits");
287 appendStringInfo(buf, ", flags: 0x%02X", xlrec->flags);
289 else if (info == XLOG_HEAP2_NEW_CID)
291 xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec;
293 appendStringInfo(buf, "rel: %u/%u/%u, tid: %u/%u",
294 xlrec->target_locator.spcOid,
295 xlrec->target_locator.dbOid,
296 xlrec->target_locator.relNumber,
297 ItemPointerGetBlockNumber(&(xlrec->target_tid)),
298 ItemPointerGetOffsetNumber(&(xlrec->target_tid)));
299 appendStringInfo(buf, ", cmin: %u, cmax: %u, combo: %u",
300 xlrec->cmin, xlrec->cmax, xlrec->combocid);
304 const char *
305 heap_identify(uint8 info)
307 const char *id = NULL;
309 switch (info & ~XLR_INFO_MASK)
311 case XLOG_HEAP_INSERT:
312 id = "INSERT";
313 break;
314 case XLOG_HEAP_INSERT | XLOG_HEAP_INIT_PAGE:
315 id = "INSERT+INIT";
316 break;
317 case XLOG_HEAP_DELETE:
318 id = "DELETE";
319 break;
320 case XLOG_HEAP_UPDATE:
321 id = "UPDATE";
322 break;
323 case XLOG_HEAP_UPDATE | XLOG_HEAP_INIT_PAGE:
324 id = "UPDATE+INIT";
325 break;
326 case XLOG_HEAP_HOT_UPDATE:
327 id = "HOT_UPDATE";
328 break;
329 case XLOG_HEAP_HOT_UPDATE | XLOG_HEAP_INIT_PAGE:
330 id = "HOT_UPDATE+INIT";
331 break;
332 case XLOG_HEAP_TRUNCATE:
333 id = "TRUNCATE";
334 break;
335 case XLOG_HEAP_CONFIRM:
336 id = "HEAP_CONFIRM";
337 break;
338 case XLOG_HEAP_LOCK:
339 id = "LOCK";
340 break;
341 case XLOG_HEAP_INPLACE:
342 id = "INPLACE";
343 break;
346 return id;
349 const char *
350 heap2_identify(uint8 info)
352 const char *id = NULL;
354 switch (info & ~XLR_INFO_MASK)
356 case XLOG_HEAP2_PRUNE:
357 id = "PRUNE";
358 break;
359 case XLOG_HEAP2_VACUUM:
360 id = "VACUUM";
361 break;
362 case XLOG_HEAP2_FREEZE_PAGE:
363 id = "FREEZE_PAGE";
364 break;
365 case XLOG_HEAP2_VISIBLE:
366 id = "VISIBLE";
367 break;
368 case XLOG_HEAP2_MULTI_INSERT:
369 id = "MULTI_INSERT";
370 break;
371 case XLOG_HEAP2_MULTI_INSERT | XLOG_HEAP_INIT_PAGE:
372 id = "MULTI_INSERT+INIT";
373 break;
374 case XLOG_HEAP2_LOCK_UPDATED:
375 id = "LOCK_UPDATED";
376 break;
377 case XLOG_HEAP2_NEW_CID:
378 id = "NEW_CID";
379 break;
380 case XLOG_HEAP2_REWRITE:
381 id = "REWRITE";
382 break;
385 return id;