Hackers,

Here is the LockObject patch I was able to come up with.  It's almost
the same patch that Rod Taylor published two years ago; basically, it
expands LOCKTAG with a ClassId attribute, and provides a LockObject
method to allow locking arbitrary objects.  I omitted the uses of the
new functionality.

I provide this mostly for review purposes; it's not intended to be
applied, because I'll submit it in conjunction with the shared
dependency patch later.

-- 
Alvaro Herrera (<alvherre[a]dcc.uchile.cl>)
"El sabio habla porque tiene algo que decir;
el tonto, porque tiene que decir algo" (Platon).
Index: contrib/userlock/user_locks.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/contrib/userlock/user_locks.c,v
retrieving revision 1.14
diff -c -r1.14 user_locks.c
*** contrib/userlock/user_locks.c       27 Aug 2004 17:07:41 -0000      1.14
--- contrib/userlock/user_locks.c       19 Dec 2004 17:12:30 -0000
***************
*** 25,32 ****
  
        memset(&tag, 0, sizeof(LOCKTAG));
        tag.dbId = MyDatabaseId;
!       tag.relId = 0;
!       tag.objId.blkno = (BlockNumber) id2;
        tag.offnum = (OffsetNumber) (id1 & 0xffff);
  
        return LockAcquire(USER_LOCKMETHOD, &tag, InvalidTransactionId,
--- 25,33 ----
  
        memset(&tag, 0, sizeof(LOCKTAG));
        tag.dbId = MyDatabaseId;
!       tag.classId = InvalidOid;
!       tag.objId = InvalidOid;
!       tag.objsubId.blkno = (BlockNumber) id2;
        tag.offnum = (OffsetNumber) (id1 & 0xffff);
  
        return LockAcquire(USER_LOCKMETHOD, &tag, InvalidTransactionId,
***************
*** 40,47 ****
  
        memset(&tag, 0, sizeof(LOCKTAG));
        tag.dbId = MyDatabaseId;
!       tag.relId = 0;
!       tag.objId.blkno = (BlockNumber) id2;
        tag.offnum = (OffsetNumber) (id1 & 0xffff);
  
        return LockRelease(USER_LOCKMETHOD, &tag, InvalidTransactionId, 
lockmode);
--- 41,49 ----
  
        memset(&tag, 0, sizeof(LOCKTAG));
        tag.dbId = MyDatabaseId;
!       tag.classId = InvalidOid;
!       tag.objId = InvalidOid;
!       tag.objsubId.blkno = (BlockNumber) id2;
        tag.offnum = (OffsetNumber) (id1 & 0xffff);
  
        return LockRelease(USER_LOCKMETHOD, &tag, InvalidTransactionId, 
lockmode);
Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.94
diff -c -r2.94 catalogs.sgml
*** doc/src/sgml/catalogs.sgml  13 Dec 2004 18:05:07 -0000      2.94
--- doc/src/sgml/catalogs.sgml  19 Dec 2004 17:02:13 -0000
***************
*** 3958,3975 ****
    <para>
     <structname>pg_locks</structname> contains one row per active lockable
     object, requested lock mode, and relevant transaction.  Thus, the same
!    lockable object may
!    appear many times, if multiple transactions are holding or waiting
!    for locks on it.  However, an object that currently has no locks on it
!    will not appear at all.  A lockable object is either a relation (e.g., a
!    table) or a transaction ID.
    </para>
  
    <para>
!    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>
--- 3958,3973 ----
    <para>
     <structname>pg_locks</structname> contains one row per active lockable
     object, requested lock mode, and relevant transaction.  Thus, the same
!    lockable object may appear many times, if multiple transactions are holding
!    or waiting for locks on it.  However, an object that currently has no locks
!    on it will not appear at all.  A lockable object is either a relation 
(e.g.,
!    a table) or a transaction ID.
    </para>
  
    <para>
!    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>
***************
*** 3986,3996 ****
      </thead>
      <tbody>
       <row>
!       <entry><structfield>relation</structfield></entry>
        <entry><type>oid</type></entry>
        <entry><literal><link 
linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
        <entry>
!        OID of the locked relation, or NULL if the lockable object
         is a transaction ID
        </entry>
       </row>
--- 3984,4003 ----
      </thead>
      <tbody>
       <row>
!       <entry><structfield>class</structfield></entry>
        <entry><type>oid</type></entry>
        <entry><literal><link 
linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
        <entry>
!          The OID of the system catalog the locked object is in, or NULL if the
!          lockable object is a transaction ID
!       </entry>
!      </row>
! <row>
!       <entry><structfield>relation</structfield></entry>
!       <entry><type>oid</type></entry>
!       <entry>any OID column</entry>
!       <entry>
!        OID of the locked object, or NULL if the lockable object
         is a transaction ID
        </entry>
       </row>
Index: src/backend/catalog/system_views.sql
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/system_views.sql,v
retrieving revision 1.10
diff -c -r1.10 system_views.sql
*** src/backend/catalog/system_views.sql        11 Oct 2004 17:24:40 -0000      
1.10
--- src/backend/catalog/system_views.sql        19 Dec 2004 16:30:10 -0000
***************
*** 258,264 ****
  
  CREATE VIEW pg_locks AS 
      SELECT * 
!     FROM pg_lock_status() AS L(relation oid, database oid, 
          transaction xid, pid int4, mode text, granted boolean);
  
  CREATE VIEW pg_settings AS 
--- 258,264 ----
  
  CREATE VIEW pg_locks AS 
      SELECT * 
!     FROM pg_lock_status() AS L(object oid, class oid, database oid, 
          transaction xid, pid int4, mode text, granted boolean);
  
  CREATE VIEW pg_settings AS 
Index: src/backend/storage/lmgr/README
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/lmgr/README,v
retrieving revision 1.15
diff -c -r1.15 README
*** src/backend/storage/lmgr/README     27 Aug 2004 17:07:41 -0000      1.15
--- src/backend/storage/lmgr/README     19 Dec 2004 18:07:48 -0000
***************
*** 79,93 ****
      any alignment-padding bytes the compiler might insert in the struct
      be zeroed out, else the hash computation will be random.
  
!     tag.relId -
!       Uniquely identifies the relation that the lock corresponds to.
      
      tag.dbId -
        Uniquely identifies the database in which the relation lives.  If
        this is a shared system relation (e.g. pg_database) the dbId must
        be set to 0.
  
!     tag.objId -
        Uniquely identifies the block/page within the relation and the
        tuple within the block.  If we are setting a table level lock
        both the blockId and tupleId (in an item pointer this is called
--- 79,100 ----
      any alignment-padding bytes the compiler might insert in the struct
      be zeroed out, else the hash computation will be random.
  
!     tag.classId -
!       Uniquely identifies the object class that the lock corresponds to.
!       To lock a relation, RelOid_pg_class is used, and XactLockTableId
!       to lock a transaction.  Other objects can be locked using the Oid
!       of the system catalog they belong to.
! 
!     tag.objId -
!       Uniquely identifies the object within the class that the lock
!       corresponds to.
      
      tag.dbId -
        Uniquely identifies the database in which the relation lives.  If
        this is a shared system relation (e.g. pg_database) the dbId must
        be set to 0.
  
!     tag.objsubId -
        Uniquely identifies the block/page within the relation and the
        tuple within the block.  If we are setting a table level lock
        both the blockId and tupleId (in an item pointer this is called
Index: src/backend/storage/lmgr/deadlock.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/lmgr/deadlock.c,v
retrieving revision 1.31
diff -c -r1.31 deadlock.c
*** src/backend/storage/lmgr/deadlock.c 29 Aug 2004 04:12:48 -0000      1.31
--- src/backend/storage/lmgr/deadlock.c 19 Dec 2004 18:49:46 -0000
***************
*** 860,883 ****
                if (i > 0)
                        appendStringInfoChar(&buf, '\n');
  
!               if (info->locktag.relId == XactLockTableId && 
info->locktag.dbId == 0)
                {
                        /* Lock is for transaction ID */
                        appendStringInfo(&buf,
                                                         gettext("Process %d 
waits for %s on transaction %u; blocked by process %d."),
                                                         info->pid,
                                                         
GetLockmodeName(info->lockmode),
!                                                        
info->locktag.objId.xid,
                                                         nextpid);
                }
!               else
                {
                        /* Lock is for a relation */
                        appendStringInfo(&buf,
                                                         gettext("Process %d 
waits for %s on relation %u of database %u; blocked by process %d."),
                                                         info->pid,
                                                         
GetLockmodeName(info->lockmode),
!                                                        info->locktag.relId,
                                                         info->locktag.dbId,
                                                         nextpid);
                }
--- 860,909 ----
                if (i > 0)
                        appendStringInfoChar(&buf, '\n');
  
!               if (info->locktag.objId == InvalidOid &&
!                       info->locktag.classId == XactLockTableId &&
!                       info->locktag.dbId == InvalidOid)
                {
                        /* Lock is for transaction ID */
                        appendStringInfo(&buf,
                                                         gettext("Process %d 
waits for %s on transaction %u; blocked by process %d."),
                                                         info->pid,
                                                         
GetLockmodeName(info->lockmode),
!                                                        
info->locktag.objsubId.xid,
                                                         nextpid);
                }
!               else if (info->locktag.dbId != InvalidOid &&
!                                info->locktag.classId == RelOid_pg_class)
                {
                        /* Lock is for a relation */
                        appendStringInfo(&buf,
                                                         gettext("Process %d 
waits for %s on relation %u of database %u; blocked by process %d."),
                                                         info->pid,
                                                         
GetLockmodeName(info->lockmode),
!                                                        info->locktag.objId,
!                                                        info->locktag.dbId,
!                                                        nextpid);
!               }
!               else if (info->locktag.dbId == InvalidOid)
!               {
!                       /* Lock is for a shared object */
!                       appendStringInfo(&buf,
!                                                        gettext("Process %d 
waits for %s on object %u of class %u; blocked by process %d."),
!                                                        info->pid,
!                                                        
GetLockmodeName(info->lockmode),
!                                                        info->locktag.objId,
!                                                        info->locktag.classId,
!                                                        nextpid);
!               }
!               else
!               {
!                       /* Lock is for an object of another class */
!                       appendStringInfo(&buf,
!                                                        gettext("Process %d 
waits for %s on object %u of class %u of database %u; blocked by process %d."),
!                                                        info->pid,
!                                                        
GetLockmodeName(info->lockmode),
!                                                        info->locktag.objId,
!                                                        info->locktag.classId,
                                                         info->locktag.dbId,
                                                         nextpid);
                }
Index: src/backend/storage/lmgr/lmgr.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/lmgr/lmgr.c,v
retrieving revision 1.70
diff -c -r1.70 lmgr.c
*** src/backend/storage/lmgr/lmgr.c     16 Sep 2004 16:58:33 -0000      1.70
--- src/backend/storage/lmgr/lmgr.c     19 Dec 2004 15:28:56 -0000
***************
*** 134,142 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = relation->rd_lockInfo.lockRelId.relId;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objId.blkno = InvalidBlockNumber;
  
        if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                         lockmode, false))
--- 134,143 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = relation->rd_lockInfo.lockRelId.relId;
!       tag.classId = RelOid_pg_class;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objsubId.blkno = InvalidBlockNumber;
  
        if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                         lockmode, false))
***************
*** 168,176 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = relation->rd_lockInfo.lockRelId.relId;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objId.blkno = InvalidBlockNumber;
  
        if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                         lockmode, true))
--- 169,178 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = relation->rd_lockInfo.lockRelId.relId;
!       tag.classId = RelOid_pg_class;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objsubId.blkno = InvalidBlockNumber;
  
        if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                         lockmode, true))
***************
*** 198,206 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = relation->rd_lockInfo.lockRelId.relId;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objId.blkno = InvalidBlockNumber;
  
        LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
  }
--- 200,209 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = relation->rd_lockInfo.lockRelId.relId;
!       tag.classId = RelOid_pg_class;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objsubId.blkno = InvalidBlockNumber;
  
        LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
  }
