? GNUmakefile ? config.log ? config.status ? diff.patch ? file.txt ? contrib/spi/.deps ? src/Makefile.global ? src/backend/postgres ? src/backend/access/common/.deps ? src/backend/access/gist/.deps ? src/backend/access/hash/.deps ? src/backend/access/heap/.deps ? src/backend/access/index/.deps ? src/backend/access/nbtree/.deps ? src/backend/access/rtree/.deps ? src/backend/access/transam/.deps ? src/backend/bootstrap/.deps ? src/backend/catalog/.deps ? src/backend/catalog/postgres.bki ? src/backend/catalog/postgres.description ? src/backend/commands/.deps ? src/backend/executor/.deps ? src/backend/lib/.deps ? src/backend/libpq/.deps ? src/backend/main/.deps ? src/backend/nodes/.deps ? src/backend/optimizer/geqo/.deps ? src/backend/optimizer/path/.deps ? src/backend/optimizer/plan/.deps ? src/backend/optimizer/prep/.deps ? src/backend/optimizer/util/.deps ? src/backend/parser/.deps ? src/backend/port/.deps ? src/backend/postmaster/.deps ? src/backend/regex/.deps ? src/backend/rewrite/.deps ? src/backend/storage/buffer/.deps ? src/backend/storage/file/.deps ? src/backend/storage/freespace/.deps ? src/backend/storage/ipc/.deps ? src/backend/storage/large_object/.deps ? src/backend/storage/lmgr/.deps ? src/backend/storage/page/.deps ? src/backend/storage/smgr/.deps ? src/backend/tcop/.deps ? src/backend/utils/.deps ? src/backend/utils/adt/.deps ? src/backend/utils/cache/.deps ? src/backend/utils/error/.deps ? src/backend/utils/fmgr/.deps ? src/backend/utils/hash/.deps ? src/backend/utils/init/.deps ? src/backend/utils/mb/.deps ? src/backend/utils/mb/conversion_procs/conversion_create.sql ? src/backend/utils/mb/conversion_procs/ascii_and_mic/.deps ? src/backend/utils/mb/conversion_procs/ascii_and_mic/libascii_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/cyrillic_and_mic/.deps ? src/backend/utils/mb/conversion_procs/cyrillic_and_mic/libcyrillic_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/euc_cn_and_mic/.deps ? src/backend/utils/mb/conversion_procs/euc_cn_and_mic/libeuc_cn_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/.deps ? src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/libeuc_jp_and_sjis.so.0 ? src/backend/utils/mb/conversion_procs/euc_kr_and_mic/.deps ? src/backend/utils/mb/conversion_procs/euc_kr_and_mic/libeuc_kr_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/euc_tw_and_big5/.deps ? src/backend/utils/mb/conversion_procs/euc_tw_and_big5/libeuc_tw_and_big5.so.0 ? src/backend/utils/mb/conversion_procs/latin2_and_win1250/.deps ? src/backend/utils/mb/conversion_procs/latin2_and_win1250/liblatin2_and_win1250.so.0 ? src/backend/utils/mb/conversion_procs/latin_and_mic/.deps ? src/backend/utils/mb/conversion_procs/latin_and_mic/liblatin_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_ascii/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_ascii/libutf8_and_ascii.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_big5/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_big5/libutf8_and_big5.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/libutf8_and_cyrillic.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/libutf8_and_euc_cn.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/libutf8_and_euc_jp.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/libutf8_and_euc_kr.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/libutf8_and_euc_tw.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_gb18030/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_gb18030/libutf8_and_gb18030.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_gbk/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_gbk/libutf8_and_gbk.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859/libutf8_and_iso8859.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/libutf8_and_iso8859_1.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_johab/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_johab/libutf8_and_johab.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_sjis/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_sjis/libutf8_and_sjis.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_tcvn/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_tcvn/libutf8_and_tcvn.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_uhc/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_uhc/libutf8_and_uhc.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win1250/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_win1250/libutf8_and_win1250.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win1256/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_win1256/libutf8_and_win1256.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win874/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_win874/libutf8_and_win874.so.0 ? src/backend/utils/misc/.deps ? src/backend/utils/mmgr/.deps ? src/backend/utils/sort/.deps ? src/backend/utils/time/.deps ? src/bin/initdb/initdb ? src/bin/initlocation/initlocation ? src/bin/ipcclean/ipcclean ? src/bin/pg_config/pg_config ? src/bin/pg_controldata/.deps ? src/bin/pg_controldata/pg_controldata ? src/bin/pg_ctl/pg_ctl ? src/bin/pg_dump/.deps ? src/bin/pg_dump/pg_dump ? src/bin/pg_dump/pg_dumpall ? src/bin/pg_dump/pg_restore ? src/bin/pg_encoding/.deps ? src/bin/pg_encoding/pg_encoding ? src/bin/pg_id/.deps ? src/bin/pg_id/pg_id ? src/bin/pg_resetxlog/.deps ? src/bin/pg_resetxlog/pg_resetxlog ? src/bin/psql/.deps ? src/bin/psql/psql ? src/bin/scripts/createlang ? src/include/pg_config.h ? src/include/stamp-h ? src/interfaces/ecpg/lib/.deps ? src/interfaces/ecpg/lib/libecpg.so.3 ? src/interfaces/ecpg/preproc/.deps ? src/interfaces/ecpg/preproc/ecpg ? src/interfaces/libpq/.deps ? src/interfaces/libpq/libpq.so.3 ? src/pl/plpgsql/src/.deps ? src/pl/plpgsql/src/libplpgsql.so.1 ? src/port/.deps ? src/test/regress/.deps ? src/test/regress/log ? src/test/regress/pg_regress ? src/test/regress/results ? src/test/regress/tmp_check ? src/test/regress/expected/constraints.out ? src/test/regress/expected/copy.out ? src/test/regress/expected/create_function_1.out ? src/test/regress/expected/create_function_2.out ? src/test/regress/expected/misc.out ? src/test/regress/sql/constraints.sql ? src/test/regress/sql/copy.sql ? src/test/regress/sql/create_function_1.sql ? src/test/regress/sql/create_function_2.sql ? src/test/regress/sql/misc.sql Index: src/backend/commands/typecmds.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/typecmds.c,v retrieving revision 1.30 diff -c -r1.30 typecmds.c *** src/backend/commands/typecmds.c 2003/02/03 21:15:43 1.30 --- src/backend/commands/typecmds.c 2003/02/16 00:33:20 *************** *** 353,358 **** --- 353,364 ---- elog(ERROR, "Type \"%s\" does not exist", TypeNameToString(typename)); + /* + * Grab an exclusive lock on the type id, the SearchSysCache confirms + * the type still exists after locking + */ + LockObject(typeoid, RelOid_pg_type, AccessExclusiveLock); + tup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), 0, 0, 0); *************** *** 376,381 **** --- 382,390 ---- object.objectSubId = 0; performDeletion(&object, behavior); + + /* Hold the lock until the end of the transaction */ + UnlockObject(typeoid, RelOid_pg_type, NoLock); } *************** *** 680,686 **** RemoveDomain(List *names, DropBehavior behavior) { TypeName *typename; ! Oid typeoid; HeapTuple tup; char typtype; ObjectAddress object; --- 689,695 ---- RemoveDomain(List *names, DropBehavior behavior) { TypeName *typename; ! Oid domainoid; HeapTuple tup; char typtype; ObjectAddress object; *************** *** 692,711 **** typename->arrayBounds = NIL; /* Use LookupTypeName here so that shell types can be removed. */ ! typeoid = LookupTypeName(typename); ! if (!OidIsValid(typeoid)) elog(ERROR, "Type \"%s\" does not exist", TypeNameToString(typename)); tup = SearchSysCache(TYPEOID, ! ObjectIdGetDatum(typeoid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "RemoveDomain: type \"%s\" does not exist", TypeNameToString(typename)); /* Permission check: must own type or its namespace */ ! if (!pg_type_ownercheck(typeoid, GetUserId()) && !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, TypeNameToString(typename)); --- 701,726 ---- typename->arrayBounds = NIL; /* Use LookupTypeName here so that shell types can be removed. */ ! domainoid = LookupTypeName(typename); ! if (!OidIsValid(domainoid)) elog(ERROR, "Type \"%s\" does not exist", TypeNameToString(typename)); + /* + * Lock the domain. The SearchSysCache confirms the domain still exists + * after locking + */ + LockObject(domainoid, RelOid_pg_type, AccessExclusiveLock); + tup = SearchSysCache(TYPEOID, ! ObjectIdGetDatum(domainoid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "RemoveDomain: type \"%s\" does not exist", TypeNameToString(typename)); /* Permission check: must own type or its namespace */ ! if (!pg_type_ownercheck(domainoid, GetUserId()) && !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, TypeNameToString(typename)); *************** *** 723,732 **** * Do the deletion */ object.classId = RelOid_pg_type; ! object.objectId = typeoid; object.objectSubId = 0; performDeletion(&object, behavior); } --- 738,750 ---- * Do the deletion */ object.classId = RelOid_pg_type; ! object.objectId = domainoid; object.objectSubId = 0; performDeletion(&object, behavior); + + /* Hold the lock until the end of the transaction */ + UnlockObject(domainoid, RelOid_pg_type, NoLock); } *************** *** 941,946 **** --- 959,970 ---- elog(ERROR, "Type \"%s\" does not exist", TypeNameToString(typename)); + /* + * Lock the domain. The SearchSysCacheCopy confirms the type + * still exists after locking + */ + LockObject(domainoid, RelOid_pg_type, AccessExclusiveLock); + tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(domainoid), 0, 0, 0); *************** *** 1025,1030 **** --- 1049,1055 ---- /* Clean up */ heap_close(rel, NoLock); heap_freetuple(newtuple); + UnlockObject(domainoid, RelOid_pg_type, NoLock); }; /* *************** *** 1056,1061 **** --- 1081,1092 ---- elog(ERROR, "Type \"%s\" does not exist", TypeNameToString(typename)); + /* + * Lock the domain. The SearchSysCacheCopy confirms the domain + * still exists after locking + */ + LockObject(domainoid, RelOid_pg_type, AccessExclusiveLock); + tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(domainoid), 0, 0, 0); *************** *** 1137,1142 **** --- 1168,1174 ---- /* Clean up */ heap_freetuple(tup); heap_close(typrel, RowExclusiveLock); + UnlockObject(domainoid, RelOid_pg_type, NoLock); } /* *************** *** 1172,1177 **** --- 1204,1215 ---- elog(ERROR, "Type \"%s\" does not exist", TypeNameToString(typename)); + /* + * Lock the domain. The SearchSysCacheCopy confirms the type still + * exists after locking. + */ + LockObject(domainoid, RelOid_pg_type, AccessExclusiveLock); + tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(domainoid), 0, 0, 0); *************** *** 1219,1224 **** --- 1257,1263 ---- heap_close(conrel, RowExclusiveLock); heap_close(rel, NoLock); + UnlockObject(domainoid, RelOid_pg_type, NoLock); }; /* *************** *** 1259,1264 **** --- 1298,1309 ---- elog(ERROR, "Type \"%s\" does not exist", TypeNameToString(typename)); + /* + * Lock the domain. The SearchSysCacheCopy confirms the domain + * still exists after locking. + */ + LockObject(domainoid, RelOid_pg_type, AccessExclusiveLock); + tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(domainoid), 0, 0, 0); *************** *** 1393,1398 **** --- 1438,1444 ---- /* Clean up */ heap_close(typrel, RowExclusiveLock); + UnlockObject(domainoid, RelOid_pg_type, NoLock); } /* *************** *** 1696,1702 **** Form_pg_type typTup; ScanKeyData key[1]; SysScanDesc scan; ! tup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); --- 1742,1751 ---- Form_pg_type typTup; ScanKeyData key[1]; SysScanDesc scan; ! ! /* Lock the domain */ ! LockObject(typeOid, RelOid_pg_type, AccessShareLock); ! tup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); *************** *** 1824,1829 **** --- 1873,1884 ---- elog(ERROR, "Type \"%s\" does not exist", TypeNameToString(typename)); + /* + * Lock the type. The SearchSysCacheCopy serves to confirm the + * domain still exists after locking + */ + LockObject(typeOid, RelOid_pg_type, AccessExclusiveLock); + tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); *************** *** 1846,1849 **** --- 1901,1905 ---- /* Clean up */ heap_close(rel, RowExclusiveLock); + UnlockObject(typeOid, RelOid_pg_type, NoLock); } Index: src/backend/parser/parse_type.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/parse_type.c,v retrieving revision 1.51 diff -c -r1.51 parse_type.c *** src/backend/parser/parse_type.c 2003/02/09 06:56:28 1.51 --- src/backend/parser/parse_type.c 2003/02/16 00:33:32 *************** *** 23,28 **** --- 23,29 ---- #include "parser/parser.h" #include "parser/parse_expr.h" #include "parser/parse_type.h" + #include "storage/lmgr.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/syscache.h" *************** *** 126,131 **** --- 127,141 ---- restype = TypenameGetTypid(typname); } } + + /* + * Lock the type as having been read for remainder of the transaction + * + * XXX: There is a small time between the above and now when the type + * could dissapear. We *should* recheck to confirm the type still + * exists, but won't for speed. + */ + LockObject(restype, RelOid_pg_type, AccessShareLock); return restype; } Index: src/backend/storage/lmgr/deadlock.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/storage/lmgr/deadlock.c,v retrieving revision 1.16 diff -c -r1.16 deadlock.c *** src/backend/storage/lmgr/deadlock.c 2003/01/16 21:01:44 1.16 --- src/backend/storage/lmgr/deadlock.c 2003/02/16 00:33:45 *************** *** 855,876 **** else nextpid = deadlockDetails[0].pid; ! if (info->locktag.relId == XactLockTableId && info->locktag.dbId == 0) { /* Lock is for transaction ID */ elog(NOTICE, "Proc %d waits for %s on transaction %u; blocked by %d", info->pid, GetLockmodeName(info->lockmode), ! info->locktag.objId.xid, nextpid); } else { /* Lock is for a relation */ ! elog(NOTICE, "Proc %d waits for %s on relation %u database %u; blocked by %d", info->pid, GetLockmodeName(info->lockmode), ! info->locktag.relId, info->locktag.dbId, nextpid); } --- 855,879 ---- else nextpid = deadlockDetails[0].pid; ! if (info->locktag.objId == InvalidOid ! && info->locktag.classId == XactLockTableId ! && info->locktag.dbId == InvalidOid) { /* Lock is for transaction ID */ elog(NOTICE, "Proc %d waits for %s on transaction %u; blocked by %d", info->pid, GetLockmodeName(info->lockmode), ! info->locktag.objsubId.xid, nextpid); } else { /* Lock is for a relation */ ! elog(NOTICE, "Proc %d waits for %s on object %u class %u database %u; blocked by %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: /projects/cvsroot/pgsql-server/src/backend/storage/lmgr/lmgr.c,v retrieving revision 1.54 diff -c -r1.54 lmgr.c *** src/backend/storage/lmgr/lmgr.c 2002/08/01 05:18:33 1.54 --- src/backend/storage/lmgr/lmgr.c 2003/02/16 00:33:49 *************** *** 126,134 **** 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, GetCurrentTransactionId(), lockmode, false)) --- 126,135 ---- 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, GetCurrentTransactionId(), lockmode, false)) *************** *** 160,168 **** 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, GetCurrentTransactionId(), lockmode, true)) --- 161,170 ---- 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, GetCurrentTransactionId(), lockmode, true)) *************** *** 190,198 **** 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, GetCurrentTransactionId(), lockmode); } --- 192,201 ---- 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, GetCurrentTransactionId(), lockmode); } *************** *** 215,223 **** 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)) --- 218,227 ---- 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)) *************** *** 233,241 **** LOCKTAG tag; MemSet(&tag, 0, sizeof(tag)); ! tag.relId = relid->relId; tag.dbId = relid->dbId; ! tag.objId.blkno = InvalidBlockNumber; LockRelease(LockTableId, &tag, InvalidTransactionId, lockmode); } --- 237,246 ---- 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); } *************** *** 253,261 **** 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, GetCurrentTransactionId(), lockmode, false)) --- 258,267 ---- 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, GetCurrentTransactionId(), lockmode, false)) *************** *** 271,279 **** 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, GetCurrentTransactionId(), lockmode); } --- 277,286 ---- 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, GetCurrentTransactionId(), lockmode); } *************** *** 294,302 **** 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, xid, ExclusiveLock, false)) --- 301,310 ---- 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, xid, ExclusiveLock, false)) *************** *** 317,325 **** 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)) --- 325,334 ---- 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)) *************** *** 334,336 **** --- 343,401 ---- 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: /projects/cvsroot/pgsql-server/src/backend/storage/lmgr/lock.c,v retrieving revision 1.119 diff -c -r1.119 lock.c *** src/backend/storage/lmgr/lock.c 2003/01/16 21:01:44 1.119 --- src/backend/storage/lmgr/lock.c 2003/02/16 00:34:04 *************** *** 97,104 **** 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)); } --- 97,104 ---- 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)); } *************** *** 107,118 **** { 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.lockmethod, 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, --- 107,118 ---- { 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.lockmethod, 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, *************** *** 129,136 **** if ( (((PROCLOCK_LOCKMETHOD(*holderP) == DEFAULT_LOCKMETHOD && Trace_locks) || (PROCLOCK_LOCKMETHOD(*holderP) == USER_LOCKMETHOD && Trace_userlocks)) ! && (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId >= (Oid) Trace_lock_oidmin)) ! || (Trace_lock_table && (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId == Trace_lock_table)) ) elog(LOG, "%s: holder(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) hold(%d,%d,%d,%d,%d,%d,%d)=%d", --- 129,136 ---- if ( (((PROCLOCK_LOCKMETHOD(*holderP) == DEFAULT_LOCKMETHOD && Trace_locks) || (PROCLOCK_LOCKMETHOD(*holderP) == USER_LOCKMETHOD && Trace_userlocks)) ! && (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.objId >= (Oid) Trace_lock_oidmin)) ! || (Trace_lock_table && (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.objId == Trace_lock_table)) ) elog(LOG, "%s: holder(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) hold(%d,%d,%d,%d,%d,%d,%d)=%d", *************** *** 417,424 **** * * lockmethod 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 * holder.xid xid or 0 0 --- 417,425 ---- * * lockmethod 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 * holder.xid xid or 0 0 *************** *** 449,455 **** #ifdef LOCK_DEBUG if (lockmethod == 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 */ --- 450,456 ---- #ifdef LOCK_DEBUG if (lockmethod == 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 */ *************** *** 572,578 **** 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; } } --- 573,579 ---- 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; } } *************** *** 993,999 **** #ifdef LOCK_DEBUG if (lockmethod == 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 */ --- 994,1000 ---- #ifdef LOCK_DEBUG if (lockmethod == 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: /projects/cvsroot/pgsql-server/src/backend/utils/adt/lockfuncs.c,v retrieving revision 1.7 diff -c -r1.7 lockfuncs.c *** src/backend/utils/adt/lockfuncs.c 2002/09/04 20:31:28 1.7 --- src/backend/utils/adt/lockfuncs.c 2003/02/16 00:34:06 *************** *** 53,70 **** /* build tupdesc for result tuples */ /* this had better match pg_locks view in initdb.sh */ ! tupdesc = CreateTemplateTupleDesc(6, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation", OIDOID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database", OIDOID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction", XIDOID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid", INT4OID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode", TEXTOID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted", BOOLOID, -1, 0, false); funcctx->slot = TupleDescGetSlot(tupdesc); --- 53,72 ---- /* build tupdesc for result tuples */ /* this had better match pg_locks view in initdb.sh */ ! tupdesc = CreateTemplateTupleDesc(7, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 1, "object", OIDOID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 2, "class", OIDOID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 3, "database", ! OIDOID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 4, "transaction", XIDOID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 5, "pid", INT4OID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 6, "mode", TEXTOID, -1, 0, false); ! TupleDescInitEntry(tupdesc, (AttrNumber) 7, "granted", BOOLOID, -1, 0, false); funcctx->slot = TupleDescGetSlot(tupdesc); *************** *** 93,100 **** PGPROC *proc; bool granted; LOCKMODE mode; ! Datum values[6]; ! char nulls[6]; HeapTuple tuple; Datum result; --- 95,102 ---- PGPROC *proc; bool granted; LOCKMODE mode; ! Datum values[7]; ! char nulls[7]; HeapTuple tuple; Datum result; *************** *** 152,177 **** 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->slot->ttc_tupleDescriptor, values, nulls); --- 154,183 ---- 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->slot->ttc_tupleDescriptor, values, nulls); Index: src/bin/initdb/initdb.sh =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/bin/initdb/initdb.sh,v retrieving revision 1.182 diff -c -r1.182 initdb.sh *** src/bin/initdb/initdb.sh 2003/01/23 23:39:01 1.182 --- src/bin/initdb/initdb.sh 2003/02/16 00:34:31 *************** *** 974,980 **** 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 \ --- 974,980 ---- 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/include/storage/lmgr.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/storage/lmgr.h,v retrieving revision 1.36 diff -c -r1.36 lmgr.h *** src/include/storage/lmgr.h 2002/06/20 20:29:52 1.36 --- src/include/storage/lmgr.h 2003/02/16 00:34:43 *************** *** 62,65 **** --- 62,69 ---- extern void XactLockTableInsert(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: /projects/cvsroot/pgsql-server/src/include/storage/lock.h,v retrieving revision 1.68 diff -c -r1.68 lock.h *** src/include/storage/lock.h 2003/01/16 21:01:45 1.68 --- src/include/storage/lock.h 2003/02/16 00:34:50 *************** *** 100,112 **** */ typedef struct LOCKTAG { ! Oid relId; Oid dbId; union { BlockNumber blkno; TransactionId xid; ! } objId; /* * offnum should be part of objId.tupleId above, but would increase --- 100,113 ---- */ typedef struct LOCKTAG { ! Oid objId; ! Oid classId; Oid dbId; union { BlockNumber blkno; TransactionId xid; ! } objsubId; /* * offnum should be part of objId.tupleId above, but would increase Index: src/test/regress/expected/rules.out =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/test/regress/expected/rules.out,v retrieving revision 1.70 diff -c -r1.70 rules.out *** src/test/regress/expected/rules.out 2002/12/14 00:24:25 1.70 --- src/test/regress/expected/rules.out 2003/02/16 00:35:56 *************** *** 1271,1277 **** --------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath); pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, pg_get_indexdef(i.oid) AS indexdef FROM (((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char")); ! pg_locks | SELECT l.relation, l."database", l."transaction", l.pid, l."mode", l.granted FROM pg_lock_status() l(relation oid, "database" oid, "transaction" xid, pid integer, "mode" text, granted boolean); pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name); pg_settings | SELECT a.name, a.setting FROM pg_show_all_settings() a(name text, setting text); pg_stat_activity | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.usename, pg_stat_get_backend_activity(s.backendid) AS current_query FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_shadow u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.usesysid)); --- 1271,1277 ---- --------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath); pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, pg_get_indexdef(i.oid) AS indexdef FROM (((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char")); ! pg_locks | SELECT l.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 FROM pg_show_all_settings() a(name text, setting text); pg_stat_activity | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.usename, pg_stat_get_backend_activity(s.backendid) AS current_query FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_shadow u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.usesysid));