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 30 Jan 2005 09:51:00 -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.95 diff -c -r2.95 catalogs.sgml *** doc/src/sgml/catalogs.sgml 5 Jan 2005 23:42:03 -0000 2.95 --- doc/src/sgml/catalogs.sgml 30 Jan 2005 09:51:02 -0000 *************** *** 174,179 **** --- 174,183 ---- + pg_shdepend + cross-database dependencies between objects + + pg_statistic planner statistics *************** *** 3139,3144 **** --- 3143,3219 ---- + + <structname>pg_shdepend</structname> + + + pg_shdepend + + + + The shared catalog pg_shdepend records the + dependency relationships between database objects and global objects, + such as users, groups and tablespaces. This information allows + DROP USER, DROP GROUP and + DROP TABLESPACE to ensure that those objects are + unreferenced before attempting to delete them. + + + + <structname>pg_shdepend</> Columns + + + + + Name + Type + References + Description + + + + + + dbid + oid + pg_database.oid + The OID of the database the dependent object is in + + + + classid + oid + pg_class.oid + The OID of the system catalog the dependent object is in + + + + objid + oid + any OID column + The OID of the specific dependent object + + + + refclassid + oid + pg_class.oid + The OID of the system catalog the referenced object is in + + + + refobjid + oid + any OID column + The OID of the specific referenced object + + + + +
+
+ + <structname>pg_statistic</structname> *************** *** 4013,4020 **** 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. --- 4088,4096 ---- 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 an arbitrary ! object in a system catalog, the most common case being a relation (e.g., a ! table), or a transaction ID. *************** *** 4038,4048 **** ! relation oid pg_class.oid ! OID of the locked relation, or NULL if the lockable object is a transaction ID --- 4114,4133 ---- ! 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: doc/src/sgml/ref/create_group.sgml =================================================================== RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/ref/create_group.sgml,v retrieving revision 1.15 diff -c -r1.15 create_group.sgml *** doc/src/sgml/ref/create_group.sgml 4 Jan 2005 00:39:53 -0000 1.15 --- doc/src/sgml/ref/create_group.sgml 30 Jan 2005 09:51:04 -0000 *************** *** 69,77 **** The SYSID clause can be used to choose the PostgreSQL group ID of the new group. ! This is normally not necessary, but may ! be useful if you need to recreate a group referenced in the ! permissions of some object. If this is not specified, the highest assigned group ID plus one --- 69,75 ---- The SYSID clause can be used to choose the PostgreSQL group ID of the new group. ! This is normally not necessary. If this is not specified, the highest assigned group ID plus one Index: doc/src/sgml/ref/create_user.sgml =================================================================== RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/ref/create_user.sgml,v retrieving revision 1.36 diff -c -r1.36 create_user.sgml *** doc/src/sgml/ref/create_user.sgml 6 Jan 2005 00:11:14 -0000 1.36 --- doc/src/sgml/ref/create_user.sgml 30 Jan 2005 09:51:05 -0000 *************** *** 65,73 **** The SYSID clause can be used to choose the PostgreSQL user ID of the new user. ! This is normally not necessary, but may ! be useful if you need to recreate the owner of an orphaned ! object. If this is not specified, the highest assigned user ID plus one --- 65,71 ---- The SYSID clause can be used to choose the PostgreSQL user ID of the new user. ! This is normally not necessary. If this is not specified, the highest assigned user ID plus one Index: src/backend/catalog/Makefile =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/Makefile,v retrieving revision 1.53 diff -c -r1.53 Makefile *** src/backend/catalog/Makefile 21 Jul 2004 20:34:45 -0000 1.53 --- src/backend/catalog/Makefile 30 Jan 2005 09:51:07 -0000 *************** *** 12,18 **** OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o \ ! pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_type.o BKIFILES = postgres.bki postgres.description --- 12,19 ---- OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o \ ! pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \ ! pg_type.o BKIFILES = postgres.bki postgres.description *************** *** 32,38 **** pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \ pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \ ! pg_tablespace.h pg_depend.h indexing.h \ ) pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include) --- 33,39 ---- pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \ pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \ ! pg_tablespace.h pg_depend.h pg_shdepend.h indexing.h \ ) pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include) Index: src/backend/catalog/aclchk.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/aclchk.c,v retrieving revision 1.110 diff -c -r1.110 aclchk.c *** src/backend/catalog/aclchk.c 27 Jan 2005 23:36:06 -0000 1.110 --- src/backend/catalog/aclchk.c 30 Jan 2005 09:51:07 -0000 *************** *** 20,25 **** --- 20,26 ---- #include "access/heapam.h" #include "catalog/catalog.h" #include "catalog/catname.h" + #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_conversion.h" *************** *** 268,273 **** --- 269,278 ---- Datum values[Natts_pg_class]; char nulls[Natts_pg_class]; char replaces[Natts_pg_class]; + List *oldgroups; + List *oldusers; + List *newgroups; + List *newusers; /* open pg_class */ relation = heap_openr(RelationRelationName, RowExclusiveLock); *************** *** 360,370 **** --- 365,388 ---- /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); + /* + * We need the members of both old and new ACLs so we can correct + * the shared dependency information. + */ + aclmembers(old_acl, &oldusers, &oldgroups); + new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, this_privileges, grantorId, ownerId); + aclmembers(new_acl, &newusers, &newgroups); + + /* Update the shared dependency ACL info */ + shdependUpdateAclInfo(RelOid_pg_class, relOid, ownerId, stmt->is_grant, + oldusers, newusers, + oldgroups, newgroups); + /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); *************** *** 437,442 **** --- 455,464 ---- Datum values[Natts_pg_database]; char nulls[Natts_pg_database]; char replaces[Natts_pg_database]; + List *oldgroups; + List *oldusers; + List *newgroups; + List *newusers; relation = heap_openr(DatabaseRelationName, RowExclusiveLock); ScanKeyInit(&entry[0], *************** *** 518,528 **** --- 540,559 ---- /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); + aclmembers(old_acl, &oldusers, &oldgroups); + new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, this_privileges, grantorId, ownerId); + aclmembers(new_acl, &newusers, &newgroups); + + /* Update the shared dependency ACL info */ + shdependUpdateAclInfo(RelOid_pg_database, HeapTupleGetOid(tuple), ownerId, stmt->is_grant, + oldusers, newusers, + oldgroups, newgroups); + /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); *************** *** 594,599 **** --- 625,634 ---- Datum values[Natts_pg_proc]; char nulls[Natts_pg_proc]; char replaces[Natts_pg_proc]; + List *oldgroups; + List *oldusers; + List *newgroups; + List *newusers; oid = LookupFuncNameTypeNames(func->funcname, func->funcargs, false); *************** *** 672,682 **** --- 707,726 ---- /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); + aclmembers(old_acl, &oldusers, &oldgroups); + new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, this_privileges, grantorId, ownerId); + aclmembers(new_acl, &newusers, &newgroups); + + /* Update the shared dependency ACL info */ + shdependUpdateAclInfo(RelOid_pg_proc, oid, ownerId, stmt->is_grant, + oldusers, newusers, + oldgroups, newgroups); + /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); *************** *** 747,752 **** --- 791,800 ---- Datum values[Natts_pg_language]; char nulls[Natts_pg_language]; char replaces[Natts_pg_language]; + List *oldgroups; + List *oldusers; + List *newgroups; + List *newusers; relation = heap_openr(LanguageRelationName, RowExclusiveLock); tuple = SearchSysCache(LANGNAME, *************** *** 835,845 **** --- 883,903 ---- /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); + aclmembers(old_acl, &oldusers, &oldgroups); + new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, this_privileges, grantorId, ownerId); + aclmembers(new_acl, &newusers, &newgroups); + + /* Update the shared dependency ACL info */ + shdependUpdateAclInfo(get_system_catalog_relid(LanguageRelationName), + HeapTupleGetOid(tuple), ownerId, stmt->is_grant, + oldusers, newusers, + oldgroups, newgroups); + /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); *************** *** 910,915 **** --- 968,977 ---- Datum values[Natts_pg_namespace]; char nulls[Natts_pg_namespace]; char replaces[Natts_pg_namespace]; + List *oldgroups; + List *oldusers; + List *newgroups; + List *newusers; relation = heap_openr(NamespaceRelationName, RowExclusiveLock); tuple = SearchSysCache(NAMESPACENAME, *************** *** 989,999 **** --- 1051,1071 ---- /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); + aclmembers(old_acl, &oldusers, &oldgroups); + new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, this_privileges, grantorId, ownerId); + aclmembers(new_acl, &newusers, &newgroups); + + /* Update the shared dependency ACL info */ + shdependUpdateAclInfo(get_system_catalog_relid(NamespaceRelationName), + HeapTupleGetOid(tuple), ownerId, stmt->is_grant, + oldusers, newusers, + oldgroups, newgroups); + /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); *************** *** 1066,1071 **** --- 1138,1147 ---- Datum values[Natts_pg_tablespace]; char nulls[Natts_pg_tablespace]; char replaces[Natts_pg_tablespace]; + List *oldgroups; + List *oldusers; + List *newgroups; + List *newusers; relation = heap_openr(TableSpaceRelationName, RowExclusiveLock); ScanKeyInit(&entry[0], *************** *** 1147,1157 **** --- 1223,1242 ---- /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); + aclmembers(old_acl, &oldusers, &oldgroups); + new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, this_privileges, grantorId, ownerId); + aclmembers(new_acl, &newusers, &newgroups); + + /* Update the shared dependency ACL info */ + shdependUpdateAclInfo(RelOid_pg_tablespace, HeapTupleGetOid(tuple), ownerId, stmt->is_grant, + oldusers, newusers, + oldgroups, newgroups); + /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); Index: src/backend/catalog/dependency.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/dependency.c,v retrieving revision 1.41 diff -c -r1.41 dependency.c *** src/backend/catalog/dependency.c 31 Dec 2004 21:59:38 -0000 1.41 --- src/backend/catalog/dependency.c 30 Jan 2005 09:51:07 -0000 *************** *** 32,40 **** --- 32,42 ---- #include "catalog/pg_rewrite.h" #include "catalog/pg_trigger.h" #include "commands/comment.h" + #include "commands/dbcommands.h" #include "commands/defrem.h" #include "commands/proclang.h" #include "commands/schemacmds.h" + #include "commands/tablespace.h" #include "commands/trigger.h" #include "commands/typecmds.h" #include "lib/stringinfo.h" *************** *** 496,501 **** --- 498,504 ---- break; } + /* delete the pg_depend tuple */ simple_heap_delete(depRel, &tup->t_self); } *************** *** 572,577 **** --- 575,588 ---- DeleteComments(object->objectId, object->classId, object->objectSubId); /* + * Delete shared dependency references related to this object. + * Sub-objects (columns) don't have dependencies on global objects, + * so skip them. + */ + if (object->objectSubId == 0) + deleteSharedDependencyRecordsFor(object->classId, object->objectId); + + /* * CommandCounterIncrement here to ensure that preceding changes are * all visible. */ *************** *** 1305,1313 **** --- 1316,1327 ---- static void init_object_classes(void) { + object_classes[OCLASS_AM] = get_system_catalog_relid(AccessMethodRelationName); object_classes[OCLASS_CLASS] = RelOid_pg_class; object_classes[OCLASS_PROC] = RelOid_pg_proc; object_classes[OCLASS_TYPE] = RelOid_pg_type; + object_classes[OCLASS_DATABASE] = RelOid_pg_database; + object_classes[OCLASS_SHADOW] = RelOid_pg_shadow; object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName); object_classes[OCLASS_CONSTRAINT] = get_system_catalog_relid(ConstraintRelationName); object_classes[OCLASS_CONVERSION] = get_system_catalog_relid(ConversionRelationName); *************** *** 1318,1323 **** --- 1332,1338 ---- object_classes[OCLASS_REWRITE] = get_system_catalog_relid(RewriteRelationName); object_classes[OCLASS_TRIGGER] = get_system_catalog_relid(TriggerRelationName); object_classes[OCLASS_SCHEMA] = get_system_catalog_relid(NamespaceRelationName); + object_classes[OCLASS_TBLSPACE] = RelOid_pg_tablespace; object_classes_initialized = true; } *************** *** 1344,1349 **** --- 1359,1376 ---- case RelOid_pg_type: Assert(object->objectSubId == 0); return OCLASS_TYPE; + + case RelOid_pg_database: + Assert(object->objectSubId == 0); + return OCLASS_DATABASE; + + case RelOid_pg_tablespace: + Assert(object->objectSubId == 0); + return OCLASS_TBLSPACE; + + case RelOid_pg_shadow: + Assert(object->objectSubId == 0); + return OCLASS_SHADOW; } /* *************** *** 1352,1357 **** --- 1379,1389 ---- if (!object_classes_initialized) init_object_classes(); + if (object->classId == object_classes[OCLASS_AM]) + { + Assert(object->objectSubId == 0); + return OCLASS_AM; + } if (object->classId == object_classes[OCLASS_CAST]) { Assert(object->objectSubId == 0); *************** *** 1439,1444 **** --- 1471,1510 ---- format_type_be(object->objectId)); break; + case OCLASS_AM: + { + Relation amDesc; + ScanKeyData skey[1]; + SysScanDesc rcscan; + HeapTuple tup; + Form_pg_am amForm; + + amDesc = heap_openr(AccessMethodRelationName, AccessShareLock); + + ScanKeyInit(&skey[0], + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + rcscan = systable_beginscan(amDesc, AmOidIndex, true, + SnapshotNow, 1, skey); + + tup = systable_getnext(rcscan); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for access method %u", + object->objectId); + + amForm = (Form_pg_am) GETSTRUCT(tup); + + appendStringInfo(&buffer, gettext("access method %s"), + amForm->amname.data); + + systable_endscan(rcscan); + heap_close(amDesc, AccessShareLock); + break; + } + case OCLASS_CAST: { Relation castDesc; *************** *** 1715,1720 **** --- 1781,1817 ---- break; } + case OCLASS_TBLSPACE: + { + char *tblspace; + + tblspace = get_tablespace_name(object->objectId); + if (!tblspace) + elog(ERROR, "cache lookup failed for tablespace %u", + object->objectId); + appendStringInfo(&buffer, gettext("tablespace %s"), tblspace); + break; + } + + case OCLASS_DATABASE: + { + char *datname; + + datname = get_database_name(object->objectId); + if (!datname) + elog(ERROR, "cache lookup failed for database %u", + object->objectId); + appendStringInfo(&buffer, gettext("database %s"), datname); + break; + } + + case OCLASS_SHADOW: + { + appendStringInfo(&buffer, gettext("user %s"), + GetUserNameFromId((AclId)object->objectId)); + break; + } + default: appendStringInfo(&buffer, "unrecognized object %u %u %d", object->classId, Index: src/backend/catalog/heap.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/heap.c,v retrieving revision 1.280 diff -c -r1.280 heap.c *** src/backend/catalog/heap.c 27 Jan 2005 03:17:17 -0000 1.280 --- src/backend/catalog/heap.c 30 Jan 2005 09:51:07 -0000 *************** *** 332,338 **** /* ---------------------------------------------------------------- * heap_create_with_catalog - Create a cataloged relation * ! * this is done in 6 steps: * * 1) CheckAttributeNamesTypes() is used to make certain the tuple * descriptor contains a valid set of attribute names and types --- 332,338 ---- /* ---------------------------------------------------------------- * heap_create_with_catalog - Create a cataloged relation * ! * this is done in 8 steps: * * 1) CheckAttributeNamesTypes() is used to make certain the tuple * descriptor contains a valid set of attribute names and types *************** *** 789,794 **** --- 789,796 ---- * make a dependency link to force the relation to be deleted if its * namespace is. Skip this in bootstrap mode, since we don't make * dependencies while bootstrapping. + * + * Also make dependency links to its owner and tablespace, as needed. */ if (!IsBootstrapProcessingMode()) { *************** *** 798,807 **** --- 800,826 ---- myself.classId = RelOid_pg_class; myself.objectId = new_rel_oid; myself.objectSubId = 0; + + /* the relation depends on its namespace */ referenced.classId = get_system_catalog_relid(NamespaceRelationName); referenced.objectId = relnamespace; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* the relation depends on its tablespace, if specified */ + if (reltablespace != 0) + { + referenced.classId = get_system_catalog_relid(TableSpaceRelationName); + referenced.objectId = reltablespace; + referenced.objectSubId = 0; + recordSharedDependencyOn(&myself, &referenced); + } + + /* the relation depends on its owner */ + referenced.classId = get_system_catalog_relid(ShadowRelationName); + referenced.objectId = GetUserId(); + referenced.objectSubId = 0; + recordSharedDependencyOn(&myself, &referenced); } /* Index: src/backend/catalog/pg_conversion.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_conversion.c,v retrieving revision 1.20 diff -c -r1.20 pg_conversion.c *** src/backend/catalog/pg_conversion.c 31 Dec 2004 21:59:38 -0000 1.20 --- src/backend/catalog/pg_conversion.c 30 Jan 2005 09:51:08 -0000 *************** *** 121,126 **** --- 121,132 ---- referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + /* record shared dependency on owner */ + referenced.classId = get_system_catalog_relid(ShadowRelationName); + referenced.objectId = conowner; + referenced.objectSubId = 0; + recordSharedDependencyOn(&myself, &referenced); + heap_freetuple(tup); heap_close(rel, RowExclusiveLock); Index: src/backend/catalog/pg_operator.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_operator.c,v retrieving revision 1.88 diff -c -r1.88 pg_operator.c *** src/backend/catalog/pg_operator.c 27 Jan 2005 23:23:51 -0000 1.88 --- src/backend/catalog/pg_operator.c 30 Jan 2005 09:51:08 -0000 *************** *** 891,896 **** --- 891,897 ---- /* In case we are updating a shell, delete any existing entries */ deleteDependencyRecordsFor(myself.classId, myself.objectId); + deleteSharedDependencyRecordsFor(myself.classId, myself.objectId); /* Dependency on namespace */ if (OidIsValid(oper->oprnamespace)) *************** *** 964,967 **** --- 965,974 ---- referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } + + /* Dependency on owner */ + referenced.classId = get_system_catalog_relid(ShadowRelationName); + referenced.objectId = oper->oprowner; + referenced.objectSubId = 0; + recordSharedDependencyOn(&myself, &referenced); } Index: src/backend/catalog/pg_proc.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_proc.c,v retrieving revision 1.123 diff -c -r1.123 pg_proc.c *** src/backend/catalog/pg_proc.c 27 Jan 2005 23:23:51 -0000 1.123 --- src/backend/catalog/pg_proc.c 30 Jan 2005 09:51:08 -0000 *************** *** 295,300 **** --- 295,303 ---- recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } + /* dependency on owner */ + recordDependencyOnCurrentUser(&myself); + heap_freetuple(tup); heap_close(rel, RowExclusiveLock); Index: src/backend/catalog/pg_type.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_type.c,v retrieving revision 1.98 diff -c -r1.98 pg_type.c *** src/backend/catalog/pg_type.c 27 Jan 2005 23:23:51 -0000 1.98 --- src/backend/catalog/pg_type.c 30 Jan 2005 09:51:08 -0000 *************** *** 485,490 **** --- 485,493 ---- /* Normal dependency on the default expression. */ if (defaultExpr) recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL); + + /* Shared dependency on owner. */ + recordDependencyOnCurrentUser(&myself); } /* Index: src/backend/catalog/system_views.sql =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/system_views.sql,v retrieving revision 1.11 diff -c -r1.11 system_views.sql *** src/backend/catalog/system_views.sql 1 Jan 2005 20:44:14 -0000 1.11 --- src/backend/catalog/system_views.sql 30 Jan 2005 09:51:08 -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/commands/conversioncmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/conversioncmds.c,v retrieving revision 1.16 diff -c -r1.16 conversioncmds.c *** src/backend/commands/conversioncmds.c 31 Dec 2004 21:59:41 -0000 1.16 --- src/backend/commands/conversioncmds.c 30 Jan 2005 09:51:08 -0000 *************** *** 18,23 **** --- 18,24 ---- #include "access/heapam.h" #include "catalog/catalog.h" #include "catalog/catname.h" + #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_type.h" *************** *** 221,226 **** --- 222,231 ---- simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); + /* Update shared dependency reference */ + shdependChangeOwner(get_system_catalog_relid(ConversionRelationName), + conversionOid, + newOwnerSysId); } heap_close(rel, NoLock); Index: src/backend/commands/dbcommands.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/dbcommands.c,v retrieving revision 1.149 diff -c -r1.149 dbcommands.c *** src/backend/commands/dbcommands.c 27 Jan 2005 23:23:55 -0000 1.149 --- src/backend/commands/dbcommands.c 30 Jan 2005 09:51:08 -0000 *************** *** 23,28 **** --- 23,29 ---- #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/catalog.h" + #include "catalog/dependency.h" #include "catalog/pg_database.h" #include "catalog/pg_shadow.h" #include "catalog/pg_tablespace.h" *************** *** 343,348 **** --- 344,350 ---- /* * Iterate through all tablespaces of the template database, and copy * each one to the new database. + * XXX maybe it could be done better using pg_shdepend info. */ rel = heap_openr(TableSpaceRelationName, AccessShareLock); scan = heap_beginscan(rel, SnapshotNow, 0, NULL); *************** *** 497,502 **** --- 499,526 ---- /* Update indexes */ CatalogUpdateIndexes(pg_database_rel, tuple); + /* Create pg_shdepend entries */ + copyTemplateDependencies(src_dboid, dboid); + /* Register tablespace and owner dependencies */ + { + ObjectAddress myself, + referenced; + + myself.classId = RelOid_pg_database; + myself.objectId = dboid; + myself.objectSubId = 0; + + referenced.classId = RelOid_pg_shadow; + referenced.objectId = datdba; + referenced.objectSubId = 0; + recordSharedDependencyOn(&myself, &referenced); + + referenced.classId = RelOid_pg_tablespace; + referenced.objectId = dst_deftablespace; + referenced.objectSubId = 0; + recordSharedDependencyOn(&myself, &referenced); + } + /* * Force dirty buffers out to disk, so that newly-connecting backends * will see the new database in pg_database right away. (They'll see *************** *** 633,638 **** --- 657,667 ---- remove_dbtablespaces(db_id); /* + * Remove shared dependency references in the database. + */ + dropDatabaseDependencies(db_id); + + /* * Force dirty buffers out to disk, so that newly-connecting backends * will see the database tuple marked dead in pg_database right away. * (They'll see an uncommitted deletion, but they don't care; see *************** *** 917,922 **** --- 946,958 ---- heap_freetuple(newtuple); + /* + * Update shared dependency references + */ + shdependChangeOwner(RelOid_pg_database, + HeapTupleGetOid(tuple), + newOwnerSysId); + /* must release buffer pins before FlushRelationBuffers */ systable_endscan(scan); Index: src/backend/commands/functioncmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/functioncmds.c,v retrieving revision 1.54 diff -c -r1.54 functioncmds.c *** src/backend/commands/functioncmds.c 27 Jan 2005 23:23:55 -0000 1.54 --- src/backend/commands/functioncmds.c 30 Jan 2005 09:51:08 -0000 *************** *** 798,803 **** --- 798,808 ---- simple_heap_update(rel, &newtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); + /* update shared dependency reference */ + shdependChangeOwner(get_system_catalog_relid(ProcedureRelationName), + procOid, + newOwnerSysId); + heap_freetuple(newtuple); } Index: src/backend/commands/opclasscmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/opclasscmds.c,v retrieving revision 1.29 diff -c -r1.29 opclasscmds.c *** src/backend/commands/opclasscmds.c 31 Dec 2004 21:59:41 -0000 1.29 --- src/backend/commands/opclasscmds.c 30 Jan 2005 09:51:08 -0000 *************** *** 392,397 **** --- 392,400 ---- recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } + /* dependency on owner */ + recordDependencyOnCurrentUser(&myself); + heap_close(rel, RowExclusiveLock); } *************** *** 964,969 **** --- 967,977 ---- CatalogUpdateIndexes(rel, tup); } + /* Update shared dependency reference */ + shdependChangeOwner(get_system_catalog_relid(OperatorClassRelationName), + amOid, + newOwnerSysId); + heap_close(rel, NoLock); heap_freetuple(tup); } Index: src/backend/commands/operatorcmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/operatorcmds.c,v retrieving revision 1.20 diff -c -r1.20 operatorcmds.c *** src/backend/commands/operatorcmds.c 31 Dec 2004 21:59:41 -0000 1.20 --- src/backend/commands/operatorcmds.c 30 Jan 2005 09:51:08 -0000 *************** *** 311,316 **** --- 311,323 ---- simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); + + /* + * Update shared dependency references. + */ + shdependChangeOwner(get_system_catalog_relid(OperatorRelationName), + operOid, + newOwnerSysId); } heap_close(rel, NoLock); Index: src/backend/commands/schemacmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/schemacmds.c,v retrieving revision 1.28 diff -c -r1.28 schemacmds.c *** src/backend/commands/schemacmds.c 27 Jan 2005 23:23:55 -0000 1.28 --- src/backend/commands/schemacmds.c 30 Jan 2005 09:51:08 -0000 *************** *** 47,52 **** --- 47,53 ---- AclId owner_userid; AclId saved_userid; AclResult aclresult; + ObjectAddress myself; saved_userid = GetUserId(); *************** *** 147,152 **** --- 148,160 ---- } } + /* Record dependency on owner*/ + myself.classId = get_system_catalog_relid(NamespaceRelationName); + myself.objectId = namespaceId; + myself.objectSubId = 0; + + recordDependencyOnCurrentUser(&myself); + /* Reset search path to normal state */ PopSpecialNamespace(namespaceId); *************** *** 345,350 **** --- 353,365 ---- CatalogUpdateIndexes(rel, newtuple); heap_freetuple(newtuple); + + /* + * Update shared dependency references. + */ + shdependChangeOwner(get_system_catalog_relid(NamespaceRelationName), + HeapTupleGetOid(tup), + newOwnerSysId); } ReleaseSysCache(tup); Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/tablecmds.c,v retrieving revision 1.145 diff -c -r1.145 tablecmds.c *** src/backend/commands/tablecmds.c 27 Jan 2005 23:23:55 -0000 1.145 --- src/backend/commands/tablecmds.c 30 Jan 2005 09:51:08 -0000 *************** *** 5310,5315 **** --- 5310,5320 ---- heap_freetuple(newtuple); /* + * Update shared dependency reference. + */ + shdependChangeOwner(RelOid_pg_class, relationOid, newOwnerSysId); + + /* * If we are operating on a table, also change the ownership of * any indexes and sequences that belong to the table, as well as * the table's toast table (if it has one) *************** *** 5493,5498 **** --- 5498,5506 ---- if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_TABLESPACE, tablespacename); + /* Update shared dependency reference */ + shdependChangeTablespace(RelOid_pg_class, tab->relid, tablespaceId); + /* Save info for Phase 3 to do the real work */ if (OidIsValid(tab->newTableSpace)) ereport(ERROR, Index: src/backend/commands/tablespace.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/tablespace.c,v retrieving revision 1.16 diff -c -r1.16 tablespace.c *** src/backend/commands/tablespace.c 27 Jan 2005 23:23:55 -0000 1.16 --- src/backend/commands/tablespace.c 31 Jan 2005 00:48:00 -0000 *************** *** 51,56 **** --- 51,57 ---- #include "access/heapam.h" #include "catalog/catalog.h" #include "catalog/catname.h" + #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/pg_namespace.h" #include "catalog/pg_tablespace.h" *************** *** 340,345 **** --- 341,360 ---- set_short_version(location); /* + * Record dependency link from tablespace to owner. + * XXX maybe this should be done after the symlink is created? + */ + { + ObjectAddress myself; + + myself.classId = RelOid_pg_tablespace; + myself.objectId = tablespaceoid; + myself.objectSubId = 0; + + recordDependencyOnCurrentUser(&myself); + } + + /* * All seems well, create the symlink */ linkloc = (char *) palloc(strlen(DataDir) + 11 + 10 + 1); *************** *** 398,403 **** --- 413,419 ---- HeapTuple tuple; ScanKeyData entry[1]; Oid tablespaceoid; + char *detail; /* don't call this in a transaction block */ PreventTransactionChain((void *) stmt, "DROP TABLESPACE"); *************** *** 439,444 **** --- 455,473 ---- aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, tablespacename); + /* Lock the tablespace */ + LockSharedObject(tablespaceoid, RelOid_pg_tablespace, AccessExclusiveLock); + + /* Verify pg_shdepend entries mentioning this tablespace. */ + if ((detail = checkSharedDependencies(RelOid_pg_tablespace, tablespaceoid)) != NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("tablespace \"%s\" cannot be dropped because some objects depend on it", tablespacename), + errdetail(detail))); + + /* Remove shared references from this tablespace to its owner */ + deleteSharedDependencyRecordsFor(RelOid_pg_tablespace, tablespaceoid); + /* * Remove the pg_tablespace tuple (this will roll back if we fail * below) *************** *** 865,870 **** --- 894,904 ---- simple_heap_update(rel, &newtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); + /* Update shared dependency reference. */ + shdependChangeOwner(RelOid_pg_tablespace, + HeapTupleGetOid(tup), + newOwnerSysId); + heap_freetuple(newtuple); } Index: src/backend/commands/typecmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/typecmds.c,v retrieving revision 1.67 diff -c -r1.67 typecmds.c *** src/backend/commands/typecmds.c 27 Jan 2005 23:23:56 -0000 1.67 --- src/backend/commands/typecmds.c 30 Jan 2005 09:51:08 -0000 *************** *** 2115,2120 **** --- 2115,2124 ---- simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); + + shdependChangeOwner(get_system_catalog_relid(TypeRelationName), + typeOid, + newOwnerSysId); } /* Clean up */ Index: src/backend/commands/user.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/user.c,v retrieving revision 1.148 diff -c -r1.148 user.c *** src/backend/commands/user.c 27 Jan 2005 23:23:56 -0000 1.148 --- src/backend/commands/user.c 31 Jan 2005 00:47:30 -0000 *************** *** 19,24 **** --- 19,25 ---- #include "access/heapam.h" #include "catalog/catname.h" + #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/pg_database.h" #include "catalog/pg_group.h" *************** *** 1091,1099 **** tmp_tuple; Relation pg_rel; TupleDesc pg_dsc; - ScanKeyData scankey; HeapScanDesc scan; AclId usesysid; tuple = SearchSysCache(SHADOWNAME, PointerGetDatum(user), --- 1092,1100 ---- tmp_tuple; Relation pg_rel; TupleDesc pg_dsc; HeapScanDesc scan; AclId usesysid; + char *detail; tuple = SearchSysCache(SHADOWNAME, PointerGetDatum(user), *************** *** 1115,1156 **** errmsg("session user cannot be dropped"))); /* ! * Check if user still owns a database. If so, error out. ! * ! * (It used to be that this function would drop the database ! * automatically. This is not only very dangerous for people that ! * don't read the manual, it doesn't seem to be the behaviour one ! * would expect either.) -- petere 2000/01/14) ! */ ! pg_rel = heap_openr(DatabaseRelationName, AccessShareLock); ! pg_dsc = RelationGetDescr(pg_rel); ! ScanKeyInit(&scankey, ! Anum_pg_database_datdba, ! BTEqualStrategyNumber, F_INT4EQ, ! Int32GetDatum(usesysid)); ! ! scan = heap_beginscan(pg_rel, SnapshotNow, 1, &scankey); ! ! if ((tmp_tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) ! { ! char *dbname; ! ! dbname = NameStr(((Form_pg_database) GETSTRUCT(tmp_tuple))->datname); ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), ! errmsg("user \"%s\" cannot be dropped", user), ! errdetail("The user owns database \"%s\".", dbname))); ! } ! ! heap_endscan(scan); ! heap_close(pg_rel, AccessShareLock); ! ! /* ! * Somehow we'd have to check for tables, views, etc. owned by the ! * user as well, but those could be spread out over all sorts of ! * databases which we don't have access to (easily). ! */ /* * Remove the user from the pg_shadow table --- 1116,1132 ---- errmsg("session user cannot be dropped"))); /* ! * Lock the user, so nobody can add dependencies to her while we drop ! * her. We keep the lock until the end of transaction. ! */ ! LockSharedObject(usesysid, RelOid_pg_shadow, AccessExclusiveLock); ! /* Verify pg_shdepend entries mentioning this user. */ ! if ((detail = checkSharedDependencies(RelOid_pg_shadow, usesysid)) != NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), ! errmsg("user \"%s\" cannot be dropped because some objects depend on it", user), ! errdetail(detail))); /* * Remove the user from the pg_shadow table *************** *** 1163,1168 **** --- 1139,1146 ---- * Remove user from groups * * try calling alter group drop user for every group + * + * XXX maybe this can be done better using pg_shdepend info */ pg_rel = heap_openr(GroupRelationName, ExclusiveLock); pg_dsc = RelationGetDescr(pg_rel); *************** *** 1747,1752 **** --- 1725,1732 ---- { Relation pg_group_rel; HeapTuple tuple; + Form_pg_group groupForm; + char *detail; /* * Make sure the user can do this. *************** *** 1771,1776 **** --- 1751,1771 ---- (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("group \"%s\" does not exist", stmt->name))); + groupForm = (Form_pg_group) GETSTRUCT(tuple); + + /* + * Lock the group, so nobody can add dependencies to it while we drop + * it. We keep the lock until the end of transaction. + */ + LockSharedObject(groupForm->grosysid, RelOid_pg_group, AccessExclusiveLock); + + /* Verify pg_shdepend entries mentioning this group. */ + if ((detail = checkSharedDependencies(RelOid_pg_group, groupForm->grosysid)) != NULL) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("group \"%s\" cannot be dropped because some objects depend on it", stmt->name), + errdetail(detail))); + simple_heap_delete(pg_group_rel, &tuple->t_self); /* 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 30 Jan 2005 09:51:14 -0000 *************** *** 79,103 **** 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 ! the position) are set to invalid, if it is a page level lock the ! blockId is valid, while the tupleId is still invalid. Finally if ! this is a tuple level lock (we currently never do this) then both ! the blockId and tupleId are set to valid specifications. This is ! how we get the appearance of a multi-level lock table while using ! only a single table (see Gray's paper on 2 phase locking if ! you are puzzled about how multi-level lock tables work). grantMask - This bitmask indicates what types of locks are currently held on the --- 79,114 ---- 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 - ! In a transaction lock, contains the Xid of the locked transaction. ! In a relation lock, uniquely identifies the block/page within the ! relation. If we are setting a table level lock, the blkno is set ! to invalid. ! ! tag.offnum - ! If it is a page level lock, objsubId is set to a valid blkno ! specification, and offnum (which in an item pointer is called the ! position) is invalid. If this is a tuple level lock (we currently ! do this only in userlocks), both objsubId and offnum are set to ! valid specifications. This is how we get the appearance of a ! multi-level lock table while using only a single table (see Gray's ! paper on 2 phase locking if you are puzzled about how multi-level ! lock tables work). grantMask - This bitmask indicates what types of locks are currently held on the Index: src/backend/storage/lmgr/deadlock.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/lmgr/deadlock.c,v retrieving revision 1.32 diff -c -r1.32 deadlock.c *** src/backend/storage/lmgr/deadlock.c 31 Dec 2004 22:01:05 -0000 1.32 --- src/backend/storage/lmgr/deadlock.c 30 Jan 2005 09:51:14 -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.71 diff -c -r1.71 lmgr.c *** src/backend/storage/lmgr/lmgr.c 31 Dec 2004 22:01:05 -0000 1.71 --- src/backend/storage/lmgr/lmgr.c 30 Jan 2005 09:51:14 -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,457 ---- if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid)) TransactionIdAbort(xid); } + + /* + * LockSharedObject + * + * Lock an arbitrary shared (non database-specific) object, such as + * a user or tablespace. + */ + void + LockSharedObject(Oid objId, Oid classId, LOCKMODE lockmode) + { + LOCKTAG tag; + + MemSet(&tag, 0, sizeof(tag)); + tag.objId = objId; + tag.classId = classId; + tag.dbId = InvalidOid; + tag.objsubId.blkno = InvalidBlockNumber; + + /* Only two reasonable lock types */ + Assert(lockmode == AccessShareLock || lockmode == AccessExclusiveLock); + + if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(), + lockmode, false)) + elog(ERROR, "LockSharedObject: LockAcquire failed"); + } + + /* + * UnlockSharedObject + */ + void + UnlockSharedObject(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 = InvalidOid; + tag.objsubId.blkno = InvalidBlockNumber; + + /* Only two reasonable lock types */ + Assert(lockmode == AccessShareLock + || lockmode == AccessExclusiveLock); + + LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode); + } + Index: src/backend/storage/lmgr/lock.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/lmgr/lock.c,v retrieving revision 1.145 diff -c -r1.145 lock.c *** src/backend/storage/lmgr/lock.c 31 Dec 2004 22:01:05 -0000 1.145 --- src/backend/storage/lmgr/lock.c 30 Jan 2005 09:51:14 -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/acl.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/utils/adt/acl.c,v retrieving revision 1.113 diff -c -r1.113 acl.c *** src/backend/utils/adt/acl.c 31 Dec 2004 22:01:21 -0000 1.113 --- src/backend/utils/adt/acl.c 30 Jan 2005 09:51:14 -0000 *************** *** 308,313 **** --- 308,361 ---- } /* + * aclmembers + * Returns all the members of the Acl, in two lists, + * one for users and other for the groups. + */ + void + aclmembers(const Acl *acl, List **users, List **groups) + { + int i; + AclItem *acldat; + + *users = NIL; + *groups = NIL; + + if (acl == NULL) + return; + + acldat = ACL_DAT(acl); + + /* + * Walk the whole ACL searching. We skip "public" items, since they don't + * refer to a particular user or group; for anything else, we first check + * that we haven't added it already to the corresponding list. + */ + for (i = 0; i < ACL_NUM(acl); i++) + { + AclItem ai = acldat[i]; + + switch (ACLITEM_GET_IDTYPE(ai)) + { + case ACL_IDTYPE_WORLD: + break; + case ACL_IDTYPE_UID: + if (!list_member_oid(*users, ai.ai_grantee)) + *users = lappend_oid(*users, ai.ai_grantee); + break; + case ACL_IDTYPE_GID: + if (!list_member_oid(*groups, ai.ai_grantee)) + *groups = lappend_oid(*groups, ai.ai_grantee); + break; + } + + if (!list_member_oid(*users, ai.ai_grantor)) + *users = lappend_oid(*users, ai.ai_grantor); + } + } + + + /* * allocacl * Allocates storage for a new Acl with 'n' entries. * Index: src/backend/utils/adt/lockfuncs.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/utils/adt/lockfuncs.c,v retrieving revision 1.16 diff -c -r1.16 lockfuncs.c *** src/backend/utils/adt/lockfuncs.c 1 Jan 2005 05:43:07 -0000 1.16 --- src/backend/utils/adt/lockfuncs.c 30 Jan 2005 09:51:14 -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/bin/initdb/initdb.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/bin/initdb/initdb.c,v retrieving revision 1.74 diff -c -r1.74 initdb.c *** src/bin/initdb/initdb.c 28 Jan 2005 00:34:32 -0000 1.74 --- src/bin/initdb/initdb.c 30 Jan 2005 09:51:19 -0000 *************** *** 174,179 **** --- 174,180 ---- static void get_set_pwd(void); static void unlimit_systables(void); static void setup_depend(void); + static void setup_shared_depend(void); static void setup_sysviews(void); static void setup_description(void); static void setup_conversion(void); *************** *** 1559,1564 **** --- 1560,1659 ---- check_ok(); } + static void + setup_shared_depend(void) + { + PG_CMD_DECL; + char **line; + static char *pg_shdepend_setup[] = { + /* + * Fill pg_shdepend with info about all existant objects. + * We need to take the ownership and tablespace into consideration. + * + * Note that we first clear the table to rid of dependencies recorded + * by normal operation, because it's incomplete. + */ + "DELETE FROM pg_shdepend\n", + + /* Entries for owners of database-local objects */ + "INSERT INTO pg_shdepend SELECT" + " (SELECT oid FROM pg_database WHERE datname=current_database())," + " 'pg_type'::regclass, oid, 'pg_shadow'::regclass, typowner" + " FROM pg_type t\n", + "INSERT INTO pg_shdepend SELECT" + " (SELECT oid FROM pg_database WHERE datname=current_database())," + " 'pg_proc'::regclass, oid, 'pg_shadow'::regclass, proowner" + " FROM pg_proc t\n", + "INSERT INTO pg_shdepend SELECT" + " (SELECT oid FROM pg_database WHERE datname=current_database())," + " 'pg_class'::regclass, oid, 'pg_shadow'::regclass, relowner" + " FROM pg_class t\n", + "INSERT INTO pg_shdepend SELECT" + " (SELECT oid FROM pg_database WHERE datname=current_database())," + " 'pg_operator'::regclass, oid, 'pg_shadow'::regclass, oprowner" + " FROM pg_operator t\n", + "INSERT INTO pg_shdepend SELECT" + " (SELECT oid FROM pg_database WHERE datname=current_database())," + " 'pg_opclass'::regclass, oid, 'pg_shadow'::regclass, opcowner" + " FROM pg_opclass t\n", + "INSERT INTO pg_shdepend SELECT" + " (SELECT oid FROM pg_database WHERE datname=current_database())," + " 'pg_am'::regclass, oid, 'pg_shadow'::regclass, amowner" + " FROM pg_am t\n", + "INSERT INTO pg_shdepend SELECT" + " (SELECT oid FROM pg_database WHERE datname=current_database())," + " 'pg_namespace'::regclass, oid, 'pg_shadow'::regclass, nspowner" + " FROM pg_namespace t\n", + "INSERT INTO pg_shdepend SELECT" + " (SELECT oid FROM pg_database WHERE datname=current_database())," + " 'pg_conversion'::regclass, oid, 'pg_shadow'::regclass, conowner" + " FROM pg_conversion t\n", + + /* Entries for tablespaces of database-local objects */ + "INSERT INTO pg_shdepend SELECT" + " (SELECT oid FROM pg_database WHERE datname=current_database())," + " 'pg_class'::regclass, oid, 'pg_tablespace'::regclass, reltablespace" + " FROM pg_class t" + " WHERE reltablespace <> 0\n", + + /* Entries for owners of shared objects */ + "INSERT INTO pg_shdepend SELECT" + " 0," + " 'pg_tablespace'::regclass, oid, 'pg_shadow'::regclass, spcowner" + " FROM pg_tablespace t\n", + "INSERT INTO pg_shdepend SELECT" + " 0," + " 'pg_database'::regclass, oid, 'pg_shadow'::regclass, datdba" + " FROM pg_database t\n", + /* Entries for tablespaces of shared objects */ + "INSERT INTO pg_shdepend SELECT" + " 0," + " 'pg_database'::regclass, oid, 'pg_tablespace'::regclass, dattablespace" + " FROM pg_database t" + " WHERE dattablespace <> 0\n", + NULL + }; + + + fputs(_("initializing pg_shdepend ... "), stdout); + fflush(stdout); + + snprintf(cmd, sizeof(cmd), + "\"%s\" %s template1 >%s", + backend_exec, backend_options, + DEVNULL); + + PG_CMD_OPEN; + + for (line = pg_shdepend_setup; *line != NULL; line++) + PG_CMD_PUTS(*line); + + PG_CMD_CLOSE; + + check_ok(); + } + + /* * set up system views */ *************** *** 2595,2600 **** --- 2690,2697 ---- setup_depend(); + setup_shared_depend(); + setup_sysviews(); setup_description(); Index: src/include/catalog/catname.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/catname.h,v retrieving revision 1.34 diff -c -r1.34 catname.h *** src/include/catalog/catname.h 31 Dec 2004 22:03:24 -0000 1.34 --- src/include/catalog/catname.h 30 Jan 2005 09:51:23 -0000 *************** *** 25,30 **** --- 25,31 ---- #define ConversionRelationName "pg_conversion" #define DatabaseRelationName "pg_database" #define DependRelationName "pg_depend" + #define SharedDependRelationName "pg_shdepend" #define DescriptionRelationName "pg_description" #define GroupRelationName "pg_group" #define IndexRelationName "pg_index" Index: src/include/catalog/dependency.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/dependency.h,v retrieving revision 1.14 diff -c -r1.14 dependency.h *** src/include/catalog/dependency.h 31 Dec 2004 22:03:24 -0000 1.14 --- src/include/catalog/dependency.h 30 Jan 2005 21:11:03 -0000 *************** *** 81,90 **** /* ! * This enum covers all system catalogs whose OIDs can appear in classId. */ typedef enum ObjectClass { OCLASS_CLASS, /* pg_class */ OCLASS_PROC, /* pg_proc */ OCLASS_TYPE, /* pg_type */ --- 81,92 ---- /* ! * This enum covers all system catalogs whose OIDs can appear in ! * pg_depend.classId or pg_shdepend.classId. */ typedef enum ObjectClass { + OCLASS_AM, /* pg_am */ OCLASS_CLASS, /* pg_class */ OCLASS_PROC, /* pg_proc */ OCLASS_TYPE, /* pg_type */ *************** *** 98,103 **** --- 100,109 ---- OCLASS_REWRITE, /* pg_rewrite */ OCLASS_TRIGGER, /* pg_trigger */ OCLASS_SCHEMA, /* pg_namespace */ + /* shared system catalogs: */ + OCLASS_TBLSPACE, /* pg_tablespace */ + OCLASS_DATABASE, /* pg_database */ + OCLASS_SHADOW, /* pg_shadow */ MAX_OCLASS /* MUST BE LAST */ } ObjectClass; *************** *** 136,139 **** --- 142,172 ---- extern long deleteDependencyRecordsFor(Oid classId, Oid objectId); + /* in pg_shdepend.c */ + + extern void recordSharedDependencyOn(const ObjectAddress *depender, + const ObjectAddress *referenced); + + extern void recordDependencyOnCurrentUser(const ObjectAddress *depender); + + extern void shdependChangeOwner(Oid classId, Oid objectId, + int newOwnerSysId); + + extern void shdependChangeTablespace(Oid classId, Oid objectId, + Oid newTblspc); + + extern void shdependUpdateAclInfo(Oid classId, Oid objectId, AclId ownerId, bool isGrant, + List *oldusers, List *newusers, + List *oldgroups, List *newgroups); + + extern char *checkSharedDependencies(Oid classId, Oid objectId); + + extern void copyTemplateDependencies(Oid templateDbId, Oid newDbId); + + extern void dropDatabaseDependencies(Oid databaseId); + + extern void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId); + + extern void deleteGlobalDependencyRecordsFor(Oid classId, Oid objectId); + #endif /* DEPENDENCY_H */ Index: src/include/catalog/indexing.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/indexing.h,v retrieving revision 1.84 diff -c -r1.84 indexing.h *** src/include/catalog/indexing.h 31 Dec 2004 22:03:24 -0000 1.84 --- src/include/catalog/indexing.h 30 Jan 2005 09:51:23 -0000 *************** *** 67,72 **** --- 67,74 ---- #define ProcedureOidIndex "pg_proc_oid_index" #define RewriteOidIndex "pg_rewrite_oid_index" #define RewriteRelRulenameIndex "pg_rewrite_rel_rulename_index" + #define SharedDependDependerIndex "pg_shdepend_depender_index" + #define SharedDependReferenceIndex "pg_shdepend_reference_index" #define ShadowNameIndex "pg_shadow_usename_index" #define ShadowSysidIndex "pg_shadow_usesysid_index" #define StatisticRelidAttnumIndex "pg_statistic_relid_att_index" *************** *** 165,170 **** --- 167,176 ---- /* This following index is not used for a cache and is not unique */ DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index on pg_rewrite using btree(oid oid_ops)); DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index on pg_rewrite using btree(ev_class oid_ops, rulename name_ops)); + /* This following index is not used for a cache and is not unique */ + DECLARE_INDEX(pg_shdepend_depender_index on pg_shdepend using btree(dbid oid_ops, classid oid_ops, objid oid_ops)); + /* This following index is not used for a cache and is not unique */ + DECLARE_INDEX(pg_shdepend_reference_index on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops)); DECLARE_UNIQUE_INDEX(pg_shadow_usename_index on pg_shadow using btree(usename name_ops)); DECLARE_UNIQUE_INDEX(pg_shadow_usesysid_index on pg_shadow using btree(usesysid int4_ops)); DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_index on pg_statistic using btree(starelid oid_ops, staattnum int2_ops)); Index: src/include/storage/lmgr.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/storage/lmgr.h,v retrieving revision 1.45 diff -c -r1.45 lmgr.h *** src/include/storage/lmgr.h 31 Dec 2004 22:03:42 -0000 1.45 --- src/include/storage/lmgr.h 30 Jan 2005 09:51:24 -0000 *************** *** 61,64 **** --- 61,68 ---- extern void XactLockTableDelete(TransactionId xid); extern void XactLockTableWait(TransactionId xid); + /* Lock an arbitrary shared object */ + extern void LockSharedObject(Oid objId, Oid classId, LOCKMODE lockmode); + extern void UnlockSharedObject(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.84 diff -c -r1.84 lock.h *** src/include/storage/lock.h 31 Dec 2004 22:03:42 -0000 1.84 --- src/include/storage/lock.h 30 Jan 2005 09:51:24 -0000 *************** *** 106,121 **** */ 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 * increase sizeof(LOCKTAG) due to padding. Currently used by * userlocks only. */ --- 106,122 ---- */ typedef struct LOCKTAG { ! Oid objId; ! Oid classId; Oid dbId; union { BlockNumber blkno; TransactionId xid; ! } objsubId; /* ! * offnum should be part of objsubId union above, but doing that would * increase sizeof(LOCKTAG) due to padding. Currently used by * userlocks only. */ Index: src/include/utils/acl.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/utils/acl.h,v retrieving revision 1.77 diff -c -r1.77 acl.h *** src/include/utils/acl.h 27 Jan 2005 23:36:14 -0000 1.77 --- src/include/utils/acl.h 30 Jan 2005 09:51:24 -0000 *************** *** 228,233 **** --- 228,234 ---- extern AclMode aclmask(const Acl *acl, AclId userid, AclId ownerid, AclMode mask, AclMaskHow how); + extern void aclmembers(const Acl *acl, List **users, List **groups); /* * SQL functions (from acl.c) Index: src/test/regress/parallel_schedule =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/test/regress/parallel_schedule,v retrieving revision 1.27 diff -c -r1.27 parallel_schedule *** src/test/regress/parallel_schedule 18 Jun 2004 06:14:25 -0000 1.27 --- src/test/regress/parallel_schedule 31 Jan 2005 00:50:25 -0000 *************** *** 68,74 **** # ---------- # The fifth group of parallel test # ---------- ! test: select_views portals_p2 rules foreign_key cluster # ---------- # The sixth group of parallel test --- 68,74 ---- # ---------- # The fifth group of parallel test # ---------- ! test: select_views portals_p2 rules foreign_key cluster dependency # ---------- # The sixth group of parallel test Index: src/test/regress/serial_schedule =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/test/regress/serial_schedule,v retrieving revision 1.26 diff -c -r1.26 serial_schedule *** src/test/regress/serial_schedule 18 Jun 2004 06:14:25 -0000 1.26 --- src/test/regress/serial_schedule 31 Jan 2005 00:49:02 -0000 *************** *** 97,99 **** --- 97,100 ---- test: rowtypes test: stats test: tablespace + test: dependency Index: src/test/regress/expected/cluster.out =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/cluster.out,v retrieving revision 1.16 diff -c -r1.16 cluster.out *** src/test/regress/expected/cluster.out 10 Jun 2004 17:56:01 -0000 1.16 --- src/test/regress/expected/cluster.out 31 Jan 2005 01:23:06 -0000 *************** *** 385,389 **** --- 385,390 ---- -- clean up \c - DROP TABLE clstr_1; + DROP TABLE clstr_2; DROP TABLE clstr_3; DROP USER clstr_user; Index: src/test/regress/expected/privileges.out =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/privileges.out,v retrieving revision 1.28 diff -c -r1.28 privileges.out *** src/test/regress/expected/privileges.out 29 Aug 2004 03:14:07 -0000 1.28 --- src/test/regress/expected/privileges.out 31 Jan 2005 01:23:02 -0000 *************** *** 601,606 **** --- 601,607 ---- DROP TABLE atest4; DROP GROUP regressgroup1; DROP GROUP regressgroup2; + REVOKE USAGE ON LANGUAGE sql FROM regressuser1; DROP USER regressuser1; DROP USER regressuser2; DROP USER regressuser3; 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 30 Jan 2005 09:51:30 -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)); Index: src/test/regress/expected/sanity_check.out =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/sanity_check.out,v retrieving revision 1.24 diff -c -r1.24 sanity_check.out *** src/test/regress/expected/sanity_check.out 18 Jun 2004 06:14:27 -0000 1.24 --- src/test/regress/expected/sanity_check.out 30 Jan 2005 09:51:30 -0000 *************** *** 55,60 **** --- 55,61 ---- pg_proc | t pg_rewrite | t pg_shadow | t + pg_shdepend | t pg_statistic | t pg_tablespace | t pg_trigger | t *************** *** 63,69 **** shighway | t tenk1 | t tenk2 | t ! (53 rows) -- -- another sanity check: every system catalog that has OIDs should have --- 64,70 ---- shighway | t tenk1 | t tenk2 | t ! (54 rows) -- -- another sanity check: every system catalog that has OIDs should have Index: src/test/regress/sql/cluster.sql =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/test/regress/sql/cluster.sql,v retrieving revision 1.8 diff -c -r1.8 cluster.sql *** src/test/regress/sql/cluster.sql 2 Jun 2004 21:01:10 -0000 1.8 --- src/test/regress/sql/cluster.sql 31 Jan 2005 00:59:44 -0000 *************** *** 156,160 **** --- 156,161 ---- -- clean up \c - DROP TABLE clstr_1; + DROP TABLE clstr_2; DROP TABLE clstr_3; DROP USER clstr_user; Index: src/test/regress/sql/privileges.sql =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/test/regress/sql/privileges.sql,v retrieving revision 1.13 diff -c -r1.13 privileges.sql *** src/test/regress/sql/privileges.sql 2 May 2004 13:38:28 -0000 1.13 --- src/test/regress/sql/privileges.sql 31 Jan 2005 01:01:22 -0000 *************** *** 339,344 **** --- 339,345 ---- DROP GROUP regressgroup1; DROP GROUP regressgroup2; + REVOKE USAGE ON LANGUAGE sql FROM regressuser1; DROP USER regressuser1; DROP USER regressuser2; DROP USER regressuser3;