/*------------------------------------------------------------------------- * * lockfuncs.c * Set-returning functions to view the state of locks within the DB. * * Copyright (c) 2002, PostgreSQL Global Development Group * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.5 2002/08/31 17:14:28 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "funcapi.h" #include "access/heapam.h" #include "catalog/pg_type.h" #include "storage/lock.h" #include "storage/proc.h" #include "utils/builtins.h" /* Working status for pg_lock_status */ typedef struct { LockData *lockData; /* state data from lmgr */ int currIdx; /* current PROCLOCK index */ } PG_Lock_Status; /* * pg_lock_status - produce a view with one row per held or awaited lock mode */ Datum pg_lock_status(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; PG_Lock_Status *mystatus; LockData *lockData; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* build tupdesc for result tuples */ /* this had better match pg_locks view in initdb.sh */ tupdesc = CreateTemplateTupleDesc(6, WITHOUTOID); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation", OIDOID, -1, 0, false); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database", OIDOID, -1, 0, false); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction", XIDOID, -1, 0, false); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid", INT4OID, -1, 0, false); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode", TEXTOID, -1, 0, false); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted", BOOLOID, -1, 0, false); funcctx->slot = TupleDescGetSlot(tupdesc); /* * Collect all the locking information that we will format * and send out as a result set. */ mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status)); funcctx->user_fctx = (void *) mystatus; mystatus->lockData = GetLockStatusData(); mystatus->currIdx = 0; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); mystatus = (PG_Lock_Status *) funcctx->user_fctx; lockData = mystatus->lockData; while (mystatus->currIdx < lockData->nelements) { PROCLOCK *holder; LOCK *lock; PGPROC *proc; bool granted; LOCKMODE mode; Datum values[6]; char nulls[6]; HeapTuple tuple; Datum result; holder = &(lockData->holders[mystatus->currIdx]); lock = &(lockData->locks[mystatus->currIdx]); proc = &(lockData->procs[mystatus->currIdx]); /* * Look to see if there are any held lock modes in this PROCLOCK. * If so, report, and destructively modify lockData so we don't * report again. */ granted = false; for (mode = 0; mode < MAX_LOCKMODES; mode++) { if (holder->holding[mode] > 0) { granted = true; holder->holding[mode] = 0; break; } } /* * If no (more) held modes to report, see if PROC is waiting for * a lock on this lock. */ if (!granted) { if (proc->waitLock == (LOCK *) MAKE_PTR(holder->tag.lock)) { /* Yes, so report it with proper mode */ mode = proc->waitLockMode; /* * We are now done with this PROCLOCK, so advance pointer * to continue with next one on next call. */ mystatus->currIdx++; } else { /* * Okay, we've displayed all the locks associated with this * PROCLOCK, proceed to the next one. */ mystatus->currIdx++; continue; } } /* * Form tuple with appropriate data. */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); if (lock->tag.relId == XactLockTableId && lock->tag.dbId == 0) { /* Lock is for transaction ID */ nulls[0] = 'n'; nulls[1] = 'n'; values[2] = TransactionIdGetDatum(lock->tag.objId.xid); } else { /* Lock is for a relation */ values[0] = ObjectIdGetDatum(lock->tag.relId); values[1] = ObjectIdGetDatum(lock->tag.dbId); nulls[2] = 'n'; } values[3] = Int32GetDatum(proc->pid); values[4] = DirectFunctionCall1(textin, CStringGetDatum(GetLockmodeName(mode))); values[5] = BoolGetDatum(granted); tuple = heap_formtuple(funcctx->slot->ttc_tupleDescriptor, values, nulls); result = TupleGetDatum(funcctx->slot, tuple); SRF_RETURN_NEXT(funcctx, result); } SRF_RETURN_DONE(funcctx); }