***************
*** 223,231 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = relid->relId;
        tag.dbId = relid->dbId;
!       tag.objId.blkno = InvalidBlockNumber;
  
        if (!LockAcquire(LockTableId, &tag, InvalidTransactionId,
                                         lockmode, false))
--- 226,235 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = relid->relId;
!       tag.classId = RelOid_pg_class;
        tag.dbId = relid->dbId;
!       tag.objsubId.blkno = InvalidBlockNumber;
  
        if (!LockAcquire(LockTableId, &tag, InvalidTransactionId,
                                         lockmode, false))
***************
*** 241,249 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = relid->relId;
        tag.dbId = relid->dbId;
!       tag.objId.blkno = InvalidBlockNumber;
  
        LockRelease(LockTableId, &tag, InvalidTransactionId, lockmode);
  }
--- 245,254 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = relid->relId;
!       tag.classId = RelOid_pg_class;
        tag.dbId = relid->dbId;
!       tag.objsubId.blkno = InvalidBlockNumber;
  
        LockRelease(LockTableId, &tag, InvalidTransactionId, lockmode);
  }
***************
*** 261,269 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = relation->rd_lockInfo.lockRelId.relId;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objId.blkno = blkno;
  
        if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                         lockmode, false))
--- 266,275 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = relation->rd_lockInfo.lockRelId.relId;
!       tag.classId = RelOid_pg_class;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objsubId.blkno = blkno;
  
        if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                         lockmode, false))
