Coverage Report

Created: 2026-08-13 07:12

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 "catalog/pg_authid_d.h"
21
#include "funcapi.h"
22
#include "miscadmin.h"
23
#include "utils/acl.h"
24
#include "utils/builtins.h"
25
26
/*
27
 * pg_get_multixact_members
28
 *
29
 * Returns information about the MultiXactMembers of the specified
30
 * MultiXactId.
31
 */
32
Datum
33
pg_get_multixact_members(PG_FUNCTION_ARGS)
34
0
{
35
0
  typedef struct
36
0
  {
37
0
    MultiXactMember *members;
38
0
    int     nmembers;
39
0
    int     iter;
40
0
  } mxact;
41
0
  MultiXactId mxid = PG_GETARG_TRANSACTIONID(0);
42
0
  mxact    *multi;
43
0
  FuncCallContext *funccxt;
44
45
0
  if (mxid < FirstMultiXactId)
46
0
    ereport(ERROR,
47
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
48
0
         errmsg("invalid MultiXactId: %u", mxid)));
49
50
0
  if (SRF_IS_FIRSTCALL())
51
0
  {
52
0
    MemoryContext oldcxt;
53
0
    TupleDesc tupdesc;
54
55
0
    funccxt = SRF_FIRSTCALL_INIT();
56
0
    oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
57
58
0
    multi = palloc_object(mxact);
59
    /* no need to allow for old values here */
60
0
    multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
61
0
                        false);
62
0
    multi->iter = 0;
63
64
0
    if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
65
0
      elog(ERROR, "return type must be a row type");
66
0
    funccxt->tuple_desc = tupdesc;
67
0
    funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
68
0
    funccxt->user_fctx = multi;
69
70
0
    MemoryContextSwitchTo(oldcxt);
71
0
  }
72
73
0
  funccxt = SRF_PERCALL_SETUP();
74
0
  multi = (mxact *) funccxt->user_fctx;
75
76
0
  while (multi->iter < multi->nmembers)
77
0
  {
78
0
    HeapTuple tuple;
79
0
    char     *values[2];
80
81
0
    values[0] = psprintf("%u", multi->members[multi->iter].xid);
82
0
    values[1] = mxstatus_to_string(multi->members[multi->iter].status);
83
84
0
    tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
85
86
0
    multi->iter++;
87
0
    pfree(values[0]);
88
0
    SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
89
0
  }
90
91
0
  SRF_RETURN_DONE(funccxt);
92
0
}
93
94
/*
95
 * pg_get_multixact_stats
96
 *
97
 * Returns statistics about current multixact usage.
98
 */
99
Datum
100
pg_get_multixact_stats(PG_FUNCTION_ARGS)
101
0
{
102
0
  TupleDesc tupdesc;
103
0
  Datum   values[4];
104
0
  bool    nulls[4];
105
106
0
  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
107
0
    ereport(ERROR,
108
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
109
0
         errmsg("return type must be a row type")));
110
111
0
  if (!has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS))
112
0
  {
113
    /*
114
     * Only superusers and roles with privileges of pg_read_all_stats can
115
     * see details.
116
     */
117
0
    memset(nulls, true, sizeof(bool) * tupdesc->natts);
118
0
  }
119
0
  else
120
0
  {
121
0
    uint64    members;
122
0
    MultiXactId oldestMultiXactId;
123
0
    uint32    multixacts;
124
0
    MultiXactOffset oldestOffset;
125
0
    MultiXactOffset nextOffset;
126
0
    uint64    membersBytes;
127
128
0
    GetMultiXactInfo(&multixacts, &nextOffset, &oldestMultiXactId, &oldestOffset);
129
0
    members = nextOffset - oldestOffset;
130
0
    membersBytes = MultiXactOffsetStorageSize(nextOffset, oldestOffset);
131
132
0
    values[0] = UInt32GetDatum(multixacts);
133
0
    values[1] = Int64GetDatum(members);
134
0
    values[2] = Int64GetDatum(membersBytes);
135
0
    values[3] = UInt32GetDatum(oldestMultiXactId);
136
0
    memset(nulls, false, sizeof(nulls));
137
0
  }
138
139
0
  return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls));
140
0
}