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.7 2002/09/04 20:31:28 momjian 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();
49 * switch to memory context appropriate for multiple function
52 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
54 /* build tupdesc for result tuples */
55 /* this had better match pg_locks view in initdb.sh */
56 tupdesc = CreateTemplateTupleDesc(6, false);
57 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation",
58 OIDOID, -1, 0, false);
59 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
60 OIDOID, -1, 0, false);
61 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction",
62 XIDOID, -1, 0, false);
63 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid",
64 INT4OID, -1, 0, false);
65 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode",
66 TEXTOID, -1, 0, false);
67 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted",
68 BOOLOID, -1, 0, false);
70 funcctx->slot = TupleDescGetSlot(tupdesc);
73 * Collect all the locking information that we will format and
74 * send out as a result set.
76 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
77 funcctx->user_fctx = (void *) mystatus;
79 mystatus->lockData = GetLockStatusData();
80 mystatus->currIdx = 0;
82 MemoryContextSwitchTo(oldcontext);
85 funcctx = SRF_PERCALL_SETUP();
86 mystatus = (PG_Lock_Status *) funcctx->user_fctx;
87 lockData = mystatus->lockData;
89 while (mystatus->currIdx < lockData->nelements)
101 holder = &(lockData->holders[mystatus->currIdx]);
102 lock = &(lockData->locks[mystatus->currIdx]);
103 proc = &(lockData->procs[mystatus->currIdx]);
106 * Look to see if there are any held lock modes in this PROCLOCK.
107 * If so, report, and destructively modify lockData so we don't
111 for (mode = 0; mode < MAX_LOCKMODES; mode++)
113 if (holder->holding[mode] > 0)
116 holder->holding[mode] = 0;
122 * If no (more) held modes to report, see if PROC is waiting for a
127 if (proc->waitLock == (LOCK *) MAKE_PTR(holder->tag.lock))
129 /* Yes, so report it with proper mode */
130 mode = proc->waitLockMode;
133 * We are now done with this PROCLOCK, so advance pointer
134 * to continue with next one on next call.
141 * Okay, we've displayed all the locks associated with
142 * this PROCLOCK, proceed to the next one.
150 * Form tuple with appropriate data.
152 MemSet(values, 0, sizeof(values));
153 MemSet(nulls, ' ', sizeof(nulls));
155 if (lock->tag.relId == XactLockTableId && lock->tag.dbId == 0)
157 /* Lock is for transaction ID */
160 values[2] = TransactionIdGetDatum(lock->tag.objId.xid);
164 /* Lock is for a relation */
165 values[0] = ObjectIdGetDatum(lock->tag.relId);
166 values[1] = ObjectIdGetDatum(lock->tag.dbId);
171 values[3] = Int32GetDatum(proc->pid);
172 values[4] = DirectFunctionCall1(textin,
173 CStringGetDatum(GetLockmodeName(mode)));
174 values[5] = BoolGetDatum(granted);
176 tuple = heap_formtuple(funcctx->slot->ttc_tupleDescriptor,
178 result = TupleGetDatum(funcctx->slot, tuple);
179 SRF_RETURN_NEXT(funcctx, result);
182 SRF_RETURN_DONE(funcctx);