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