/*------------------------------------------------------------------------- * * pg_depend.c * routines to support manipulation of the pg_depend relation * * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/catalog/pg_depend.c,v 1.5 2002/08/11 21:17:34 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/genam.h" #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/indexing.h" #include "catalog/dependency.h" #include "catalog/pg_depend.h" #include "miscadmin.h" #include "utils/fmgroids.h" static bool isObjectPinned(const ObjectAddress *object, Relation rel); /* * Record a dependency between 2 objects via their respective objectAddress. * The first argument is the dependent object, the second the one it * references. * * This simply creates an entry in pg_depend, without any other processing. */ void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior) { recordMultipleDependencies(depender, referenced, 1, behavior); } /* * Record multiple dependencies (of the same kind) for a single dependent * object. This has a little less overhead than recording each separately. */ void recordMultipleDependencies(const ObjectAddress *depender, const ObjectAddress *referenced, int nreferenced, DependencyType behavior) { Relation dependDesc; CatalogIndexState indstate; HeapTuple tup; int i; char nulls[Natts_pg_depend]; Datum values[Natts_pg_depend]; if (nreferenced <= 0) return; /* nothing to do */ /* * During bootstrap, do nothing since pg_depend may not exist yet. * initdb will fill in appropriate pg_depend entries after bootstrap. */ if (IsBootstrapProcessingMode()) return; dependDesc = heap_openr(DependRelationName, RowExclusiveLock); /* Don't open indexes unless we need to make an update */ indstate = NULL; memset(nulls, ' ', sizeof(nulls)); for (i = 0; i < nreferenced; i++, referenced++) { /* * If the referenced object is pinned by the system, there's no real * need to record dependencies on it. This saves lots of space in * pg_depend, so it's worth the time taken to check. */ if (!isObjectPinned(referenced, dependDesc)) { /* * Record the Dependency. Note we don't bother to check for * duplicate dependencies; there's no harm in them. */ values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId); values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId); values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId); values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId); values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId); values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId); values[Anum_pg_depend_deptype -1] = CharGetDatum((char) behavior); tup = heap_formtuple(dependDesc->rd_att, values, nulls); simple_heap_insert(dependDesc, tup); /* keep indexes current */ if (indstate == NULL) indstate = CatalogOpenIndexes(dependDesc); CatalogIndexInsert(indstate, tup); heap_freetuple(tup); } } if (indstate != NULL) CatalogCloseIndexes(indstate); heap_close(dependDesc, RowExclusiveLock); } /* * deleteDependencyRecordsFor -- delete all records with given depender * classId/objectId. Returns the number of records deleted. * * This is used when redefining an existing object. Links leading to the * object do not change, and links leading from it will be recreated * (possibly with some differences from before). */ long deleteDependencyRecordsFor(Oid classId, Oid objectId) { long count = 0; Relation depRel; ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; depRel = heap_openr(DependRelationName, RowExclusiveLock); ScanKeyEntryInitialize(&key[0], 0x0, Anum_pg_depend_classid, F_OIDEQ, ObjectIdGetDatum(classId)); ScanKeyEntryInitialize(&key[1], 0x0, Anum_pg_depend_objid, F_OIDEQ, ObjectIdGetDatum(objectId)); scan = systable_beginscan(depRel, DependDependerIndex, true, SnapshotNow, 2, key); while (HeapTupleIsValid(tup = systable_getnext(scan))) { simple_heap_delete(depRel, &tup->t_self); count++; } systable_endscan(scan); heap_close(depRel, RowExclusiveLock); return count; } /* * isObjectPinned() * * Test if an object is required for basic database functionality. * Caller must already have opened pg_depend. * * The passed subId, if any, is ignored; we assume that only whole objects * are pinned (and that this implies pinning their components). */ static bool isObjectPinned(const ObjectAddress *object, Relation rel) { bool ret = false; SysScanDesc scan; HeapTuple tup; ScanKeyData key[2]; ScanKeyEntryInitialize(&key[0], 0x0, Anum_pg_depend_refclassid, F_OIDEQ, ObjectIdGetDatum(object->classId)); ScanKeyEntryInitialize(&key[1], 0x0, Anum_pg_depend_refobjid, F_OIDEQ, ObjectIdGetDatum(object->objectId)); scan = systable_beginscan(rel, DependReferenceIndex, true, SnapshotNow, 2, key); /* * Since we won't generate additional pg_depend entries for pinned * objects, there can be at most one entry referencing a pinned * object. Hence, it's sufficient to look at the first returned * tuple; we don't need to loop. */ tup = systable_getnext(scan); if (HeapTupleIsValid(tup)) { Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup); if (foundDep->deptype == DEPENDENCY_PIN) ret = true; } systable_endscan(scan); return ret; }