diff options
Diffstat (limited to 'src/backend/catalog/dependency.c')
-rw-r--r-- | src/backend/catalog/dependency.c | 119 |
1 files changed, 109 insertions, 10 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 12b654504d7..8ca95a3fd65 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.74 2008/06/08 22:41:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.75 2008/06/11 21:53:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -62,6 +62,7 @@ #include "storage/lmgr.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -752,7 +753,7 @@ findDependentObjects(const ObjectAddress *object, * * targetObjects: list of objects that are scheduled to be deleted * behavior: RESTRICT or CASCADE - * msglevel: elog level for non-debug notice messages + * msglevel: elog level for non-error report messages * origObject: base object of deletion, or NULL if not available * (the latter case occurs in DROP OWNED) */ @@ -763,9 +764,37 @@ reportDependentObjects(const ObjectAddresses *targetObjects, const ObjectAddress *origObject) { bool ok = true; + StringInfoData clientdetail; + StringInfoData logdetail; + int numReportedClient = 0; + int numNotReportedClient = 0; int i; /* + * If no error is to be thrown, and the msglevel is too low to be shown + * to either client or server log, there's no need to do any of the work. + * + * Note: this code doesn't know all there is to be known about elog + * levels, but it works for NOTICE and DEBUG2, which are the only values + * msglevel can currently have. We also assume we are running in a normal + * operating environment. + */ + if (behavior == DROP_CASCADE && + msglevel < client_min_messages && + (msglevel < log_min_messages || log_min_messages == LOG)) + return; + + /* + * 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(&clientdetail); + initStringInfo(&logdetail); + + /* * We process the list back to front (ie, in dependency order not deletion * order), since this makes for a more understandable display. */ @@ -773,34 +802,82 @@ reportDependentObjects(const ObjectAddresses *targetObjects, { const ObjectAddress *obj = &targetObjects->refs[i]; const ObjectAddressExtra *extra = &targetObjects->extras[i]; + char *objDesc; /* Ignore the original deletion target(s) */ if (extra->flags & DEPFLAG_ORIGINAL) continue; + objDesc = getObjectDescription(obj); + /* * If, at any stage of the recursive search, we reached the object * via an AUTO or INTERNAL dependency, then it's okay to delete it * even in RESTRICT mode. */ if (extra->flags & (DEPFLAG_AUTO | DEPFLAG_INTERNAL)) + { + /* + * auto-cascades are reported at DEBUG2, not msglevel. We + * don't try to combine them with the regular message because + * the results are too confusing when client_min_messages and + * log_min_messages are different. + */ ereport(DEBUG2, (errmsg("drop auto-cascades to %s", - getObjectDescription(obj)))); + objDesc))); + } else if (behavior == DROP_RESTRICT) { - ereport(msglevel, - (errmsg("%s depends on %s", - getObjectDescription(obj), - getObjectDescription(&extra->dependee)))); + char *otherDesc = getObjectDescription(&extra->dependee); + + if (numReportedClient < MAX_REPORTED_DEPS) + { + /* separate entries with a newline */ + if (clientdetail.len != 0) + appendStringInfoChar(&clientdetail, '\n'); + appendStringInfo(&clientdetail, _("%s depends on %s"), + objDesc, otherDesc); + numReportedClient++; + } + else + numNotReportedClient++; + /* separate entries with a newline */ + if (logdetail.len != 0) + appendStringInfoChar(&logdetail, '\n'); + appendStringInfo(&logdetail, _("%s depends on %s"), + objDesc, otherDesc); + pfree(otherDesc); ok = false; } else - ereport(msglevel, - (errmsg("drop cascades to %s", - getObjectDescription(obj)))); + { + if (numReportedClient < MAX_REPORTED_DEPS) + { + /* separate entries with a newline */ + if (clientdetail.len != 0) + appendStringInfoChar(&clientdetail, '\n'); + appendStringInfo(&clientdetail, _("drop cascades to %s"), + objDesc); + numReportedClient++; + } + else + numNotReportedClient++; + /* separate entries with a newline */ + if (logdetail.len != 0) + appendStringInfoChar(&logdetail, '\n'); + appendStringInfo(&logdetail, _("drop cascades to %s"), + objDesc); + } + + pfree(objDesc); } + if (numNotReportedClient > 0) + appendStringInfo(&clientdetail, _("\nand %d other objects " + "(see server log for list)"), + numNotReportedClient); + if (!ok) { if (origObject) @@ -808,13 +885,35 @@ reportDependentObjects(const ObjectAddresses *targetObjects, (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), errmsg("cannot drop %s because other objects depend on it", getObjectDescription(origObject)), + errdetail("%s", clientdetail.data), + errdetail_log("%s", logdetail.data), errhint("Use DROP ... CASCADE to drop the dependent objects too."))); else ereport(ERROR, (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), errmsg("cannot drop desired object(s) because other objects depend on them"), + errdetail("%s", clientdetail.data), + errdetail_log("%s", logdetail.data), errhint("Use DROP ... CASCADE to drop the dependent objects too."))); } + else if (numReportedClient > 1) + { + ereport(msglevel, + /* translator: %d always has a value larger than 1 */ + (errmsg("drop cascades to %d other objects", + numReportedClient + numNotReportedClient), + errdetail("%s", clientdetail.data), + errdetail_log("%s", logdetail.data))); + } + else if (numReportedClient == 1) + { + /* we just use the single item as-is */ + ereport(msglevel, + (errmsg_internal("%s", clientdetail.data))); + } + + pfree(clientdetail.data); + pfree(logdetail.data); } /* |