aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/catalog/pg_shdepend.c132
-rw-r--r--src/test/regress/expected/dependency.out4
2 files changed, 111 insertions, 25 deletions
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 63a7f4838f8..4a9b4efb050 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -74,6 +74,13 @@ typedef enum
REMOTE_OBJECT
} SharedDependencyObjectType;
+typedef struct
+{
+ ObjectAddress object;
+ char deptype;
+ SharedDependencyObjectType objtype;
+} ShDependObjectInfo;
+
static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2);
static Oid classIdGetDbId(Oid classId);
static void shdepChangeDep(Relation sdepRel,
@@ -497,6 +504,56 @@ typedef struct
} remoteDep;
/*
+ * qsort comparator for ShDependObjectInfo items
+ */
+static int
+shared_dependency_comparator(const void *a, const void *b)
+{
+ const ShDependObjectInfo *obja = (const ShDependObjectInfo *) a;
+ const ShDependObjectInfo *objb = (const ShDependObjectInfo *) 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;
+
+ /*
+ * 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;
+
+ /*
+ * Last, sort on deptype, in case the same object has multiple dependency
+ * types. (Note that there's no need to consider objtype, as that's
+ * determined by the catalog OID.)
+ */
+ if (obja->deptype < objb->deptype)
+ return -1;
+ if (obja->deptype > objb->deptype)
+ return 1;
+
+ return 0;
+}
+
+/*
* checkSharedDependencies
*
* Check whether there are shared dependency entries for a given shared
@@ -531,6 +588,9 @@ checkSharedDependencies(Oid classId, Oid objectId,
List *remDeps = NIL;
ListCell *cell;
ObjectAddress object;
+ ShDependObjectInfo *objects;
+ int numobjects;
+ int allocedobjects;
StringInfoData descs;
StringInfoData alldescs;
@@ -538,9 +598,17 @@ checkSharedDependencies(Oid classId, Oid objectId,
* 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 = (ShDependObjectInfo *)
+ palloc(allocedobjects * sizeof(ShDependObjectInfo));
+ numobjects = 0;
initStringInfo(&descs);
initStringInfo(&alldescs);
@@ -580,36 +648,26 @@ checkSharedDependencies(Oid classId, Oid objectId,
/*
* If it's a dependency local to this database or it's a shared
- * object, describe it.
+ * 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)
- {
- 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 (sdepForm->dbid == MyDatabaseId ||
+ sdepForm->dbid == InvalidOid)
{
- if (numReportedDeps < MAX_REPORTED_DEPS)
+ if (numobjects >= allocedobjects)
{
- numReportedDeps++;
- storeObjectDescription(&descs, SHARED_OBJECT, &object,
- sdepForm->deptype, 0);
+ allocedobjects *= 2;
+ objects = (ShDependObjectInfo *)
+ repalloc(objects,
+ allocedobjects * sizeof(ShDependObjectInfo));
}
- else
- numNotReportedDeps++;
- storeObjectDescription(&alldescs, SHARED_OBJECT, &object,
- sdepForm->deptype, 0);
+ objects[numobjects].object = object;
+ objects[numobjects].deptype = sdepForm->deptype;
+ objects[numobjects].objtype = (sdepForm->dbid == MyDatabaseId) ?
+ LOCAL_OBJECT : SHARED_OBJECT;
+ numobjects++;
}
else
{
@@ -648,6 +706,33 @@ checkSharedDependencies(Oid classId, Oid objectId,
table_close(sdepRel, AccessShareLock);
/*
+ * Sort and report local and shared objects.
+ */
+ if (numobjects > 1)
+ qsort((void *) objects, numobjects,
+ sizeof(ShDependObjectInfo), 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)
@@ -670,6 +755,7 @@ checkSharedDependencies(Oid classId, Oid objectId,
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 8d31110b874..2f04b712a4f 100644
--- a/src/test/regress/expected/dependency.out
+++ b/src/test/regress/expected/dependency.out
@@ -128,8 +128,8 @@ FROM pg_type JOIN pg_class c ON typrelid = c.oid WHERE typname = 'deptest_t';
-- 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
+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;