***************
*** 282,290 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = relation->rd_lockInfo.lockRelId.relId;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objId.blkno = blkno;
  
        return LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                           lockmode, true);
--- 288,297 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = relation->rd_lockInfo.lockRelId.relId;
!       tag.classId = RelOid_pg_class;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objsubId.blkno = blkno;
  
        return LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                           lockmode, true);
***************
*** 299,307 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = relation->rd_lockInfo.lockRelId.relId;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objId.blkno = blkno;
  
        LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
  }
--- 306,315 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = relation->rd_lockInfo.lockRelId.relId;
!       tag.classId = RelOid_pg_class;
        tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
!       tag.objsubId.blkno = blkno;
  
        LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
  }
***************
*** 319,327 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = XactLockTableId;
        tag.dbId = InvalidOid;          /* xids are globally unique */
!       tag.objId.xid = xid;
  
        if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                         ExclusiveLock, false))
--- 327,336 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = InvalidOid;
!       tag.classId = XactLockTableId;
        tag.dbId = InvalidOid;          /* xids are globally unique */
!       tag.objsubId.xid = xid;
  
        if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
                                         ExclusiveLock, false))
***************
*** 342,350 ****
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.relId = XactLockTableId;
        tag.dbId = InvalidOid;          /* xids are globally unique */
