Code review for pg_locks feature. Make shmemoffset of PROCLOCK structs
authorTom Lane
Sat, 31 Aug 2002 17:14:28 +0000 (17:14 +0000)
committerTom Lane
Sat, 31 Aug 2002 17:14:28 +0000 (17:14 +0000)
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
src/backend/storage/lmgr/lock.c
src/backend/utils/adt/lockfuncs.c
src/bin/initdb/initdb.sh
src/include/catalog/catversion.h
src/include/storage/lock.h
src/test/regress/expected/rules.out

index e759789c1f44ae95c7df3a65e48e5e29e83cc546..6e801174e88cdc936f829c5cf59dc459c6205781 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -593,22 +593,25 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S;
 
    
    
-    When the pg_locks 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 pg_locks 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.
    
    
 
    
-   The pg_locks 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 pg_locks 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.)
    
 
    
@@ -627,31 +630,50 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S;
      
       relation
       oid
-      The OID of the locked relation. When querying
-      pg_locks, this column can be joined with the
-      pg_class system catalog to get more
-      information on the locked relation.
+      The OID of the locked relation, or NULL if the lockable
+      object is a transaction ID. This column can be joined
+      with the pg_class 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 database column is either the
+      current database's OID or zero).
+      
      
 
      
       database
       oid
       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 pg_locks, this
-       column can be joined with the pg_database
-       system catalog to get more information on the locked object's
-       database.
+       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 pg_database
+       system catalog to get more information on the locked object's
+       database.
+      
      
 
      
-      backendpid
+      transaction
+      xid
+      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.
+      
+     
+
+     
+      pid
       int4
       The process ID of the
        PostgreSQL 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 pg_stat_activity view to access
+       with the pg_stat_activity view to get
        more information on the backend holding or waiting to hold the
        lock.
      
@@ -659,7 +681,8 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S;
      
       mode
       text
-      The mode of the lock. For more information on the
+      The mode of the requested or held lock on the lockable
+      object. For more information on the
       different lock modes available in
       PostgreSQL, refer to the
       User's Guide.
@@ -667,13 +690,14 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S;
 
      
       isgranted
-      text
-      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.
+      bool
+      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.
      
     
    
index 154c49b3e92a18d2b2527af9b7ae4cbcc25072f0..db4cf76f2fd5104619d7e02c0905d907488ab6c0 100644 (file)
@@ -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);
index 199efbacd26bdfdd20d88480f287db8eb5b51396..b1ccceebcb9aa53b380b4ab7cd3af1fee276e3c0 100644 (file)
@@ -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;
-}
index 33264050c8edfbeec3df485d58f1d4a2f0ba13f1..7441105e000c78323d457ce4c3ed4f5da0810b82 100644 (file)
@@ -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 \
index 15f81094c8eb86f2af103aa7a595362587f9e8c6..f561dee66b1c58db453be10da83cd8c9e5d03943 100644 (file)
@@ -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
index bedf6d7faf77db4e8b940a9c1c156bee6f1e0ee0..4c09bdda7c868afd7669e6b5dc8f96f0a075092c 100644 (file)
@@ -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);
index 77420cd2b2dc266ece14661ba4a67c0d806e7280..0cfd3f103d46c0c027417149204f772f6b7a743b 100644 (file)
@@ -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));