00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "postgres.h"
00026
00027 #include "access/multixact.h"
00028 #include "access/relscan.h"
00029 #include "access/xact.h"
00030 #include "catalog/namespace.h"
00031 #include "funcapi.h"
00032 #include "miscadmin.h"
00033 #include "storage/bufmgr.h"
00034 #include "storage/procarray.h"
00035 #include "utils/acl.h"
00036 #include "utils/builtins.h"
00037 #include "utils/rel.h"
00038 #include "utils/tqual.h"
00039
00040
00041 PG_MODULE_MAGIC;
00042
00043 PG_FUNCTION_INFO_V1(pgrowlocks);
00044
00045 extern Datum pgrowlocks(PG_FUNCTION_ARGS);
00046
00047
00048
00049
00050
00051
00052
00053 #define NCHARS 32
00054
00055 typedef struct
00056 {
00057 Relation rel;
00058 HeapScanDesc scan;
00059 int ncolumns;
00060 } MyData;
00061
00062 #define Atnum_tid 0
00063 #define Atnum_xmax 1
00064 #define Atnum_ismulti 2
00065 #define Atnum_xids 3
00066 #define Atnum_modes 4
00067 #define Atnum_pids 5
00068
00069 Datum
00070 pgrowlocks(PG_FUNCTION_ARGS)
00071 {
00072 FuncCallContext *funcctx;
00073 HeapScanDesc scan;
00074 HeapTuple tuple;
00075 TupleDesc tupdesc;
00076 AttInMetadata *attinmeta;
00077 Datum result;
00078 MyData *mydata;
00079 Relation rel;
00080
00081 if (SRF_IS_FIRSTCALL())
00082 {
00083 text *relname;
00084 RangeVar *relrv;
00085 MemoryContext oldcontext;
00086 AclResult aclresult;
00087
00088 funcctx = SRF_FIRSTCALL_INIT();
00089 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
00090
00091
00092 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
00093 elog(ERROR, "return type must be a row type");
00094
00095 attinmeta = TupleDescGetAttInMetadata(tupdesc);
00096 funcctx->attinmeta = attinmeta;
00097
00098 relname = PG_GETARG_TEXT_P(0);
00099 relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
00100 rel = heap_openrv(relrv, AccessShareLock);
00101
00102
00103 aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
00104 ACL_SELECT);
00105 if (aclresult != ACLCHECK_OK)
00106 aclcheck_error(aclresult, ACL_KIND_CLASS,
00107 RelationGetRelationName(rel));
00108
00109 scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
00110 mydata = palloc(sizeof(*mydata));
00111 mydata->rel = rel;
00112 mydata->scan = scan;
00113 mydata->ncolumns = tupdesc->natts;
00114 funcctx->user_fctx = mydata;
00115
00116 MemoryContextSwitchTo(oldcontext);
00117 }
00118
00119 funcctx = SRF_PERCALL_SETUP();
00120 attinmeta = funcctx->attinmeta;
00121 mydata = (MyData *) funcctx->user_fctx;
00122 scan = mydata->scan;
00123
00124
00125 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
00126 {
00127 HTSU_Result htsu;
00128 TransactionId xmax;
00129 uint16 infomask;
00130
00131
00132 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
00133
00134 htsu = HeapTupleSatisfiesUpdate(tuple->t_data,
00135 GetCurrentCommandId(false),
00136 scan->rs_cbuf);
00137 xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
00138 infomask = tuple->t_data->t_infomask;
00139
00140
00141
00142
00143
00144 if (htsu == HeapTupleBeingUpdated ||
00145 (htsu == HeapTupleMayBeUpdated &&
00146 !(infomask & HEAP_XMAX_INVALID) &&
00147 !(infomask & HEAP_XMAX_IS_MULTI) &&
00148 (xmax == GetCurrentTransactionIdIfAny())))
00149 {
00150 char **values;
00151
00152 values = (char **) palloc(mydata->ncolumns * sizeof(char *));
00153
00154 values[Atnum_tid] = (char *) DirectFunctionCall1(tidout,
00155 PointerGetDatum(&tuple->t_self));
00156
00157 values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
00158 snprintf(values[Atnum_xmax], NCHARS, "%d", xmax);
00159 if (infomask & HEAP_XMAX_IS_MULTI)
00160 {
00161 MultiXactMember *members;
00162 int nmembers;
00163 bool first = true;
00164 bool allow_old;
00165
00166 values[Atnum_ismulti] = pstrdup("true");
00167
00168 allow_old = !(infomask & HEAP_LOCK_MASK) &&
00169 (infomask & HEAP_XMAX_LOCK_ONLY);
00170 nmembers = GetMultiXactIdMembers(xmax, &members, allow_old);
00171 if (nmembers == -1)
00172 {
00173 values[Atnum_xids] = "{0}";
00174 values[Atnum_modes] = "{transient upgrade status}";
00175 values[Atnum_pids] = "{0}";
00176 }
00177 else
00178 {
00179 int j;
00180
00181 values[Atnum_xids] = palloc(NCHARS * nmembers);
00182 values[Atnum_modes] = palloc(NCHARS * nmembers);
00183 values[Atnum_pids] = palloc(NCHARS * nmembers);
00184
00185 strcpy(values[Atnum_xids], "{");
00186 strcpy(values[Atnum_modes], "{");
00187 strcpy(values[Atnum_pids], "{");
00188
00189 for (j = 0; j < nmembers; j++)
00190 {
00191 char buf[NCHARS];
00192
00193 if (!first)
00194 {
00195 strcat(values[Atnum_xids], ",");
00196 strcat(values[Atnum_modes], ",");
00197 strcat(values[Atnum_pids], ",");
00198 }
00199 snprintf(buf, NCHARS, "%d", members[j].xid);
00200 strcat(values[Atnum_xids], buf);
00201 switch (members[j].status)
00202 {
00203 case MultiXactStatusUpdate:
00204 snprintf(buf, NCHARS, "Update");
00205 break;
00206 case MultiXactStatusNoKeyUpdate:
00207 snprintf(buf, NCHARS, "No Key Update");
00208 break;
00209 case MultiXactStatusForUpdate:
00210 snprintf(buf, NCHARS, "For Update");
00211 break;
00212 case MultiXactStatusForNoKeyUpdate:
00213 snprintf(buf, NCHARS, "For No Key Update");
00214 break;
00215 case MultiXactStatusForShare:
00216 snprintf(buf, NCHARS, "Share");
00217 break;
00218 case MultiXactStatusForKeyShare:
00219 snprintf(buf, NCHARS, "Key Share");
00220 break;
00221 }
00222 strcat(values[Atnum_modes], buf);
00223 snprintf(buf, NCHARS, "%d",
00224 BackendXidGetPid(members[j].xid));
00225 strcat(values[Atnum_pids], buf);
00226
00227 first = false;
00228 }
00229
00230 strcat(values[Atnum_xids], "}");
00231 strcat(values[Atnum_modes], "}");
00232 strcat(values[Atnum_pids], "}");
00233 }
00234 }
00235 else
00236 {
00237 values[Atnum_ismulti] = pstrdup("false");
00238
00239 values[Atnum_xids] = palloc(NCHARS * sizeof(char));
00240 snprintf(values[Atnum_xids], NCHARS, "{%d}", xmax);
00241
00242 values[Atnum_modes] = palloc(NCHARS);
00243 if (infomask & HEAP_XMAX_LOCK_ONLY)
00244 {
00245 if (HEAP_XMAX_IS_SHR_LOCKED(infomask))
00246 snprintf(values[Atnum_modes], NCHARS, "{For Share}");
00247 else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
00248 snprintf(values[Atnum_modes], NCHARS, "{For Key Share}");
00249 else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
00250 {
00251 if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
00252 snprintf(values[Atnum_modes], NCHARS, "{For Update}");
00253 else
00254 snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}");
00255 }
00256 else
00257
00258 snprintf(values[Atnum_modes], NCHARS,
00259 "{transient upgrade status}");
00260 }
00261 else
00262 {
00263 if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
00264 snprintf(values[Atnum_modes], NCHARS, "{Update}");
00265 else
00266 snprintf(values[Atnum_modes], NCHARS, "{No Key Update}");
00267 }
00268
00269 values[Atnum_pids] = palloc(NCHARS * sizeof(char));
00270 snprintf(values[Atnum_pids], NCHARS, "{%d}",
00271 BackendXidGetPid(xmax));
00272 }
00273
00274 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
00275
00276
00277 tuple = BuildTupleFromCStrings(attinmeta, values);
00278
00279
00280 result = HeapTupleGetDatum(tuple);
00281
00282
00283
00284
00285
00286
00287 SRF_RETURN_NEXT(funcctx, result);
00288 }
00289 else
00290 {
00291 LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
00292 }
00293 }
00294
00295 heap_endscan(scan);
00296 heap_close(mydata->rel, AccessShareLock);
00297
00298 SRF_RETURN_DONE(funcctx);
00299 }