!       tag.objId.xid = xid;
  
        LockRelease(LockTableId, &tag, GetTopTransactionId(), ExclusiveLock);
  }
--- 351,360 ----
        LOCKTAG         tag;
  
        MemSet(&tag, 0, sizeof(tag));
!       tag.objId = InvalidOid;
!       tag.classId = XactLockTableId;
        tag.dbId = InvalidOid;          /* xids are globally unique */
!       tag.objsubId.xid = xid;
  
        LockRelease(LockTableId, &tag, GetTopTransactionId(), ExclusiveLock);
  }
***************
*** 373,381 ****
                Assert(!TransactionIdEquals(xid, myxid));
  
                MemSet(&tag, 0, sizeof(tag));
!               tag.relId = XactLockTableId;
                tag.dbId = InvalidOid;
!               tag.objId.xid = xid;
  
                if (!LockAcquire(LockTableId, &tag, myxid, ShareLock, false))
                        elog(ERROR, "LockAcquire failed");
--- 383,392 ----
                Assert(!TransactionIdEquals(xid, myxid));
  
                MemSet(&tag, 0, sizeof(tag));
!               tag.objId = InvalidOid;
!               tag.classId = XactLockTableId;
                tag.dbId = InvalidOid;
!               tag.objsubId.xid = xid;
  
                if (!LockAcquire(LockTableId, &tag, myxid, ShareLock, false))
                        elog(ERROR, "LockAcquire failed");
