1 /*-------------------------------------------------------------------------
4 * Set-returning functions to view the state of locks within the DB.
6 * Copyright (c) 2002, PostgreSQL Global Development Group
9 * $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.5 2002/08/31 17:14:28 tgl Exp $
11 *-------------------------------------------------------------------------
16 #include "access/heapam.h"
17 #include "catalog/pg_type.h"
18 #include "storage/lock.h"
19 #include "storage/proc.h"
20 #include "utils/builtins.h"
23 /* Working status for pg_lock_status */
26 LockData *lockData; /* state data from lmgr */
27 int currIdx; /* current PROCLOCK index */
31 * pg_lock_status - produce a view with one row per held or awaited lock mode
34 pg_lock_status(PG_FUNCTION_ARGS)
36 FuncCallContext *funcctx;
37 PG_Lock_Status *mystatus;
40 if (SRF_IS_FIRSTCALL())
43 MemoryContext oldcontext;
45 /* create a function context for cross-call persistence */
46 funcctx = SRF_FIRSTCALL_INIT();
48 /* switch to memory context appropriate for multiple function calls */
49 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
51 /* build tupdesc for result tuples */
52 /* this had better match pg_locks view in initdb.sh */
53 tupdesc = CreateTemplateTupleDesc(6, WITHOUTOID);
54 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation",
55 OIDOID, -1, 0, false);
56 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
57 OIDOID, -1, 0, false);
58 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction",
59 XIDOID, -1, 0, false);
60 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid",
61 INT4OID, -1, 0, false);
62 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode",
63 TEXTOID, -1, 0, false);
64 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted",
65 BOOLOID, -1, 0, false);
67 funcctx->slot = TupleDescGetSlot(tupdesc);
70 * Collect all the locking information that we will format
71 * and send out as a result set.
73 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
74 funcctx->user_fctx = (void *) mystatus;
76 mystatus->lockData = GetLockStatusData();
77 mystatus->currIdx = 0;
79 MemoryContextSwitchTo(oldcontext);
82 funcctx = SRF_PERCALL_SETUP();
83 mystatus = (PG_Lock_Status *) funcctx->user_fctx;
84 lockData = mystatus->lockData;
86 while (mystatus->currIdx < lockData->nelements)
98 holder = &(lockData->holders[mystatus->currIdx]);
99 lock = &(lockData->locks[mystatus->currIdx]);
100 proc = &(lockData->procs[mystatus->currIdx]);
103 * Look to see if there are any held lock modes in this PROCLOCK.
104 * If so, report, and destructively modify lockData so we don't
108 for (mode = 0; mode < MAX_LOCKMODES; mode++)
110 if (holder->holding[mode] > 0)
113 holder->holding[mode] = 0;
119 * If no (more) held modes to report, see if PROC is waiting for
120 * a lock on this lock.
124 if (proc->waitLock == (LOCK *) MAKE_PTR(holder->tag.lock))
126 /* Yes, so report it with proper mode */
127 mode = proc->waitLockMode;
129 * We are now done with this PROCLOCK, so advance pointer
130 * to continue with next one on next call.
137 * Okay, we've displayed all the locks associated with this
138 * PROCLOCK, proceed to the next one.
146 * Form tuple with appropriate data.
148 MemSet(values, 0, sizeof(values));
149 MemSet(nulls, ' ', sizeof(nulls));
151 if (lock->tag.relId == XactLockTableId && lock->tag.dbId == 0)
153 /* Lock is for transaction ID */
156 values[2] = TransactionIdGetDatum(lock->tag.objId.xid);
160 /* Lock is for a relation */
161 values[0] = ObjectIdGetDatum(lock->tag.relId);
162 values[1] = ObjectIdGetDatum(lock->tag.dbId);
167 values[3] = Int32GetDatum(proc->pid);
168 values[4] = DirectFunctionCall1(textin,
169 CStringGetDatum(GetLockmodeName(mode)));
170 values[5] = BoolGetDatum(granted);
172 tuple = heap_formtuple(funcctx->slot->ttc_tupleDescriptor,
174 result = TupleGetDatum(funcctx->slot, tuple);
175 SRF_RETURN_NEXT(funcctx, result);
178 SRF_RETURN_DONE(funcctx);