Peter Geoghegan <p...@bowt.ie> writes: > On Sun, Mar 24, 2019 at 11:02 AM Tom Lane <t...@sss.pgh.pa.us> wrote: >> I think I can probably get that done today, but if you don't want to >> wait, feel free to put in the detail-suppression for now.
> I'll monitor the situation, and proceed with a stopgap > detail-suppression fix this evening if, for whatever reason, it seems > necessary. It turns out we can't use the ObjectAddresses infrastructure because it doesn't store enough information. So that means an extra qsort comparator function, which is slightly annoying, but it's still not a huge amount of code. This flips one expected result to another order from what it was. (I experimented with OID-descending sort, but that flips two other expected results.) If no objections, I'll push shortly. regards, tom lane
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 63a7f48..5b74040 100644 *** a/src/backend/catalog/pg_shdepend.c --- b/src/backend/catalog/pg_shdepend.c *************** typedef enum *** 74,79 **** --- 74,86 ---- REMOTE_OBJECT } SharedDependencyObjectType; + typedef struct + { + ObjectAddress object; + char deptype; + SharedDependencyObjectType objtype; + } ShDepObjectInfo; + static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2); static Oid classIdGetDbId(Oid classId); static void shdepChangeDep(Relation sdepRel, *************** typedef struct *** 497,502 **** --- 504,548 ---- } remoteDep; /* + * qsort comparator for ShDepObjectInfo items + */ + static int + shared_dependency_comparator(const void *a, const void *b) + { + const ShDepObjectInfo *obja = (const ShDepObjectInfo *) a; + const ShDepObjectInfo *objb = (const ShDepObjectInfo *) b; + + /* + * Primary sort key is OID ascending. + */ + if (obja->object.objectId < objb->object.objectId) + return -1; + if (obja->object.objectId > objb->object.objectId) + return 1; + + /* + * Next sort on catalog ID, in case identical OIDs appear in different + * catalogs. Sort direction is pretty arbitrary here. + */ + if (obja->object.classId < objb->object.classId) + return -1; + if (obja->object.classId > objb->object.classId) + return 1; + + /* + * Last, sort on object subId. + * + * We sort the subId as an unsigned int so that 0 (the whole object) will + * come first. + */ + if ((unsigned int) obja->object.objectSubId < (unsigned int) objb->object.objectSubId) + return -1; + if ((unsigned int) obja->object.objectSubId > (unsigned int) objb->object.objectSubId) + return 1; + return 0; + } + + /* * checkSharedDependencies * * Check whether there are shared dependency entries for a given shared *************** checkSharedDependencies(Oid classId, Oid *** 531,536 **** --- 577,585 ---- List *remDeps = NIL; ListCell *cell; ObjectAddress object; + ShDepObjectInfo *objects; + int numobjects; + int allocedobjects; StringInfoData descs; StringInfoData alldescs; *************** checkSharedDependencies(Oid classId, Oid *** 538,546 **** --- 587,603 ---- * 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. + * + * For stability of regression test results, we sort local and shared + * objects by OID before reporting them. We don't worry about the order + * in which other databases are reported, though. */ #define MAX_REPORTED_DEPS 100 + allocedobjects = 128; /* arbitrary initial array size */ + objects = (ShDepObjectInfo *) + palloc(allocedobjects * sizeof(ShDepObjectInfo)); + numobjects = 0; initStringInfo(&descs); initStringInfo(&alldescs); *************** checkSharedDependencies(Oid classId, Oid *** 580,615 **** /* * If it's a dependency local to this database or it's a shared ! * object, describe it. * * If it's a remote dependency, keep track of it so we can report the * number of them later. */ ! if (sdepForm->dbid == MyDatabaseId) ! { ! if (numReportedDeps < MAX_REPORTED_DEPS) ! { ! numReportedDeps++; ! storeObjectDescription(&descs, LOCAL_OBJECT, &object, ! sdepForm->deptype, 0); ! } ! else ! numNotReportedDeps++; ! storeObjectDescription(&alldescs, LOCAL_OBJECT, &object, ! sdepForm->deptype, 0); ! } ! else if (sdepForm->dbid == InvalidOid) { ! if (numReportedDeps < MAX_REPORTED_DEPS) { ! numReportedDeps++; ! storeObjectDescription(&descs, SHARED_OBJECT, &object, ! sdepForm->deptype, 0); } ! else ! numNotReportedDeps++; ! storeObjectDescription(&alldescs, SHARED_OBJECT, &object, ! sdepForm->deptype, 0); } else { --- 637,662 ---- /* * If it's a dependency local to this database or it's a shared ! * object, add it to the objects array. * * If it's a remote dependency, keep track of it so we can report the * number of them later. */ ! if (sdepForm->dbid == MyDatabaseId || ! sdepForm->dbid == InvalidOid) { ! if (numobjects >= allocedobjects) { ! allocedobjects *= 2; ! objects = (ShDepObjectInfo *) ! repalloc(objects, ! allocedobjects * sizeof(ShDepObjectInfo)); } ! objects[numobjects].object = object; ! objects[numobjects].deptype = sdepForm->deptype; ! objects[numobjects].objtype = (sdepForm->dbid == MyDatabaseId) ? ! LOCAL_OBJECT : SHARED_OBJECT; ! numobjects++; } else { *************** checkSharedDependencies(Oid classId, Oid *** 648,653 **** --- 695,727 ---- table_close(sdepRel, AccessShareLock); /* + * Sort and report local and shared objects. + */ + if (numobjects > 1) + qsort((void *) objects, numobjects, + sizeof(ShDepObjectInfo), shared_dependency_comparator); + + for (int i = 0; i < numobjects; i++) + { + if (numReportedDeps < MAX_REPORTED_DEPS) + { + numReportedDeps++; + storeObjectDescription(&descs, + objects[i].objtype, + &objects[i].object, + objects[i].deptype, + 0); + } + else + numNotReportedDeps++; + storeObjectDescription(&alldescs, + objects[i].objtype, + &objects[i].object, + objects[i].deptype, + 0); + } + + /* * Summarize dependencies in remote databases. */ foreach(cell, remDeps) *************** checkSharedDependencies(Oid classId, Oid *** 670,675 **** --- 744,750 ---- SHARED_DEPENDENCY_INVALID, dep->count); } + pfree(objects); list_free_deep(remDeps); if (descs.len == 0) diff --git a/src/test/regress/expected/dependency.out b/src/test/regress/expected/dependency.out index 8d31110..2f04b71 100644 *** a/src/test/regress/expected/dependency.out --- b/src/test/regress/expected/dependency.out *************** FROM pg_type JOIN pg_class c ON typrelid *** 128,135 **** -- doesn't work: grant still exists DROP USER regress_dep_user1; ERROR: role "regress_dep_user1" cannot be dropped because some objects depend on it ! DETAIL: privileges for table deptest1 ! privileges for database regression owner of default privileges on new relations belonging to role regress_dep_user1 in schema deptest DROP OWNED BY regress_dep_user1; DROP USER regress_dep_user1; --- 128,135 ---- -- doesn't work: grant still exists DROP USER regress_dep_user1; ERROR: role "regress_dep_user1" cannot be dropped because some objects depend on it ! DETAIL: privileges for database regression ! privileges for table deptest1 owner of default privileges on new relations belonging to role regress_dep_user1 in schema deptest DROP OWNED BY regress_dep_user1; DROP USER regress_dep_user1;