***************
*** 393,395 ****
--- 404,462 ----
        if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
                TransactionIdAbort(xid);
  }
+ 
+ /*
+  * LockObject
+  *
+  * Lock an arbitrary database object.  A standard relation lock would lock the
+  * classId of RelOid_pg_class and objId of the relations OID within the 
pg_class
+  * table.  LockObject allows classId to be specified by the caller, thus 
allowing
+  * locks on any row in any system table.
+  *
+  * If classId is NOT a system table (protected from removal), an additional 
lock
+  * should be held on the relation to prevent it from being dropped.
+  */
+ void
+ LockObject(Oid objId, Oid classId, LOCKMODE lockmode)
+ {
+       LOCKTAG         tag;
+ 
+       MemSet(&tag, 0, sizeof(tag));
+       tag.objId = objId;
+       tag.classId = classId;
+       tag.dbId = MyDatabaseId;
+       tag.objsubId.blkno = InvalidBlockNumber;
+ 
+       /* Only two reasonable lock types */
+       Assert(lockmode == AccessShareLock || lockmode == AccessExclusiveLock);
+ 
+       if (!LockAcquire(LockTableId, &tag, GetCurrentTransactionId(),
+                                        lockmode, false))
+               elog(ERROR, "LockObject: LockAcquire failed");
+ }
+ 
+ /*
+  * UnlockObject
+  */
+ void
+ UnlockObject(Oid objId, Oid classId, LOCKMODE lockmode)
+ {
+       LOCKTAG         tag;
+ 
+       /* NoLock is a no-op */
+       if (lockmode == NoLock)
+               return;
+ 
+       MemSet(&tag, 0, sizeof(tag));
+       tag.objId = objId;
+       tag.classId = classId;
+       tag.dbId = MyDatabaseId;
+       tag.objsubId.blkno = InvalidBlockNumber;
+ 
+       /* Only two reasonable lock types */
+       Assert(lockmode == AccessShareLock
+                 || lockmode == AccessExclusiveLock);
+ 
+       LockRelease(LockTableId, &tag, GetCurrentTransactionId(), lockmode);
+ }
+ 
Index: src/backend/storage/lmgr/lock.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/lmgr/lock.c,v
retrieving revision 1.144
diff -c -r1.144 lock.c
*** src/backend/storage/lmgr/lock.c     20 Nov 2004 20:16:54 -0000      1.144
--- src/backend/storage/lmgr/lock.c     18 Dec 2004 23:45:34 -0000
***************
*** 110,117 ****
        return
                (((LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD && Trace_locks)
           || (LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD && Trace_userlocks))
!                && (lock->tag.relId >= (Oid) Trace_lock_oidmin))
!               || (Trace_lock_table && (lock->tag.relId == Trace_lock_table));
  }
  
  
--- 110,117 ----
        return
                (((LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD && Trace_locks)
           || (LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD && Trace_userlocks))
!                && (lock->tag.objId >= (Oid) Trace_lock_oidmin))
!               || (Trace_lock_table && (lock->tag.objId == Trace_lock_table));
  }
  
  
