mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-11 19:20:40 +08:00
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:
parent
ebff1d4dc6
commit
c4f2a0458d
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user