8
8
* Portions Copyright (c) 1994, Regents of the University of California
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.74 2008/06/08 22:41:04 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.75 2008/06/11 21:53:48 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
62
62
#include "storage/lmgr.h"
63
63
#include "utils/builtins.h"
64
64
#include "utils/fmgroids.h"
65
+ #include "utils/guc.h"
65
66
#include "utils/lsyscache.h"
66
67
#include "utils/syscache.h"
67
68
#include "utils/tqual.h"
@@ -752,7 +753,7 @@ findDependentObjects(const ObjectAddress *object,
752
753
*
753
754
* targetObjects: list of objects that are scheduled to be deleted
754
755
* behavior: RESTRICT or CASCADE
755
- * msglevel: elog level for non-debug notice messages
756
+ * msglevel: elog level for non-error report messages
756
757
* origObject: base object of deletion, or NULL if not available
757
758
* (the latter case occurs in DROP OWNED)
758
759
*/
@@ -763,8 +764,36 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
763
764
const ObjectAddress * origObject )
764
765
{
765
766
bool ok = true;
767
+ StringInfoData clientdetail ;
768
+ StringInfoData logdetail ;
769
+ int numReportedClient = 0 ;
770
+ int numNotReportedClient = 0 ;
766
771
int i ;
767
772
773
+ /*
774
+ * If no error is to be thrown, and the msglevel is too low to be shown
775
+ * to either client or server log, there's no need to do any of the work.
776
+ *
777
+ * Note: this code doesn't know all there is to be known about elog
778
+ * levels, but it works for NOTICE and DEBUG2, which are the only values
779
+ * msglevel can currently have. We also assume we are running in a normal
780
+ * operating environment.
781
+ */
782
+ if (behavior == DROP_CASCADE &&
783
+ msglevel < client_min_messages &&
784
+ (msglevel < log_min_messages || log_min_messages == LOG ))
785
+ return ;
786
+
787
+ /*
788
+ * We limit the number of dependencies reported to the client to
789
+ * MAX_REPORTED_DEPS, since client software may not deal well with
790
+ * enormous error strings. The server log always gets a full report.
791
+ */
792
+ #define MAX_REPORTED_DEPS 100
793
+
794
+ initStringInfo (& clientdetail );
795
+ initStringInfo (& logdetail );
796
+
768
797
/*
769
798
* We process the list back to front (ie, in dependency order not deletion
770
799
* order), since this makes for a more understandable display.
@@ -773,48 +802,118 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
773
802
{
774
803
const ObjectAddress * obj = & targetObjects -> refs [i ];
775
804
const ObjectAddressExtra * extra = & targetObjects -> extras [i ];
805
+ char * objDesc ;
776
806
777
807
/* Ignore the original deletion target(s) */
778
808
if (extra -> flags & DEPFLAG_ORIGINAL )
779
809
continue ;
780
810
811
+ objDesc = getObjectDescription (obj );
812
+
781
813
/*
782
814
* If, at any stage of the recursive search, we reached the object
783
815
* via an AUTO or INTERNAL dependency, then it's okay to delete it
784
816
* even in RESTRICT mode.
785
817
*/
786
818
if (extra -> flags & (DEPFLAG_AUTO | DEPFLAG_INTERNAL ))
819
+ {
820
+ /*
821
+ * auto-cascades are reported at DEBUG2, not msglevel. We
822
+ * don't try to combine them with the regular message because
823
+ * the results are too confusing when client_min_messages and
824
+ * log_min_messages are different.
825
+ */
787
826
ereport (DEBUG2 ,
788
827
(errmsg ("drop auto-cascades to %s" ,
789
- getObjectDescription (obj ))));
828
+ objDesc )));
829
+ }
790
830
else if (behavior == DROP_RESTRICT )
791
831
{
792
- ereport (msglevel ,
793
- (errmsg ("%s depends on %s" ,
794
- getObjectDescription (obj ),
795
- getObjectDescription (& extra -> dependee ))));
832
+ char * otherDesc = getObjectDescription (& extra -> dependee );
833
+
834
+ if (numReportedClient < MAX_REPORTED_DEPS )
835
+ {
836
+ /* separate entries with a newline */
837
+ if (clientdetail .len != 0 )
838
+ appendStringInfoChar (& clientdetail , '\n' );
839
+ appendStringInfo (& clientdetail , _ ("%s depends on %s" ),
840
+ objDesc , otherDesc );
841
+ numReportedClient ++ ;
842
+ }
843
+ else
844
+ numNotReportedClient ++ ;
845
+ /* separate entries with a newline */
846
+ if (logdetail .len != 0 )
847
+ appendStringInfoChar (& logdetail , '\n' );
848
+ appendStringInfo (& logdetail , _ ("%s depends on %s" ),
849
+ objDesc , otherDesc );
850
+ pfree (otherDesc );
796
851
ok = false;
797
852
}
798
853
else
799
- ereport (msglevel ,
800
- (errmsg ("drop cascades to %s" ,
801
- getObjectDescription (obj ))));
854
+ {
855
+ if (numReportedClient < MAX_REPORTED_DEPS )
856
+ {
857
+ /* separate entries with a newline */
858
+ if (clientdetail .len != 0 )
859
+ appendStringInfoChar (& clientdetail , '\n' );
860
+ appendStringInfo (& clientdetail , _ ("drop cascades to %s" ),
861
+ objDesc );
862
+ numReportedClient ++ ;
863
+ }
864
+ else
865
+ numNotReportedClient ++ ;
866
+ /* separate entries with a newline */
867
+ if (logdetail .len != 0 )
868
+ appendStringInfoChar (& logdetail , '\n' );
869
+ appendStringInfo (& logdetail , _ ("drop cascades to %s" ),
870
+ objDesc );
871
+ }
872
+
873
+ pfree (objDesc );
802
874
}
803
875
876
+ if (numNotReportedClient > 0 )
877
+ appendStringInfo (& clientdetail , _ ("\nand %d other objects "
878
+ "(see server log for list)" ),
879
+ numNotReportedClient );
880
+
804
881
if (!ok )
805
882
{
806
883
if (origObject )
807
884
ereport (ERROR ,
808
885
(errcode (ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST ),
809
886
errmsg ("cannot drop %s because other objects depend on it" ,
810
887
getObjectDescription (origObject )),
888
+ errdetail ("%s" , clientdetail .data ),
889
+ errdetail_log ("%s" , logdetail .data ),
811
890
errhint ("Use DROP ... CASCADE to drop the dependent objects too." )));
812
891
else
813
892
ereport (ERROR ,
814
893
(errcode (ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST ),
815
894
errmsg ("cannot drop desired object(s) because other objects depend on them" ),
895
+ errdetail ("%s" , clientdetail .data ),
896
+ errdetail_log ("%s" , logdetail .data ),
816
897
errhint ("Use DROP ... CASCADE to drop the dependent objects too." )));
817
898
}
899
+ else if (numReportedClient > 1 )
900
+ {
901
+ ereport (msglevel ,
902
+ /* translator: %d always has a value larger than 1 */
903
+ (errmsg ("drop cascades to %d other objects" ,
904
+ numReportedClient + numNotReportedClient ),
905
+ errdetail ("%s" , clientdetail .data ),
906
+ errdetail_log ("%s" , logdetail .data )));
907
+ }
908
+ else if (numReportedClient == 1 )
909
+ {
910
+ /* we just use the single item as-is */
911
+ ereport (msglevel ,
912
+ (errmsg_internal ("%s" , clientdetail .data )));
913
+ }
914
+
915
+ pfree (clientdetail .data );
916
+ pfree (logdetail .data );
818
917
}
819
918
820
919
/*
0 commit comments