***************
*** 120,131 ****
  {
        if (LOCK_DEBUG_ENABLED(lock))
                elog(LOG,
!                        "%s: lock(%lx) tbl(%d) rel(%u) db(%u) obj(%u) 
grantMask(%x) "
                         "req(%d,%d,%d,%d,%d,%d,%d)=%d "
                         "grant(%d,%d,%d,%d,%d,%d,%d)=%d wait(%d) type(%s)",
                         where, MAKE_OFFSET(lock),
!                        lock->tag.lockmethodid, lock->tag.relId, 
lock->tag.dbId,
!                        lock->tag.objId.blkno, lock->grantMask,
                         lock->requested[1], lock->requested[2], 
lock->requested[3],
                         lock->requested[4], lock->requested[5], 
lock->requested[6],
                         lock->requested[7], lock->nRequested,
--- 120,131 ----
  {
        if (LOCK_DEBUG_ENABLED(lock))
                elog(LOG,
!                        "%s: lock(%lx) tbl(%d) obj(%u) class(%u) db(%u) 
objsub(%u) grantMask(%x) "
                         "req(%d,%d,%d,%d,%d,%d,%d)=%d "
                         "grant(%d,%d,%d,%d,%d,%d,%d)=%d wait(%d) type(%s)",
                         where, MAKE_OFFSET(lock),
!                        lock->tag.lockmethodid, lock->tag.objId, 
lock->tag.classId, lock->tag.dbId,
!                        lock->tag.objsubId.blkno, lock->grantMask,
                         lock->requested[1], lock->requested[2], 
lock->requested[3],
                         lock->requested[4], lock->requested[5], 
lock->requested[6],
                         lock->requested[7], lock->nRequested,
***************
*** 142,149 ****
        if (
                (((PROCLOCK_LOCKMETHOD(*proclockP) == DEFAULT_LOCKMETHOD && 
Trace_locks)
                  || (PROCLOCK_LOCKMETHOD(*proclockP) == USER_LOCKMETHOD && 
Trace_userlocks))
!                && (((LOCK *) MAKE_PTR(proclockP->tag.lock))->tag.relId >= 
(Oid) Trace_lock_oidmin))
!               || (Trace_lock_table && (((LOCK *) 
MAKE_PTR(proclockP->tag.lock))->tag.relId == Trace_lock_table))
                )
                elog(LOG,
                "%s: proclock(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) 
hold(%x)",
--- 142,149 ----
        if (
                (((PROCLOCK_LOCKMETHOD(*proclockP) == DEFAULT_LOCKMETHOD && 
Trace_locks)
                  || (PROCLOCK_LOCKMETHOD(*proclockP) == USER_LOCKMETHOD && 
Trace_userlocks))
!                && (((LOCK *) MAKE_PTR(proclockP->tag.lock))->tag.objId >= 
(Oid) Trace_lock_oidmin))
!               || (Trace_lock_table && (((LOCK *) 
MAKE_PTR(proclockP->tag.lock))->tag.objId == Trace_lock_table))
                )
                elog(LOG,
                "%s: proclock(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) 
hold(%x)",
***************
*** 422,429 ****
   *
   *            lockmethodid                                    1               
                2
   *            tag.dbId                                                
database oid    database oid
!  *            tag.relId                                               rel oid 
or 0    0
!  *            tag.objId                                               block 
id                lock id2
   *                                                                            
or xact id
   *            tag.offnum                                              0       
                        lock id1
   *            proclock.xid                                    xid or 0        
        0
--- 422,430 ----
   *
   *            lockmethodid                                    1               
                2
   *            tag.dbId                                                
database oid    database oid
!  *            tag.classId                                             class 
oid               0
!  *            tag.objId                                               rel oid 
or 0    0
!  *            tag.objsubId                                    block id        
        lock id2
   *                                                                            
or xact id
   *            tag.offnum                                              0       
                        lock id1
   *            proclock.xid                                    xid or 0        
        0
***************
*** 456,462 ****
  #ifdef LOCK_DEBUG
        if (lockmethodid == USER_LOCKMETHOD && Trace_userlocks)
                elog(LOG, "LockAcquire: user lock [%u] %s",
!                        locktag->objId.blkno, lock_mode_names[lockmode]);
  #endif
  
        /* ???????? This must be changed when short term locks will be used */
--- 457,463 ----
  #ifdef LOCK_DEBUG
        if (lockmethodid == USER_LOCKMETHOD && Trace_userlocks)
                elog(LOG, "LockAcquire: user lock [%u] %s",
!                        locktag->objsubId.blkno, lock_mode_names[lockmode]);
  #endif
  
        /* ???????? This must be changed when short term locks will be used */
***************
*** 665,671 ****
                                elog(LOG, "deadlock risk: raising lock level"
                                         " from %s to %s on object %u/%u/%u",
                                         lock_mode_names[i], 
lock_mode_names[lockmode],
!                                lock->tag.relId, lock->tag.dbId, 
lock->tag.objId.blkno);
                                break;
                        }
                }
--- 666,672 ----
                                elog(LOG, "deadlock risk: raising lock level"
                                         " from %s to %s on object %u/%u/%u",
                                         lock_mode_names[i], 
lock_mode_names[lockmode],
!                                lock->tag.objId, lock->tag.dbId, 
lock->tag.objsubId.blkno);
                                break;
                        }
                }
***************
*** 1150,1156 ****
  
  #ifdef LOCK_DEBUG
        if (lockmethodid == USER_LOCKMETHOD && Trace_userlocks)
!               elog(LOG, "LockRelease: user lock tag [%u] %d", 
locktag->objId.blkno, lockmode);
  #endif
  
        /* ???????? This must be changed when short term locks will be used */
--- 1151,1157 ----
  
  #ifdef LOCK_DEBUG
        if (lockmethodid == USER_LOCKMETHOD && Trace_userlocks)
!               elog(LOG, "LockRelease: user lock tag [%u] %d", 
locktag->objsubId.blkno, lockmode);
  #endif
  
        /* ???????? This must be changed when short term locks will be used */
Index: src/backend/utils/adt/lockfuncs.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/utils/adt/lockfuncs.c,v
retrieving revision 1.15
diff -c -r1.15 lockfuncs.c
*** src/backend/utils/adt/lockfuncs.c   29 Aug 2004 04:12:51 -0000      1.15
--- src/backend/utils/adt/lockfuncs.c   18 Dec 2004 23:39:23 -0000
***************
*** 53,70 ****
  
                /* build tupdesc for result tuples */
                /* this had better match pg_locks view in system_views.sql */
!               tupdesc = CreateTemplateTupleDesc(6, false);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation",
                                                   OIDOID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
                                                   OIDOID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction",
                                                   XIDOID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid",
                                                   INT4OID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode",
                                                   TEXTOID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted",
                                                   BOOLOID, -1, 0);
  
                funcctx->tuple_desc = BlessTupleDesc(tupdesc);
--- 53,72 ----
  
                /* build tupdesc for result tuples */
                /* this had better match pg_locks view in system_views.sql */
!               tupdesc = CreateTemplateTupleDesc(7, false);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 1, "object",
                                                   OIDOID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 2, "class",
                                                   OIDOID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 3, "database",
!                                                  OIDOID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 4, "transaction",
                                                   XIDOID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 5, "pid",
                                                   INT4OID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 6, "mode",
                                                   TEXTOID, -1, 0);
