]> granicus.if.org Git - postgresql/commitdiff
Ensure pg_dump_sort.c sorts null vs non-null namespace consistently.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 7 Aug 2018 17:13:42 +0000 (13:13 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 7 Aug 2018 17:13:42 +0000 (13:13 -0400)
The original coding here (which is, I believe, my fault) supposed that
it didn't need to concern itself with the possibility that one object
of a given type-priority has a namespace while another doesn't.  But
that's not reliably true anymore, if it ever was; and if it does happen
then it's possible that DOTypeNameCompare returns self-inconsistent
comparison results.  That leads to unspecified behavior in qsort()
and a resultant weird output order from pg_dump.

This should end up being only a cosmetic problem, because any ordering
constraints that actually matter should be enforced by the later
dependency-based sort.  Still, it's a bug, so back-patch.

Report and fix by Jacob Champion, though I editorialized on his
patch to the extent of making NULL sort after non-NULL, for consistency
with our usual sorting definitions.

Discussion: https://postgr.es/m/CABAq_6Hw+V-Kj7PNfD5tgOaWT_-qaYkc+SRmJkPLeUjYXLdxwQ@mail.gmail.com

src/bin/pg_dump/pg_dump_sort.c

index d2b0949d6b3eb2083b018eef75b38565c8788ec9..6227a8fd26843452f36c62733bbf6026b95581d3 100644 (file)
@@ -223,7 +223,7 @@ DOTypeNameCompare(const void *p1, const void *p2)
        DumpableObject *obj2 = *(DumpableObject *const *) p2;
        int                     cmpval;
 
-       /* Sort by type */
+       /* Sort by type's priority */
        cmpval = dbObjectTypePriority[obj1->objType] -
                dbObjectTypePriority[obj2->objType];
 
@@ -231,17 +231,24 @@ DOTypeNameCompare(const void *p1, const void *p2)
                return cmpval;
 
        /*
-        * Sort by namespace.  Note that all objects of the same type should
-        * either have or not have a namespace link, so we needn't be fancy about
-        * cases where one link is null and the other not.
+        * Sort by namespace.  Typically, all objects of the same priority would
+        * either have or not have a namespace link, but there are exceptions.
+        * Sort NULL namespace after non-NULL in such cases.
         */
-       if (obj1->namespace && obj2->namespace)
+       if (obj1->namespace)
        {
-               cmpval = strcmp(obj1->namespace->dobj.name,
-                                               obj2->namespace->dobj.name);
-               if (cmpval != 0)
-                       return cmpval;
+               if (obj2->namespace)
+               {
+                       cmpval = strcmp(obj1->namespace->dobj.name,
+                                                       obj2->namespace->dobj.name);
+                       if (cmpval != 0)
+                               return cmpval;
+               }
+               else
+                       return -1;
        }
+       else if (obj2->namespace)
+               return 1;
 
        /* Sort by name */
        cmpval = strcmp(obj1->name, obj2->name);