Esempio n. 1
0
	/*
	 * Report dependencies on remote databases.  If we're truncating the
	 * output already, don't put a line per database, but a single one for all
	 * of them.  Otherwise add as many as fit in MAX_REPORTED_DEPS.
	 */
	foreach(cell, remDeps)
	{
		remoteDep  *dep = lfirst(cell);

		object.classId = DatabaseRelationId;
		object.objectId = dep->dbOid;
		object.objectSubId = 0;

		if (numReportedDeps < MAX_REPORTED_DEPS)
		{
			numReportedDeps++;
			storeObjectDescription(&descs, REMOTE_OBJECT, &object,
								   SHARED_DEPENDENCY_INVALID, dep->count);
		}
		else
		{
			numNotReportedDbs++;
			/* initialize the server-only log line */
			if (alldescs.len == 0)
				appendBinaryStringInfo(&alldescs, descs.data, descs.len);

			storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
								   SHARED_DEPENDENCY_INVALID, dep->count);
		}
	}
Esempio n. 2
0
	/*
	 * Summarize dependencies in remote databases.
	 */
	foreach(cell, remDeps)
	{
		remoteDep  *dep = lfirst(cell);

		object.classId = DatabaseRelationId;
		object.objectId = dep->dbOid;
		object.objectSubId = 0;

		if (numReportedDeps < MAX_REPORTED_DEPS)
		{
			numReportedDeps++;
			storeObjectDescription(&descs, REMOTE_OBJECT, &object,
								   SHARED_DEPENDENCY_INVALID, dep->count);
		}
		else
			numNotReportedDbs++;
		storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
							   SHARED_DEPENDENCY_INVALID, dep->count);
	}
Esempio n. 3
0
/*
 * checkSharedDependencies
 *
 * Check whether there are shared dependency entries for a given shared
 * object; return true if so.
 *
 * In addition, return a string containing a newline-separated list of object
 * descriptions that depend on the shared object, or NULL if none is found.
 * We actually return two such strings; the "detail" result is suitable for
 * returning to the client as an errdetail() string, and is limited in size.
 * The "detail_log" string is potentially much longer, and should be emitted
 * to the server log only.
 *
 * We can find three different kinds of dependencies: dependencies on objects
 * of the current database; dependencies on shared objects; and dependencies
 * on objects local to other databases.  We can (and do) provide descriptions
 * of the two former kinds of objects, but we can't do that for "remote"
 * objects, so we just provide a count of them.
 *
 * If we find a SHARED_DEPENDENCY_PIN entry, we can error out early.
 */
bool
checkSharedDependencies(Oid classId, Oid objectId,
						char **detail_msg, char **detail_log_msg)
{
	Relation	sdepRel;
	ScanKeyData key[2];
	SysScanDesc scan;
	HeapTuple	tup;
	int			numReportedDeps = 0;
	int			numNotReportedDeps = 0;
	int			numNotReportedDbs = 0;
	List	   *remDeps = NIL;
	ListCell   *cell;
	ObjectAddress object;
	StringInfoData descs;
	StringInfoData alldescs;

	/*
	 * We limit the number of dependencies reported to the client to
	 * MAX_REPORTED_DEPS, since client software may not deal well with
	 * enormous error strings.  The server log always gets a full report.
	 */
#define MAX_REPORTED_DEPS 100

	initStringInfo(&descs);
	initStringInfo(&alldescs);

	sdepRel = heap_open(SharedDependRelationId, AccessShareLock);

	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,
							  NULL, 2, key);

	while (HeapTupleIsValid(tup = systable_getnext(scan)))
	{
		Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);

		/* This case can be dispatched quickly */
		if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
		{
			object.classId = classId;
			object.objectId = objectId;
			object.objectSubId = 0;
			ereport(ERROR,
					(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
					 errmsg("cannot drop %s because it is required by the database system",
							getObjectDescription(&object))));
		}

		object.classId = sdepForm->classid;
		object.objectId = sdepForm->objid;
		object.objectSubId = sdepForm->objsubid;

		/*
		 * If it's a dependency local to this database or it's a shared
		 * object, describe it.
		 *
		 * If it's a remote dependency, keep track of it so we can report the
		 * number of them later.
		 */
		if (sdepForm->dbid == MyDatabaseId)
		{
			if (numReportedDeps < MAX_REPORTED_DEPS)
			{
				numReportedDeps++;
				storeObjectDescription(&descs, LOCAL_OBJECT, &object,
									   sdepForm->deptype, 0);
			}
			else
				numNotReportedDeps++;
			storeObjectDescription(&alldescs, LOCAL_OBJECT, &object,
								   sdepForm->deptype, 0);
		}
		else if (sdepForm->dbid == InvalidOid)
		{
			if (numReportedDeps < MAX_REPORTED_DEPS)
			{
				numReportedDeps++;
				storeObjectDescription(&descs, SHARED_OBJECT, &object,
									   sdepForm->deptype, 0);
			}
			else
				numNotReportedDeps++;
			storeObjectDescription(&alldescs, 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);
			}
		}
	}