From 60b450c7e7eec0a0cf585acf9d41644f6a5d794c Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Mon, 30 May 2022 18:25:23 +0700
Subject: [PATCH v1 5/5] Replace qsort's partitioning scheme

Our previous qsort algorithm is described in the 1993 paper "Engineering
a Sort Function". It's solution to the "Dutch national flag problem" for
handling duplicates is to swap elements equal to the pivot to the edges
of the partition, and after partitioning swaps them to the middle. This
has the disadvantage that every element needs to be checked for equality
to the pivot before swapping, which is a wasted cost when there are
no duplicates.

Instead, use the asymetric partitioning scheme from "pattern-defeating
quicksort", described in the 2021 paper with the same name by Orson
Peters. There are two partition functions, "partition right" and
"partition left". Partition right puts elements equal or greater than
the pivot on the right side and is the default method. Partition left is
only used when the sequence follows a previous partition pivot (i.e. is
not the leftmost subsequence) and the current pivot is equal to that
previous pivot. In that case, elements equal to the pivot are swapped
left. Since all elements on the left side are in their proper place,
no further work is needed on the left partition.
---
 src/include/lib/sort_template.h               | 259 ++++++++++++------
 .../modules/test_sort_perf/test_sort_perf.c   |   8 +-
 src/test/regress/expected/create_index.out    |   2 +-
 src/test/regress/expected/groupingsets.out    |  34 +--
 src/test/regress/expected/inet.out            |   4 +-
 src/test/regress/expected/merge.out           |  12 +-
 src/test/regress/expected/sqljson.out         |   4 +-
 src/test/regress/expected/tsrf.out            | 104 +++----
 src/test/regress/expected/tuplesort.out       |   6 +-
 src/test/regress/expected/window.out          | 108 ++++----
 10 files changed, 308 insertions(+), 233 deletions(-)

diff --git a/src/include/lib/sort_template.h b/src/include/lib/sort_template.h
index ed21af297c..cf9794a9fa 100644
--- a/src/include/lib/sort_template.h
+++ b/src/include/lib/sort_template.h
@@ -54,12 +54,10 @@
  *
  * HISTORY
  *
- *	  Modifications from vanilla NetBSD source:
- *	  - Add do ... while() macro fix
- *	  - Remove __inline, _DIAGASSERTs, __P
- *	  - Take care to recurse on the smaller partition, to bound stack usage
- *	  - Convert into a header that can generate specialized functions
- *	  - Add optimization for likely reversed input
+ *	  - 2002: NetBSD qsort based on J. L. Bentley and M. D. McIlroy,
+ *		"Engineering a sort function", SP&E November 1993
+ *	  - 2021: Convert into a header that can generate specialized functions
+ *	  - 2022: Pattern-defeating qsort
  *
  * IDENTIFICATION
  *		src/include/lib/sort_template.h
@@ -67,41 +65,31 @@
  *-------------------------------------------------------------------------
  */
 
-/*	  $NetBSD: qsort.c,v 1.13 2003/08/07 16:43:42 agc Exp $   */
-
-/*-
- * Copyright (c) 1992, 1993
- *	  The Regents of the University of California.  All rights reserved.
+/*
+ * Qsort routine based on Orson R. L. Peters, "Pattern-defeating Quicksort",
+ * arXiv:2106.05123 [cs.DS]
+ *		https://arxiv.org/pdf/2106.05123.pdf
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *	  notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *	  notice, this list of conditions and the following disclaimer in the
- *	  documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *	  may be used to endorse or promote products derived from this software
- *	  without specific prior written permission.
+ * C++ implementation by the paper author:
+ *		https://github.com/orlp/pdqsort
+ * Rust:
+ *		https://docs.rs/pdqsort/1.0.3/src/pdqsort/lib.rs.html
+ * Go:
+ *		https://github.com/golang/go/blob/72e77a7f41bbf45d466119444307fd3ae996e257/src/sort/zsortfunc.go
  *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Qsort routine based on J. L. Bentley and M. D. McIlroy,
- * "Engineering a sort function",
- * Software--Practice and Experience 23 (1993) 1249-1265.
+ * Innovations adapted from Go and/or Rust:
+ * - The coding style for the partition functions and partial sort
+ * - Attempt partial insertion sort on each individual partition after
+ * 		recursion/iteration instead of before, and also speculatively at the
+ *		root level
+ * - Optimization for likely reversed input
+ *
+ * Our implementation differs from the original C++ as follows:
+ * - We retain our previous pivot candidate selection
+ * - No swapping of pivot candidates while computing medians
+ * - No attempt to break up patterns on bad partitions
+ * - No BlockQuicksort optimizations
+ * - No fallback to heap sort
  *
  * We have modified their original by recursing on the smaller partition and iterating on the larger one,
  * which ensures we cannot recurse more than log(N) levels (since the
@@ -190,6 +178,8 @@ ST_SCOPE void ST_SORT(ST_ELEMENT_TYPE * first, size_t n
 /* sort private helper functions */
 #define ST_MED3 ST_MAKE_NAME(ST_SORT, med3)
 #define ST_PARTIAL_INSERTION_SORT ST_MAKE_NAME(ST_SORT, insertion_sort_partial)
+#define ST_PARTITION_LEFT ST_MAKE_NAME(ST_SORT, partition_left)
+#define ST_PARTITION_RIGHT ST_MAKE_NAME(ST_SORT, partition_right)
 #define ST_SORT_INTERNAL ST_MAKE_NAME(ST_SORT, internal)
 #define ST_SWAP ST_MAKE_NAME(ST_SORT, swap)
 #define ST_SWAPN ST_MAKE_NAME(ST_SORT, swapn)
@@ -221,8 +211,18 @@ ST_SCOPE void ST_SORT(ST_ELEMENT_TYPE * first, size_t n
 			ST_SORT_INVOKE_ELEMENT_SIZE									\
 			ST_SORT_INVOKE_COMPARE										\
 			ST_SORT_INVOKE_ARG)
-#define DO_SORT(a_, n_, bal_, ap_)										\
-	ST_SORT_INTERNAL((a_), (n_), (bal_), (ap_)							\
+#define DO_PARTITION_LEFT(begin_, end_)									\
+	ST_PARTITION_LEFT((begin_), (end_)									\
+			ST_SORT_INVOKE_ELEMENT_SIZE									\
+			ST_SORT_INVOKE_COMPARE										\
+			ST_SORT_INVOKE_ARG)
+#define DO_PARTITION_RIGHT(begin_, end_, ap_)							\
+	ST_PARTITION_RIGHT((begin_), (end_), (ap_)							\
+			ST_SORT_INVOKE_ELEMENT_SIZE									\
+			ST_SORT_INVOKE_COMPARE										\
+			ST_SORT_INVOKE_ARG)
+#define DO_SORT(a_, n_, l_, bal_, ap_)									\
+	ST_SORT_INTERNAL((a_), (n_), (l_), (bal_), (ap_)					\
 			ST_SORT_INVOKE_ELEMENT_SIZE									\
 			ST_SORT_INVOKE_COMPARE										\
 			ST_SORT_INVOKE_ARG)
@@ -365,11 +365,110 @@ ST_PARTIAL_INSERTION_SORT(ST_POINTER_TYPE * begin, size_t n
 	return false;
 }
 
+// Partitions [begin, end) around pivot *begin. Elements equal
+// to the pivot are put in the right-hand partition. Returns the position of the pivot after
+// partitioning and whether the passed sequence was already correctly partitioned. Assumes the
+// pivot is a median of at least 3 elements and that [begin, end) is at least
+// insertion_sort_threshold long.
+static inline ST_POINTER_TYPE *
+ST_PARTITION_RIGHT(ST_POINTER_TYPE * begin,
+				  ST_POINTER_TYPE * end,
+				  bool * already_partitioned
+				  ST_SORT_PROTO_ELEMENT_SIZE
+				  ST_SORT_PROTO_COMPARE
+				  ST_SORT_PROTO_ARG)
+{
+	// first and last are inclusive of the elements remaining to be partitioned
+	ST_POINTER_TYPE *pivot = begin;
+	ST_POINTER_TYPE *first = begin + ST_POINTER_STEP;
+	ST_POINTER_TYPE *last = end - ST_POINTER_STEP;
+
+	// Find the first element greater than or equal than the pivot
+	// WIP: if we guaranteed median of three during pivot selection, we can remove the guard
+	while (first <= last && DO_COMPARE(first, pivot) < 0)
+		first += ST_POINTER_STEP;
+
+	// Find the first element strictly smaller than the pivot.
+	while (first <= last && !(DO_COMPARE(last, pivot) < 0))
+		last -= ST_POINTER_STEP;
+
+	// If the pointers crossed, the sequence was already correctly partitioned.
+	if (first > last)
+		*already_partitioned = true;
+	else
+	{
+		*already_partitioned = false;
+
+		DO_SWAP(first, last);
+		first += ST_POINTER_STEP;
+		last -= ST_POINTER_STEP;
+
+		// Keep swapping pairs of elements that are on the wrong side of the pivot. Previously
+		// swapped pairs guard the searches, which is why the first iteration is special-cased
+		// above.
+		for (;;)
+		{
+			while (DO_COMPARE(first, pivot) < 0)
+				first += ST_POINTER_STEP;
+
+			while (!(DO_COMPARE(last, pivot) < 0))
+				last -= ST_POINTER_STEP;
+
+			if (first > last)
+				break;
+
+			DO_SWAP(first, last);
+			first += ST_POINTER_STEP;
+			last -= ST_POINTER_STEP;
+			DO_CHECK_FOR_INTERRUPTS();
+		}
+	}
+
+	// Put the pivot in the right place.
+	DO_SWAP(pivot, last);
+	return last;
+}
+
+// Similar to ST_PARTITION_RIGHT, except elements equal to the pivot are put to the left of
+// the pivot, and it doesn't check or return if the passed sequence was already partitioned.
+static inline ST_POINTER_TYPE *
+ST_PARTITION_LEFT(ST_POINTER_TYPE * begin,
+				  ST_POINTER_TYPE * end
+				  ST_SORT_PROTO_ELEMENT_SIZE
+				  ST_SORT_PROTO_COMPARE
+				  ST_SORT_PROTO_ARG)
+{
+	// first and last are inclusive of the elements remaining to be partitioned
+	ST_POINTER_TYPE *pivot = begin;
+	ST_POINTER_TYPE *first = begin + ST_POINTER_STEP;
+	ST_POINTER_TYPE *last = end - ST_POINTER_STEP;
+
+	for (;;)
+	{
+		while (first <= last && !(DO_COMPARE(pivot, first) < 0))
+			first += ST_POINTER_STEP;
+
+		while (first <= last && DO_COMPARE(pivot, last) < 0)
+			last -= ST_POINTER_STEP;
+
+		if (first > last)
+			break;
+
+		DO_SWAP(first, last);
+		first += ST_POINTER_STEP;
+		last -= ST_POINTER_STEP;
+		DO_CHECK_FOR_INTERRUPTS();
+	}
+
+	return first;
+}
+
 /*
  * Workhorse for ST_SORT
  */
 static void
 ST_SORT_INTERNAL(ST_POINTER_TYPE * data, size_t n,
+				 bool leftmost,
 				 bool balanced,
 				 bool already_partitioned
 		ST_SORT_PROTO_ELEMENT_SIZE
@@ -377,10 +476,7 @@ ST_SORT_INTERNAL(ST_POINTER_TYPE * data, size_t n,
 		ST_SORT_PROTO_ARG)
 {
 	ST_POINTER_TYPE *a = data,
-			   *pa,
-			   *pb,
-			   *pc,
-			   *pd,
+			   *pivot_pos,
 			   *pl,
 			   *pm,
 			   *pn;
@@ -388,8 +484,7 @@ ST_SORT_INTERNAL(ST_POINTER_TYPE * data, size_t n,
 				d2,
 				n1,
 				n2;
-	int			r,
-				num_reversed;
+	int			num_reversed;
 
 loop:
 	DO_CHECK_FOR_INTERRUPTS();
@@ -397,7 +492,7 @@ loop:
 	{
 		for (pm = a + ST_POINTER_STEP; pm < a + n * ST_POINTER_STEP;
 			 pm += ST_POINTER_STEP)
-			for (pl = pm; pl > a && DO_COMPARE(pl - ST_POINTER_STEP, pl) > 0;
+			for (pl = pm; pl > a && DO_COMPARE(pl, pl - ST_POINTER_STEP) < 0;
 				 pl -= ST_POINTER_STEP)
 				DO_SWAP(pl, pl - ST_POINTER_STEP);
 		return;
@@ -452,46 +547,23 @@ loop:
 
 	/* put the pivot at the beginning */
 	DO_SWAP(a, pm);
-	pa = pb = a + ST_POINTER_STEP;
-	pc = pd = a + (n - 1) * ST_POINTER_STEP;
-	for (;;)
+
+	// If *(a - 1) is the pivot of a previous partition operation
+	// there is no element in [a, pn) that is smaller than *(a - 1). Then if our
+	// pivot compares equal to *(a - 1) we change strategy, putting equal elements in
+	// the left partition, greater elements in the right partition. We do not have to
+	// recurse on the left partition, since it's sorted (all equal).
+	pn = a + n * ST_POINTER_STEP;
+	if (!leftmost && !(DO_COMPARE(a - ST_POINTER_STEP, a) < 0))
 	{
-		while (pb <= pc && (r = DO_COMPARE(pb, a)) <= 0)
-		{
-			if (r == 0)
-			{
-				DO_SWAP(pa, pb);
-				already_partitioned = false;
-				pa += ST_POINTER_STEP;
-			}
-			pb += ST_POINTER_STEP;
-			DO_CHECK_FOR_INTERRUPTS();
-		}
-		while (pb <= pc && (r = DO_COMPARE(pc, a)) >= 0)
-		{
-			if (r == 0)
-			{
-				DO_SWAP(pc, pd);
-				already_partitioned = false;
-				pd -= ST_POINTER_STEP;
-			}
-			pc -= ST_POINTER_STEP;
-			DO_CHECK_FOR_INTERRUPTS();
-		}
-		if (pb > pc)
-			break;
-		DO_SWAP(pb, pc);
-		already_partitioned = false;
-		pb += ST_POINTER_STEP;
-		pc -= ST_POINTER_STEP;
+		a = DO_PARTITION_LEFT(a, pn);
+		n = (pn - a) / ST_POINTER_STEP;
+		goto loop;
 	}
-	pn = a + n * ST_POINTER_STEP;
-	d1 = Min(pa - a, pb - pa);
-	DO_SWAPN(a, pb - d1, d1);
-	d1 = Min(pd - pc, pn - pd - ST_POINTER_STEP);
-	DO_SWAPN(pb, pn - d1, d1);
-	d1 = pb - pa;
-	d2 = pd - pc;
+
+	pivot_pos = DO_PARTITION_RIGHT(a, pn, &already_partitioned);
+	d1 = pivot_pos - a;
+	d2 = pn - (pivot_pos + ST_POINTER_STEP);
 	n1 = d1 / ST_POINTER_STEP;
 	n2 = d2 / ST_POINTER_STEP;
 	if (d1 <= d2)
@@ -499,13 +571,14 @@ loop:
 		/* Recurse on left partition, then iterate on right partition */
 		balanced = n1 >= n / 8;
 		if (d1 > ST_POINTER_STEP)
-			DO_SORT(a, n1, balanced, already_partitioned);
+			DO_SORT(a, n1, leftmost, balanced, already_partitioned);
 		if (d2 > ST_POINTER_STEP)
 		{
 			/* Iterate rather than recurse to save stack space */
-			/* DO_SORT(pn - d2, n2, ...) */
+			/* DO_SORT(pn - d2, n2, false, ...) */
 			a = pn - d2;
 			n = n2;
+			leftmost = false;
 			goto loop;
 		}
 	}
@@ -514,11 +587,11 @@ loop:
 		/* Recurse on right partition, then iterate on left partition */
 		balanced = n2 >= n / 8;
 		if (d2 > ST_POINTER_STEP)
-			DO_SORT(pn - d2, n2, balanced, already_partitioned);
+			DO_SORT(pn - d2, n2, false, balanced, already_partitioned);
 		if (d1 > ST_POINTER_STEP)
 		{
 			/* Iterate rather than recurse to save stack space */
-			/* DO_SORT(a, n1, ...) */
+			/* DO_SORT(a, n1, leftmost, ...) */
 			n = n1;
 			goto loop;
 		}
@@ -536,7 +609,7 @@ ST_SORT(ST_ELEMENT_TYPE * data, size_t n
 {
 	ST_POINTER_TYPE *begin = (ST_POINTER_TYPE *) data;
 
-	DO_SORT(begin, n, true, true);
+	DO_SORT(begin, n, true, true, true);
 
 #ifdef USE_ASSERT_CHECKING
 	/* WIP: verify the sorting worked */
@@ -554,6 +627,8 @@ ST_SORT(ST_ELEMENT_TYPE * data, size_t n
 #undef DO_COMPARE
 #undef DO_MED3
 #undef DO_PARTIAL_INSERTION_SORT
+#undef DO_PARTITION_LEFT
+#undef DO_PARTITION_RIGHT
 #undef DO_SORT
 #undef DO_SWAP
 #undef DO_SWAPN
@@ -569,6 +644,8 @@ ST_SORT(ST_ELEMENT_TYPE * data, size_t n
 #undef ST_MAKE_PREFIX
 #undef ST_MED3
 #undef ST_PARTIAL_INSERTION_SORT
+#undef ST_PARTITION_LEFT
+#undef ST_PARTITION_RIGHT
 #undef ST_POINTER_STEP
 #undef ST_POINTER_TYPE
 #undef ST_SCOPE
diff --git a/src/test/modules/test_sort_perf/test_sort_perf.c b/src/test/modules/test_sort_perf/test_sort_perf.c
index d162e42049..1e56dfe8b0 100644
--- a/src/test/modules/test_sort_perf/test_sort_perf.c
+++ b/src/test/modules/test_sort_perf/test_sort_perf.c
@@ -21,12 +21,10 @@ btint4fastcmp(const void * x, const void * y)
 	int32		*a = (int32 *) x;
 	int32		*b = (int32 *) y;
 
-	if (*a > *b)
-		return 1;
-	else if (*a == *b)
-		return 0;
-	else
+	if (*a < *b)
 		return -1;
+	else
+		return 1;
 }
 
 // specialized qsort with inlined comparator
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 0a544e7167..e14f269ff9 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -172,8 +172,8 @@ SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
  (10,10)
  (-5,-12)
  (5.1,34.5)
- (Infinity,1e+300)
  (1e+300,Infinity)
+ (Infinity,1e+300)
  (NaN,NaN)
  
 (11 rows)
diff --git a/src/test/regress/expected/groupingsets.out b/src/test/regress/expected/groupingsets.out
index fcad5c4093..5c2605c280 100644
--- a/src/test/regress/expected/groupingsets.out
+++ b/src/test/regress/expected/groupingsets.out
@@ -1938,21 +1938,21 @@ set jit_above_cost = 0;
 explain (costs off)
 select g100, g10, sum(g::numeric), count(*), max(g::text)
 from gs_data_1 group by cube (g1000, g100,g10);
-             QUERY PLAN             
-------------------------------------
+            QUERY PLAN             
+-----------------------------------
  GroupAggregate
-   Group Key: g1000, g100, g10
-   Group Key: g1000, g100
-   Group Key: g1000
+   Group Key: g10, g100
+   Group Key: g10
    Group Key: ()
-   Sort Key: g100, g10
-     Group Key: g100, g10
+   Sort Key: g100, g1000, g10
+     Group Key: g100, g1000, g10
+     Group Key: g100, g1000
      Group Key: g100
-   Sort Key: g10, g1000
-     Group Key: g10, g1000
-     Group Key: g10
+   Sort Key: g1000, g10
+     Group Key: g1000, g10
+     Group Key: g1000
    ->  Sort
-         Sort Key: g1000, g100, g10
+         Sort Key: g10, g100
          ->  Seq Scan on gs_data_1
 (14 rows)
 
@@ -1968,13 +1968,13 @@ from gs_data_1 group by cube (g1000, g100,g10);
           QUERY PLAN          
 ------------------------------
  MixedAggregate
-   Hash Key: g1000, g100, g10
-   Hash Key: g1000, g100
-   Hash Key: g1000
-   Hash Key: g100, g10
-   Hash Key: g100
-   Hash Key: g10, g1000
+   Hash Key: g10, g100
    Hash Key: g10
+   Hash Key: g100, g1000, g10
+   Hash Key: g100, g1000
+   Hash Key: g100
+   Hash Key: g1000, g10
+   Hash Key: g1000
    Group Key: ()
    ->  Seq Scan on gs_data_1
 (10 rows)
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index d5bf9e2aaa..0885578584 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -390,9 +390,9 @@ SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i;
       c      |      i      
 -------------+-------------
  10.0.0.0/8  | 9.1.2.3/8
- 10.0.0.0/32 | 10.1.2.3/8
  10.0.0.0/8  | 10.1.2.3/8
  10.0.0.0/8  | 10.1.2.3/8
+ 10.0.0.0/32 | 10.1.2.3/8
  10.1.0.0/16 | 10.1.2.3/16
  10.1.2.0/24 | 10.1.2.3/24
  10.1.2.3/32 | 10.1.2.3
@@ -538,9 +538,9 @@ SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i;
       c      |      i      
 -------------+-------------
  10.0.0.0/8  | 9.1.2.3/8
- 10.0.0.0/32 | 10.1.2.3/8
  10.0.0.0/8  | 10.1.2.3/8
  10.0.0.0/8  | 10.1.2.3/8
+ 10.0.0.0/32 | 10.1.2.3/8
  10.1.0.0/16 | 10.1.2.3/16
  10.1.2.0/24 | 10.1.2.3/24
  10.1.2.3/32 | 10.1.2.3
diff --git a/src/test/regress/expected/merge.out b/src/test/regress/expected/merge.out
index af670e28e7..cda5e375c3 100644
--- a/src/test/regress/expected/merge.out
+++ b/src/test/regress/expected/merge.out
@@ -1554,14 +1554,14 @@ SELECT * FROM pa_target ORDER BY tid;
    5 |     500 | initial
    5 |      50 | inserted by merge
    6 |      60 | inserted by merge
-   7 |     700 | initial
    7 |      70 | inserted by merge
+   7 |     700 | initial
    8 |      80 | inserted by merge
    9 |      90 | inserted by merge
    9 |     900 | initial
   10 |     100 | inserted by merge
-  11 |    1100 | initial
   11 |     110 | inserted by merge
+  11 |    1100 | initial
   12 |     120 | inserted by merge
   13 |    1300 | initial
   13 |     130 | inserted by merge
@@ -1583,8 +1583,8 @@ SELECT * FROM pa_target ORDER BY tid;
 -----+---------+--------------------------
    2 |     110 | initial updated by merge
    2 |      20 | inserted by merge
-   4 |      40 | inserted by merge
    4 |     330 | initial updated by merge
+   4 |      40 | inserted by merge
    6 |     550 | initial updated by merge
    6 |      60 | inserted by merge
    8 |      80 | inserted by merge
@@ -1665,11 +1665,11 @@ SELECT * FROM pa_target ORDER BY tid;
    7 |     700 | initial
    7 |      70 | inserted by merge
    8 |      80 | inserted by merge
-   9 |     900 | initial
    9 |      90 | inserted by merge
+   9 |     900 | initial
   10 |     100 | inserted by merge
-  11 |     110 | inserted by merge
   11 |    1100 | initial
+  11 |     110 | inserted by merge
   12 |     120 | inserted by merge
   13 |    1300 | initial
   13 |     130 | inserted by merge
@@ -1691,8 +1691,8 @@ SELECT * FROM pa_target ORDER BY tid;
 -----+---------+--------------------------
    2 |     110 | initial updated by merge
    2 |      20 | inserted by merge
-   4 |      40 | inserted by merge
    4 |     330 | initial updated by merge
+   4 |      40 | inserted by merge
    6 |     550 | initial updated by merge
    6 |      60 | inserted by merge
    8 |      80 | inserted by merge
diff --git a/src/test/regress/expected/sqljson.out b/src/test/regress/expected/sqljson.out
index 0883261535..224fc30e8a 100644
--- a/src/test/regress/expected/sqljson.out
+++ b/src/test/regress/expected/sqljson.out
@@ -873,12 +873,12 @@ FROM
 	(VALUES (NULL), (3), (1), (NULL), (NULL), (5), (2), (4), (NULL), (5), (4)) foo(bar);
  bar | json_arrayagg 
 -----+---------------
+   2 | [4, 4]
    4 | [4, 4]
    4 | [4, 4]
-   2 | [4, 4]
    5 | [5, 3, 5]
-   3 | [5, 3, 5]
    1 | [5, 3, 5]
+   3 | [5, 3, 5]
    5 | [5, 3, 5]
      | 
      | 
diff --git a/src/test/regress/expected/tsrf.out b/src/test/regress/expected/tsrf.out
index ef3bd4f539..e76ddd11cd 100644
--- a/src/test/regress/expected/tsrf.out
+++ b/src/test/regress/expected/tsrf.out
@@ -349,108 +349,108 @@ SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(d
  dataa |  b  | g | count 
 -------+-----+---+-------
  b     |     | 1 |     1
- a     | foo | 1 |     1
  a     |     | 1 |     2
- b     | bar | 1 |     1
+ a     | foo | 1 |     1
+       | foo | 1 |     1
  a     | bar | 1 |     1
-       |     | 1 |     3
        | bar | 1 |     2
-       | foo | 1 |     1
-       | bar | 2 |     2
+ b     | bar | 1 |     1
+       |     | 1 |     3
  a     | bar | 2 |     1
+ a     |     | 2 |     2
+ b     | bar | 2 |     1
+       |     | 2 |     3
  b     |     | 2 |     1
+       | bar | 2 |     2
  a     | foo | 2 |     1
        | foo | 2 |     1
- a     |     | 2 |     2
-       |     | 2 |     3
- b     | bar | 2 |     1
 (16 rows)
 
 SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g);
  dataa |  b  | g | count 
 -------+-----+---+-------
+       | bar | 1 |     2
+       | foo | 1 |     1
+       |     | 1 |     3
+       | bar | 2 |     2
+       | foo | 2 |     1
+       |     | 2 |     3
+       |     |   |     6
  a     | bar | 1 |     1
  a     | bar | 2 |     1
  a     | bar |   |     2
- a     | foo | 1 |     1
- a     | foo | 2 |     1
- a     | foo |   |     2
- a     |     |   |     4
  b     | bar | 1 |     1
  b     | bar | 2 |     1
  b     | bar |   |     2
- b     |     |   |     2
-       |     |   |     6
-       | bar | 1 |     2
-       | bar | 2 |     2
        | bar |   |     4
-       | foo | 1 |     1
-       | foo | 2 |     1
+ a     | foo | 1 |     1
+ a     | foo | 2 |     1
+ a     | foo |   |     2
        | foo |   |     2
  a     |     | 1 |     2
- b     |     | 1 |     1
-       |     | 1 |     3
  a     |     | 2 |     2
+ a     |     |   |     4
+ b     |     | 1 |     1
  b     |     | 2 |     1
-       |     | 2 |     3
+ b     |     |   |     2
 (24 rows)
 
 SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g) ORDER BY dataa;
  dataa |  b  | g | count 
 -------+-----+---+-------
- a     | foo | 1 |     1
  a     | foo |   |     2
- a     |     |   |     4
- a     |     | 1 |     2
+ a     | foo | 2 |     1
  a     |     | 2 |     2
- a     | bar | 2 |     1
- a     | bar | 1 |     1
+ a     |     | 1 |     2
  a     | bar |   |     2
- a     | foo | 2 |     1
- b     | bar |   |     2
- b     |     | 1 |     1
- b     | bar | 1 |     1
+ a     |     |   |     4
+ a     | foo | 1 |     1
+ a     | bar | 1 |     1
+ a     | bar | 2 |     1
  b     |     |   |     2
- b     |     | 2 |     1
+ b     | bar | 1 |     1
  b     | bar | 2 |     1
-       | bar | 1 |     2
-       |     |   |     6
-       | bar | 2 |     2
-       | bar |   |     4
-       | foo | 1 |     1
-       | foo | 2 |     1
+ b     | bar |   |     2
+ b     |     | 2 |     1
+ b     |     | 1 |     1
        | foo |   |     2
-       |     | 1 |     3
+       | foo | 1 |     1
        |     | 2 |     3
+       | bar | 2 |     2
+       |     | 1 |     3
+       | foo | 2 |     1
+       |     |   |     6
+       | bar |   |     4
+       | bar | 1 |     2
 (24 rows)
 
 SELECT dataa, datab b, generate_series(1,2) g, count(*) FROM few GROUP BY CUBE(dataa, datab, g) ORDER BY g;
  dataa |  b  | g | count 
 -------+-----+---+-------
        | bar | 1 |     2
+ a     |     | 1 |     2
+       |     | 1 |     3
  a     | foo | 1 |     1
- b     | bar | 1 |     1
- a     | bar | 1 |     1
        | foo | 1 |     1
- a     |     | 1 |     2
+ b     | bar | 1 |     1
  b     |     | 1 |     1
-       |     | 1 |     3
+ a     | bar | 1 |     1
+ a     | bar | 2 |     1
        | foo | 2 |     1
- b     |     | 2 |     1
-       | bar | 2 |     2
        |     | 2 |     3
  b     | bar | 2 |     1
- a     | bar | 2 |     1
- a     | foo | 2 |     1
+ b     |     | 2 |     1
  a     |     | 2 |     2
- a     | foo |   |     2
+       | bar | 2 |     2
+ a     | foo | 2 |     1
  b     | bar |   |     2
- b     |     |   |     2
-       |     |   |     6
  a     |     |   |     4
- a     | bar |   |     2
+ a     | foo |   |     2
        | bar |   |     4
        | foo |   |     2
+ a     | bar |   |     2
+       |     |   |     6
+ b     |     |   |     2
 (24 rows)
 
 reset enable_hashagg;
@@ -598,8 +598,8 @@ FROM (VALUES (3, 2), (3,1), (1,1), (1,4), (5,3), (5,1)) AS t(a, b);
  a | b | g 
 ---+---+---
  1 | 4 | 1
- 5 | 1 | 2
- 5 | 3 | 3
+ 3 | 2 | 2
+ 1 | 4 | 3
 (3 rows)
 
 -- LIMIT / OFFSET is evaluated after SRF evaluation
diff --git a/src/test/regress/expected/tuplesort.out b/src/test/regress/expected/tuplesort.out
index 4bdd466a09..8b9f64fa65 100644
--- a/src/test/regress/expected/tuplesort.out
+++ b/src/test/regress/expected/tuplesort.out
@@ -260,8 +260,8 @@ FROM abbrev_abort_uuids
 ORDER BY ctid LIMIT 5;
   id   |           abort_increasing           |           abort_decreasing           |          noabort_increasing          |          noabort_decreasing          
 -------+--------------------------------------+--------------------------------------+--------------------------------------+--------------------------------------
- 20001 | 00000000-0000-0000-0000-000000020000 | 00000000-0000-0000-0000-000000000000 | 00009991-0000-0000-0000-000000020000 | 00000000-0000-0000-0000-000000000000
  20010 | 00000000-0000-0000-0000-000000020000 | 00000000-0000-0000-0000-000000000000 | 00009991-0000-0000-0000-000000020000 | 00000000-0000-0000-0000-000000000000
+ 20001 | 00000000-0000-0000-0000-000000020000 | 00000000-0000-0000-0000-000000000000 | 00009991-0000-0000-0000-000000020000 | 00000000-0000-0000-0000-000000000000
  20000 | 00000000-0000-0000-0000-000000019999 | 00000000-0000-0000-0000-000000000001 | 00009990-0000-0000-0000-000000019999 | 00000001-0000-0000-0000-000000000001
  19999 | 00000000-0000-0000-0000-000000019998 | 00000000-0000-0000-0000-000000000002 | 00009989-0000-0000-0000-000000019998 | 00000002-0000-0000-0000-000000000002
  20009 | 00000000-0000-0000-0000-000000019997 | 00000000-0000-0000-0000-000000000003 | 00009988-0000-0000-0000-000000019997 | 00000003-0000-0000-0000-000000000003
@@ -304,8 +304,8 @@ FROM abbrev_abort_uuids
 ORDER BY ctid DESC LIMIT 5;
   id   |           abort_increasing           |           abort_decreasing           |          noabort_increasing          |          noabort_decreasing          
 -------+--------------------------------------+--------------------------------------+--------------------------------------+--------------------------------------
-     0 |                                      |                                      |                                      | 
  20002 |                                      |                                      |                                      | 
+     0 |                                      |                                      |                                      | 
  20003 |                                      |                                      |                                      | 
  10009 | 00000000-0000-0000-0000-000000010008 | 00000000-0000-0000-0000-000000009992 | 00010008-0000-0000-0000-000000010008 | 00009992-0000-0000-0000-000000009992
  10008 | 00000000-0000-0000-0000-000000010007 | 00000000-0000-0000-0000-000000009993 | 00010007-0000-0000-0000-000000010007 | 00009993-0000-0000-0000-000000009993
@@ -335,8 +335,8 @@ FROM abbrev_abort_uuids
 ORDER BY ctid DESC LIMIT 5;
   id   |           abort_increasing           |           abort_decreasing           |          noabort_increasing          |          noabort_decreasing          
 -------+--------------------------------------+--------------------------------------+--------------------------------------+--------------------------------------
-     0 |                                      |                                      |                                      | 
  20003 |                                      |                                      |                                      | 
+     0 |                                      |                                      |                                      | 
  20002 |                                      |                                      |                                      | 
   9993 | 00000000-0000-0000-0000-000000009992 | 00000000-0000-0000-0000-000000010008 | 00009992-0000-0000-0000-000000009992 | 00010008-0000-0000-0000-000000010008
   9994 | 00000000-0000-0000-0000-000000009993 | 00000000-0000-0000-0000-000000010007 | 00009993-0000-0000-0000-000000009993 | 00010007-0000-0000-0000-000000010007
diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out
index c4fc72df93..81f1d250da 100644
--- a/src/test/regress/expected/window.out
+++ b/src/test/regress/expected/window.out
@@ -23,13 +23,13 @@ SELECT depname, empno, salary, sum(salary) OVER (PARTITION BY depname) FROM emps
 -----------+-------+--------+-------
  develop   |     7 |   4200 | 25100
  develop   |     9 |   4500 | 25100
- develop   |    10 |   5200 | 25100
  develop   |    11 |   5200 | 25100
+ develop   |    10 |   5200 | 25100
  develop   |     8 |   6000 | 25100
  personnel |     5 |   3500 |  7400
  personnel |     2 |   3900 |  7400
- sales     |     3 |   4800 | 14600
  sales     |     4 |   4800 | 14600
+ sales     |     3 |   4800 | 14600
  sales     |     1 |   5000 | 14600
 (10 rows)
 
@@ -43,8 +43,8 @@ SELECT depname, empno, salary, rank() OVER (PARTITION BY depname ORDER BY salary
  develop   |     8 |   6000 |    5
  personnel |     5 |   3500 |    1
  personnel |     2 |   3900 |    2
- sales     |     3 |   4800 |    1
  sales     |     4 |   4800 |    1
+ sales     |     3 |   4800 |    1
  sales     |     1 |   5000 |    3
 (10 rows)
 
@@ -79,15 +79,15 @@ SELECT depname, empno, salary, sum(salary) OVER w FROM empsalary WINDOW w AS (PA
   depname  | empno | salary |  sum  
 -----------+-------+--------+-------
  develop   |     7 |   4200 | 25100
- develop   |    10 |   5200 | 25100
- develop   |     9 |   4500 | 25100
- develop   |     8 |   6000 | 25100
  develop   |    11 |   5200 | 25100
- personnel |     5 |   3500 |  7400
+ develop   |     8 |   6000 | 25100
+ develop   |     9 |   4500 | 25100
+ develop   |    10 |   5200 | 25100
  personnel |     2 |   3900 |  7400
+ personnel |     5 |   3500 |  7400
+ sales     |     4 |   4800 | 14600
  sales     |     3 |   4800 | 14600
  sales     |     1 |   5000 | 14600
- sales     |     4 |   4800 | 14600
 (10 rows)
 
 SELECT depname, empno, salary, rank() OVER w FROM empsalary WINDOW w AS (PARTITION BY depname ORDER BY salary) ORDER BY rank() OVER w;
@@ -97,11 +97,11 @@ SELECT depname, empno, salary, rank() OVER w FROM empsalary WINDOW w AS (PARTITI
  develop   |     7 |   4200 |    1
  sales     |     3 |   4800 |    1
  sales     |     4 |   4800 |    1
- personnel |     2 |   3900 |    2
  develop   |     9 |   4500 |    2
- sales     |     1 |   5000 |    3
- develop   |    10 |   5200 |    3
+ personnel |     2 |   3900 |    2
  develop   |    11 |   5200 |    3
+ develop   |    10 |   5200 |    3
+ sales     |     1 |   5000 |    3
  develop   |     8 |   6000 |    5
 (10 rows)
 
@@ -804,8 +804,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   45 |       8 |    0
-  45 |       4 |    0
   45 |       0 |    0
+  45 |       4 |    0
   33 |       5 |    1
   33 |       9 |    1
   33 |       1 |    1
@@ -922,9 +922,9 @@ SELECT first_value(unique1) over (ORDER BY four rows between current row and 2 f
 FROM tenk1 WHERE unique1 < 10;
  first_value | unique1 | four 
 -------------+---------+------
-           4 |       8 |    0
-           0 |       4 |    0
-           5 |       0 |    0
+           0 |       8 |    0
+           4 |       0 |    0
+           5 |       4 |    0
            9 |       5 |    1
            1 |       9 |    1
            6 |       1 |    1
@@ -940,8 +940,8 @@ FROM tenk1 WHERE unique1 < 10;
  first_value | unique1 | four 
 -------------+---------+------
              |       8 |    0
-           5 |       4 |    0
            5 |       0 |    0
+           5 |       4 |    0
              |       5 |    1
            6 |       9 |    1
            6 |       1 |    1
@@ -957,8 +957,8 @@ FROM tenk1 WHERE unique1 < 10;
  first_value | unique1 | four 
 -------------+---------+------
            8 |       8 |    0
-           4 |       4 |    0
            0 |       0 |    0
+           4 |       4 |    0
            5 |       5 |    1
            9 |       9 |    1
            1 |       1 |    1
@@ -973,9 +973,9 @@ SELECT last_value(unique1) over (ORDER BY four rows between current row and 2 fo
 FROM tenk1 WHERE unique1 < 10;
  last_value | unique1 | four 
 ------------+---------+------
-          0 |       8 |    0
-          5 |       4 |    0
-          9 |       0 |    0
+          4 |       8 |    0
+          5 |       0 |    0
+          9 |       4 |    0
           1 |       5 |    1
           6 |       9 |    1
           2 |       1 |    1
@@ -991,8 +991,8 @@ FROM tenk1 WHERE unique1 < 10;
  last_value | unique1 | four 
 ------------+---------+------
             |       8 |    0
-          5 |       4 |    0
-          9 |       0 |    0
+          5 |       0 |    0
+          9 |       4 |    0
             |       5 |    1
           6 |       9 |    1
           2 |       1 |    1
@@ -1008,8 +1008,8 @@ FROM tenk1 WHERE unique1 < 10;
  last_value | unique1 | four 
 ------------+---------+------
           8 |       8 |    0
-          5 |       4 |    0
-          9 |       0 |    0
+          5 |       0 |    0
+          9 |       4 |    0
           5 |       5 |    1
           6 |       9 |    1
           2 |       1 |    1
@@ -1076,8 +1076,8 @@ FROM tenk1 WHERE unique1 < 10 WINDOW w AS (order by four);
  sum | unique1 | four 
 -----+---------+------
   45 |       8 |    0
-  45 |       4 |    0
   45 |       0 |    0
+  45 |       4 |    0
   33 |       5 |    1
   33 |       9 |    1
   33 |       1 |    1
@@ -1093,8 +1093,8 @@ FROM tenk1 WHERE unique1 < 10 WINDOW w AS (order by four);
  sum | unique1 | four 
 -----+---------+------
    4 |       8 |    0
-   8 |       4 |    0
   12 |       0 |    0
+   8 |       4 |    0
   22 |       5 |    1
   18 |       9 |    1
   26 |       1 |    1
@@ -1110,8 +1110,8 @@ FROM tenk1 WHERE unique1 < 10 WINDOW w AS (order by four);
  sum | unique1 | four 
 -----+---------+------
      |       8 |    0
-     |       4 |    0
      |       0 |    0
+     |       4 |    0
   12 |       5 |    1
   12 |       9 |    1
   12 |       1 |    1
@@ -1127,8 +1127,8 @@ FROM tenk1 WHERE unique1 < 10 WINDOW w AS (order by four);
  sum | unique1 | four 
 -----+---------+------
    8 |       8 |    0
-   4 |       4 |    0
    0 |       0 |    0
+   4 |       4 |    0
   17 |       5 |    1
   21 |       9 |    1
   13 |       1 |    1
@@ -1145,9 +1145,9 @@ FROM tenk1 WHERE unique1 < 10
 WINDOW w AS (order by four range between current row and unbounded following);
  first_value | nth_2 | last_value | unique1 | four 
 -------------+-------+------------+---------+------
-           8 |     4 |          7 |       8 |    0
-           8 |     4 |          7 |       4 |    0
-           8 |     4 |          7 |       0 |    0
+           8 |     0 |          7 |       8 |    0
+           8 |     0 |          7 |       0 |    0
+           8 |     0 |          7 |       4 |    0
            5 |     9 |          7 |       5 |    1
            5 |     9 |          7 |       9 |    1
            5 |     9 |          7 |       1 |    1
@@ -1350,8 +1350,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
      |       8 |    0
-     |       4 |    0
      |       0 |    0
+     |       4 |    0
   12 |       5 |    1
   12 |       9 |    1
   12 |       1 |    1
@@ -1370,9 +1370,9 @@ FROM tenk1 WHERE unique1 < 10;
      |       7 |    3
   10 |       6 |    2
   10 |       2 |    2
+  18 |       1 |    1
   18 |       9 |    1
   18 |       5 |    1
-  18 |       1 |    1
   23 |       8 |    0
   23 |       4 |    0
   23 |       0 |    0
@@ -1384,8 +1384,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
      |       8 |    0
-     |       4 |    0
      |       0 |    0
+     |       4 |    0
   12 |       5 |    1
   12 |       9 |    1
   12 |       1 |    1
@@ -1401,8 +1401,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
      |       8 |    0
-     |       4 |    0
      |       0 |    0
+     |       4 |    0
   12 |       5 |    1
   12 |       9 |    1
   12 |       1 |    1
@@ -1418,8 +1418,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
      |       8 |    0
-     |       4 |    0
      |       0 |    0
+     |       4 |    0
   12 |       5 |    1
   12 |       9 |    1
   12 |       1 |    1
@@ -1435,8 +1435,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
      |       8 |    0
-     |       4 |    0
      |       0 |    0
+     |       4 |    0
   12 |       5 |    1
   12 |       9 |    1
   12 |       1 |    1
@@ -1452,8 +1452,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   41 |       8 |    0
-  37 |       4 |    0
   33 |       0 |    0
+  37 |       4 |    0
   35 |       5 |    1
   39 |       9 |    1
   31 |       1 |    1
@@ -1469,8 +1469,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   33 |       8 |    0
-  33 |       4 |    0
   33 |       0 |    0
+  33 |       4 |    0
   30 |       5 |    1
   30 |       9 |    1
   30 |       1 |    1
@@ -2589,8 +2589,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   12 |       8 |    0
-  12 |       4 |    0
   12 |       0 |    0
+  12 |       4 |    0
   27 |       5 |    1
   27 |       9 |    1
   27 |       1 |    1
@@ -2606,8 +2606,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   45 |       8 |    0
-  45 |       4 |    0
   45 |       0 |    0
+  45 |       4 |    0
   45 |       5 |    1
   45 |       9 |    1
   45 |       1 |    1
@@ -2623,8 +2623,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   45 |       8 |    0
-  45 |       4 |    0
   45 |       0 |    0
+  45 |       4 |    0
   33 |       5 |    1
   33 |       9 |    1
   33 |       1 |    1
@@ -2640,8 +2640,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   45 |       8 |    0
-  45 |       4 |    0
   45 |       0 |    0
+  45 |       4 |    0
   45 |       5 |    1
   45 |       9 |    1
   45 |       1 |    1
@@ -2657,8 +2657,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   33 |       8 |    0
-  33 |       4 |    0
   33 |       0 |    0
+  33 |       4 |    0
   18 |       5 |    1
   18 |       9 |    1
   18 |       1 |    1
@@ -2674,8 +2674,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   35 |       8 |    0
-  35 |       4 |    0
   35 |       0 |    0
+  35 |       4 |    0
   45 |       5 |    1
   45 |       9 |    1
   45 |       1 |    1
@@ -2691,8 +2691,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
      |       8 |    0
-     |       4 |    0
      |       0 |    0
+     |       4 |    0
   12 |       5 |    1
   12 |       9 |    1
   12 |       1 |    1
@@ -2708,8 +2708,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   27 |       8 |    0
-  27 |       4 |    0
   27 |       0 |    0
+  27 |       4 |    0
   35 |       5 |    1
   35 |       9 |    1
   35 |       1 |    1
@@ -2725,8 +2725,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   12 |       8 |    0
-  12 |       4 |    0
   12 |       0 |    0
+  12 |       4 |    0
   15 |       5 |    1
   15 |       9 |    1
   15 |       1 |    1
@@ -2742,8 +2742,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   19 |       8 |    0
-  23 |       4 |    0
   27 |       0 |    0
+  23 |       4 |    0
   30 |       5 |    1
   26 |       9 |    1
   34 |       1 |    1
@@ -2759,8 +2759,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   15 |       8 |    0
-  15 |       4 |    0
   15 |       0 |    0
+  15 |       4 |    0
   20 |       5 |    1
   20 |       9 |    1
   20 |       1 |    1
@@ -2776,8 +2776,8 @@ FROM tenk1 WHERE unique1 < 10;
  sum | unique1 | four 
 -----+---------+------
   23 |       8 |    0
-  19 |       4 |    0
   15 |       0 |    0
+  19 |       4 |    0
   25 |       5 |    1
   29 |       9 |    1
   21 |       1 |    1
@@ -3642,8 +3642,8 @@ WHERE c <= 3;
      2 | personnel |   3900 | 1
      5 | personnel |   3500 | 2
      1 | sales     |   5000 | 1
-     4 | sales     |   4800 | 3
      3 | sales     |   4800 | 3
+     4 | sales     |   4800 | 3
 (8 rows)
 
 -- Some more complex cases with multiple window clauses
@@ -3685,8 +3685,8 @@ SELECT * FROM
 ) e WHERE rn <= 1 AND c1 <= 3;
   depname  | empno | salary | enroll_date | c1 | rn | c2 | c3 
 -----------+-------+--------+-------------+----+----+----+----
- personnel |     5 |   3500 | 12-10-2007  |  2 |  1 |  2 |  2
- sales     |     3 |   4800 | 08-01-2007  |  3 |  1 |  3 |  3
+ personnel |     2 |   3900 | 12-23-2006  |  2 |  1 |  2 |  2
+ sales     |     4 |   4800 | 08-08-2007  |  3 |  1 |  3 |  3
 (2 rows)
 
 -- Tests to ensure we don't push down the run condition when it's not valid to
-- 
2.36.1

