Age Owner Branch data 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/fmgrprotos.h"
41 : : #include "utils/rel.h"
42 : : #include "utils/snapmgr.h"
43 : : #include "utils/tuplestore.h"
44 : : #include "utils/varlena.h"
45 : :
405 tgl@sss.pgh.pa.us 46 :CBC 2 : PG_MODULE_MAGIC_EXT(
47 : : .name = "pgrowlocks",
48 : : .version = PG_VERSION
49 : : );
50 : :
7317 ishii@postgresql.org 51 : 2 : PG_FUNCTION_INFO_V1(pgrowlocks);
52 : :
53 : : /* ----------
54 : : * pgrowlocks:
55 : : * returns tids of rows being locked
56 : : * ----------
57 : : */
58 : :
59 : : #define NCHARS 32
60 : :
61 : : #define Atnum_tid 0
62 : : #define Atnum_xmax 1
63 : : #define Atnum_ismulti 2
64 : : #define Atnum_xids 3
65 : : #define Atnum_modes 4
66 : : #define Atnum_pids 5
67 : :
68 : : Datum
69 : 12 : pgrowlocks(PG_FUNCTION_ARGS)
70 : : {
2241 tgl@sss.pgh.pa.us 71 : 12 : text *relname = PG_GETARG_TEXT_PP(0);
72 : 12 : ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
73 : : AttInMetadata *attinmeta;
74 : : Relation rel;
75 : : RangeVar *relrv;
76 : : TableScanDesc scan;
77 : : HeapScanDesc hscan;
78 : : HeapTuple tuple;
79 : : AclResult aclresult;
80 : : char **values;
81 : :
1295 michael@paquier.xyz 82 : 12 : InitMaterializedSRF(fcinfo, 0);
83 : :
84 : : /* Access the table */
2241 tgl@sss.pgh.pa.us 85 : 12 : relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
86 : 12 : rel = relation_openrv(relrv, AccessShareLock);
87 : :
88 [ - + ]: 12 : if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2241 tgl@sss.pgh.pa.us 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.")));
2241 tgl@sss.pgh.pa.us 94 [ - + ]:CBC 12 : else if (rel->rd_rel->relkind != RELKIND_RELATION)
2241 tgl@sss.pgh.pa.us 95 [ # # ]:UBC 0 : ereport(ERROR,
96 : : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
97 : : errmsg("\"%s\" is not a table",
98 : : RelationGetRelationName(rel))));
917 drowley@postgresql.o 99 [ - + ]:CBC 12 : else if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
917 drowley@postgresql.o 100 [ # # ]:UBC 0 : ereport(ERROR,
101 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
102 : : errmsg("only heap AM is supported")));
103 : :
104 : : /*
105 : : * check permissions: must have SELECT on table or be in
106 : : * pg_stat_scan_tables
107 : : */
2241 tgl@sss.pgh.pa.us 108 :CBC 12 : aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
109 : : ACL_SELECT);
110 [ - + ]: 12 : if (aclresult != ACLCHECK_OK)
1499 mail@joeconway.com 111 :UBC 0 : aclresult = has_privs_of_role(GetUserId(), ROLE_PG_STAT_SCAN_TABLES) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
112 : :
2241 tgl@sss.pgh.pa.us 113 [ - + ]:CBC 12 : if (aclresult != ACLCHECK_OK)
2241 tgl@sss.pgh.pa.us 114 :UBC 0 : aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
115 : 0 : RelationGetRelationName(rel));
116 : :
117 : : /* Scan the relation */
36 melanieplageman@gmai 118 :GNC 12 : scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL, SO_NONE);
2241 tgl@sss.pgh.pa.us 119 :CBC 12 : hscan = (HeapScanDesc) scan;
120 : :
1519 michael@paquier.xyz 121 : 12 : attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
122 : :
123 : 12 : values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *));
124 : :
7317 ishii@postgresql.org 125 [ + + ]: 36 : while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
126 : : {
127 : : TM_Result htsu;
128 : : TransactionId xmax;
129 : : uint16 infomask;
130 : :
131 : : /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
2612 andres@anarazel.de 132 : 24 : LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_SHARE);
133 : :
4670 rhaas@postgresql.org 134 : 24 : htsu = HeapTupleSatisfiesUpdate(tuple,
135 : : GetCurrentCommandId(false),
136 : : hscan->rs_cbuf);
4850 alvherre@alvh.no-ip. 137 : 24 : xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
138 : 24 : infomask = tuple->t_data->t_infomask;
139 : :
140 : : /*
141 : : * A tuple is locked if HTSU returns BeingModified.
142 : : */
2600 andres@anarazel.de 143 [ + + ]: 24 : if (htsu == TM_BeingModified)
144 : : {
270 peter@eisentraut.org 145 :GNC 22 : values[Atnum_tid] = DatumGetCString(DirectFunctionCall1(tidout,
146 : : PointerGetDatum(&tuple->t_self)));
147 : :
4850 alvherre@alvh.no-ip. 148 :CBC 22 : values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
1609 peter@eisentraut.org 149 : 22 : snprintf(values[Atnum_xmax], NCHARS, "%u", xmax);
4850 alvherre@alvh.no-ip. 150 [ + + ]: 22 : if (infomask & HEAP_XMAX_IS_MULTI)
151 : : {
152 : : MultiXactMember *members;
153 : : int nmembers;
154 : 8 : bool first = true;
155 : : bool allow_old;
156 : :
157 : 8 : values[Atnum_ismulti] = pstrdup("true");
158 : :
3602 159 : 8 : allow_old = HEAP_LOCKED_UPGRADED(infomask);
4298 160 : 8 : nmembers = GetMultiXactIdMembers(xmax, &members, allow_old,
161 : : false);
4850 162 [ - + ]: 8 : if (nmembers == -1)
163 : : {
4850 alvherre@alvh.no-ip. 164 :UBC 0 : values[Atnum_xids] = "{0}";
165 : 0 : values[Atnum_modes] = "{transient upgrade status}";
166 : 0 : values[Atnum_pids] = "{0}";
167 : : }
168 : : else
169 : : {
170 : : int j;
171 : :
4850 alvherre@alvh.no-ip. 172 :CBC 8 : values[Atnum_xids] = palloc(NCHARS * nmembers);
173 : 8 : values[Atnum_modes] = palloc(NCHARS * nmembers);
174 : 8 : values[Atnum_pids] = palloc(NCHARS * nmembers);
175 : :
176 : 8 : strcpy(values[Atnum_xids], "{");
177 : 8 : strcpy(values[Atnum_modes], "{");
178 : 8 : strcpy(values[Atnum_pids], "{");
179 : :
180 [ + + ]: 24 : for (j = 0; j < nmembers; j++)
181 : : {
182 : : char buf[NCHARS];
183 : :
184 [ + + ]: 16 : if (!first)
185 : : {
186 : 8 : strcat(values[Atnum_xids], ",");
187 : 8 : strcat(values[Atnum_modes], ",");
188 : 8 : strcat(values[Atnum_pids], ",");
189 : : }
1609 peter@eisentraut.org 190 : 16 : snprintf(buf, NCHARS, "%u", members[j].xid);
4850 alvherre@alvh.no-ip. 191 : 16 : strcat(values[Atnum_xids], buf);
192 [ + + + + : 16 : switch (members[j].status)
+ + - ]
193 : : {
194 : 1 : case MultiXactStatusUpdate:
195 : 1 : snprintf(buf, NCHARS, "Update");
196 : 1 : break;
197 : 1 : case MultiXactStatusNoKeyUpdate:
198 : 1 : snprintf(buf, NCHARS, "No Key Update");
199 : 1 : break;
200 : 2 : case MultiXactStatusForUpdate:
201 : 2 : snprintf(buf, NCHARS, "For Update");
202 : 2 : break;
203 : 2 : case MultiXactStatusForNoKeyUpdate:
204 : 2 : snprintf(buf, NCHARS, "For No Key Update");
205 : 2 : break;
206 : 2 : case MultiXactStatusForShare:
952 bruce@momjian.us 207 : 2 : snprintf(buf, NCHARS, "For Share");
4850 alvherre@alvh.no-ip. 208 : 2 : break;
209 : 8 : case MultiXactStatusForKeyShare:
952 bruce@momjian.us 210 : 8 : snprintf(buf, NCHARS, "For Key Share");
4850 alvherre@alvh.no-ip. 211 : 8 : break;
212 : : }
213 : 16 : strcat(values[Atnum_modes], buf);
214 : 16 : snprintf(buf, NCHARS, "%d",
215 : 16 : BackendXidGetPid(members[j].xid));
216 : 16 : strcat(values[Atnum_pids], buf);
217 : :
218 : 16 : first = false;
219 : : }
220 : :
221 : 8 : strcat(values[Atnum_xids], "}");
222 : 8 : strcat(values[Atnum_modes], "}");
223 : 8 : strcat(values[Atnum_pids], "}");
224 : : }
225 : : }
226 : : else
227 : : {
228 : 14 : values[Atnum_ismulti] = pstrdup("false");
229 : :
230 : 14 : values[Atnum_xids] = palloc(NCHARS * sizeof(char));
1609 peter@eisentraut.org 231 : 14 : snprintf(values[Atnum_xids], NCHARS, "{%u}", xmax);
232 : :
4850 alvherre@alvh.no-ip. 233 : 14 : values[Atnum_modes] = palloc(NCHARS);
234 [ + + ]: 14 : if (infomask & HEAP_XMAX_LOCK_ONLY)
235 : : {
236 [ + + ]: 12 : if (HEAP_XMAX_IS_SHR_LOCKED(infomask))
237 : 2 : snprintf(values[Atnum_modes], NCHARS, "{For Share}");
238 [ + + ]: 10 : else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
239 : 6 : snprintf(values[Atnum_modes], NCHARS, "{For Key Share}");
240 [ + - ]: 4 : else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
241 : : {
4842 242 [ + + ]: 4 : if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
243 : 2 : snprintf(values[Atnum_modes], NCHARS, "{For Update}");
244 : : else
245 : 2 : snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}");
246 : : }
247 : : else
248 : : /* neither keyshare nor exclusive bit it set */
4850 alvherre@alvh.no-ip. 249 :UBC 0 : snprintf(values[Atnum_modes], NCHARS,
250 : : "{transient upgrade status}");
251 : : }
252 : : else
253 : : {
4850 alvherre@alvh.no-ip. 254 [ + + ]:CBC 2 : if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
255 : 1 : snprintf(values[Atnum_modes], NCHARS, "{Update}");
256 : : else
4842 257 : 1 : snprintf(values[Atnum_modes], NCHARS, "{No Key Update}");
258 : : }
259 : :
4850 260 : 14 : values[Atnum_pids] = palloc(NCHARS * sizeof(char));
261 : 14 : snprintf(values[Atnum_pids], NCHARS, "{%d}",
262 : : BackendXidGetPid(xmax));
263 : : }
264 : :
2612 andres@anarazel.de 265 : 22 : LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
266 : :
267 : : /* build a tuple */
7317 ishii@postgresql.org 268 : 22 : tuple = BuildTupleFromCStrings(attinmeta, values);
1519 michael@paquier.xyz 269 : 22 : tuplestore_puttuple(rsinfo->setResult, tuple);
270 : : }
271 : : else
272 : : {
2612 andres@anarazel.de 273 : 2 : LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
274 : : }
275 : : }
276 : :
277 : 12 : table_endscan(scan);
2241 tgl@sss.pgh.pa.us 278 : 12 : table_close(rel, AccessShareLock);
279 : 12 : return (Datum) 0;
280 : : }
|