@@ -219,6 +219,8 @@ struct Tuplesortstate
219219 * tuples to return? */
220220 bool boundUsed ; /* true if we made use of a bounded heap */
221221 int bound ; /* if bounded, the maximum number of tuples */
222+ int prefix ; /* number of prefix keys by which input data is already sorted */
223+ int matchedKeys ; /* number of matched keys */
222224 int64 availMem ; /* remaining memory available, in bytes */
223225 int64 allowedMem ; /* total memory allowed, in bytes */
224226 int maxTapes ; /* number of tapes (Knuth's T) */
@@ -458,7 +460,7 @@ struct Tuplesortstate
458460
459461
460462static Tuplesortstate * tuplesort_begin_common (int workMem , bool randomAccess );
461- static void puttuple_common (Tuplesortstate * state , SortTuple * tuple );
463+ static bool puttuple_common (Tuplesortstate * state , SortTuple * tuple );
462464static bool consider_abort_common (Tuplesortstate * state );
463465static void inittapes (Tuplesortstate * state );
464466static void selectnewtape (Tuplesortstate * state );
@@ -575,7 +577,7 @@ tuplesort_begin_common(int workMem, bool randomAccess)
575577 state -> availMem = state -> allowedMem ;
576578 state -> sortcontext = sortcontext ;
577579 state -> tapeset = NULL ;
578-
580+ state -> prefix = 0 ;
579581 state -> memtupcount = 0 ;
580582
581583 /*
@@ -613,7 +615,7 @@ tuplesort_begin_heap(TupleDesc tupDesc,
613615 int nkeys , AttrNumber * attNums ,
614616 Oid * sortOperators , Oid * sortCollations ,
615617 bool * nullsFirstFlags ,
616- int workMem , bool randomAccess )
618+ int workMem , bool randomAccess , int prefix )
617619{
618620 Tuplesortstate * state = tuplesort_begin_common (workMem , randomAccess );
619621 MemoryContext oldcontext ;
@@ -648,6 +650,7 @@ tuplesort_begin_heap(TupleDesc tupDesc,
648650
649651 /* Prepare SortSupport data for each column */
650652 state -> sortKeys = (SortSupport ) palloc0 (nkeys * sizeof (SortSupportData ));
653+ state -> prefix = prefix ;
651654
652655 for (i = 0 ; i < nkeys ; i ++ )
653656 {
@@ -1202,21 +1205,22 @@ grow_memtuples(Tuplesortstate *state)
12021205 *
12031206 * Note that the input data is always copied; the caller need not save it.
12041207 */
1205- void
1208+ bool
12061209tuplesort_puttupleslot (Tuplesortstate * state , TupleTableSlot * slot )
12071210{
12081211 MemoryContext oldcontext = MemoryContextSwitchTo (state -> sortcontext );
12091212 SortTuple stup ;
1210-
1213+ bool needmore ;
12111214 /*
12121215 * Copy the given tuple into memory we control, and decrease availMem.
12131216 * Then call the common code.
12141217 */
12151218 COPYTUP (state , & stup , (void * ) slot );
12161219
1217- puttuple_common (state , & stup );
1220+ needmore = puttuple_common (state , & stup );
12181221
12191222 MemoryContextSwitchTo (oldcontext );
1223+ return needmore ;
12201224}
12211225
12221226/*
@@ -1397,7 +1401,7 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
13971401/*
13981402 * Shared code for tuple and datum cases.
13991403 */
1400- static void
1404+ static bool
14011405puttuple_common (Tuplesortstate * state , SortTuple * tuple )
14021406{
14031407 switch (state -> status )
@@ -1441,14 +1445,14 @@ puttuple_common(Tuplesortstate *state, SortTuple *tuple)
14411445 pg_rusage_show (& state -> ru_start ));
14421446#endif
14431447 make_bounded_heap (state );
1444- return ;
1448+ break ;
14451449 }
14461450
14471451 /*
14481452 * Done if we still fit in available memory and have array slots.
14491453 */
14501454 if (state -> memtupcount < state -> memtupsize && !LACKMEM (state ))
1451- return ;
1455+ break ;
14521456
14531457 /*
14541458 * Nope; time to switch to tape-based operation.
@@ -1475,6 +1479,9 @@ puttuple_common(Tuplesortstate *state, SortTuple *tuple)
14751479 {
14761480 /* new tuple <= top of the heap, so we can discard it */
14771481 free_sort_tuple (state , tuple );
1482+ if (state -> prefix > state -> matchedKeys && state -> memtupcount >= state -> bound ) {
1483+ return false;
1484+ }
14781485 CHECK_FOR_INTERRUPTS ();
14791486 }
14801487 else
@@ -1517,6 +1524,7 @@ puttuple_common(Tuplesortstate *state, SortTuple *tuple)
15171524 elog (ERROR , "invalid tuplesort state" );
15181525 break ;
15191526 }
1527+ return true;
15201528}
15211529
15221530static bool
@@ -3071,19 +3079,20 @@ comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
30713079 HeapTupleData rtup ;
30723080 TupleDesc tupDesc ;
30733081 int nkey ;
3074- int32 compare ;
3082+ int32 compare = 0 ;
30753083 AttrNumber attno ;
30763084 Datum datum1 ,
30773085 datum2 ;
30783086 bool isnull1 ,
30793087 isnull2 ;
30803088
3089+ state -> matchedKeys = 0 ;
30813090
30823091 /* Compare the leading sort key */
30833092 compare = ApplySortComparator (a -> datum1 , a -> isnull1 ,
30843093 b -> datum1 , b -> isnull1 ,
30853094 sortKey );
3086- if (compare != 0 )
3095+ if (compare != 0 )
30873096 return compare ;
30883097
30893098 /* Compare additional sort keys */
@@ -3119,10 +3128,11 @@ comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
31193128 datum2 , isnull2 ,
31203129 sortKey );
31213130 if (compare != 0 )
3122- return compare ;
3131+ break ;
31233132 }
3133+ state -> matchedKeys = nkey ;
31243134
3125- return 0 ;
3135+ return compare ;
31263136}
31273137
31283138static void
0 commit comments