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 **** pg_locks 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. ! 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. --- 3958,3973 ---- pg_locks 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. ! 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.
*************** *** 3986,3996 **** ! relation oid pg_class.oid ! OID of the locked relation, or NULL if the lockable object is a transaction ID --- 3984,4003 ---- ! class oid pg_class.oid ! The OID of the system catalog the locked object is in, or NULL if the ! lockable object is a transaction ID ! ! ! ! relation ! oid ! any OID column ! ! OID of the locked object, or NULL if the lockable object is a transaction ID 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));