#include "postgres.h"#include "access/multixact.h"#include "access/relscan.h"#include "access/xact.h"#include "catalog/namespace.h"#include "funcapi.h"#include "miscadmin.h"#include "storage/bufmgr.h"#include "storage/procarray.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/rel.h"#include "utils/tqual.h"
Go to the source code of this file.
Data Structures | |
| struct | MyData |
Defines | |
| #define | NCHARS 32 |
| #define | Atnum_tid 0 |
| #define | Atnum_xmax 1 |
| #define | Atnum_ismulti 2 |
| #define | Atnum_xids 3 |
| #define | Atnum_modes 4 |
| #define | Atnum_pids 5 |
Functions | |
| PG_FUNCTION_INFO_V1 (pgrowlocks) | |
| Datum | pgrowlocks (PG_FUNCTION_ARGS) |
Variables | |
| PG_MODULE_MAGIC | |
| #define Atnum_ismulti 2 |
Definition at line 64 of file pgrowlocks.c.
| #define Atnum_modes 4 |
Definition at line 66 of file pgrowlocks.c.
Referenced by pgrowlocks().
| #define Atnum_pids 5 |
Definition at line 67 of file pgrowlocks.c.
Referenced by pgrowlocks().
| #define Atnum_tid 0 |
Definition at line 62 of file pgrowlocks.c.
| #define Atnum_xids 3 |
Definition at line 65 of file pgrowlocks.c.
Referenced by pgrowlocks().
| #define Atnum_xmax 1 |
Definition at line 63 of file pgrowlocks.c.
Referenced by pgrowlocks().
| #define NCHARS 32 |
Definition at line 53 of file pgrowlocks.c.
Referenced by build_pgstattuple_type(), and pgrowlocks().
| PG_FUNCTION_INFO_V1 | ( | pgrowlocks | ) |
| Datum pgrowlocks | ( | PG_FUNCTION_ARGS | ) |
Definition at line 70 of file pgrowlocks.c.
References AccessShareLock, ACL_KIND_CLASS, ACL_SELECT, aclcheck_error(), ACLCHECK_OK, Atnum_modes, Atnum_pids, Atnum_xids, Atnum_xmax, FuncCallContext::attinmeta, BackendXidGetPid(), buf, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BuildTupleFromCStrings(), DirectFunctionCall1, elog, ERROR, ForwardScanDirection, get_call_result_type(), GetCurrentCommandId(), GetCurrentTransactionIdIfAny(), GetMultiXactIdMembers(), GetUserId(), heap_beginscan(), heap_close, heap_endscan(), heap_getnext(), HEAP_KEYS_UPDATED, heap_openrv(), HEAP_XMAX_INVALID, HEAP_XMAX_IS_EXCL_LOCKED, HEAP_XMAX_IS_KEYSHR_LOCKED, HEAP_XMAX_IS_MULTI, HEAP_XMAX_IS_SHR_LOCKED, HEAP_XMAX_LOCK_ONLY, HeapTupleBeingUpdated, HeapTupleGetDatum, HeapTupleHeaderGetRawXmax, HeapTupleMayBeUpdated, HeapTupleSatisfiesUpdate(), LockBuffer(), makeRangeVarFromNameList(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, MultiXactStatusForKeyShare, MultiXactStatusForNoKeyUpdate, MultiXactStatusForShare, MultiXactStatusForUpdate, MultiXactStatusNoKeyUpdate, MultiXactStatusUpdate, tupleDesc::natts, NCHARS, MyData::ncolumns, NULL, palloc(), pg_class_aclcheck(), PG_GETARG_TEXT_P, PointerGetDatum, pstrdup(), MyData::rel, RelationGetRelationName, RelationGetRelid, HeapScanDescData::rs_cbuf, MyData::scan, SnapshotNow, snprintf(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, status(), HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleHeaderData::t_infomask2, HeapTupleData::t_self, textToQualifiedNameList(), tidout(), TupleDescGetAttInMetadata(), TYPEFUNC_COMPOSITE, FuncCallContext::user_fctx, and values.
{
FuncCallContext *funcctx;
HeapScanDesc scan;
HeapTuple tuple;
TupleDesc tupdesc;
AttInMetadata *attinmeta;
Datum result;
MyData *mydata;
Relation rel;
if (SRF_IS_FIRSTCALL())
{
text *relname;
RangeVar *relrv;
MemoryContext oldcontext;
AclResult aclresult;
funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
attinmeta = TupleDescGetAttInMetadata(tupdesc);
funcctx->attinmeta = attinmeta;
relname = PG_GETARG_TEXT_P(0);
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
rel = heap_openrv(relrv, AccessShareLock);
/* check permissions: must have SELECT on table */
aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
ACL_SELECT);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_CLASS,
RelationGetRelationName(rel));
scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
mydata = palloc(sizeof(*mydata));
mydata->rel = rel;
mydata->scan = scan;
mydata->ncolumns = tupdesc->natts;
funcctx->user_fctx = mydata;
MemoryContextSwitchTo(oldcontext);
}
funcctx = SRF_PERCALL_SETUP();
attinmeta = funcctx->attinmeta;
mydata = (MyData *) funcctx->user_fctx;
scan = mydata->scan;
/* scan the relation */
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
HTSU_Result htsu;
TransactionId xmax;
uint16 infomask;
/* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
htsu = HeapTupleSatisfiesUpdate(tuple->t_data,
GetCurrentCommandId(false),
scan->rs_cbuf);
xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
infomask = tuple->t_data->t_infomask;
/*
* a tuple is locked if HTSU returns BeingUpdated, and if it returns
* MayBeUpdated but the Xmax is valid and pointing at us.
*/
if (htsu == HeapTupleBeingUpdated ||
(htsu == HeapTupleMayBeUpdated &&
!(infomask & HEAP_XMAX_INVALID) &&
!(infomask & HEAP_XMAX_IS_MULTI) &&
(xmax == GetCurrentTransactionIdIfAny())))
{
char **values;
values = (char **) palloc(mydata->ncolumns * sizeof(char *));
values[Atnum_tid] = (char *) DirectFunctionCall1(tidout,
PointerGetDatum(&tuple->t_self));
values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
snprintf(values[Atnum_xmax], NCHARS, "%d", xmax);
if (infomask & HEAP_XMAX_IS_MULTI)
{
MultiXactMember *members;
int nmembers;
bool first = true;
bool allow_old;
values[Atnum_ismulti] = pstrdup("true");
allow_old = !(infomask & HEAP_LOCK_MASK) &&
(infomask & HEAP_XMAX_LOCK_ONLY);
nmembers = GetMultiXactIdMembers(xmax, &members, allow_old);
if (nmembers == -1)
{
values[Atnum_xids] = "{0}";
values[Atnum_modes] = "{transient upgrade status}";
values[Atnum_pids] = "{0}";
}
else
{
int j;
values[Atnum_xids] = palloc(NCHARS * nmembers);
values[Atnum_modes] = palloc(NCHARS * nmembers);
values[Atnum_pids] = palloc(NCHARS * nmembers);
strcpy(values[Atnum_xids], "{");
strcpy(values[Atnum_modes], "{");
strcpy(values[Atnum_pids], "{");
for (j = 0; j < nmembers; j++)
{
char buf[NCHARS];
if (!first)
{
strcat(values[Atnum_xids], ",");
strcat(values[Atnum_modes], ",");
strcat(values[Atnum_pids], ",");
}
snprintf(buf, NCHARS, "%d", members[j].xid);
strcat(values[Atnum_xids], buf);
switch (members[j].status)
{
case MultiXactStatusUpdate:
snprintf(buf, NCHARS, "Update");
break;
case MultiXactStatusNoKeyUpdate:
snprintf(buf, NCHARS, "No Key Update");
break;
case MultiXactStatusForUpdate:
snprintf(buf, NCHARS, "For Update");
break;
case MultiXactStatusForNoKeyUpdate:
snprintf(buf, NCHARS, "For No Key Update");
break;
case MultiXactStatusForShare:
snprintf(buf, NCHARS, "Share");
break;
case MultiXactStatusForKeyShare:
snprintf(buf, NCHARS, "Key Share");
break;
}
strcat(values[Atnum_modes], buf);
snprintf(buf, NCHARS, "%d",
BackendXidGetPid(members[j].xid));
strcat(values[Atnum_pids], buf);
first = false;
}
strcat(values[Atnum_xids], "}");
strcat(values[Atnum_modes], "}");
strcat(values[Atnum_pids], "}");
}
}
else
{
values[Atnum_ismulti] = pstrdup("false");
values[Atnum_xids] = palloc(NCHARS * sizeof(char));
snprintf(values[Atnum_xids], NCHARS, "{%d}", xmax);
values[Atnum_modes] = palloc(NCHARS);
if (infomask & HEAP_XMAX_LOCK_ONLY)
{
if (HEAP_XMAX_IS_SHR_LOCKED(infomask))
snprintf(values[Atnum_modes], NCHARS, "{For Share}");
else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
snprintf(values[Atnum_modes], NCHARS, "{For Key Share}");
else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
{
if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
snprintf(values[Atnum_modes], NCHARS, "{For Update}");
else
snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}");
}
else
/* neither keyshare nor exclusive bit it set */
snprintf(values[Atnum_modes], NCHARS,
"{transient upgrade status}");
}
else
{
if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
snprintf(values[Atnum_modes], NCHARS, "{Update}");
else
snprintf(values[Atnum_modes], NCHARS, "{No Key Update}");
}
values[Atnum_pids] = palloc(NCHARS * sizeof(char));
snprintf(values[Atnum_pids], NCHARS, "{%d}",
BackendXidGetPid(xmax));
}
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
/* build a tuple */
tuple = BuildTupleFromCStrings(attinmeta, values);
/* make the tuple into a datum */
result = HeapTupleGetDatum(tuple);
/*
* no need to pfree what we allocated; it's on a short-lived memory
* context anyway
*/
SRF_RETURN_NEXT(funcctx, result);
}
else
{
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
}
}
heap_endscan(scan);
heap_close(mydata->rel, AccessShareLock);
SRF_RETURN_DONE(funcctx);
}
Definition at line 41 of file pgrowlocks.c.
1.7.1