Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit af6550d

Browse files
committed
Sort dependent objects before reporting them in DROP ROLE.
Commit 8aa9dd7 didn't quite finish the job in this area after all, because DROP ROLE has a code path distinct from DROP OWNED BY, and it was still reporting dependent objects in whatever order the index scan returned them in. Buildfarm experience shows that index ordering of equal-keyed objects is significantly less stable than before in the wake of using heap TIDs as tie-breakers. So if we try to hide the unstable ordering by suppressing DETAIL reports, we're just going to end up having to do that for every DROP that reports multiple objects. That's not great from a coverage or problem-detection standpoint, and it's something we'll inevitably forget in future patches, leading to more iterations of fixing-an- unstable-result. So let's just bite the bullet and sort here too. Discussion: https://postgr.es/m/E1h6eep-0001Mw-Vd@gemulon.postgresql.org
1 parent 59ab3be commit af6550d

File tree

2 files changed

+111
-25
lines changed

2 files changed

+111
-25
lines changed

src/backend/catalog/pg_shdepend.c

+109-23
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ typedef enum
7474
REMOTE_OBJECT
7575
} SharedDependencyObjectType;
7676

77+
typedef struct
78+
{
79+
ObjectAddress object;
80+
char deptype;
81+
SharedDependencyObjectType objtype;
82+
} ShDependObjectInfo;
83+
7784
static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2);
7885
static Oid classIdGetDbId(Oid classId);
7986
static void shdepChangeDep(Relation sdepRel,
@@ -496,6 +503,56 @@ typedef struct
496503
int count;
497504
} remoteDep;
498505

506+
/*
507+
* qsort comparator for ShDependObjectInfo items
508+
*/
509+
static int
510+
shared_dependency_comparator(const void *a, const void *b)
511+
{
512+
const ShDependObjectInfo *obja = (const ShDependObjectInfo *) a;
513+
const ShDependObjectInfo *objb = (const ShDependObjectInfo *) b;
514+
515+
/*
516+
* Primary sort key is OID ascending.
517+
*/
518+
if (obja->object.objectId < objb->object.objectId)
519+
return -1;
520+
if (obja->object.objectId > objb->object.objectId)
521+
return 1;
522+
523+
/*
524+
* Next sort on catalog ID, in case identical OIDs appear in different
525+
* catalogs. Sort direction is pretty arbitrary here.
526+
*/
527+
if (obja->object.classId < objb->object.classId)
528+
return -1;
529+
if (obja->object.classId > objb->object.classId)
530+
return 1;
531+
532+
/*
533+
* Sort on object subId.
534+
*
535+
* We sort the subId as an unsigned int so that 0 (the whole object) will
536+
* come first.
537+
*/
538+
if ((unsigned int) obja->object.objectSubId < (unsigned int) objb->object.objectSubId)
539+
return -1;
540+
if ((unsigned int) obja->object.objectSubId > (unsigned int) objb->object.objectSubId)
541+
return 1;
542+
543+
/*
544+
* Last, sort on deptype, in case the same object has multiple dependency
545+
* types. (Note that there's no need to consider objtype, as that's
546+
* determined by the catalog OID.)
547+
*/
548+
if (obja->deptype < objb->deptype)
549+
return -1;
550+
if (obja->deptype > objb->deptype)
551+
return 1;
552+
553+
return 0;
554+
}
555+
499556
/*
500557
* checkSharedDependencies
501558
*
@@ -531,16 +588,27 @@ checkSharedDependencies(Oid classId, Oid objectId,
531588
List *remDeps = NIL;
532589
ListCell *cell;
533590
ObjectAddress object;
591+
ShDependObjectInfo *objects;
592+
int numobjects;
593+
int allocedobjects;
534594
StringInfoData descs;
535595
StringInfoData alldescs;
536596

537597
/*
538598
* We limit the number of dependencies reported to the client to
539599
* MAX_REPORTED_DEPS, since client software may not deal well with
540600
* enormous error strings. The server log always gets a full report.
601+
*
602+
* For stability of regression test results, we sort local and shared
603+
* objects by OID before reporting them. We don't worry about the order
604+
* in which other databases are reported, though.
541605
*/
542606
#define MAX_REPORTED_DEPS 100
543607

