📄 pg_shdepend.c
字号:
sdepForm->deptype, 0); } else if (sdepForm->dbid == InvalidOid) { numSharedDeps++; if (++totalDeps <= MAX_REPORTED_DEPS) storeObjectDescription(&descs, SHARED_OBJECT, &object, sdepForm->deptype, 0); } else { /* It's not local nor shared, so it must be remote. */ remoteDep *dep; bool stored = false; /* * XXX this info is kept on a simple List. Maybe it's not good * for performance, but using a hash table seems needlessly * complex. The expected number of databases is not high anyway, * I suppose. */ foreach(cell, remDeps) { dep = lfirst(cell); if (dep->dbOid == sdepForm->dbid) { dep->count++; stored = true; break; } } if (!stored) { dep = (remoteDep *) palloc(sizeof(remoteDep)); dep->dbOid = sdepForm->dbid; dep->count = 1; remDeps = lappend(remDeps, dep); totalDeps++; } } } systable_endscan(scan); heap_close(sdepRel, AccessShareLock); if (totalDeps > MAX_REPORTED_DEPS) { /* * Report seems unreasonably long, so reduce it to per-database info * * Note: we don't ever suppress per-database totals, which should be * OK as long as there aren't too many databases ... */ descs.len = 0; /* reset to empty */ descs.data[0] = '\0'; if (numLocalDeps > 0) { appendStringInfo(&descs, _("%d objects in this database"), numLocalDeps); if (numSharedDeps > 0) appendStringInfoChar(&descs, '\n'); } if (numSharedDeps > 0) appendStringInfo(&descs, _("%d shared objects"), numSharedDeps); } foreach(cell, remDeps) { remoteDep *dep = lfirst(cell); object.classId = DatabaseRelationId; object.objectId = dep->dbOid; object.objectSubId = 0; storeObjectDescription(&descs, REMOTE_OBJECT, &object, SHARED_DEPENDENCY_INVALID, dep->count); } list_free_deep(remDeps); if (descs.len == 0) { pfree(descs.data); return NULL; } return descs.data;}/* * copyTemplateDependencies * * Routine to create the initial shared dependencies of a new database. * We simply copy the dependencies from the template database. */voidcopyTemplateDependencies(Oid templateDbId, Oid newDbId){ Relation sdepRel; TupleDesc sdepDesc; ScanKeyData key[1]; SysScanDesc scan; HeapTuple tup; CatalogIndexState indstate; Datum values[Natts_pg_shdepend]; bool nulls[Natts_pg_shdepend]; bool replace[Natts_pg_shdepend]; sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); sdepDesc = RelationGetDescr(sdepRel); indstate = CatalogOpenIndexes(sdepRel); /* Scan all entries with dbid = templateDbId */ ScanKeyInit(&key[0], Anum_pg_shdepend_dbid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(templateDbId)); scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, SnapshotNow, 1, key); /* Set up to copy the tuples except for inserting newDbId */ memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); memset(replace, false, sizeof(replace)); replace[Anum_pg_shdepend_dbid - 1] = true; values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId); /* * Copy the entries of the original database, changing the database Id to * that of the new database. Note that because we are not copying rows * with dbId == 0 (ie, rows describing dependent shared objects) we won't * copy the ownership dependency of the template database itself; this is * what we want. */ while (HeapTupleIsValid(tup = systable_getnext(scan))) { HeapTuple newtup; newtup = heap_modify_tuple(tup, sdepDesc, values, nulls, replace); simple_heap_insert(sdepRel, newtup); /* Keep indexes current */ CatalogIndexInsert(indstate, newtup); heap_freetuple(newtup); } systable_endscan(scan); CatalogCloseIndexes(indstate); heap_close(sdepRel, RowExclusiveLock);}/* * dropDatabaseDependencies * * Delete pg_shdepend entries corresponding to a database that's being * dropped. */voiddropDatabaseDependencies(Oid databaseId){ Relation sdepRel; ScanKeyData key[1]; SysScanDesc scan; HeapTuple tup; sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); /* * First, delete all the entries that have the database Oid in the dbid * field. */ ScanKeyInit(&key[0], Anum_pg_shdepend_dbid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(databaseId)); /* We leave the other index fields unspecified */ scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, SnapshotNow, 1, key); while (HeapTupleIsValid(tup = systable_getnext(scan))) { simple_heap_delete(sdepRel, &tup->t_self); } systable_endscan(scan); /* Now delete all entries corresponding to the database itself */ shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, InvalidOid, InvalidOid, SHARED_DEPENDENCY_INVALID); heap_close(sdepRel, RowExclusiveLock);}/* * deleteSharedDependencyRecordsFor * * Delete all pg_shdepend entries corresponding to an object that's being * dropped or modified. The object is assumed to be either a shared object * or local to the current database (the classId tells us which). */voiddeleteSharedDependencyRecordsFor(Oid classId, Oid objectId){ Relation sdepRel; sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock); shdepDropDependency(sdepRel, classId, objectId, InvalidOid, InvalidOid, SHARED_DEPENDENCY_INVALID); heap_close(sdepRel, RowExclusiveLock);}/* * shdepAddDependency * Internal workhorse for inserting into pg_shdepend * * sdepRel must be the pg_shdepend relation, already opened and suitably * locked. */static voidshdepAddDependency(Relation sdepRel, Oid classId, Oid objectId, Oid refclassId, Oid refobjId, SharedDependencyType deptype){ HeapTuple tup; Datum values[Natts_pg_shdepend]; bool nulls[Natts_pg_shdepend]; /* * Make sure the object doesn't go away while we record the dependency on * it. DROP routines should lock the object exclusively before they check * shared dependencies. */ shdepLockAndCheckObject(refclassId, refobjId); memset(nulls, false, sizeof(nulls)); /* * Form the new tuple and record the dependency. */ values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId)); values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId); values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId); values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId); values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId); values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype); tup = heap_form_tuple(sdepRel->rd_att, values, nulls); simple_heap_insert(sdepRel, tup); /* keep indexes current */ CatalogUpdateIndexes(sdepRel, tup); /* clean up */ heap_freetuple(tup);}/* * shdepDropDependency * Internal workhorse for deleting entries from pg_shdepend. * * We drop entries having the following properties: * dependent object is the one identified by classId/objectId * if refclassId isn't InvalidOid, it must match the entry's refclassid * if refobjId isn't InvalidOid, it must match the entry's refobjid * if deptype isn't SHARED_DEPENDENCY_INVALID, it must match entry's deptype * * sdepRel must be the pg_shdepend relation, already opened and suitably * locked. */static voidshdepDropDependency(Relation sdepRel, Oid classId, Oid objectId, Oid refclassId, Oid refobjId, SharedDependencyType deptype){ ScanKeyData key[3]; SysScanDesc scan; HeapTuple tup; /* Scan for entries matching the dependent object */ ScanKeyInit(&key[0], Anum_pg_shdepend_dbid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classIdGetDbId(classId))); ScanKeyInit(&key[1], Anum_pg_shdepend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId)); ScanKeyInit(&key[2], Anum_pg_shdepend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId)); scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true, SnapshotNow, 3, key); while (HeapTupleIsValid(tup = systable_getnext(scan))) { Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup); /* Filter entries according to additional parameters */ if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId) continue; if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId) continue; if (deptype != SHARED_DEPENDENCY_INVALID && shdepForm->deptype != deptype) continue; /* OK, delete it */ simple_heap_delete(sdepRel, &tup->t_self); } systable_endscan(scan);}/* * classIdGetDbId * * Get the database Id that should be used in pg_shdepend, given the OID * of the catalog containing the object. For shared objects, it's 0 * (InvalidOid); for all other objects, it's the current database Id. * * XXX it's awfully tempting to hard-wire this instead of doing a syscache * lookup ... but resist the temptation, unless you can prove it's a * bottleneck. */static OidclassIdGetDbId(Oid classId){ Oid dbId; HeapTuple tup; tup = SearchSysCache(RELOID, ObjectIdGetDatum(classId), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for relation %u", classId); if (((Form_pg_class) GETSTRUCT(tup))->relisshared) dbId = InvalidOid; else dbId = MyDatabaseId; ReleaseSysCache(tup); return dbId;}/* * shdepLockAndCheckObject * * Lock the object that we are about to record a dependency on. * After it's locked, verify that it hasn't been dropped while we * weren't looking. If the object has been dropped, this function * does not return! */static voidshdepLockAndCheckObject(Oid classId, Oid objectId){ /* AccessShareLock should be OK, since we are not modifying the object */ LockSharedObject(classId, objectId, 0, AccessShareLock); /* * We have to recognize sinval updates here, else our local syscache may * still contain the object even if it was just dropped. */ AcceptInvalidationMessages(); switch (classId) { case AuthIdRelationId: if (!SearchSysCacheExists(AUTHOID, ObjectIdGetDatum(objectId), 0, 0, 0)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role %u was concurrently dropped", objectId))); break; /* * Currently, this routine need not support any other shared * object types besides roles. If we wanted to record explicit * dependencies on databases or tablespaces, we'd need code along * these lines: */#ifdef NOT_USED case TableSpaceRelationId: { /* For lack of a syscache on pg_tablespace, do this: */ char *tablespace = get_tablespace_name(objectId); if (tablespace == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace %u was concurrently dropped", objectId))); pfree(tablespace); break; }#endif default: elog(ERROR, "unrecognized shared classId: %u", classId); }}/* * storeObjectDescription * Append the description of a dependent object to "descs" * * While searching for dependencies of a shared object, we stash the * descriptions of dependent objects we find in a single string, which we * later pass to ereport() in the DETAIL field when somebody attempts to * drop a referenced shared object. * * When type is LOCAL_OBJECT or SHARED_OBJECT, we expect object to be the * dependent object, deptype is the dependency type, and count is not used. * When type is REMOTE_OBJECT, we expect object to be the database object, * and count to be nonzero; deptype is not used in this case. */static voidstoreObjectDescription(StringInfo descs, objectType type, ObjectAddress *object, SharedDependencyType deptype, int count){ char *objdesc = getObjectDescription(object); /* separate entries with a newline */ if (descs->len != 0) appendStringInfoChar(descs, '\n'); switch (type) { case LOCAL_OBJECT: case SHARED_OBJECT: if (deptype == SHARED_DEPENDENCY_OWNER) appendStringInfo(descs, _("owner of %s"), objdesc); else if (deptype == SHARED_DEPENDENCY_ACL) appendStringInfo(descs, _("access to %s"), objdesc); else elog(ERROR, "unrecognized dependency type: %d", (int) deptype); break; case REMOTE_OBJECT: /* translator: %s will always be "database %s" */ appendStringInfo(descs, _("%d objects in %s"), count, objdesc); break; default: elog(ERROR, "unrecognized object type: %d", type); } pfree(objdesc);}/* * isSharedObjectPinned * Return whether a given shared object has a SHARED_DEPENDENCY_PIN entry. * * sdepRel must be the pg_shdepend relation, already opened and suitably * locked. */static boolisSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel){ bool result = false; ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; ScanKeyInit(&key[0], Anum_pg_shdepend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId)); ScanKeyInit(&key[1], Anum_pg_shdepend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId)); scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true, SnapshotNow, 2, key); /* * Since we won't generate additional pg_shdepend 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_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup); if (shdepForm->deptype == SHARED_DEPENDENCY_PIN) result = true; } systable_endscan(scan); return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -