Improve reporting of dependencies in DROP to work like the scheme that we

devised for pg_shdepend, namely the individual dependencies are reported as
DETAIL lines rather than coming out as separate NOTICEs.  The client-side
report is capped at 100 lines, but the server log always gets a full report.
This commit is contained in:
Tom Lane 2008-06-11 21:53:49 +00:00
parent ebff1d4dc6
commit c4f2a0458d
10 changed files with 199 additions and 87 deletions

View File

@ -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,8 +764,36 @@ 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);
}
/*

View File

@ -1161,8 +1161,9 @@ order by relname, attnum;
(8 rows)
drop table p1, p2 cascade;
NOTICE: drop cascades to table c1
NOTICE: drop cascades to table gc1
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table c1
drop cascades to table gc1
--
-- Test the ALTER TABLE WITHOUT OIDS command
--
@ -1469,8 +1470,9 @@ select alter2.plus1(41);
-- clean up
drop schema alter2 cascade;
NOTICE: drop cascades to table alter2.t1
NOTICE: drop cascades to view alter2.v1
NOTICE: drop cascades to function alter2.plus1(integer)
NOTICE: drop cascades to type alter2.posint
NOTICE: drop cascades to type alter2.ctype
NOTICE: drop cascades to 5 other objects
DETAIL: drop cascades to table alter2.t1
drop cascades to view alter2.v1
drop cascades to function alter2.plus1(integer)
drop cascades to type alter2.posint
drop cascades to type alter2.ctype

View File

@ -237,43 +237,45 @@ And relnamespace IN (SELECT OID FROM pg_namespace WHERE nspname LIKE 'pg_temp%')
(1 row)
DROP SCHEMA temp_view_test CASCADE;
NOTICE: drop cascades to table temp_view_test.base_table
NOTICE: drop cascades to view v7_temp
NOTICE: drop cascades to view v10_temp
NOTICE: drop cascades to view v11_temp
NOTICE: drop cascades to view v12_temp
NOTICE: drop cascades to view v2_temp
NOTICE: drop cascades to view v4_temp
NOTICE: drop cascades to view v6_temp
NOTICE: drop cascades to view v8_temp
NOTICE: drop cascades to view v9_temp
NOTICE: drop cascades to table temp_view_test.base_table2
NOTICE: drop cascades to view v5_temp
NOTICE: drop cascades to view temp_view_test.v1
NOTICE: drop cascades to view temp_view_test.v2
NOTICE: drop cascades to view temp_view_test.v3
NOTICE: drop cascades to view temp_view_test.v4
NOTICE: drop cascades to view temp_view_test.v5
NOTICE: drop cascades to view temp_view_test.v6
NOTICE: drop cascades to view temp_view_test.v7
NOTICE: drop cascades to view temp_view_test.v8
NOTICE: drop cascades to sequence temp_view_test.seq1
NOTICE: drop cascades to view temp_view_test.v9
NOTICE: drop cascades to 22 other objects
DETAIL: drop cascades to table temp_view_test.base_table
drop cascades to view v7_temp
drop cascades to view v10_temp
drop cascades to view v11_temp
drop cascades to view v12_temp
drop cascades to view v2_temp
drop cascades to view v4_temp
drop cascades to view v6_temp
drop cascades to view v8_temp
drop cascades to view v9_temp
drop cascades to table temp_view_test.base_table2
drop cascades to view v5_temp
drop cascades to view temp_view_test.v1
drop cascades to view temp_view_test.v2
drop cascades to view temp_view_test.v3
drop cascades to view temp_view_test.v4
drop cascades to view temp_view_test.v5
drop cascades to view temp_view_test.v6
drop cascades to view temp_view_test.v7
drop cascades to view temp_view_test.v8
drop cascades to sequence temp_view_test.seq1
drop cascades to view temp_view_test.v9
DROP SCHEMA testviewschm2 CASCADE;
NOTICE: drop cascades to table t1
NOTICE: drop cascades to view temporal1
NOTICE: drop cascades to view temporal2
NOTICE: drop cascades to view temporal3
NOTICE: drop cascades to view temporal4
NOTICE: drop cascades to table t2
NOTICE: drop cascades to view nontemp1
NOTICE: drop cascades to view nontemp2
NOTICE: drop cascades to view nontemp3
NOTICE: drop cascades to view nontemp4
NOTICE: drop cascades to table tbl1
NOTICE: drop cascades to table tbl2
NOTICE: drop cascades to table tbl3
NOTICE: drop cascades to table tbl4
NOTICE: drop cascades to view mytempview
NOTICE: drop cascades to view pubview
NOTICE: drop cascades to 16 other objects
DETAIL: drop cascades to table t1
drop cascades to view temporal1
drop cascades to view temporal2
drop cascades to view temporal3
drop cascades to view temporal4
drop cascades to table t2
drop cascades to view nontemp1
drop cascades to view nontemp2
drop cascades to view nontemp3
drop cascades to view nontemp4
drop cascades to table tbl1
drop cascades to table tbl2
drop cascades to table tbl3
drop cascades to table tbl4
drop cascades to view mytempview
drop cascades to view pubview
SET search_path to public;

View File

@ -7,8 +7,8 @@ comment on domain domaindroptest is 'About to drop this..';
create domain dependenttypetest domaindroptest;
-- fail because of dependent type
drop domain domaindroptest;
NOTICE: type dependenttypetest depends on type domaindroptest
ERROR: cannot drop type domaindroptest because other objects depend on it
DETAIL: type dependenttypetest depends on type domaindroptest
HINT: Use DROP ... CASCADE to drop the dependent objects too.
drop domain domaindroptest cascade;
NOTICE: drop cascades to type dependenttypetest
@ -266,8 +266,9 @@ ERROR: domain dnotnulltest does not allow null values
alter domain dnotnulltest drop not null;
update domnotnull set col1 = null;
drop domain dnotnulltest cascade;
NOTICE: drop cascades to table domnotnull column col1
NOTICE: drop cascades to table domnotnull column col2
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table domnotnull column col1
drop cascades to table domnotnull column col2
-- Test ALTER DOMAIN .. DEFAULT ..
create table domdeftest (col1 ddef1);
insert into domdeftest default values;
@ -395,8 +396,9 @@ insert into dtest values('xz23'); -- fail
ERROR: value for domain dtop violates check constraint "dtop_check"
drop table dtest;
drop domain vchar4 cascade;
NOTICE: drop cascades to type dinter
NOTICE: drop cascades to type dtop
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to type dinter
drop cascades to type dtop
-- Make sure that constraints of newly-added domain columns are
-- enforced correctly, even if there's no default value for the new
-- column. Per bug #1433

View File

@ -257,8 +257,8 @@ SELECT * FROM FKTABLE;
-- this should fail for lack of CASCADE
DROP TABLE PKTABLE;
NOTICE: constraint constrname2 on table fktable depends on table pktable
ERROR: cannot drop table pktable because other objects depend on it
DETAIL: constraint constrname2 on table fktable depends on table pktable
HINT: Use DROP ... CASCADE to drop the dependent objects too.
DROP TABLE PKTABLE CASCADE;
NOTICE: drop cascades to constraint constrname2 on table fktable
@ -1157,15 +1157,16 @@ FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2);
ERROR: foreign key constraint "fk_241_132" cannot be implemented
DETAIL: Key columns "x2" and "id1" are of incompatible types: character varying and integer.
DROP TABLE pktable, fktable CASCADE;
NOTICE: drop cascades to constraint fktable_x3_fkey on table fktable
NOTICE: drop cascades to constraint fk_1_3 on table fktable
NOTICE: drop cascades to constraint fktable_x2_fkey on table fktable
NOTICE: drop cascades to constraint fk_4_2 on table fktable
NOTICE: drop cascades to constraint fktable_x1_fkey on table fktable
NOTICE: drop cascades to constraint fk_5_1 on table fktable
NOTICE: drop cascades to constraint fk_123_123 on table fktable
NOTICE: drop cascades to constraint fk_213_213 on table fktable
NOTICE: drop cascades to constraint fk_253_213 on table fktable
NOTICE: drop cascades to 9 other objects
DETAIL: drop cascades to constraint fktable_x3_fkey on table fktable
drop cascades to constraint fk_1_3 on table fktable
drop cascades to constraint fktable_x2_fkey on table fktable
drop cascades to constraint fk_4_2 on table fktable
drop cascades to constraint fktable_x1_fkey on table fktable
drop cascades to constraint fk_5_1 on table fktable
drop cascades to constraint fk_123_123 on table fktable
drop cascades to constraint fk_213_213 on table fktable
drop cascades to constraint fk_253_213 on table fktable
-- test a tricky case: we can elide firing the FK check trigger during
-- an UPDATE if the UPDATE did not change the foreign key
-- field. However, we can't do this if our transaction was the one that

View File

@ -844,9 +844,10 @@ Inherits: c1,
c2
drop table p1 cascade;
NOTICE: drop cascades to table c1
NOTICE: drop cascades to table c2
NOTICE: drop cascades to table c3
NOTICE: drop cascades to 3 other objects
DETAIL: drop cascades to table c1
drop cascades to table c2
drop cascades to table c3
drop table p2 cascade;
create table pp1 (f1 int);
create table cc1 (f2 text, f3 int) inherits (pp1);
@ -900,5 +901,6 @@ Inherits: pp1,
cc1
drop table pp1 cascade;
NOTICE: drop cascades to table cc1
NOTICE: drop cascades to table cc2
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table cc1
drop cascades to table cc2

View File

@ -39,8 +39,9 @@ SELECT * FROM test_schema_1.abc_view;
(3 rows)
DROP SCHEMA test_schema_1 CASCADE;
NOTICE: drop cascades to table test_schema_1.abc
NOTICE: drop cascades to view test_schema_1.abc_view
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table test_schema_1.abc
drop cascades to view test_schema_1.abc_view
-- verify that the objects were dropped
SELECT COUNT(*) FROM pg_class WHERE relnamespace =
(SELECT oid FROM pg_namespace WHERE nspname = 'test_schema_1');

View File

@ -148,12 +148,12 @@ CREATE TEMP TABLE t1 (
NOTICE: CREATE TABLE will create implicit sequence "t1_f1_seq" for serial column "t1.f1"
-- Both drops should fail, but with different error messages:
DROP SEQUENCE t1_f1_seq;
NOTICE: default for table t1 column f1 depends on sequence t1_f1_seq
ERROR: cannot drop sequence t1_f1_seq because other objects depend on it
DETAIL: default for table t1 column f1 depends on sequence t1_f1_seq
HINT: Use DROP ... CASCADE to drop the dependent objects too.
DROP SEQUENCE myseq2;
NOTICE: default for table t1 column f2 depends on sequence myseq2
ERROR: cannot drop sequence myseq2 because other objects depend on it
DETAIL: default for table t1 column f2 depends on sequence myseq2
HINT: Use DROP ... CASCADE to drop the dependent objects too.
-- This however will work:
DROP SEQUENCE myseq3;

View File

@ -141,10 +141,12 @@ SELECT * FROM trunc_e;
(0 rows)
DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE;
NOTICE: drop cascades to constraint trunc_b_a_fkey on table trunc_b
NOTICE: drop cascades to constraint trunc_e_a_fkey on table trunc_e
NOTICE: drop cascades to constraint trunc_d_a_fkey on table trunc_d
NOTICE: drop cascades to constraint trunc_e_b_fkey on table trunc_e
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to constraint trunc_b_a_fkey on table trunc_b
drop cascades to constraint trunc_e_a_fkey on table trunc_e
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to constraint trunc_d_a_fkey on table trunc_d
drop cascades to constraint trunc_e_b_fkey on table trunc_e
-- Test ON TRUNCATE triggers
CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);
CREATE TABLE trunc_trigger_log (tgop text, tglevel text, tgwhen text,

View File

@ -65,9 +65,10 @@ ERROR: tablespace "nosuchspace" does not exist
DROP TABLESPACE testspace;
ERROR: tablespace "testspace" is not empty
DROP SCHEMA testschema CASCADE;
NOTICE: drop cascades to table testschema.foo
NOTICE: drop cascades to table testschema.asselect
NOTICE: drop cascades to table testschema.asexecute
NOTICE: drop cascades to table testschema.atable
NOTICE: drop cascades to 4 other objects
DETAIL: drop cascades to table testschema.foo
drop cascades to table testschema.asselect
drop cascades to table testschema.asexecute
drop cascades to table testschema.atable
-- Should succeed
DROP TABLESPACE testspace;