608+
allocedobjects = 128; /* arbitrary initial array size */
609+
objects = (ShDependObjectInfo *)
610+
palloc(allocedobjects * sizeof(ShDependObjectInfo));
611+
numobjects = 0;
544612
initStringInfo(&descs);
545613
initStringInfo(&alldescs);
546614

@@ -580,36 +648,26 @@ checkSharedDependencies(Oid classId, Oid objectId,
580648

581649
/*
582650
* If it's a dependency local to this database or it's a shared
583-
* object, describe it.
651+
* object, add it to the objects array.
584652
*
585653
* If it's a remote dependency, keep track of it so we can report the
586654
* number of them later.
587655
*/
588-
if (sdepForm->dbid == MyDatabaseId)
589-
{
590-
if (numReportedDeps < MAX_REPORTED_DEPS)
591-
{
592-
numReportedDeps++;
593-
storeObjectDescription(&descs, LOCAL_OBJECT, &object,
594-
sdepForm->deptype, 0);
595-
}
596-
else
597-
numNotReportedDeps++;
598-
storeObjectDescription(&alldescs, LOCAL_OBJECT, &object,
599-
sdepForm->deptype, 0);
600-
}
601-
else if (sdepForm->dbid == InvalidOid)
656+
if (sdepForm->dbid == MyDatabaseId ||
657+
sdepForm->dbid == InvalidOid)
602658
{
603-
if (numReportedDeps < MAX_REPORTED_DEPS)
659+
if (numobjects >= allocedobjects)
604660
{
605-
numReportedDeps++;
606-
storeObjectDescription(&descs, SHARED_OBJECT, &object,
607-
sdepForm->deptype, 0);
661+
allocedobjects *= 2;
662+
objects = (ShDependObjectInfo *)
663+
repalloc(objects,
664+
allocedobjects * sizeof(ShDependObjectInfo));
608665
}
609-
else
610-
numNotReportedDeps++;
611-
storeObjectDescription(&alldescs, SHARED_OBJECT, &object,
612-
sdepForm->deptype, 0);
666+
objects[numobjects].object = object;
667+
objects[numobjects].deptype = sdepForm->deptype;
668+
objects[numobjects].objtype = (sdepForm->dbid == MyDatabaseId) ?
669+
LOCAL_OBJECT : SHARED_OBJECT;
670+
numobjects++;
613671
}
614672
else
615673
{
@@ -647,6 +705,33 @@ checkSharedDependencies(Oid classId, Oid objectId,
647705

648706
table_close(sdepRel, AccessShareLock);
649707

708+
/*
709+
* Sort and report local and shared objects.
710+
*/
711+
if (numobjects > 1)
712+
qsort((void *) objects, numobjects,
713+
sizeof(ShDependObjectInfo), shared_dependency_comparator);
714+
715+
for (int i = 0; i < numobjects; i++)
716+
{
717+
if (numReportedDeps < MAX_REPORTED_DEPS)
718+
{
719+
numReportedDeps++;
720+
storeObjectDescription(&descs,
721+
objects[i].objtype,
722+
&objects[i].object,
723+
objects[i].deptype,
724+
0);
725+
}
726+
else
727+
numNotReportedDeps++;
728+
storeObjectDescription(&alldescs,
729+
objects[i].objtype,
730+
&objects[i].object,
731+
objects[i].deptype,
732+
0);
733+
}
734+
650735
/*
651736
* Summarize dependencies in remote databases.
652737
*/
@@ -670,6 +755,7 @@ checkSharedDependencies(Oid classId, Oid objectId,
670755
SHARED_DEPENDENCY_INVALID, dep->count);
671756
}
672757

758+
pfree(objects);
673759
list_free_deep(remDeps);
674760

675761
if (descs.len == 0)

src/test/regress/expected/dependency.out

+2-2
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ FROM pg_type JOIN pg_class c ON typrelid = c.oid WHERE typname = 'deptest_t';
128128
-- doesn't work: grant still exists
129129
DROP USER regress_dep_user1;
130130
ERROR: role "regress_dep_user1" cannot be dropped because some objects depend on it
131-
DETAIL: privileges for table deptest1
132-
privileges for database regression
131+
DETAIL: privileges for database regression
132+
privileges for table deptest1
133133
owner of default privileges on new relations belonging to role regress_dep_user1 in schema deptest
134134
DROP OWNED BY regress_dep_user1;
135135
DROP USER regress_dep_user1;

0 commit comments

Comments
 (0)