Index: doc/src/sgml/monitoring.sgml
===================================================================
RCS file: /var/lib/cvs/pgsql-server/doc/src/sgml/monitoring.sgml,v
retrieving revision 1.10
diff -c -r1.10 monitoring.sgml
*** doc/src/sgml/monitoring.sgml	4 Aug 2002 19:51:30 -0000	1.10
--- doc/src/sgml/monitoring.sgml	14 Aug 2002 15:05:09 -0000
***************
*** 543,548 ****
--- 543,676 ----
  
   </sect2>
   </sect1>
+ 
+   <sect1 id="monitoring-locks">
+    <title>Viewing Locks</title>
+ 
+    <para>
+ 	Another useful tool for monitoring database activity is the
+ 	<literal>pg_locks</literal> system catalog. This allows the
+ 	database administrator to view information about the outstanding
+ 	locks in the lock manager. For example, this capability can be
+ 	used to:
+ 	<itemizedlist>
+ 	 <listitem>
+ 	  <para>
+ 	   View all the locks currently outstanding, all the locks on
+ 	   relations in a particular database, all the locks on a
+ 	   particular relation, or all the locks held by a particular
+ 	   <productname>PostgreSQL</productname> backend.
+ 	  </para>
+ 	 </listitem>
+ 	 <listitem>
+ 	  <para>
+ 	   View the relation in the current database with the most
+ 	   un-granted locks (which might be a source of contention among
+ 	   database clients).
+ 	  </para>
+ 	 </listitem>
+ 	 <listitem>
+ 	  <para>
+ 	   Determine the effect of lock contention on overall database
+ 	   performance, as well as the extent to which contention varies
+ 	   with overall database traffic.
+ 	  </para>
+ 	 </listitem>
+ 	</itemizedlist>
+ 
+ 	For more information on locking and managing concurrency with
+ 	<productname>PostgreSQL</productname>, refer to the
+ 	<citetitle>Administrator's Guide</citetitle>.
+    </para>
+ 
+    <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.
+ 	</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).
+    </para>
+ 
+    <table>
+ 	<title>Lock Status System View</title>
+ 
+ 	<tgroup cols="3">
+ 	 <thead>
+ 	  <row>
+ 	   <entry>Column Name</entry>
+ 	   <entry>Type</entry>
+ 	   <entry>Description</entry>
+ 	  </row>
+ 	 </thead>
+ 
+ 	 <tbody>
+ 	  <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>
+ 	  </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>
+ 	  </row>
+ 
+ 	  <row>
+ 	   <entry><structfield>backendpid</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
+ 		more information on the backend holding or waiting to hold the
+ 		lock.</entry>
+ 	  </row>
+ 
+ 	  <row>
+ 	   <entry><structfield>mode</structfield></entry>
+ 	   <entry><type>text</type></entry>
+ 	   <entry>The mode of the lock. For more information on the
+ 	   different lock modes available in
+ 	   <productname>PostgreSQL</productname>, refer to the
+ 	   <citetitle>User's Guide</citetitle>.</entry>
+ 	  </row>
+ 
+ 	  <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>
+ 	  </row>
+ 	 </tbody>
+ 	</tgroup>
+    </table>
+   </sect1>
  </chapter>
  
  <!-- Keep this comment at the end of the file
