Age Owner TLA Line data Source code
1 : /*
2 : * contrib/pgrowlocks/pgrowlocks.c
3 : *
4 : * Copyright (c) 2005-2006 Tatsuo Ishii
5 : *
6 : * Permission to use, copy, modify, and distribute this software and
7 : * its documentation for any purpose, without fee, and without a
8 : * written agreement is hereby granted, provided that the above
9 : * copyright notice and this paragraph and the following two
10 : * paragraphs appear in all copies.
11 : *
12 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
13 : * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
14 : * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
15 : * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
16 : * OF THE POSSIBILITY OF SUCH DAMAGE.
17 : *
18 : * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
19 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 : * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
21 : * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
22 : * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 : */
24 :
25 : #include "postgres.h"
26 :
27 : #include "access/heapam.h"
28 : #include "access/multixact.h"
29 : #include "access/relscan.h"
30 : #include "access/tableam.h"
31 : #include "access/xact.h"
32 : #include "catalog/namespace.h"
33 : #include "catalog/pg_am_d.h"
34 : #include "catalog/pg_authid.h"
35 : #include "funcapi.h"
36 : #include "miscadmin.h"
37 : #include "storage/bufmgr.h"
38 : #include "storage/procarray.h"
39 : #include "utils/acl.h"
40 : #include "utils/builtins.h"
41 : #include "utils/rel.h"
42 : #include "utils/snapmgr.h"
43 : #include "utils/varlena.h"
44 :
6158 tgl 45 CBC 2 : PG_MODULE_MAGIC;
46 :
6195 ishii 47 2 : PG_FUNCTION_INFO_V1(pgrowlocks);
48 :
49 : /* ----------
50 : * pgrowlocks:
51 : * returns tids of rows being locked
52 : * ----------
53 : */
54 :
55 : #define NCHARS 32
56 :
57 : #define Atnum_tid 0
58 : #define Atnum_xmax 1
59 : #define Atnum_ismulti 2
60 : #define Atnum_xids 3
61 : #define Atnum_modes 4
62 : #define Atnum_pids 5
63 :
64 : Datum
65 12 : pgrowlocks(PG_FUNCTION_ARGS)
66 : {
1119 tgl 67 12 : text *relname = PG_GETARG_TEXT_PP(0);
68 12 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
69 : AttInMetadata *attinmeta;
70 : Relation rel;
71 : RangeVar *relrv;
72 : TableScanDesc scan;
73 : HeapScanDesc hscan;
74 : HeapTuple tuple;
75 : AclResult aclresult;
76 : char **values;
77 :
173 michael 78 12 : InitMaterializedSRF(fcinfo, 0);
79 :
80 : /* Access the table */
1119 tgl 81 12 : relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
82 12 : rel = relation_openrv(relrv, AccessShareLock);
83 :
84 12 : if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
1119 tgl 85 UBC 0 : ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
86 : errmsg("only heap AM is supported")));
87 :
1119 tgl 88 CBC 12 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1119 tgl 89 UBC 0 : ereport(ERROR,
90 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
91 : errmsg("\"%s\" is a partitioned table",
92 : RelationGetRelationName(rel)),
93 : errdetail("Partitioned tables do not contain rows.")));
1119 tgl 94 CBC 12 : else if (rel->rd_rel->relkind != RELKIND_RELATION)
1119 tgl 95 UBC 0 : ereport(ERROR,
96 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
97 : errmsg("\"%s\" is not a table",
98 : RelationGetRelationName(rel))));
99 :
100 : /*
101 : * check permissions: must have SELECT on table or be in
102 : * pg_stat_scan_tables
103 : */
1119 tgl 104 CBC 12 : aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
105 : ACL_SELECT);
106 12 : if (aclresult != ACLCHECK_OK)
377 mail 107 UBC 0 : aclresult = has_privs_of_role(GetUserId(), ROLE_PG_STAT_SCAN_TABLES) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
108 :
1119 tgl 109 CBC 12 : if (aclresult != ACLCHECK_OK)
1119 tgl 110 UBC 0 : aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
111 0 : RelationGetRelationName(rel));
112 :
113 : /* Scan the relation */
1119 tgl 114 CBC 12 : scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL);
115 12 : hscan = (HeapScanDesc) scan;
116 :
397 michael 117 12 : attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
118 :
119 12 : values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *));
120 :
6195 ishii 121 36 : while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
122 : {
123 : TM_Result htsu;
124 : TransactionId xmax;
125 : uint16 infomask;
126 :
127 : /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
1490 andres 128 24 : LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_SHARE);
129 :
3548 rhaas 130 24 : htsu = HeapTupleSatisfiesUpdate(tuple,
131 : GetCurrentCommandId(false),
132 : hscan->rs_cbuf);
3728 alvherre 133 24 : xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
134 24 : infomask = tuple->t_data->t_infomask;
135 :
136 : /*
137 : * A tuple is locked if HTSU returns BeingModified.
138 : */
1478 andres 139 24 : if (htsu == TM_BeingModified)
140 : {
3728 alvherre 141 22 : values[Atnum_tid] = (char *) DirectFunctionCall1(tidout,
142 : PointerGetDatum(&tuple->t_self));
143 :
144 22 : values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
487 peter 145 22 : snprintf(values[Atnum_xmax], NCHARS, "%u", xmax);
3728 alvherre 146 22 : if (infomask & HEAP_XMAX_IS_MULTI)
147 : {
148 : MultiXactMember *members;
149 : int nmembers;
150 8 : bool first = true;
151 : bool allow_old;
152 :
153 8 : values[Atnum_ismulti] = pstrdup("true");
154 :
2480 155 8 : allow_old = HEAP_LOCKED_UPGRADED(infomask);
3176 156 8 : nmembers = GetMultiXactIdMembers(xmax, &members, allow_old,
157 : false);
3728 158 8 : if (nmembers == -1)
159 : {
3728 alvherre 160 UBC 0 : values[Atnum_xids] = "{0}";
161 0 : values[Atnum_modes] = "{transient upgrade status}";
162 0 : values[Atnum_pids] = "{0}";
163 : }
164 : else
165 : {
166 : int j;
167 :
3728 alvherre 168 CBC 8 : values[Atnum_xids] = palloc(NCHARS * nmembers);
169 8 : values[Atnum_modes] = palloc(NCHARS * nmembers);
170 8 : values[Atnum_pids] = palloc(NCHARS * nmembers);
171 :
172 8 : strcpy(values[Atnum_xids], "{");
173 8 : strcpy(values[Atnum_modes], "{");
174 8 : strcpy(values[Atnum_pids], "{");
175 :
176 24 : for (j = 0; j < nmembers; j++)
177 : {
178 : char buf[NCHARS];
179 :
180 16 : if (!first)
181 : {
182 8 : strcat(values[Atnum_xids], ",");
183 8 : strcat(values[Atnum_modes], ",");
184 8 : strcat(values[Atnum_pids], ",");
185 : }
487 peter 186 16 : snprintf(buf, NCHARS, "%u", members[j].xid);
3728 alvherre 187 16 : strcat(values[Atnum_xids], buf);
188 16 : switch (members[j].status)
189 : {
190 1 : case MultiXactStatusUpdate:
191 1 : snprintf(buf, NCHARS, "Update");
192 1 : break;
193 1 : case MultiXactStatusNoKeyUpdate:
194 1 : snprintf(buf, NCHARS, "No Key Update");
195 1 : break;
196 2 : case MultiXactStatusForUpdate:
197 2 : snprintf(buf, NCHARS, "For Update");
198 2 : break;
199 2 : case MultiXactStatusForNoKeyUpdate:
200 2 : snprintf(buf, NCHARS, "For No Key Update");
201 2 : break;
202 2 : case MultiXactStatusForShare:
203 2 : snprintf(buf, NCHARS, "Share");
204 2 : break;
205 8 : case MultiXactStatusForKeyShare:
206 8 : snprintf(buf, NCHARS, "Key Share");
207 8 : break;
208 : }
209 16 : strcat(values[Atnum_modes], buf);
210 16 : snprintf(buf, NCHARS, "%d",
211 16 : BackendXidGetPid(members[j].xid));
212 16 : strcat(values[Atnum_pids], buf);
213 :
214 16 : first = false;
215 : }
216 :
217 8 : strcat(values[Atnum_xids], "}");
218 8 : strcat(values[Atnum_modes], "}");
219 8 : strcat(values[Atnum_pids], "}");
220 : }
221 : }
222 : else
223 : {
224 14 : values[Atnum_ismulti] = pstrdup("false");
225 :
226 14 : values[Atnum_xids] = palloc(NCHARS * sizeof(char));
487 peter 227 14 : snprintf(values[Atnum_xids], NCHARS, "{%u}", xmax);
228 :
3728 alvherre 229 14 : values[Atnum_modes] = palloc(NCHARS);
230 14 : if (infomask & HEAP_XMAX_LOCK_ONLY)
231 : {
232 12 : if (HEAP_XMAX_IS_SHR_LOCKED(infomask))
233 2 : snprintf(values[Atnum_modes], NCHARS, "{For Share}");
234 10 : else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
235 6 : snprintf(values[Atnum_modes], NCHARS, "{For Key Share}");
236 4 : else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
237 : {
3720 238 4 : if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
239 2 : snprintf(values[Atnum_modes], NCHARS, "{For Update}");
240 : else
241 2 : snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}");
242 : }
243 : else
244 : /* neither keyshare nor exclusive bit it set */
3728 alvherre 245 UBC 0 : snprintf(values[Atnum_modes], NCHARS,
246 : "{transient upgrade status}");
247 : }
248 : else
249 : {
3728 alvherre 250 CBC 2 : if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
251 1 : snprintf(values[Atnum_modes], NCHARS, "{Update}");
252 : else
3720 253 1 : snprintf(values[Atnum_modes], NCHARS, "{No Key Update}");
254 : }
255 :
3728 256 14 : values[Atnum_pids] = palloc(NCHARS * sizeof(char));
257 14 : snprintf(values[Atnum_pids], NCHARS, "{%d}",
258 : BackendXidGetPid(xmax));
259 : }
260 :
1490 andres 261 22 : LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
262 :
263 : /* build a tuple */
6195 ishii 264 22 : tuple = BuildTupleFromCStrings(attinmeta, values);
397 michael 265 22 : tuplestore_puttuple(rsinfo->setResult, tuple);
266 : }
267 : else
268 : {
1490 andres 269 2 : LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
270 : }
271 : }
272 :
273 12 : table_endscan(scan);
1119 tgl 274 12 : table_close(rel, AccessShareLock);
275 12 : return (Datum) 0;
276 : }
|