!               TupleDescInitEntry(tupdesc, (AttrNumber) 7, "granted",
                                                   BOOLOID, -1, 0);
  
                funcctx->tuple_desc = BlessTupleDesc(tupdesc);
***************
*** 93,100 ****
                PGPROC     *proc;
                bool            granted;
                LOCKMODE        mode = 0;
!               Datum           values[6];
!               char            nulls[6];
                HeapTuple       tuple;
                Datum           result;
  
--- 95,102 ----
                PGPROC     *proc;
                bool            granted;
                LOCKMODE        mode = 0;
!               Datum           values[7];
!               char            nulls[7];
                HeapTuple       tuple;
                Datum           result;
  
***************
*** 155,180 ****
                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->tuple_desc, values, nulls);
                result = HeapTupleGetDatum(tuple);
--- 157,186 ----
                MemSet(values, 0, sizeof(values));
                MemSet(nulls, ' ', sizeof(nulls));
  
!               if (lock->tag.objId == InvalidOid
!                       && lock->tag.classId == XactLockTableId
!                       && lock->tag.dbId == InvalidOid)
                {
                        /* Lock is for transaction ID */
                        nulls[0] = 'n';
                        nulls[1] = 'n';
!                       nulls[2] = 'n';
!                       values[3] = 
TransactionIdGetDatum(lock->tag.objsubId.xid);
                }
                else
                {
                        /* Lock is for a relation */
!                       values[0] = ObjectIdGetDatum(lock->tag.objId);
!                       values[1] = ObjectIdGetDatum(lock->tag.classId);
!                       values[2] = ObjectIdGetDatum(lock->tag.dbId);
!                       nulls[3] = 'n';
  
                }
  