Index: doc/src/sgml/mvcc.sgml
===================================================================
RCS file: /var/lib/cvs/pgsql-server/doc/src/sgml/mvcc.sgml,v
retrieving revision 2.26
diff -c -r2.26 mvcc.sgml
*** doc/src/sgml/mvcc.sgml	5 Aug 2002 19:43:31 -0000	2.26
--- doc/src/sgml/mvcc.sgml	14 Aug 2002 15:05:09 -0000
***************
*** 408,414 ****
      modes on the same table at the same time.  (However, a transaction
      never conflicts with itself --- for example, it may acquire
      <literal>ACCESS EXCLUSIVE</literal> lock and later acquire
!     <literal>ACCESS SHARE</literal> lock on the same table.)  Nonconflicting
      lock modes may be held concurrently by many transactions.  Notice in
      particular that some lock modes are self-conflicting (for example,
      <literal>ACCESS EXCLUSIVE</literal> cannot be held by more than one
--- 408,414 ----
      modes on the same table at the same time.  (However, a transaction
      never conflicts with itself --- for example, it may acquire
      <literal>ACCESS EXCLUSIVE</literal> lock and later acquire
!     <literal>ACCESS SHARE</literal> lock on the same table.)  Non-conflicting
      lock modes may be held concurrently by many transactions.  Notice in
      particular that some lock modes are self-conflicting (for example,
      <literal>ACCESS EXCLUSIVE</literal> cannot be held by more than one
***************
*** 416,421 ****
--- 416,429 ----
      <literal>ACCESS SHARE</literal> can be held by multiple transactions).
      Once acquired, a lock mode is held till end of transaction.
     </para>
+ 
+ 	<para>
+ 	 To examine a list of the currently outstanding locks in a
+ 	 database server, use the <literal>pg_locks</literal> system
+ 	 view. For more information on monitoring the status of the lock
+ 	 manager subsystem, refer to the <citetitle>Administrator's
+ 	 Guide</citetitle>.
+ 	</para>
  
       <variablelist>
        <title>Table-level lock modes</title>
Index: src/backend/storage/lmgr/lock.c
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/backend/storage/lmgr/lock.c,v
retrieving revision 1.111
diff -c -r1.111 lock.c
*** src/backend/storage/lmgr/lock.c	1 Aug 2002 05:18:33 -0000	1.111
--- src/backend/storage/lmgr/lock.c	14 Aug 2002 15:05:09 -0000
***************
*** 1359,1364 ****
--- 1359,1424 ----
  	return size;
  }
  
