/src/postgres/src/backend/access/rmgrdesc/xactdesc.c
Line | Count | Source |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * xactdesc.c |
4 | | * rmgr descriptor routines for access/transam/xact.c |
5 | | * |
6 | | * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group |
7 | | * Portions Copyright (c) 1994, Regents of the University of California |
8 | | * |
9 | | * |
10 | | * IDENTIFICATION |
11 | | * src/backend/access/rmgrdesc/xactdesc.c |
12 | | * |
13 | | *------------------------------------------------------------------------- |
14 | | */ |
15 | | #include "postgres.h" |
16 | | |
17 | | #include "access/transam.h" |
18 | | #include "access/xact.h" |
19 | | #include "replication/origin.h" |
20 | | #include "storage/sinval.h" |
21 | | #include "storage/standbydefs.h" |
22 | | #include "utils/timestamp.h" |
23 | | |
24 | | /* |
25 | | * Parse the WAL format of an xact commit and abort records into an easier to |
26 | | * understand format. |
27 | | * |
28 | | * These routines are in xactdesc.c because they're accessed in backend (when |
29 | | * replaying WAL) and frontend (pg_waldump) code. This file is the only xact |
30 | | * specific one shared between both. They're complicated enough that |
31 | | * duplication would be bothersome. |
32 | | */ |
33 | | |
34 | | void |
35 | | ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed) |
36 | 0 | { |
37 | 0 | char *data = ((char *) xlrec) + MinSizeOfXactCommit; |
38 | |
|
39 | 0 | memset(parsed, 0, sizeof(*parsed)); |
40 | |
|
41 | 0 | parsed->xinfo = 0; /* default, if no XLOG_XACT_HAS_INFO is |
42 | | * present */ |
43 | |
|
44 | 0 | parsed->xact_time = xlrec->xact_time; |
45 | |
|
46 | 0 | if (info & XLOG_XACT_HAS_INFO) |
47 | 0 | { |
48 | 0 | xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data; |
49 | |
|
50 | 0 | parsed->xinfo = xl_xinfo->xinfo; |
51 | |
|
52 | 0 | data += sizeof(xl_xact_xinfo); |
53 | 0 | } |
54 | |
|
55 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_DBINFO) |
56 | 0 | { |
57 | 0 | xl_xact_dbinfo *xl_dbinfo = (xl_xact_dbinfo *) data; |
58 | |
|
59 | 0 | parsed->dbId = xl_dbinfo->dbId; |
60 | 0 | parsed->tsId = xl_dbinfo->tsId; |
61 | |
|
62 | 0 | data += sizeof(xl_xact_dbinfo); |
63 | 0 | } |
64 | |
|
65 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS) |
66 | 0 | { |
67 | 0 | xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data; |
68 | |
|
69 | 0 | parsed->nsubxacts = xl_subxacts->nsubxacts; |
70 | 0 | parsed->subxacts = xl_subxacts->subxacts; |
71 | |
|
72 | 0 | data += MinSizeOfXactSubxacts; |
73 | 0 | data += parsed->nsubxacts * sizeof(TransactionId); |
74 | 0 | } |
75 | |
|
76 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_RELFILELOCATORS) |
77 | 0 | { |
78 | 0 | xl_xact_relfilelocators *xl_rellocators = (xl_xact_relfilelocators *) data; |
79 | |
|
80 | 0 | parsed->nrels = xl_rellocators->nrels; |
81 | 0 | parsed->xlocators = xl_rellocators->xlocators; |
82 | |
|
83 | 0 | data += MinSizeOfXactRelfileLocators; |
84 | 0 | data += xl_rellocators->nrels * sizeof(RelFileLocator); |
85 | 0 | } |
86 | |
|
87 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_DROPPED_STATS) |
88 | 0 | { |
89 | 0 | xl_xact_stats_items *xl_drops = (xl_xact_stats_items *) data; |
90 | |
|
91 | 0 | parsed->nstats = xl_drops->nitems; |
92 | 0 | parsed->stats = xl_drops->items; |
93 | |
|
94 | 0 | data += MinSizeOfXactStatsItems; |
95 | 0 | data += xl_drops->nitems * sizeof(xl_xact_stats_item); |
96 | 0 | } |
97 | |
|
98 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_INVALS) |
99 | 0 | { |
100 | 0 | xl_xact_invals *xl_invals = (xl_xact_invals *) data; |
101 | |
|
102 | 0 | parsed->nmsgs = xl_invals->nmsgs; |
103 | 0 | parsed->msgs = xl_invals->msgs; |
104 | |
|
105 | 0 | data += MinSizeOfXactInvals; |
106 | 0 | data += xl_invals->nmsgs * sizeof(SharedInvalidationMessage); |
107 | 0 | } |
108 | |
|
109 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE) |
110 | 0 | { |
111 | 0 | xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data; |
112 | |
|
113 | 0 | parsed->twophase_xid = xl_twophase->xid; |
114 | |
|
115 | 0 | data += sizeof(xl_xact_twophase); |
116 | |
|
117 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_GID) |
118 | 0 | { |
119 | 0 | strlcpy(parsed->twophase_gid, data, sizeof(parsed->twophase_gid)); |
120 | 0 | data += strlen(data) + 1; |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | | /* Note: no alignment is guaranteed after this point */ |
125 | |
|
126 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN) |
127 | 0 | { |
128 | 0 | xl_xact_origin xl_origin; |
129 | | |
130 | | /* no alignment is guaranteed, so copy onto stack */ |
131 | 0 | memcpy(&xl_origin, data, sizeof(xl_origin)); |
132 | |
|
133 | 0 | parsed->origin_lsn = xl_origin.origin_lsn; |
134 | 0 | parsed->origin_timestamp = xl_origin.origin_timestamp; |
135 | |
|
136 | 0 | data += sizeof(xl_xact_origin); |
137 | 0 | } |
138 | 0 | } |
139 | | |
140 | | void |
141 | | ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed) |
142 | 0 | { |
143 | 0 | char *data = ((char *) xlrec) + MinSizeOfXactAbort; |
144 | |
|
145 | 0 | memset(parsed, 0, sizeof(*parsed)); |
146 | |
|
147 | 0 | parsed->xinfo = 0; /* default, if no XLOG_XACT_HAS_INFO is |
148 | | * present */ |
149 | |
|
150 | 0 | parsed->xact_time = xlrec->xact_time; |
151 | |
|
152 | 0 | if (info & XLOG_XACT_HAS_INFO) |
153 | 0 | { |
154 | 0 | xl_xact_xinfo *xl_xinfo = (xl_xact_xinfo *) data; |
155 | |
|
156 | 0 | parsed->xinfo = xl_xinfo->xinfo; |
157 | |
|
158 | 0 | data += sizeof(xl_xact_xinfo); |
159 | 0 | } |
160 | |
|
161 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_DBINFO) |
162 | 0 | { |
163 | 0 | xl_xact_dbinfo *xl_dbinfo = (xl_xact_dbinfo *) data; |
164 | |
|
165 | 0 | parsed->dbId = xl_dbinfo->dbId; |
166 | 0 | parsed->tsId = xl_dbinfo->tsId; |
167 | |
|
168 | 0 | data += sizeof(xl_xact_dbinfo); |
169 | 0 | } |
170 | |
|
171 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_SUBXACTS) |
172 | 0 | { |
173 | 0 | xl_xact_subxacts *xl_subxacts = (xl_xact_subxacts *) data; |
174 | |
|
175 | 0 | parsed->nsubxacts = xl_subxacts->nsubxacts; |
176 | 0 | parsed->subxacts = xl_subxacts->subxacts; |
177 | |
|
178 | 0 | data += MinSizeOfXactSubxacts; |
179 | 0 | data += parsed->nsubxacts * sizeof(TransactionId); |
180 | 0 | } |
181 | |
|
182 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_RELFILELOCATORS) |
183 | 0 | { |
184 | 0 | xl_xact_relfilelocators *xl_rellocator = (xl_xact_relfilelocators *) data; |
185 | |
|
186 | 0 | parsed->nrels = xl_rellocator->nrels; |
187 | 0 | parsed->xlocators = xl_rellocator->xlocators; |
188 | |
|
189 | 0 | data += MinSizeOfXactRelfileLocators; |
190 | 0 | data += xl_rellocator->nrels * sizeof(RelFileLocator); |
191 | 0 | } |
192 | |
|
193 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_DROPPED_STATS) |
194 | 0 | { |
195 | 0 | xl_xact_stats_items *xl_drops = (xl_xact_stats_items *) data; |
196 | |
|
197 | 0 | parsed->nstats = xl_drops->nitems; |
198 | 0 | parsed->stats = xl_drops->items; |
199 | |
|
200 | 0 | data += MinSizeOfXactStatsItems; |
201 | 0 | data += xl_drops->nitems * sizeof(xl_xact_stats_item); |
202 | 0 | } |
203 | |
|
204 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_TWOPHASE) |
205 | 0 | { |
206 | 0 | xl_xact_twophase *xl_twophase = (xl_xact_twophase *) data; |
207 | |
|
208 | 0 | parsed->twophase_xid = xl_twophase->xid; |
209 | |
|
210 | 0 | data += sizeof(xl_xact_twophase); |
211 | |
|
212 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_GID) |
213 | 0 | { |
214 | 0 | strlcpy(parsed->twophase_gid, data, sizeof(parsed->twophase_gid)); |
215 | 0 | data += strlen(data) + 1; |
216 | 0 | } |
217 | 0 | } |
218 | | |
219 | | /* Note: no alignment is guaranteed after this point */ |
220 | |
|
221 | 0 | if (parsed->xinfo & XACT_XINFO_HAS_ORIGIN) |
222 | 0 | { |
223 | 0 | xl_xact_origin xl_origin; |
224 | | |
225 | | /* no alignment is guaranteed, so copy onto stack */ |
226 | 0 | memcpy(&xl_origin, data, sizeof(xl_origin)); |
227 | |
|
228 | 0 | parsed->origin_lsn = xl_origin.origin_lsn; |
229 | 0 | parsed->origin_timestamp = xl_origin.origin_timestamp; |
230 | |
|
231 | 0 | data += sizeof(xl_xact_origin); |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | | /* |
236 | | * ParsePrepareRecord |
237 | | */ |
238 | | void |
239 | | ParsePrepareRecord(uint8 info, xl_xact_prepare *xlrec, xl_xact_parsed_prepare *parsed) |
240 | 0 | { |
241 | 0 | char *bufptr; |
242 | |
|
243 | 0 | bufptr = ((char *) xlrec) + MAXALIGN(sizeof(xl_xact_prepare)); |
244 | |
|
245 | 0 | memset(parsed, 0, sizeof(*parsed)); |
246 | |
|
247 | 0 | parsed->xact_time = xlrec->prepared_at; |
248 | 0 | parsed->origin_lsn = xlrec->origin_lsn; |
249 | 0 | parsed->origin_timestamp = xlrec->origin_timestamp; |
250 | 0 | parsed->twophase_xid = xlrec->xid; |
251 | 0 | parsed->dbId = xlrec->database; |
252 | 0 | parsed->nsubxacts = xlrec->nsubxacts; |
253 | 0 | parsed->nrels = xlrec->ncommitrels; |
254 | 0 | parsed->nabortrels = xlrec->nabortrels; |
255 | 0 | parsed->nstats = xlrec->ncommitstats; |
256 | 0 | parsed->nabortstats = xlrec->nabortstats; |
257 | 0 | parsed->nmsgs = xlrec->ninvalmsgs; |
258 | |
|
259 | 0 | strlcpy(parsed->twophase_gid, bufptr, GIDSIZE); |
260 | 0 | bufptr += MAXALIGN(xlrec->gidlen); |
261 | |
|
262 | 0 | parsed->subxacts = (TransactionId *) bufptr; |
263 | 0 | bufptr += MAXALIGN(xlrec->nsubxacts * sizeof(TransactionId)); |
264 | |
|
265 | 0 | parsed->xlocators = (RelFileLocator *) bufptr; |
266 | 0 | bufptr += MAXALIGN(xlrec->ncommitrels * sizeof(RelFileLocator)); |
267 | |
|
268 | 0 | parsed->abortlocators = (RelFileLocator *) bufptr; |
269 | 0 | bufptr += MAXALIGN(xlrec->nabortrels * sizeof(RelFileLocator)); |
270 | |
|
271 | 0 | parsed->stats = (xl_xact_stats_item *) bufptr; |
272 | 0 | bufptr += MAXALIGN(xlrec->ncommitstats * sizeof(xl_xact_stats_item)); |
273 | |
|
274 | 0 | parsed->abortstats = (xl_xact_stats_item *) bufptr; |
275 | 0 | bufptr += MAXALIGN(xlrec->nabortstats * sizeof(xl_xact_stats_item)); |
276 | |
|
277 | 0 | parsed->msgs = (SharedInvalidationMessage *) bufptr; |
278 | 0 | bufptr += MAXALIGN(xlrec->ninvalmsgs * sizeof(SharedInvalidationMessage)); |
279 | 0 | } |
280 | | |
281 | | static void |
282 | | xact_desc_relations(StringInfo buf, char *label, int nrels, |
283 | | RelFileLocator *xlocators) |
284 | 0 | { |
285 | 0 | int i; |
286 | |
|
287 | 0 | if (nrels > 0) |
288 | 0 | { |
289 | 0 | appendStringInfo(buf, "; %s:", label); |
290 | 0 | for (i = 0; i < nrels; i++) |
291 | 0 | { |
292 | 0 | appendStringInfo(buf, " %s", |
293 | 0 | relpathperm(xlocators[i], MAIN_FORKNUM).str); |
294 | 0 | } |
295 | 0 | } |
296 | 0 | } |
297 | | |
298 | | static void |
299 | | xact_desc_subxacts(StringInfo buf, int nsubxacts, TransactionId *subxacts) |
300 | 0 | { |
301 | 0 | int i; |
302 | |
|
303 | 0 | if (nsubxacts > 0) |
304 | 0 | { |
305 | 0 | appendStringInfoString(buf, "; subxacts:"); |
306 | 0 | for (i = 0; i < nsubxacts; i++) |
307 | 0 | appendStringInfo(buf, " %u", subxacts[i]); |
308 | 0 | } |
309 | 0 | } |
310 | | |
311 | | static void |
312 | | xact_desc_stats(StringInfo buf, const char *label, |
313 | | int ndropped, xl_xact_stats_item *dropped_stats) |
314 | 0 | { |
315 | 0 | int i; |
316 | |
|
317 | 0 | if (ndropped > 0) |
318 | 0 | { |
319 | 0 | appendStringInfo(buf, "; %sdropped stats:", label); |
320 | 0 | for (i = 0; i < ndropped; i++) |
321 | 0 | { |
322 | 0 | uint64 objid = |
323 | 0 | ((uint64) dropped_stats[i].objid_hi) << 32 | dropped_stats[i].objid_lo; |
324 | |
|
325 | 0 | appendStringInfo(buf, " %d/%u/%" PRIu64, |
326 | 0 | dropped_stats[i].kind, |
327 | 0 | dropped_stats[i].dboid, |
328 | 0 | objid); |
329 | 0 | } |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | | static void |
334 | | xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, ReplOriginId origin_id) |
335 | 0 | { |
336 | 0 | xl_xact_parsed_commit parsed; |
337 | |
|
338 | 0 | ParseCommitRecord(info, xlrec, &parsed); |
339 | | |
340 | | /* If this is a prepared xact, show the xid of the original xact */ |
341 | 0 | if (TransactionIdIsValid(parsed.twophase_xid)) |
342 | 0 | appendStringInfo(buf, "%u: ", parsed.twophase_xid); |
343 | |
|
344 | 0 | appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time)); |
345 | |
|
346 | 0 | xact_desc_relations(buf, "rels", parsed.nrels, parsed.xlocators); |
347 | 0 | xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts); |
348 | 0 | xact_desc_stats(buf, "", parsed.nstats, parsed.stats); |
349 | |
|
350 | 0 | standby_desc_invalidations(buf, parsed.nmsgs, parsed.msgs, parsed.dbId, |
351 | 0 | parsed.tsId, |
352 | 0 | XactCompletionRelcacheInitFileInval(parsed.xinfo)); |
353 | |
|
354 | 0 | if (XactCompletionApplyFeedback(parsed.xinfo)) |
355 | 0 | appendStringInfoString(buf, "; apply_feedback"); |
356 | |
|
357 | 0 | if (XactCompletionForceSyncCommit(parsed.xinfo)) |
358 | 0 | appendStringInfoString(buf, "; sync"); |
359 | |
|
360 | 0 | if (parsed.xinfo & XACT_XINFO_HAS_ORIGIN) |
361 | 0 | { |
362 | 0 | appendStringInfo(buf, "; origin: node %u, lsn %X/%08X, at %s", |
363 | 0 | origin_id, |
364 | 0 | LSN_FORMAT_ARGS(parsed.origin_lsn), |
365 | 0 | timestamptz_to_str(parsed.origin_timestamp)); |
366 | 0 | } |
367 | 0 | } |
368 | | |
369 | | static void |
370 | | xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec, ReplOriginId origin_id) |
371 | 0 | { |
372 | 0 | xl_xact_parsed_abort parsed; |
373 | |
|
374 | 0 | ParseAbortRecord(info, xlrec, &parsed); |
375 | | |
376 | | /* If this is a prepared xact, show the xid of the original xact */ |
377 | 0 | if (TransactionIdIsValid(parsed.twophase_xid)) |
378 | 0 | appendStringInfo(buf, "%u: ", parsed.twophase_xid); |
379 | |
|
380 | 0 | appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time)); |
381 | |
|
382 | 0 | xact_desc_relations(buf, "rels", parsed.nrels, parsed.xlocators); |
383 | 0 | xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts); |
384 | |
|
385 | 0 | if (parsed.xinfo & XACT_XINFO_HAS_ORIGIN) |
386 | 0 | { |
387 | 0 | appendStringInfo(buf, "; origin: node %u, lsn %X/%08X, at %s", |
388 | 0 | origin_id, |
389 | 0 | LSN_FORMAT_ARGS(parsed.origin_lsn), |
390 | 0 | timestamptz_to_str(parsed.origin_timestamp)); |
391 | 0 | } |
392 | |
|
393 | 0 | xact_desc_stats(buf, "", parsed.nstats, parsed.stats); |
394 | 0 | } |
395 | | |
396 | | static void |
397 | | xact_desc_prepare(StringInfo buf, uint8 info, xl_xact_prepare *xlrec, ReplOriginId origin_id) |
398 | 0 | { |
399 | 0 | xl_xact_parsed_prepare parsed; |
400 | |
|
401 | 0 | ParsePrepareRecord(info, xlrec, &parsed); |
402 | |
|
403 | 0 | appendStringInfo(buf, "gid %s: ", parsed.twophase_gid); |
404 | 0 | appendStringInfoString(buf, timestamptz_to_str(parsed.xact_time)); |
405 | |
|
406 | 0 | xact_desc_relations(buf, "rels(commit)", parsed.nrels, parsed.xlocators); |
407 | 0 | xact_desc_relations(buf, "rels(abort)", parsed.nabortrels, |
408 | 0 | parsed.abortlocators); |
409 | 0 | xact_desc_stats(buf, "commit ", parsed.nstats, parsed.stats); |
410 | 0 | xact_desc_stats(buf, "abort ", parsed.nabortstats, parsed.abortstats); |
411 | 0 | xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts); |
412 | |
|
413 | 0 | standby_desc_invalidations(buf, parsed.nmsgs, parsed.msgs, parsed.dbId, |
414 | 0 | parsed.tsId, xlrec->initfileinval); |
415 | | |
416 | | /* |
417 | | * Check if the replication origin has been set in this record in the same |
418 | | * way as PrepareRedoAdd(). |
419 | | */ |
420 | 0 | if (origin_id != InvalidReplOriginId) |
421 | 0 | appendStringInfo(buf, "; origin: node %u, lsn %X/%08X, at %s", |
422 | 0 | origin_id, |
423 | 0 | LSN_FORMAT_ARGS(parsed.origin_lsn), |
424 | 0 | timestamptz_to_str(parsed.origin_timestamp)); |
425 | 0 | } |
426 | | |
427 | | static void |
428 | | xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec) |
429 | 0 | { |
430 | 0 | int i; |
431 | |
|
432 | 0 | appendStringInfoString(buf, "subxacts:"); |
433 | |
|
434 | 0 | for (i = 0; i < xlrec->nsubxacts; i++) |
435 | 0 | appendStringInfo(buf, " %u", xlrec->xsub[i]); |
436 | 0 | } |
437 | | |
438 | | void |
439 | | xact_desc(StringInfo buf, XLogReaderState *record) |
440 | 0 | { |
441 | 0 | char *rec = XLogRecGetData(record); |
442 | 0 | uint8 info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK; |
443 | |
|
444 | 0 | if (info == XLOG_XACT_COMMIT || info == XLOG_XACT_COMMIT_PREPARED) |
445 | 0 | { |
446 | 0 | xl_xact_commit *xlrec = (xl_xact_commit *) rec; |
447 | |
|
448 | 0 | xact_desc_commit(buf, XLogRecGetInfo(record), xlrec, |
449 | 0 | XLogRecGetOrigin(record)); |
450 | 0 | } |
451 | 0 | else if (info == XLOG_XACT_ABORT || info == XLOG_XACT_ABORT_PREPARED) |
452 | 0 | { |
453 | 0 | xl_xact_abort *xlrec = (xl_xact_abort *) rec; |
454 | |
|
455 | 0 | xact_desc_abort(buf, XLogRecGetInfo(record), xlrec, |
456 | 0 | XLogRecGetOrigin(record)); |
457 | 0 | } |
458 | 0 | else if (info == XLOG_XACT_PREPARE) |
459 | 0 | { |
460 | 0 | xl_xact_prepare *xlrec = (xl_xact_prepare *) rec; |
461 | |
|
462 | 0 | xact_desc_prepare(buf, XLogRecGetInfo(record), xlrec, |
463 | 0 | XLogRecGetOrigin(record)); |
464 | 0 | } |
465 | 0 | else if (info == XLOG_XACT_ASSIGNMENT) |
466 | 0 | { |
467 | 0 | xl_xact_assignment *xlrec = (xl_xact_assignment *) rec; |
468 | | |
469 | | /* |
470 | | * Note that we ignore the WAL record's xid, since we're more |
471 | | * interested in the top-level xid that issued the record and which |
472 | | * xids are being reported here. |
473 | | */ |
474 | 0 | appendStringInfo(buf, "xtop %u: ", xlrec->xtop); |
475 | 0 | xact_desc_assignment(buf, xlrec); |
476 | 0 | } |
477 | 0 | else if (info == XLOG_XACT_INVALIDATIONS) |
478 | 0 | { |
479 | 0 | xl_xact_invals *xlrec = (xl_xact_invals *) rec; |
480 | |
|
481 | 0 | standby_desc_invalidations(buf, xlrec->nmsgs, xlrec->msgs, InvalidOid, |
482 | 0 | InvalidOid, false); |
483 | 0 | } |
484 | 0 | } |
485 | | |
486 | | const char * |
487 | | xact_identify(uint8 info) |
488 | 0 | { |
489 | 0 | const char *id = NULL; |
490 | |
|
491 | 0 | switch (info & XLOG_XACT_OPMASK) |
492 | 0 | { |
493 | 0 | case XLOG_XACT_COMMIT: |
494 | 0 | id = "COMMIT"; |
495 | 0 | break; |
496 | 0 | case XLOG_XACT_PREPARE: |
497 | 0 | id = "PREPARE"; |
498 | 0 | break; |
499 | 0 | case XLOG_XACT_ABORT: |
500 | 0 | id = "ABORT"; |
501 | 0 | break; |
502 | 0 | case XLOG_XACT_COMMIT_PREPARED: |
503 | 0 | id = "COMMIT_PREPARED"; |
504 | 0 | break; |
505 | 0 | case XLOG_XACT_ABORT_PREPARED: |
506 | 0 | id = "ABORT_PREPARED"; |
507 | 0 | break; |
508 | 0 | case XLOG_XACT_ASSIGNMENT: |
509 | 0 | id = "ASSIGNMENT"; |
510 | 0 | break; |
511 | 0 | case XLOG_XACT_INVALIDATIONS: |
512 | 0 | id = "INVALIDATION"; |
513 | 0 | break; |
514 | 0 | } |
515 | | |
516 | 0 | return id; |
517 | 0 | } |