Ensure pg_dump_sort.c sorts null vs non-null namespace consistently.

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
This commit is contained in:
Tom Lane 2018-08-07 13:13:42 -04:00
parent e0ee930539
commit 5b5ed4756c
1 changed files with 16 additions and 9 deletions

View 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);