+ /*
+  * GetLockStatusData - Return a summary of the lock manager's internal
+  * status, for use in a user-level statistical 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.
+  */
+ void
+ GetLockStatusData(LockData *data)
+ {
+ 	HTAB		*holderTable;
+ 	PROCLOCK	*holder;
+ 	HASH_SEQ_STATUS seqstat;
+ 	int i = 0;
+ 
+ 	data->currIdx = 0;
+ 
+ 	LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
+ 
+ 	holderTable = LockMethodTable[DEFAULT_LOCKMETHOD]->holderHash;
+ 
+ 	data->nelements = holderTable->hctl->nentries;
+ 
+ 	data->procs = (PGPROC *) palloc(sizeof(PGPROC) * data->nelements);
+ 	data->locks = (LOCK *) palloc(sizeof(LOCK) * data->nelements);
+ 	data->holders = (PROCLOCK *) palloc(sizeof(PROCLOCK) * data->nelements);
+ 
+ 	hash_seq_init(&seqstat, holderTable);
+ 
+ 	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);
+ 
+ 		memcpy(&(data->procs[i]), proc, sizeof(PGPROC));
+ 		memcpy(&(data->locks[i]), lock, sizeof(LOCK));
+ 		memcpy(&(data->holders[i]), holder, sizeof(PROCLOCK));
+ 
+ 		i++;
+ 	}
+ 
+ 	Assert(i == data->nelements);
+ 
+ 	LWLockRelease(LockMgrLock);
+ }
+ 
+ char *
+ GetLockmodeName(LOCKMODE mode)
+ {
+ 	Assert(mode <= MAX_LOCKMODES);
+ 	return lock_mode_names[mode];
+ }
  
  #ifdef LOCK_DEBUG
  /*
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/backend/tcop/utility.c,v
retrieving revision 1.169
diff -c -r1.169 utility.c
*** src/backend/tcop/utility.c	7 Aug 2002 21:45:02 -0000	1.169
--- src/backend/tcop/utility.c	14 Aug 2002 15:05:09 -0000
***************
*** 239,246 ****
  			break;
  
  			/*
! 			 * ******************************** portal manipulation ********************************
! 			 *
  			 */
  		case T_ClosePortalStmt:
  			{
--- 239,245 ----
  			break;
  
  			/*
! 			 * ************************* portal manipulation ***************************
  			 */
  		case T_ClosePortalStmt:
  			{
Index: src/backend/utils/adt/Makefile
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/backend/utils/adt/Makefile,v
retrieving revision 1.51
diff -c -r1.51 Makefile
*** src/backend/utils/adt/Makefile	4 Oct 2001 04:13:40 -0000	1.51
--- src/backend/utils/adt/Makefile	14 Aug 2002 15:05:09 -0000
***************
*** 17,23 ****
  
  OBJS = acl.o arrayfuncs.o arrayutils.o bool.o cash.o char.o \
  	date.o datetime.o datum.o float.o format_type.o \
! 	geo_ops.o geo_selfuncs.o int.o int8.o like.o \
  	misc.o nabstime.o name.o not_in.o numeric.o numutils.o \
  	oid.o oracle_compat.o \
  	regexp.o regproc.o ruleutils.o selfuncs.o sets.o \
--- 17,23 ----
  
  OBJS = acl.o arrayfuncs.o arrayutils.o bool.o cash.o char.o \
  	date.o datetime.o datum.o float.o format_type.o \
! 	geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \
  	misc.o nabstime.o name.o not_in.o numeric.o numutils.o \
  	oid.o oracle_compat.o \
  	regexp.o regproc.o ruleutils.o selfuncs.o sets.o \
Index: src/backend/utils/adt/lockfuncs.c
===================================================================
RCS file: src/backend/utils/adt/lockfuncs.c
diff -N src/backend/utils/adt/lockfuncs.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/backend/utils/adt/lockfuncs.c	14 Aug 2002 15:05:09 -0000
***************
*** 0 ****
--- 1,146 ----
+ /*
+  * lockfuncs.c
+  *		Set-returning functions to view the state of locks within the DB.
+  * 
+  * Copyright (c) 2002, PostgreSQL Global Development Group
+  *
+  * IDENTIFICATION
+  *		$Header$
+  */
+ 
+ #include "postgres.h"
+ #include "fmgr.h"
+ #include "funcapi.h"
+ #include "storage/lmgr.h"
+ #include "storage/lock.h"
+ #include "storage/lwlock.h"
+ #include "storage/proc.h"
+ 
+ Datum lock_status_srf(PG_FUNCTION_ARGS);
+ 
+ static int next_lock(int locks[]);
+ 
+ Datum
+ lock_status_srf(PG_FUNCTION_ARGS)
+ {
+ 	FuncCallContext		*funccxt;
+ 	LockData			*lockData;
+ 
+ 	if (SRF_IS_FIRSTCALL())
+ 	{
+ 		MemoryContext	oldcxt;
+ 		TupleDesc		tupdesc;
+ 
+ 		funccxt = SRF_FIRSTCALL_INIT();
+ 		tupdesc = RelationNameGetTupleDesc("pg_catalog.pg_locks_result");
+ 		funccxt->slot = TupleDescGetSlot(tupdesc);
+ 		funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
+ 
+ 		oldcxt = MemoryContextSwitchTo(funccxt->fmctx);
+ 
+ 		/*
+ 		 * 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.
+ 		 */
+ 		funccxt->user_fctx = (LockData *) palloc(sizeof(LockData));
+ 
+ 		GetLockStatusData(funccxt->user_fctx);
+ 
+ 		MemoryContextSwitchTo(oldcxt);
+ 	}
+ 
+ 	funccxt	= SRF_PERCALL_SETUP();
+ 	lockData = (LockData *) funccxt->user_fctx;
+ 
+ 	while (lockData->currIdx < lockData->nelements)
+ 	{
+ 		PROCLOCK		 *holder;
+ 		LOCK			 *lock;
+ 		PGPROC			 *proc;
+ 		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	= funccxt->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);
+ 
+ 		/*
+ 		 * 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.
+ 		 */
+ 		if (holder->nHolding > 0)
+ 		{
+ 			/* Already held locks */
+ 			mode = next_lock(holder->holding);
+ 			holder->holding[mode]--;
+ 			holder->nHolding--;
+ 
+ 			strcpy(values[4], "t");
+ 		}
+ 		else if (proc->waitLock != NULL)
+ 		{
+ 			/* Lock that is still being waited on */
+ 			mode = proc->waitLockMode;
+ 			proc->waitLock = NULL;
+ 			proc->waitLockMode = NoLock;
+ 
+ 			strcpy(values[4], "f");
+ 		}
+ 		else
+ 		{
+ 			/*
+ 			 * Okay, we've displayed all the lock's belonging to this PROCLOCK,
+ 			 * procede to the next one.
+ 			 */
+ 			lockData->currIdx++;
+ 			continue;
+ 		}
+ 
+ 		strncpy(values[3], GetLockmodeName(mode), 32);
+ 
+ 		tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
+ 		result = TupleGetDatum(funccxt->slot, tuple);
+ 		SRF_RETURN_NEXT(funccxt, result);
+ 	}
+ 
+ 	SRF_RETURN_DONE(funccxt);
+ }
+ 
+ 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: src/bin/initdb/initdb.sh
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/bin/initdb/initdb.sh,v
retrieving revision 1.165
diff -c -r1.165 initdb.sh
*** src/bin/initdb/initdb.sh	8 Aug 2002 19:39:05 -0000	1.165
--- src/bin/initdb/initdb.sh	14 Aug 2002 15:05:10 -0000
***************
*** 799,806 ****
      FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
      WHERE C.relkind = 'v';
  
- -- XXX why does pg_tables include sequences?
- 
  CREATE VIEW pg_tables AS \
      SELECT \
          N.nspname AS schemaname, \
--- 799,804 ----
***************
*** 1014,1019 ****
--- 1012,1032 ----
                      pg_stat_get_db_blocks_hit(D.oid) AS blks_read, \
              pg_stat_get_db_blocks_hit(D.oid) AS blks_hit \
      FROM pg_database D;
+ 
+ CREATE VIEW pg_locks_result AS \
+ 	SELECT \
+ 			''::oid AS relation, \
+ 			''::oid AS database, \
+ 			''::int4 AS backendpid, \
+ 			''::text AS mode, \
+ 			NULL::bool AS isgranted;
+ 
+ UPDATE pg_proc SET \
+ 	prorettype = (SELECT oid FROM pg_type \
+ 		WHERE typname = 'pg_locks_result') \
+ 	WHERE proname = 'pg_lock_status';
+ 
+ CREATE VIEW pg_locks AS SELECT * FROM pg_lock_status();
  
  EOF
  if [ "$?" -ne 0 ]; then
Index: src/include/catalog/catversion.h
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/include/catalog/catversion.h,v
retrieving revision 1.148
diff -c -r1.148 catversion.h
*** src/include/catalog/catversion.h	13 Aug 2002 20:40:44 -0000	1.148
--- src/include/catalog/catversion.h	14 Aug 2002 15:05:10 -0000
***************
*** 53,58 ****
   */
  
  /*							yyyymmddN */
! #define CATALOG_VERSION_NO	200208131
  
  #endif
--- 53,58 ----
   */
  
  /*							yyyymmddN */
! #define CATALOG_VERSION_NO	200208141
  
  #endif
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.253
diff -c -r1.253 pg_proc.h
*** src/include/catalog/pg_proc.h	9 Aug 2002 16:45:15 -0000	1.253
--- src/include/catalog/pg_proc.h	14 Aug 2002 15:05:10 -0000
***************
*** 2674,2679 ****
--- 2674,2681 ----
  DATA(insert OID = 1915 (  numeric_uplus    PGNSP PGUID 12 f f t f i 1 1700 "1700"  numeric_uplus - _null_ ));
  DESCR("unary plus");
  
+ DATA(insert OID = 1920 (  pg_lock_status   PGNSP PGUID 12 f f f t v 0 0 "0" lock_status_srf - _null_ ));
+ DESCR("view system lock information");
  DATA(insert OID = 1922 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 25 25"  has_table_privilege_name_name - _null_ ));
  DESCR("user privilege on relation by username, rel name");
  DATA(insert OID = 1923 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25"  has_table_privilege_name_id - _null_ ));
Index: src/include/storage/lock.h
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/include/storage/lock.h,v
retrieving revision 1.64
diff -c -r1.64 lock.h
*** src/include/storage/lock.h	1 Aug 2002 05:18:34 -0000	1.64
--- src/include/storage/lock.h	14 Aug 2002 15:05:10 -0000
***************
*** 203,208 ****
--- 203,223 ----
  #define PROCLOCK_LOCKMETHOD(holder) \
  		(((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.
+  */
+ typedef struct
+ {
+ 	int		  nelements;	/* The length of holders, procs, & locks */
+ 	int		  currIdx;		/* Current element being examined */
+ 	PGPROC	 *procs;
+ 	LOCK	 *locks;
+ 	PROCLOCK *holders;
+ } LockData;
  
  /*
   * function prototypes
***************
*** 227,232 ****
--- 242,249 ----
  extern int	LockShmemSize(int maxBackends);
  extern bool DeadLockCheck(PGPROC *proc);
  extern void InitDeadLockChecking(void);
+ extern void GetLockStatusData(LockData *data);
+ extern char *GetLockmodeName(LOCKMODE mode);
  
  #ifdef LOCK_DEBUG
  extern void DumpLocks(void);
Index: src/include/storage/shmem.h
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/include/storage/shmem.h,v
retrieving revision 1.37
diff -c -r1.37 shmem.h
*** src/include/storage/shmem.h	20 Jun 2002 20:29:52 -0000	1.37
--- src/include/storage/shmem.h	14 Aug 2002 15:05:10 -0000
***************
*** 53,60 ****
  #define SHM_OFFSET_VALID(xx_offs)\
    (((xx_offs) != 0) && ((xx_offs) != INVALID_OFFSET))
  
! 
! /* shmemqueue.c */
  typedef struct SHM_QUEUE
  {
  	SHMEM_OFFSET prev;
--- 53,59 ----
  #define SHM_OFFSET_VALID(xx_offs)\
    (((xx_offs) != 0) && ((xx_offs) != INVALID_OFFSET))
  
! /* shmqueue.c */
  typedef struct SHM_QUEUE
  {
  	SHMEM_OFFSET prev;
Index: src/test/regress/expected/rules.out
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/test/regress/expected/rules.out,v
retrieving revision 1.55
diff -c -r1.55 rules.out
*** src/test/regress/expected/rules.out	8 Aug 2002 19:39:05 -0000	1.55
--- src/test/regress/expected/rules.out	14 Aug 2002 15:05:10 -0000
***************
*** 1268,1273 ****
--- 1268,1275 ----
  --------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   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 pg_lock_status.relation, pg_lock_status."database", pg_lock_status.backendpid, pg_lock_status."mode", pg_lock_status.isgranted FROM pg_lock_status();
+  pg_locks_result          | SELECT 0::oid AS relation, 0::oid AS "database", 0 AS backendpid, ''::text AS "mode", NULL::boolean AS isgranted;
   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_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));
   pg_stat_all_indexes      | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x 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");
***************
*** 1304,1310 ****
   shoelace_obsolete        | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
   street                   | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
   toyemp                   | SELECT emp.name, emp.age, emp."location", (12 * emp.salary) AS annualsal FROM emp;
! (38 rows)
  
  SELECT tablename, rulename, definition FROM pg_rules 
  	ORDER BY tablename, rulename;
--- 1306,1312 ----
   shoelace_obsolete        | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
   street                   | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
   toyemp                   | SELECT emp.name, emp.age, emp."location", (12 * emp.salary) AS annualsal FROM emp;
! (40 rows)
  
  SELECT tablename, rulename, definition FROM pg_rules 
  	ORDER BY tablename, rulename;