!               values[4] = Int32GetDatum(proc->pid);
!               values[5] = DirectFunctionCall1(textin,
                                                                 
CStringGetDatum(GetLockmodeName(mode)));
!               values[6] = BoolGetDatum(granted);
  
                tuple = heap_formtuple(funcctx->tuple_desc, values, nulls);
                result = HeapTupleGetDatum(tuple);
Index: src/include/storage/lmgr.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/storage/lmgr.h,v
retrieving revision 1.44
diff -c -r1.44 lmgr.h
*** src/include/storage/lmgr.h  16 Sep 2004 16:58:42 -0000      1.44
--- src/include/storage/lmgr.h  17 Dec 2004 17:57:36 -0000
***************
*** 61,64 ****
--- 61,68 ----
  extern void XactLockTableDelete(TransactionId xid);
  extern void XactLockTableWait(TransactionId xid);
  
+ /* Lock an arbitrary database object in the current database */
+ extern void LockObject(Oid objId, Oid classId, LOCKMODE lockmode);
+ extern void UnlockObject(Oid objId, Oid classId, LOCKMODE lockmode);
+ 
  #endif   /* LMGR_H */
Index: src/include/storage/lock.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/storage/lock.h,v
retrieving revision 1.83
diff -c -r1.83 lock.h
*** src/include/storage/lock.h  29 Aug 2004 05:06:58 -0000      1.83
--- src/include/storage/lock.h  17 Dec 2004 17:57:36 -0000
***************
*** 106,118 ****
   */
  typedef struct LOCKTAG
  {
!       Oid                     relId;
        Oid                     dbId;
        union
        {
                BlockNumber blkno;
                TransactionId xid;
!       }                       objId;
  
        /*
         * offnum should be part of objId union above, but doing that would
--- 106,119 ----
   */
  typedef struct LOCKTAG
  {
!       Oid                     objId;
!       Oid                     classId;
        Oid                     dbId;
        union
        {
                BlockNumber blkno;
                TransactionId xid;
!       }                       objsubId;
  
        /*
         * offnum should be part of objId union above, but doing that would
Index: src/test/regress/expected/rules.out
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/rules.out,v
retrieving revision 1.95
diff -c -r1.95 rules.out
*** src/test/regress/expected/rules.out 27 Oct 2004 18:09:41 -0000      1.95
--- src/test/regress/expected/rules.out 19 Dec 2004 18:59:25 -0000
***************
*** 1276,1282 ****
  
--------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   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, t.spcname AS "tablespace", 
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))) LEFT JOIN pg_tablespace t ON 
((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 
'i'::"char"));
!  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, a.category, 
a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, 
a.max_val FROM pg_show_all_settings() a(name text, setting text, category text, 
short_desc text, extra_desc text, context text, vartype text, source text, 
min_val text, max_val 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, 
pg_stat_get_backend_activity_start(s.backendid) AS query_start 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));
--- 1276,1282 ----
  
--------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   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, t.spcname AS "tablespace", 
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))) LEFT JOIN pg_tablespace t ON 
((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 
'i'::"char"));
!  pg_locks                 | SELECT l."object", l."class", l."database", 
l."transaction", l.pid, l."mode", l.granted FROM pg_lock_status() l("object" 
oid, "class" 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, a.category, 
a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, 
a.max_val FROM pg_show_all_settings() a(name text, setting text, category text, 
short_desc text, extra_desc text, context text, vartype text, source text, 
min_val text, max_val 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, 
pg_stat_get_backend_activity_start(s.backendid) AS query_start 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));
---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faqs/FAQ.html

Reply via email to