Coverage Report

Created: 2026-10-16 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/adt/multixactfuncs.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * multixactfuncs.c
4
 *    Functions for accessing multixact-related data.
5
 *
6
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 * IDENTIFICATION
10
 *    src/backend/utils/adt/multixactfuncs.c
11
 *
12
 *-------------------------------------------------------------------------
13
 */
14
15
#include "postgres.h"
16
17
#include "access/htup_details.h"
18
#include "access/multixact.h"
19
#include "access/multixact_internal.h"
20
#include "access/xlog.h"
21
#include "catalog/pg_authid_d.h"
22
#include "funcapi.h"
23
#include "miscadmin.h"
24
#include "utils/acl.h"
25
#include "utils/builtins.h"
26
27
/*
28
 * pg_get_multixact_members
29
 *
30
 * Returns information about the MultiXactMembers of the specified
31
 * MultiXactId.
32
 */
33
Datum
34
pg_get_multixact_members(PG_FUNCTION_ARGS)
35
0
{
36
0
  typedef struct
37
0
  {
38
0
    MultiXactMember *members;
39
0
    int     nmembers;
40
0
    int     iter;
41
0
  } mxact;
42
0
  MultiXactId mxid = PG_GETARG_TRANSACTIONID(0);
43
0
  mxact    *multi;
44
0
  FuncCallContext *funccxt;
45
46
0
  if (mxid < FirstMultiXactId)
47
0
    ereport(ERROR,
48
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
49
0
         errmsg("invalid MultiXactId: %u", mxid)));
50
51
0
  if (SRF_IS_FIRSTCALL())
52
0
  {
53
0
    MemoryContext oldcxt;
54
0
    TupleDesc tupdesc;
55
56
0
    funccxt = SRF_FIRSTCALL_INIT();
57
0
    oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
58
59
0
    multi = palloc_object(mxact);
60
    /* no need to allow for old values here */
61
0
    multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
62
0
                        false);
63
0
    multi->iter = 0;
64
65
0
    if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
66
0
      elog(ERROR, "return type must be a row type");
67
0
    funccxt->tuple_desc = tupdesc;
68
0
    funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
69
0
    funccxt->user_fctx = multi;
70
71
0
    MemoryContextSwitchTo(oldcxt);
72
0
  }
73
74
0
  funccxt = SRF_PERCALL_SETUP();
75
0
  multi = (mxact *) funccxt->user_fctx;
76
77
0
  while (multi->iter < multi->nmembers)
78
0
  {
79
0
    HeapTuple tuple;
80
0
    char     *values[2];
81
82
0
    values[0] = psprintf("%u", multi->members[multi->iter].xid);
83
0
    values[1] = mxstatus_to_string(multi->members[multi->iter].status);
84
85
0
    tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
86
87
0
    multi->iter++;
88
0
    pfree(values[0]);
89
0
    SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
90
0
  }
91
92
0
  SRF_RETURN_DONE(funccxt);
93
0
}
94
95
/*
96
 * pg_get_multixact_stats
97
 *
98
 * Returns statistics about current multixact usage.
99
 */
100
Datum
101
pg_get_multixact_stats(PG_FUNCTION_ARGS)
102
0
{
103
0
  TupleDesc tupdesc;
104
0
  Datum   values[4];
105
0
  bool    nulls[4];
106
107
0
  if (RecoveryInProgress())
108
0
    ereport(ERROR,
109
0
        (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
110
0
         errmsg("recovery is in progress"),
111
0
         errhint("%s cannot be executed during recovery.",
112
0
             "pg_get_multixact_stats()")));
113
114
0
  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
115
0
    ereport(ERROR,
116
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
117
0
         errmsg("return type must be a row type")));
118
119
0
  if (!has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS))
120
0
  {
121
    /*
122
     * Only superusers and roles with privileges of pg_read_all_stats can
123
     * see details.
124
     */
125
0
    memset(nulls, true, sizeof(bool) * tupdesc->natts);
126
0
  }
127
0
  else
128
0
  {
129
0
    uint64    members;
130
0
    MultiXactId oldestMultiXactId;
131
0
    uint32    multixacts;
132
0
    MultiXactOffset oldestOffset;
133
0
    MultiXactOffset nextOffset;
134
0
    uint64    membersBytes;
135
136
0
    GetMultiXactInfo(&multixacts, &nextOffset, &oldestMultiXactId, &oldestOffset);
137
0
    members = nextOffset - oldestOffset;
138
0
    membersBytes = MultiXactOffsetStorageSize(nextOffset, oldestOffset);
139
140
0
    values[0] = UInt32GetDatum(multixacts);
141
0
    values[1] = Int64GetDatum(members);
142
0
    values[2] = Int64GetDatum(membersBytes);
143
0
    values[3] = UInt32GetDatum(oldestMultiXactId);
144
0
    memset(nulls, false, sizeof(nulls));
145
0
  }
146
147
0
  return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls));
148
0
}