Commit 689dea42 authored by Alvaro Herrera's avatar Alvaro Herrera

Report all dependent objects to the server log when a shared object is dropped,

and only a truncated log of the objects in the current database to the client.
Also, instead of reporting object counts for all databases on which the user
might own objects, report only as many as fit in the predefined line count.

This is to avoid flooding the client when the user owns too many objects,
which could cause problems.

Per report from Ed L. on April 4th and subsequent discussion.
parent ed9a31b8
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.18 2007/05/11 17:57:12 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.19 2007/05/14 16:50:36 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -456,6 +456,9 @@ typedef struct ...@@ -456,6 +456,9 @@ typedef struct
* Check whether there are shared dependency entries for a given shared * Check whether there are shared dependency entries for a given shared
* object. Returns a string containing a newline-separated list of object * object. Returns a string containing a newline-separated list of object
* descriptions that depend on the shared object, or NULL if none is found. * descriptions that depend on the shared object, or NULL if none is found.
* The size of the returned string is limited to about MAX_REPORTED_DEPS lines;
* if there are more objects than that, the output is returned truncated at
* that point and the full message is logged to the postmaster log.
* *
* We can find three different kinds of dependencies: dependencies on objects * We can find three different kinds of dependencies: dependencies on objects
* of the current database; dependencies on shared objects; and dependencies * of the current database; dependencies on shared objects; and dependencies
...@@ -472,21 +475,26 @@ checkSharedDependencies(Oid classId, Oid objectId) ...@@ -472,21 +475,26 @@ checkSharedDependencies(Oid classId, Oid objectId)
ScanKeyData key[2]; ScanKeyData key[2];
SysScanDesc scan; SysScanDesc scan;
HeapTuple tup; HeapTuple tup;
int totalDeps = 0; int numNotReportedDeps = 0;
int numLocalDeps = 0; int numReportedDeps = 0;
int numSharedDeps = 0; int numNotReportedDbs = 0;
List *remDeps = NIL; List *remDeps = NIL;
ListCell *cell; ListCell *cell;
ObjectAddress object; ObjectAddress object;
StringInfoData descs; StringInfoData descs;
StringInfoData alldescs;
/* /*
* We try to limit the number of reported dependencies to something sane, * We try to limit the number of dependencies reported to the client to
* both for the user's sake and to avoid blowing out memory. * something sane, both for the user's sake and to avoid blowing out
* memory. The server log always gets a full report, which is collected
* in a separate StringInfo if and only if we detect that the original
* report is going to be truncated.
*/ */
#define MAX_REPORTED_DEPS 100 #define MAX_REPORTED_DEPS 100
initStringInfo(&descs); initStringInfo(&descs);
initStringInfo(&alldescs);
sdepRel = heap_open(SharedDependRelationId, AccessShareLock); sdepRel = heap_open(SharedDependRelationId, AccessShareLock);
...@@ -531,17 +539,35 @@ checkSharedDependencies(Oid classId, Oid objectId) ...@@ -531,17 +539,35 @@ checkSharedDependencies(Oid classId, Oid objectId)
*/ */
if (sdepForm->dbid == MyDatabaseId) if (sdepForm->dbid == MyDatabaseId)
{ {
numLocalDeps++; if (++numReportedDeps <= MAX_REPORTED_DEPS)
if (++totalDeps <= MAX_REPORTED_DEPS)
storeObjectDescription(&descs, LOCAL_OBJECT, &object, storeObjectDescription(&descs, LOCAL_OBJECT, &object,
sdepForm->deptype, 0); sdepForm->deptype, 0);
else
{
numNotReportedDeps++;
/* initialize the server-only log line */
if (alldescs.len == 0)
appendBinaryStringInfo(&alldescs, descs.data, descs.len);
storeObjectDescription(&alldescs, LOCAL_OBJECT, &object,
sdepForm->deptype, 0);
}
} }
else if (sdepForm->dbid == InvalidOid) else if (sdepForm->dbid == InvalidOid)
{ {
numSharedDeps++; if (++numReportedDeps <= MAX_REPORTED_DEPS)
if (++totalDeps <= MAX_REPORTED_DEPS)
storeObjectDescription(&descs, SHARED_OBJECT, &object, storeObjectDescription(&descs, SHARED_OBJECT, &object,
sdepForm->deptype, 0); sdepForm->deptype, 0);
else
{
numNotReportedDeps++;
/* initialize the server-only log line */
if (alldescs.len == 0)
appendBinaryStringInfo(&alldescs, descs.data, descs.len);
storeObjectDescription(&alldescs, SHARED_OBJECT, &object,
sdepForm->deptype, 0);
}
} }
else else
{ {
...@@ -571,7 +597,6 @@ checkSharedDependencies(Oid classId, Oid objectId) ...@@ -571,7 +597,6 @@ checkSharedDependencies(Oid classId, Oid objectId)
dep->dbOid = sdepForm->dbid; dep->dbOid = sdepForm->dbid;
dep->count = 1; dep->count = 1;
remDeps = lappend(remDeps, dep); remDeps = lappend(remDeps, dep);
totalDeps++;
} }
} }
} }
...@@ -580,28 +605,11 @@ checkSharedDependencies(Oid classId, Oid objectId) ...@@ -580,28 +605,11 @@ checkSharedDependencies(Oid classId, Oid objectId)
heap_close(sdepRel, AccessShareLock); heap_close(sdepRel, AccessShareLock);
if (totalDeps > MAX_REPORTED_DEPS) /*
{ * 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
* Report seems unreasonably long, so reduce it to per-database info * of them. Otherwise add as many as fit in MAX_REPORTED_DEPS.
* */
* Note: we don't ever suppress per-database totals, which should be
* OK as long as there aren't too many databases ...
*/
resetStringInfo(&descs);
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) foreach(cell, remDeps)
{ {
remoteDep *dep = lfirst(cell); remoteDep *dep = lfirst(cell);
...@@ -610,8 +618,35 @@ checkSharedDependencies(Oid classId, Oid objectId) ...@@ -610,8 +618,35 @@ checkSharedDependencies(Oid classId, Oid objectId)
object.objectId = dep->dbOid; object.objectId = dep->dbOid;
object.objectSubId = 0; object.objectSubId = 0;
storeObjectDescription(&descs, REMOTE_OBJECT, &object, if (alldescs.len != 0)
SHARED_DEPENDENCY_INVALID, dep->count); {
numNotReportedDbs++;
storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
SHARED_DEPENDENCY_INVALID, dep->count);
}
else
{
if (numReportedDeps <= MAX_REPORTED_DEPS)
{
numReportedDeps++;
storeObjectDescription(&descs, REMOTE_OBJECT, &object,
SHARED_DEPENDENCY_INVALID, dep->count);
}
else
{
/* initialize the server-only log line */
numNotReportedDbs++;
appendBinaryStringInfo(&alldescs, descs.data, descs.len);
storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
SHARED_DEPENDENCY_INVALID, dep->count);
}
}
}
if (numNotReportedDbs > 0)
{
appendStringInfo(&descs, "\nand objects in other %d databases",
numNotReportedDbs);
} }
list_free_deep(remDeps); list_free_deep(remDeps);
...@@ -619,9 +654,27 @@ checkSharedDependencies(Oid classId, Oid objectId) ...@@ -619,9 +654,27 @@ checkSharedDependencies(Oid classId, Oid objectId)
if (descs.len == 0) if (descs.len == 0)
{ {
pfree(descs.data); pfree(descs.data);
pfree(alldescs.data);
return NULL; return NULL;
} }
if (numNotReportedDbs + numNotReportedDeps > 0)
{
ObjectAddress obj;
obj.classId = classId;
obj.objectId = objectId;
obj.objectSubId = 0;
ereport(LOG,
(errmsg("objects dependent on %s", getObjectDescription(&obj)),
errdetail(alldescs.data)));
if (numNotReportedDeps > 0)
appendStringInfo(&descs, "\nand other %d objects",
numNotReportedDeps);
}
pfree(alldescs.data);
return descs.data; return descs.data;
} }
...@@ -977,8 +1030,12 @@ storeObjectDescription(StringInfo descs, objectType type, ...@@ -977,8 +1030,12 @@ storeObjectDescription(StringInfo descs, objectType type,
break; break;
case REMOTE_OBJECT: case REMOTE_OBJECT:
/* translator: %s will always be "database %s" */ if (count == 1)
appendStringInfo(descs, _("%d objects in %s"), count, objdesc); /* translator: %s will always be "database %s" */
appendStringInfo(descs, _("one object in %s"), objdesc);
else
/* translator: %s will always be "database %s" */
appendStringInfo(descs, _("%d objects in %s"), count, objdesc);
break; break;
default: default:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment