Fix tuplecmp() to ensure repeatable sort ordering of tuples
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 10 Jul 1999 18:21:59 +0000 (18:21 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 10 Jul 1999 18:21:59 +0000 (18:21 +0000)
that contain null fields.  Old code would produce erratic sort results
because comparisons of tuples containing nulls could produce inconsistent
answers.

src/backend/utils/sort/lselect.c

index 76c1b8158c1c7c41474667affbc02b4c8ab2ac90..965a48e3cd2a95c87f594a2dc7cbdd8e0d3f7c55 100644 (file)
@@ -186,41 +186,49 @@ puttuple(struct leftist ** treep,
 int
 tuplecmp(HeapTuple ltup, HeapTuple rtup, LeftistContext context)
 {
-       Datum           lattr,
-                               rattr;
-       int                     nkey = 0;
+       int                     nkey;
        int                     result = 0;
-       bool            isnull;
 
        if (ltup == (HeapTuple) NULL)
                return 0;
        if (rtup == (HeapTuple) NULL)
                return 1;
-       while (nkey < context->nKeys && !result)
+       for (nkey = 0; nkey < context->nKeys; nkey++)
        {
-               lattr = heap_getattr(ltup,
-                                                        context->scanKeys[nkey].sk_attno,
-                                                        context->tupDesc, &isnull);
-               if (isnull)
-                       return 0;
-               rattr = heap_getattr(rtup,
-                                                        context->scanKeys[nkey].sk_attno,
-                                                        context->tupDesc,
-                                                        &isnull);
-               if (isnull)
+               ScanKey         thisKey = & context->scanKeys[nkey];
+               Datum           lattr,
+                                       rattr;
+               bool            lisnull,
+                                       risnull;
+
+               lattr = heap_getattr(ltup, thisKey->sk_attno,
+                                                        context->tupDesc, &lisnull);
+               rattr = heap_getattr(rtup, thisKey->sk_attno,
+                                                        context->tupDesc, &risnull);
+               if (lisnull)
+               {
+                       if (risnull)
+                               continue;               /* treat two nulls as equal */
+                       return 0;                       /* else, a null sorts after all else */
+               }
+               if (risnull)
                        return 1;
-               if (context->scanKeys[nkey].sk_flags & SK_COMMUTE)
+               if (thisKey->sk_flags & SK_COMMUTE)
+               {
+                       if (!(result =
+                                 (long) (*fmgr_faddr(&thisKey->sk_func)) (rattr, lattr)))
+                               result =
+                                       -(long) (*fmgr_faddr(&thisKey->sk_func)) (lattr, rattr);
+               }
+               else
                {
                        if (!(result =
-                                 (long) (*fmgr_faddr(&context->scanKeys[nkey].sk_func)) (rattr, lattr)))
+                                 (long) (*fmgr_faddr(&thisKey->sk_func)) (lattr, rattr)))
                                result =
-                                       -(long) (*fmgr_faddr(&context->scanKeys[nkey].sk_func)) (lattr, rattr);
+                                       -(long) (*fmgr_faddr(&thisKey->sk_func)) (rattr, lattr);
                }
-               else if (!(result =
-                                  (long) (*fmgr_faddr(&context->scanKeys[nkey].sk_func)) (lattr, rattr)))
-                       result =
-                               -(long) (*fmgr_faddr(&context->scanKeys[nkey].sk_func)) (rattr, lattr);
-               nkey++;
+               if (result)
+                       break;
        }
        return result == 1;
 }