/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 | } |