aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-06-11 21:53:49 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-06-11 21:53:49 +0000
commitc4f2a0458dc029d1214f013f1434f70f5194e56d (patch)
treea1407b9ccb82efc43b61e92bb8e1f304362f2344 /src
parentebff1d4dc6eee53185c8b96a07abb941c1ead17c (diff)
downloadpostgresql-c4f2a0458dc029d1214f013f1434f70f5194e56d.tar.gz
postgresql-c4f2a0458dc029d1214f013f1434f70f5194e56d.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/dependency.c119
-rw-r--r--src/test/regress/expected/alter_table.out16
-rw-r--r--src/test/regress/expected/create_view.out78
-rw-r--r--src/test/regress/expected/domain.out12
-rw-r--r--src/test/regress/expected/foreign_key.out21
-rw-r--r--src/test/regress/expected/inherit.out12
-rw-r--r--src/test/regress/expected/namespace.out5
-rw-r--r--src/test/regress/expected/sequence.out4
-rw-r--r--src/test/regress/expected/truncate.out10
-rw-r--r--src/test/regress/output/tablespace.source9
10 files changed, 199 insertions, 87 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);
}
/*
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index e7aef8bf59d..daf9482c4ad 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -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
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index 3eae7e90ccd..cbee9dceed8 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -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;
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 179c8c63471..fd88b16ccee 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -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
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index 87e6591ea35..e3086d2e085 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -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
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 7c7ac0ef338..100edb35396 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -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
diff --git a/src/test/regress/expected/namespace.out b/src/test/regress/expected/namespace.out
index 94b3e5e99b0..58a0c4dc81d 100644
--- a/src/test/regress/expected/namespace.out
+++ b/src/test/regress/expected/namespace.out
@@ -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');
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 84ece98357b..823039ae955 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -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;
diff --git a/src/test/regress/expected/truncate.out b/src/test/regress/expected/truncate.out
index d0a99a554a6..520db9d9b17 100644
--- a/src/test/regress/expected/truncate.out
+++ b/src/test/regress/expected/truncate.out
@@ -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,
diff --git a/src/test/regress/output/tablespace.source b/src/test/regress/output/tablespace.source
index 6337798c625..8065505be95 100644
--- a/src/test/regress/output/tablespace.source
+++ b/src/test/regress/output/tablespace.source
@@ -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;