From 1bab464eb40ceb96a9dedbf11393b7b51c55ec0a Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Sat, 31 Aug 2002 17:14:28 +0000 Subject: [PATCH] Code review for pg_locks feature. Make shmemoffset of PROCLOCK structs available (else there's no way to interpret the list links). Change pg_locks view to show transaction ID locks separately from ordinary relation locks. Avoid showing N duplicate rows when the same lock is held multiple times (seems unlikely that users care about exact hold count). Improve documentation. --- doc/src/sgml/monitoring.sgml | 88 ++++++++----- src/backend/storage/lmgr/lock.c | 59 +++++---- src/backend/utils/adt/lockfuncs.c | 186 +++++++++++++++------------- src/bin/initdb/initdb.sh | 13 +- src/include/catalog/catversion.h | 4 +- src/include/storage/lock.h | 23 ++-- src/test/regress/expected/rules.out | 2 +- 7 files changed, 212 insertions(+), 163 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index e759789c1f4..6e801174e88 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/monitoring.sgml,v 1.12 2002/08/20 04:47:52 momjian Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/monitoring.sgml,v 1.13 2002/08/31 17:14:27 tgl Exp $ --> <chapter id="monitoring"> @@ -593,22 +593,25 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S; <note> <para> - When the <literal>pg_locks</literal> view is accessed, an - exclusive lock on an internal lock manager data structure must be - acquired to ensure that the data produced by the view is - consistent. The lock held on this structure conflicts with normal - database operations, and can therefore have an effect on overall - database performance. Nevertheless, the performance impact of - accessing this view should be minimal in most situations. + When the <literal>pg_locks</literal> view is accessed, the + internal lock manager data structures are momentarily locked, + and a copy is made for the view to display. This ensures that + the view produces a consistent set of results, while not blocking + normal lock manager operations longer than necessary. Nonetheless + there could be some impact on database performance if this view is + examined often. </para> </note> <para> - The <literal>pg_locks</literal> view contains one row per - lock. This means that if there are multiple locks on a single - relation (which may or may not conflict with one another), a - single relation may show up many times. Furthermore, only - table-level locks are displayed (not row-level ones). + The <literal>pg_locks</literal> view contains one row per lockable + object and requested lock mode. Thus, the same lockable object + may appear many times, if multiple transactions are holding or + waiting for locks on it. A lockable object is either a relation + or a transaction ID. (Note that this view includes only table-level + locks, not row-level ones. If a transaction is waiting for a + row-level lock, it will appear in the view as waiting for the + transaction ID of the current holder of that row lock.) </para> <table> @@ -627,31 +630,50 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S; <row> <entry><structfield>relation</structfield></entry> <entry><type>oid</type></entry> - <entry>The OID of the locked relation. When querying - <literal>pg_locks</literal>, this column can be joined with the - <literal>pg_class</literal> system catalog to get more - information on the locked relation.</entry> + <entry>The OID of the locked relation, or NULL if the lockable + object is a transaction ID. This column can be joined + with the <literal>pg_class</literal> system catalog to get more + information on the locked relation. Note however that this will + only work for relations in the current database (those for which + the <structfield>database</structfield> column is either the + current database's OID or zero). + </entry> </row> <row> <entry><structfield>database</structfield></entry> <entry><type>oid</type></entry> <entry>The OID of the database in which the locked relation - exists. If the lock is on a globally-shared object, this value - will be 0. When querying <literal>pg_locks</literal>, this - column can be joined with the <literal>pg_database</literal> - system catalog to get more information on the locked object's - database.</entry> + exists, or NULL if the lockable object is a transaction ID. + If the lock is on a globally-shared table, this field will be + zero. This + column can be joined with the <literal>pg_database</literal> + system catalog to get more information on the locked object's + database. + </entry> </row> <row> - <entry><structfield>backendpid</structfield></entry> + <entry><structfield>transaction</structfield></entry> + <entry><type>xid</type></entry> + <entry>The ID of a transaction, or NULL if the lockable object + is a relation. Every transaction holds ExclusiveLock on its + transaction ID for its entire duration. If one transaction finds + it necessary to wait specifically for another transaction, it + does so by attempting to acquire ShareLock on the other transaction + ID. That will succeed only when the other transaction terminates + and releases its locks. + </entry> + </row> + + <row> + <entry><structfield>pid</structfield></entry> <entry><type>int4</type></entry> <entry>The process ID of the <productname>PostgreSQL</productname> backend that has acquired or is attempting to acquire the lock. If you have enabled the statistics collector, this column can be joined - with the <literal>pg_stat_activity</literal> view to access + with the <literal>pg_stat_activity</literal> view to get more information on the backend holding or waiting to hold the lock.</entry> </row> @@ -659,7 +681,8 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S; <row> <entry><structfield>mode</structfield></entry> <entry><type>text</type></entry> - <entry>The mode of the lock. For more information on the + <entry>The mode of the requested or held lock on the lockable + object. For more information on the different lock modes available in <productname>PostgreSQL</productname>, refer to the <citetitle>User's Guide</citetitle>.</entry> @@ -667,13 +690,14 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S; <row> <entry><structfield>isgranted</structfield></entry> - <entry><type>text</type></entry> - <entry>A boolean column indicating whether or not this - particular lock has been granted. If the lock has not been - granted, the backend atempting to acquire it will sleep until - the lock is released (or a deadlock situation is detected). A - single backend can be waiting to acquire at most one lock at - any given time.</entry> + <entry><type>bool</type></entry> + <entry>True if this lock has been granted (is held by this + backend). False indicates that this backend is currently + waiting to acquire this lock, which implies that some other + backend is holding a conflicting lock mode on the same lockable + object. This backend will sleep until the other lock is released + (or a deadlock situation is detected). A single backend can be + waiting to acquire at most one lock at a time.</entry> </row> </tbody> </tgroup> diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 154c49b3e92..db4cf76f2fd 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.112 2002/08/17 13:04:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.113 2002/08/31 17:14:27 tgl Exp $ * * NOTES * Outside modules can create a lock table and acquire/release @@ -1361,59 +1361,68 @@ LockShmemSize(int maxBackends) /* * GetLockStatusData - Return a summary of the lock manager's internal - * status, for use in a user-level statistical reporting function. + * status, for use in a user-level reporting function. * - * This function should be passed a pointer to a LockData struct. It fills - * the structure with the appropriate information and returns. The goal - * is to hold the LockMgrLock for as short a time as possible; thus, the - * function simply makes a copy of the necessary data and releases the - * lock, allowing the caller to contemplate and format the data for - * as long as it pleases. + * The return data consists of an array of PROCLOCK objects, with the + * associated PGPROC and LOCK objects for each. Note that multiple + * copies of the same PGPROC and/or LOCK objects are likely to appear. + * It is the caller's responsibility to match up duplicates if wanted. + * + * The design goal is to hold the LockMgrLock for as short a time as possible; + * thus, this function simply makes a copy of the necessary data and releases + * the lock, allowing the caller to contemplate and format the data for as + * long as it pleases. */ -void -GetLockStatusData(LockData *data) +LockData * +GetLockStatusData(void) { + LockData *data; HTAB *holderTable; PROCLOCK *holder; HASH_SEQ_STATUS seqstat; - int i = 0; + int i; - data->currIdx = 0; + data = (LockData *) palloc(sizeof(LockData)); LWLockAcquire(LockMgrLock, LW_EXCLUSIVE); holderTable = LockMethodTable[DEFAULT_LOCKMETHOD]->holderHash; - data->nelements = holderTable->hctl->nentries; + data->nelements = i = holderTable->hctl->nentries; + + if (i == 0) + i = 1; /* avoid palloc(0) if empty table */ - data->procs = (PGPROC *) palloc(sizeof(PGPROC) * data->nelements); - data->locks = (LOCK *) palloc(sizeof(LOCK) * data->nelements); - data->holders = (PROCLOCK *) palloc(sizeof(PROCLOCK) * data->nelements); + data->holderaddrs = (SHMEM_OFFSET *) palloc(sizeof(SHMEM_OFFSET) * i); + data->holders = (PROCLOCK *) palloc(sizeof(PROCLOCK) * i); + data->procs = (PGPROC *) palloc(sizeof(PGPROC) * i); + data->locks = (LOCK *) palloc(sizeof(LOCK) * i); hash_seq_init(&seqstat, holderTable); + i = 0; while ( (holder = hash_seq_search(&seqstat)) ) { - PGPROC *proc; - LOCK *lock; - - /* Only do a shallow copy */ - proc = (PGPROC *) MAKE_PTR(holder->tag.proc); - lock = (LOCK *) MAKE_PTR(holder->tag.lock); + PGPROC *proc = (PGPROC *) MAKE_PTR(holder->tag.proc); + LOCK *lock = (LOCK *) MAKE_PTR(holder->tag.lock); + data->holderaddrs[i] = MAKE_OFFSET(holder); + memcpy(&(data->holders[i]), holder, sizeof(PROCLOCK)); memcpy(&(data->procs[i]), proc, sizeof(PGPROC)); memcpy(&(data->locks[i]), lock, sizeof(LOCK)); - memcpy(&(data->holders[i]), holder, sizeof(PROCLOCK)); i++; } + LWLockRelease(LockMgrLock); + Assert(i == data->nelements); - LWLockRelease(LockMgrLock); + return data; } -char * +/* Provide the textual name of any lock mode */ +const char * GetLockmodeName(LOCKMODE mode) { Assert(mode <= MAX_LOCKMODES); diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 199efbacd26..b1ccceebcb9 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -1,36 +1,46 @@ -/* +/*------------------------------------------------------------------------- + * * 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.4 2002/08/29 17:14:33 tgl Exp $ + * $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/lmgr.h" #include "storage/lock.h" -#include "storage/lwlock.h" #include "storage/proc.h" #include "utils/builtins.h" -static int next_lock(int locks[]); - +/* 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; - LockData *lockData; - MemoryContext oldcontext; + 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(); @@ -38,124 +48,132 @@ pg_lock_status(PG_FUNCTION_ARGS) /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - tupdesc = CreateTemplateTupleDesc(5, WITHOUTOID); + /* 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, "backendpid", + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction", + XIDOID, -1, 0, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid", INT4OID, -1, 0, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 4, "mode", + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode", TEXTOID, -1, 0, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 5, "isgranted", + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted", BOOLOID, -1, 0, false); funcctx->slot = TupleDescGetSlot(tupdesc); - funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); /* - * Preload all the locking information that we will eventually format - * and send out as a result set. This is palloc'ed, but since the - * MemoryContext is reset when the SRF finishes, we don't need to - * free it ourselves. + * Collect all the locking information that we will format + * and send out as a result set. */ - funcctx->user_fctx = (LockData *) palloc(sizeof(LockData)); + mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status)); + funcctx->user_fctx = (void *) mystatus; - GetLockStatusData(funcctx->user_fctx); + mystatus->lockData = GetLockStatusData(); + mystatus->currIdx = 0; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); - lockData = (LockData *) funcctx->user_fctx; + mystatus = (PG_Lock_Status *) funcctx->user_fctx; + lockData = mystatus->lockData; - while (lockData->currIdx < lockData->nelements) + 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; - char **values; - LOCKMODE mode; - int num_attrs; - int i; - int currIdx = lockData->currIdx; - - holder = &(lockData->holders[currIdx]); - lock = &(lockData->locks[currIdx]); - proc = &(lockData->procs[currIdx]); - num_attrs = funcctx->attinmeta->tupdesc->natts; - - values = (char **) palloc(sizeof(*values) * num_attrs); - - for (i = 0; i < num_attrs; i++) - values[i] = (char *) palloc(32); - /* The OID of the locked relation */ - snprintf(values[0], 32, "%u", lock->tag.relId); - /* The database the relation is in */ - snprintf(values[1], 32, "%u", lock->tag.dbId); - /* The PID of the backend holding or waiting for the lock */ - snprintf(values[2], 32, "%d", proc->pid); + holder = &(lockData->holders[mystatus->currIdx]); + lock = &(lockData->locks[mystatus->currIdx]); + proc = &(lockData->procs[mystatus->currIdx]); /* - * We need to report both the locks held (i.e. successfully acquired) - * by this holder, as well as the locks upon which it is still - * waiting, if any. Since a single PROCLOCK struct may contain - * multiple locks, we may need to loop several times before we - * advance the array index and continue on. + * 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. */ - if (holder->nHolding > 0) + granted = false; + for (mode = 0; mode < MAX_LOCKMODES; mode++) { - /* Already held locks */ - mode = next_lock(holder->holding); - holder->holding[mode]--; - holder->nHolding--; - - strcpy(values[4], "t"); + if (holder->holding[mode] > 0) + { + granted = true; + holder->holding[mode] = 0; + break; + } } - else if (proc->waitLock != NULL) + + /* + * If no (more) held modes to report, see if PROC is waiting for + * a lock on this lock. + */ + if (!granted) { - /* Lock that is still being waited on */ - mode = proc->waitLockMode; - proc->waitLock = NULL; - proc->waitLockMode = NoLock; + 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; + } + } - strcpy(values[4], "f"); + /* + * 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 { - /* - * Okay, we've displayed all the lock's belonging to this PROCLOCK, - * procede to the next one. - */ - lockData->currIdx++; - continue; + /* Lock is for a relation */ + values[0] = ObjectIdGetDatum(lock->tag.relId); + values[1] = ObjectIdGetDatum(lock->tag.dbId); + nulls[2] = 'n'; + } - strncpy(values[3], GetLockmodeName(mode), 32); + values[3] = Int32GetDatum(proc->pid); + values[4] = DirectFunctionCall1(textin, + CStringGetDatum(GetLockmodeName(mode))); + values[5] = BoolGetDatum(granted); - tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); + tuple = heap_formtuple(funcctx->slot->ttc_tupleDescriptor, + values, nulls); result = TupleGetDatum(funcctx->slot, tuple); SRF_RETURN_NEXT(funcctx, result); } SRF_RETURN_DONE(funcctx); } - -static LOCKMODE -next_lock(int locks[]) -{ - LOCKMODE i; - - for (i = 0; i < MAX_LOCKMODES; i++) - { - if (locks[i] != 0) - return i; - } - - /* No locks found: this should not occur */ - Assert(false); - return -1; -} diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh index 33264050c8e..7441105e000 100644 --- a/src/bin/initdb/initdb.sh +++ b/src/bin/initdb/initdb.sh @@ -27,7 +27,7 @@ # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # -# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.169 2002/08/27 04:00:28 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.170 2002/08/31 17:14:28 tgl Exp $ # #------------------------------------------------------------------------- @@ -978,15 +978,12 @@ CREATE VIEW pg_stat_database AS \ FROM pg_database D; CREATE VIEW pg_locks AS \ - SELECT \ - L.relation, L.database, L.backendpid, L.mode, L.isgranted \ - FROM pg_lock_status() AS L(relation oid, database oid, \ - backendpid int4, mode text, isgranted boolean); + SELECT * \ + FROM pg_lock_status() AS L(relation oid, database oid, \ + transaction xid, pid int4, mode text, granted boolean); CREATE VIEW pg_settings AS \ - SELECT \ - A.name, \ - A.setting \ + SELECT * \ FROM pg_show_all_settings() AS A(name text, setting text); CREATE RULE pg_settings_u AS \ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 15f81094c8e..f561dee66b1 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.155 2002/08/30 19:23:20 tgl Exp $ + * $Id: catversion.h,v 1.156 2002/08/31 17:14:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200208301 +#define CATALOG_VERSION_NO 200208311 #endif diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index bedf6d7faf7..4c09bdda7c8 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: lock.h,v 1.65 2002/08/17 13:04:18 momjian Exp $ + * $Id: lock.h,v 1.66 2002/08/31 17:14:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -204,19 +204,20 @@ typedef struct PROCLOCK (((LOCK *) MAKE_PTR((holder).tag.lock))->tag.lockmethod) /* - * This struct is used to encapsulate information passed from lmgr - * internals to the lock listing statistical functions (lockfuncs.c). - * It's just a convenient bundle of other lock.h structures. All - * the information at a given index (holders[i], procs[i], locks[i]) - * is related. + * This struct holds information passed from lmgr internals to the lock + * listing user-level functions (lockfuncs.c). For each PROCLOCK in the + * system, the SHMEM_OFFSET, PROCLOCK itself, and associated PGPROC and + * LOCK objects are stored. (Note there will often be multiple copies + * of the same PGPROC or LOCK.) We do not store the SHMEM_OFFSET of the + * PGPROC or LOCK separately, since they're in the PROCLOCK's tag fields. */ typedef struct { - int nelements; /* The length of holders, procs, & locks */ - int currIdx; /* Current element being examined */ + int nelements; /* The length of each of the arrays */ + SHMEM_OFFSET *holderaddrs; + PROCLOCK *holders; PGPROC *procs; LOCK *locks; - PROCLOCK *holders; } LockData; /* @@ -242,8 +243,8 @@ extern void RemoveFromWaitQueue(PGPROC *proc); extern int LockShmemSize(int maxBackends); extern bool DeadLockCheck(PGPROC *proc); extern void InitDeadLockChecking(void); -extern void GetLockStatusData(LockData *data); -extern char *GetLockmodeName(LOCKMODE mode); +extern LockData *GetLockStatusData(void); +extern const char *GetLockmodeName(LOCKMODE mode); #ifdef LOCK_DEBUG extern void DumpLocks(void); diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 77420cd2b2d..0cfd3f103d4 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1268,7 +1268,7 @@ SELECT viewname, definition FROM pg_views ORDER BY viewname; --------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath); pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, pg_get_indexdef(i.oid) AS indexdef FROM (((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char")); - pg_locks | SELECT l.relation, l."database", l.backendpid, l."mode", l.isgranted FROM pg_lock_status() l(relation oid, "database" oid, backendpid integer, "mode" text, isgranted boolean); + pg_locks | SELECT l.relation, l."database", l."transaction", l.pid, l."mode", l.granted FROM pg_lock_status() l(relation oid, "database" oid, "transaction" xid, pid integer, "mode" text, granted boolean); pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name); pg_settings | SELECT a.name, a.setting FROM pg_show_all_settings() a(name text, setting text); pg_stat_activity | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.usename, pg_stat_get_backend_activity(s.backendid) AS current_query FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_shadow u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.usesysid)); -- GitLab