LCOV - code coverage report
Current view: top level - src/backend/utils/sort - tuplesortvariants.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 95.1 % 782 744
Test Date: 2026-03-10 08:14:43 Functions: 94.1 % 51 48
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * tuplesortvariants.c
       4              :  *    Implementation of tuple sorting variants.
       5              :  *
       6              :  * This module handles the sorting of heap tuples, index tuples, or single
       7              :  * Datums.  The implementation is based on the generalized tuple sorting
       8              :  * facility given in tuplesort.c.  Support other kinds of sortable objects
       9              :  * could be easily added here, another module, or even an extension.
      10              :  *
      11              :  *
      12              :  * Copyright (c) 2022-2026, PostgreSQL Global Development Group
      13              :  *
      14              :  * IDENTIFICATION
      15              :  *    src/backend/utils/sort/tuplesortvariants.c
      16              :  *
      17              :  *-------------------------------------------------------------------------
      18              :  */
      19              : 
      20              : #include "postgres.h"
      21              : 
      22              : #include "access/brin_tuple.h"
      23              : #include "access/gin.h"
      24              : #include "access/gin_tuple.h"
      25              : #include "access/hash.h"
      26              : #include "access/htup_details.h"
      27              : #include "access/nbtree.h"
      28              : #include "catalog/index.h"
      29              : #include "catalog/pg_collation.h"
      30              : #include "executor/executor.h"
      31              : #include "pg_trace.h"
      32              : #include "utils/builtins.h"
      33              : #include "utils/datum.h"
      34              : #include "utils/guc.h"
      35              : #include "utils/lsyscache.h"
      36              : #include "utils/rel.h"
      37              : #include "utils/tuplesort.h"
      38              : 
      39              : 
      40              : /* sort-type codes for sort__start probes */
      41              : #define HEAP_SORT       0
      42              : #define INDEX_SORT      1
      43              : #define DATUM_SORT      2
      44              : #define CLUSTER_SORT    3
      45              : 
      46              : static void removeabbrev_heap(Tuplesortstate *state, SortTuple *stups,
      47              :                               int count);
      48              : static void removeabbrev_cluster(Tuplesortstate *state, SortTuple *stups,
      49              :                                  int count);
      50              : static void removeabbrev_index(Tuplesortstate *state, SortTuple *stups,
      51              :                                int count);
      52              : static void removeabbrev_index_brin(Tuplesortstate *state, SortTuple *stups,
      53              :                                     int count);
      54              : static void removeabbrev_index_gin(Tuplesortstate *state, SortTuple *stups,
      55              :                                    int count);
      56              : static void removeabbrev_datum(Tuplesortstate *state, SortTuple *stups,
      57              :                                int count);
      58              : static int  comparetup_heap(const SortTuple *a, const SortTuple *b,
      59              :                             Tuplesortstate *state);
      60              : static int  comparetup_heap_tiebreak(const SortTuple *a, const SortTuple *b,
      61              :                                      Tuplesortstate *state);
      62              : static void writetup_heap(Tuplesortstate *state, LogicalTape *tape,
      63              :                           SortTuple *stup);
      64              : static void readtup_heap(Tuplesortstate *state, SortTuple *stup,
      65              :                          LogicalTape *tape, unsigned int len);
      66              : static int  comparetup_cluster(const SortTuple *a, const SortTuple *b,
      67              :                                Tuplesortstate *state);
      68              : static int  comparetup_cluster_tiebreak(const SortTuple *a, const SortTuple *b,
      69              :                                         Tuplesortstate *state);
      70              : static void writetup_cluster(Tuplesortstate *state, LogicalTape *tape,
      71              :                              SortTuple *stup);
      72              : static void readtup_cluster(Tuplesortstate *state, SortTuple *stup,
      73              :                             LogicalTape *tape, unsigned int tuplen);
      74              : static int  comparetup_index_btree(const SortTuple *a, const SortTuple *b,
      75              :                                    Tuplesortstate *state);
      76              : static int  comparetup_index_btree_tiebreak(const SortTuple *a, const SortTuple *b,
      77              :                                             Tuplesortstate *state);
      78              : static int  comparetup_index_hash(const SortTuple *a, const SortTuple *b,
      79              :                                   Tuplesortstate *state);
      80              : static int  comparetup_index_hash_tiebreak(const SortTuple *a, const SortTuple *b,
      81              :                                            Tuplesortstate *state);
      82              : static int  comparetup_index_brin(const SortTuple *a, const SortTuple *b,
      83              :                                   Tuplesortstate *state);
      84              : static int  comparetup_index_gin(const SortTuple *a, const SortTuple *b,
      85              :                                  Tuplesortstate *state);
      86              : static void writetup_index(Tuplesortstate *state, LogicalTape *tape,
      87              :                            SortTuple *stup);
      88              : static void readtup_index(Tuplesortstate *state, SortTuple *stup,
      89              :                           LogicalTape *tape, unsigned int len);
      90              : static void writetup_index_brin(Tuplesortstate *state, LogicalTape *tape,
      91              :                                 SortTuple *stup);
      92              : static void readtup_index_brin(Tuplesortstate *state, SortTuple *stup,
      93              :                                LogicalTape *tape, unsigned int len);
      94              : static void writetup_index_gin(Tuplesortstate *state, LogicalTape *tape,
      95              :                                SortTuple *stup);
      96              : static void readtup_index_gin(Tuplesortstate *state, SortTuple *stup,
      97              :                               LogicalTape *tape, unsigned int len);
      98              : static int  comparetup_datum(const SortTuple *a, const SortTuple *b,
      99              :                              Tuplesortstate *state);
     100              : static int  comparetup_datum_tiebreak(const SortTuple *a, const SortTuple *b,
     101              :                                       Tuplesortstate *state);
     102              : static void writetup_datum(Tuplesortstate *state, LogicalTape *tape,
     103              :                            SortTuple *stup);
     104              : static void readtup_datum(Tuplesortstate *state, SortTuple *stup,
     105              :                           LogicalTape *tape, unsigned int len);
     106              : static void freestate_cluster(Tuplesortstate *state);
     107              : 
     108              : /*
     109              :  * Data structure pointed by "TuplesortPublic.arg" for the CLUSTER case.  Set by
     110              :  * the tuplesort_begin_cluster.
     111              :  */
     112              : typedef struct
     113              : {
     114              :     TupleDesc   tupDesc;
     115              : 
     116              :     IndexInfo  *indexInfo;      /* info about index being used for reference */
     117              :     EState     *estate;         /* for evaluating index expressions */
     118              : } TuplesortClusterArg;
     119              : 
     120              : /*
     121              :  * Data structure pointed by "TuplesortPublic.arg" for the IndexTuple case.
     122              :  * Set by tuplesort_begin_index_xxx and used only by the IndexTuple routines.
     123              :  */
     124              : typedef struct
     125              : {
     126              :     Relation    heapRel;        /* table the index is being built on */
     127              :     Relation    indexRel;       /* index being built */
     128              : } TuplesortIndexArg;
     129              : 
     130              : /*
     131              :  * Data structure pointed by "TuplesortPublic.arg" for the index_btree subcase.
     132              :  */
     133              : typedef struct
     134              : {
     135              :     TuplesortIndexArg index;
     136              : 
     137              :     bool        enforceUnique;  /* complain if we find duplicate tuples */
     138              :     bool        uniqueNullsNotDistinct; /* unique constraint null treatment */
     139              : } TuplesortIndexBTreeArg;
     140              : 
     141              : /*
     142              :  * Data structure pointed by "TuplesortPublic.arg" for the index_hash subcase.
     143              :  */
     144              : typedef struct
     145              : {
     146              :     TuplesortIndexArg index;
     147              : 
     148              :     uint32      high_mask;      /* masks for sortable part of hash code */
     149              :     uint32      low_mask;
     150              :     uint32      max_buckets;
     151              : } TuplesortIndexHashArg;
     152              : 
     153              : /*
     154              :  * Data structure pointed by "TuplesortPublic.arg" for the Datum case.
     155              :  * Set by tuplesort_begin_datum and used only by the DatumTuple routines.
     156              :  */
     157              : typedef struct
     158              : {
     159              :     /* the datatype oid of Datum's to be sorted */
     160              :     Oid         datumType;
     161              :     /* we need typelen in order to know how to copy the Datums. */
     162              :     int         datumTypeLen;
     163              : } TuplesortDatumArg;
     164              : 
     165              : /*
     166              :  * Computing BrinTuple size with only the tuple is difficult, so we want to track
     167              :  * the length referenced by the SortTuple. That's what BrinSortTuple is meant
     168              :  * to do - it's essentially a BrinTuple prefixed by its length.
     169              :  */
     170              : typedef struct BrinSortTuple
     171              : {
     172              :     Size        tuplen;
     173              :     BrinTuple   tuple;
     174              : } BrinSortTuple;
     175              : 
     176              : /* Size of the BrinSortTuple, given length of the BrinTuple. */
     177              : #define BRINSORTTUPLE_SIZE(len)     (offsetof(BrinSortTuple, tuple) + (len))
     178              : 
     179              : 
     180              : Tuplesortstate *
     181        62138 : tuplesort_begin_heap(TupleDesc tupDesc,
     182              :                      int nkeys, AttrNumber *attNums,
     183              :                      Oid *sortOperators, Oid *sortCollations,
     184              :                      bool *nullsFirstFlags,
     185              :                      int workMem, SortCoordinate coordinate, int sortopt)
     186              : {
     187        62138 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     188              :                                                    sortopt);
     189        62138 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     190              :     MemoryContext oldcontext;
     191              :     int         i;
     192              : 
     193        62138 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     194              : 
     195              :     Assert(nkeys > 0);
     196              : 
     197        62138 :     if (trace_sort)
     198            0 :         elog(LOG,
     199              :              "begin tuple sort: nkeys = %d, workMem = %d, randomAccess = %c",
     200              :              nkeys, workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     201              : 
     202        62138 :     base->nKeys = nkeys;
     203              : 
     204              :     TRACE_POSTGRESQL_SORT_START(HEAP_SORT,
     205              :                                 false,  /* no unique check */
     206              :                                 nkeys,
     207              :                                 workMem,
     208              :                                 sortopt & TUPLESORT_RANDOMACCESS,
     209              :                                 PARALLEL_SORT(coordinate));
     210              : 
     211        62138 :     base->removeabbrev = removeabbrev_heap;
     212        62138 :     base->comparetup = comparetup_heap;
     213        62138 :     base->comparetup_tiebreak = comparetup_heap_tiebreak;
     214        62138 :     base->writetup = writetup_heap;
     215        62138 :     base->readtup = readtup_heap;
     216        62138 :     base->haveDatum1 = true;
     217        62138 :     base->arg = tupDesc;     /* assume we need not copy tupDesc */
     218              : 
     219              :     /* Prepare SortSupport data for each column */
     220        62138 :     base->sortKeys = (SortSupport) palloc0(nkeys * sizeof(SortSupportData));
     221              : 
     222       152450 :     for (i = 0; i < nkeys; i++)
     223              :     {
     224        90318 :         SortSupport sortKey = base->sortKeys + i;
     225              : 
     226              :         Assert(attNums[i] != 0);
     227              :         Assert(sortOperators[i] != 0);
     228              : 
     229        90318 :         sortKey->ssup_cxt = CurrentMemoryContext;
     230        90318 :         sortKey->ssup_collation = sortCollations[i];
     231        90318 :         sortKey->ssup_nulls_first = nullsFirstFlags[i];
     232        90318 :         sortKey->ssup_attno = attNums[i];
     233              :         /* Convey if abbreviation optimization is applicable in principle */
     234        90318 :         sortKey->abbreviate = (i == 0 && base->haveDatum1);
     235              : 
     236        90318 :         PrepareSortSupportFromOrderingOp(sortOperators[i], sortKey);
     237              :     }
     238              : 
     239              :     /*
     240              :      * The "onlyKey" optimization cannot be used with abbreviated keys, since
     241              :      * tie-breaker comparisons may be required.  Typically, the optimization
     242              :      * is only of value to pass-by-value types anyway, whereas abbreviated
     243              :      * keys are typically only of value to pass-by-reference types.
     244              :      */
     245        62132 :     if (nkeys == 1 && !base->sortKeys->abbrev_converter)
     246        35786 :         base->onlyKey = base->sortKeys;
     247              : 
     248        62132 :     MemoryContextSwitchTo(oldcontext);
     249              : 
     250        62132 :     return state;
     251              : }
     252              : 
     253              : Tuplesortstate *
     254           58 : tuplesort_begin_cluster(TupleDesc tupDesc,
     255              :                         Relation indexRel,
     256              :                         int workMem,
     257              :                         SortCoordinate coordinate, int sortopt)
     258              : {
     259           58 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     260              :                                                    sortopt);
     261           58 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     262              :     BTScanInsert indexScanKey;
     263              :     MemoryContext oldcontext;
     264              :     TuplesortClusterArg *arg;
     265              :     int         i;
     266              : 
     267              :     Assert(indexRel->rd_rel->relam == BTREE_AM_OID);
     268              : 
     269           58 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     270           58 :     arg = palloc0_object(TuplesortClusterArg);
     271              : 
     272           58 :     if (trace_sort)
     273            0 :         elog(LOG,
     274              :              "begin tuple sort: nkeys = %d, workMem = %d, randomAccess = %c",
     275              :              RelationGetNumberOfAttributes(indexRel),
     276              :              workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     277              : 
     278           58 :     base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
     279              : 
     280              :     TRACE_POSTGRESQL_SORT_START(CLUSTER_SORT,
     281              :                                 false,  /* no unique check */
     282              :                                 base->nKeys,
     283              :                                 workMem,
     284              :                                 sortopt & TUPLESORT_RANDOMACCESS,
     285              :                                 PARALLEL_SORT(coordinate));
     286              : 
     287           58 :     base->removeabbrev = removeabbrev_cluster;
     288           58 :     base->comparetup = comparetup_cluster;
     289           58 :     base->comparetup_tiebreak = comparetup_cluster_tiebreak;
     290           58 :     base->writetup = writetup_cluster;
     291           58 :     base->readtup = readtup_cluster;
     292           58 :     base->freestate = freestate_cluster;
     293           58 :     base->arg = arg;
     294              : 
     295           58 :     arg->indexInfo = BuildIndexInfo(indexRel);
     296              : 
     297              :     /*
     298              :      * If we don't have a simple leading attribute, we don't currently
     299              :      * initialize datum1, so disable optimizations that require it.
     300              :      */
     301           58 :     if (arg->indexInfo->ii_IndexAttrNumbers[0] == 0)
     302           12 :         base->haveDatum1 = false;
     303              :     else
     304           46 :         base->haveDatum1 = true;
     305              : 
     306           58 :     arg->tupDesc = tupDesc;      /* assume we need not copy tupDesc */
     307              : 
     308           58 :     indexScanKey = _bt_mkscankey(indexRel, NULL);
     309              : 
     310           58 :     if (arg->indexInfo->ii_Expressions != NULL)
     311              :     {
     312              :         TupleTableSlot *slot;
     313              :         ExprContext *econtext;
     314              : 
     315              :         /*
     316              :          * We will need to use FormIndexDatum to evaluate the index
     317              :          * expressions.  To do that, we need an EState, as well as a
     318              :          * TupleTableSlot to put the table tuples into.  The econtext's
     319              :          * scantuple has to point to that slot, too.
     320              :          */
     321           12 :         arg->estate = CreateExecutorState();
     322           12 :         slot = MakeSingleTupleTableSlot(tupDesc, &TTSOpsHeapTuple);
     323           12 :         econtext = GetPerTupleExprContext(arg->estate);
     324           12 :         econtext->ecxt_scantuple = slot;
     325              :     }
     326              : 
     327              :     /* Prepare SortSupport data for each column */
     328           58 :     base->sortKeys = (SortSupport) palloc0(base->nKeys *
     329              :                                            sizeof(SortSupportData));
     330              : 
     331          128 :     for (i = 0; i < base->nKeys; i++)
     332              :     {
     333           70 :         SortSupport sortKey = base->sortKeys + i;
     334           70 :         ScanKey     scanKey = indexScanKey->scankeys + i;
     335              :         bool        reverse;
     336              : 
     337           70 :         sortKey->ssup_cxt = CurrentMemoryContext;
     338           70 :         sortKey->ssup_collation = scanKey->sk_collation;
     339           70 :         sortKey->ssup_nulls_first =
     340           70 :             (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
     341           70 :         sortKey->ssup_attno = scanKey->sk_attno;
     342              :         /* Convey if abbreviation optimization is applicable in principle */
     343           70 :         sortKey->abbreviate = (i == 0 && base->haveDatum1);
     344              : 
     345              :         Assert(sortKey->ssup_attno != 0);
     346              : 
     347           70 :         reverse = (scanKey->sk_flags & SK_BT_DESC) != 0;
     348              : 
     349           70 :         PrepareSortSupportFromIndexRel(indexRel, reverse, sortKey);
     350              :     }
     351              : 
     352           58 :     pfree(indexScanKey);
     353              : 
     354           58 :     MemoryContextSwitchTo(oldcontext);
     355              : 
     356           58 :     return state;
     357              : }
     358              : 
     359              : Tuplesortstate *
     360        48103 : tuplesort_begin_index_btree(Relation heapRel,
     361              :                             Relation indexRel,
     362              :                             bool enforceUnique,
     363              :                             bool uniqueNullsNotDistinct,
     364              :                             int workMem,
     365              :                             SortCoordinate coordinate,
     366              :                             int sortopt)
     367              : {
     368        48103 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     369              :                                                    sortopt);
     370        48103 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     371              :     BTScanInsert indexScanKey;
     372              :     TuplesortIndexBTreeArg *arg;
     373              :     MemoryContext oldcontext;
     374              :     int         i;
     375              : 
     376        48103 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     377        48103 :     arg = palloc_object(TuplesortIndexBTreeArg);
     378              : 
     379        48103 :     if (trace_sort)
     380            0 :         elog(LOG,
     381              :              "begin index sort: unique = %c, workMem = %d, randomAccess = %c",
     382              :              enforceUnique ? 't' : 'f',
     383              :              workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     384              : 
     385        48103 :     base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
     386              : 
     387              :     TRACE_POSTGRESQL_SORT_START(INDEX_SORT,
     388              :                                 enforceUnique,
     389              :                                 base->nKeys,
     390              :                                 workMem,
     391              :                                 sortopt & TUPLESORT_RANDOMACCESS,
     392              :                                 PARALLEL_SORT(coordinate));
     393              : 
     394        48103 :     base->removeabbrev = removeabbrev_index;
     395        48103 :     base->comparetup = comparetup_index_btree;
     396        48103 :     base->comparetup_tiebreak = comparetup_index_btree_tiebreak;
     397        48103 :     base->writetup = writetup_index;
     398        48103 :     base->readtup = readtup_index;
     399        48103 :     base->haveDatum1 = true;
     400        48103 :     base->arg = arg;
     401              : 
     402        48103 :     arg->index.heapRel = heapRel;
     403        48103 :     arg->index.indexRel = indexRel;
     404        48103 :     arg->enforceUnique = enforceUnique;
     405        48103 :     arg->uniqueNullsNotDistinct = uniqueNullsNotDistinct;
     406              : 
     407        48103 :     indexScanKey = _bt_mkscankey(indexRel, NULL);
     408              : 
     409              :     /* Prepare SortSupport data for each column */
     410        48103 :     base->sortKeys = (SortSupport) palloc0(base->nKeys *
     411              :                                            sizeof(SortSupportData));
     412              : 
     413       127466 :     for (i = 0; i < base->nKeys; i++)
     414              :     {
     415        79363 :         SortSupport sortKey = base->sortKeys + i;
     416        79363 :         ScanKey     scanKey = indexScanKey->scankeys + i;
     417              :         bool        reverse;
     418              : 
     419        79363 :         sortKey->ssup_cxt = CurrentMemoryContext;
     420        79363 :         sortKey->ssup_collation = scanKey->sk_collation;
     421        79363 :         sortKey->ssup_nulls_first =
     422        79363 :             (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
     423        79363 :         sortKey->ssup_attno = scanKey->sk_attno;
     424              :         /* Convey if abbreviation optimization is applicable in principle */
     425        79363 :         sortKey->abbreviate = (i == 0 && base->haveDatum1);
     426              : 
     427              :         Assert(sortKey->ssup_attno != 0);
     428              : 
     429        79363 :         reverse = (scanKey->sk_flags & SK_BT_DESC) != 0;
     430              : 
     431        79363 :         PrepareSortSupportFromIndexRel(indexRel, reverse, sortKey);
     432              :     }
     433              : 
     434        48103 :     pfree(indexScanKey);
     435              : 
     436        48103 :     MemoryContextSwitchTo(oldcontext);
     437              : 
     438        48103 :     return state;
     439              : }
     440              : 
     441              : Tuplesortstate *
     442            4 : tuplesort_begin_index_hash(Relation heapRel,
     443              :                            Relation indexRel,
     444              :                            uint32 high_mask,
     445              :                            uint32 low_mask,
     446              :                            uint32 max_buckets,
     447              :                            int workMem,
     448              :                            SortCoordinate coordinate,
     449              :                            int sortopt)
     450              : {
     451            4 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     452              :                                                    sortopt);
     453            4 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     454              :     MemoryContext oldcontext;
     455              :     TuplesortIndexHashArg *arg;
     456              : 
     457            4 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     458            4 :     arg = palloc_object(TuplesortIndexHashArg);
     459              : 
     460            4 :     if (trace_sort)
     461            0 :         elog(LOG,
     462              :              "begin index sort: high_mask = 0x%x, low_mask = 0x%x, "
     463              :              "max_buckets = 0x%x, workMem = %d, randomAccess = %c",
     464              :              high_mask,
     465              :              low_mask,
     466              :              max_buckets,
     467              :              workMem,
     468              :              sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     469              : 
     470            4 :     base->nKeys = 1;         /* Only one sort column, the hash code */
     471              : 
     472            4 :     base->removeabbrev = removeabbrev_index;
     473            4 :     base->comparetup = comparetup_index_hash;
     474            4 :     base->comparetup_tiebreak = comparetup_index_hash_tiebreak;
     475            4 :     base->writetup = writetup_index;
     476            4 :     base->readtup = readtup_index;
     477            4 :     base->haveDatum1 = true;
     478            4 :     base->arg = arg;
     479              : 
     480            4 :     arg->index.heapRel = heapRel;
     481            4 :     arg->index.indexRel = indexRel;
     482              : 
     483            4 :     arg->high_mask = high_mask;
     484            4 :     arg->low_mask = low_mask;
     485            4 :     arg->max_buckets = max_buckets;
     486              : 
     487            4 :     MemoryContextSwitchTo(oldcontext);
     488              : 
     489            4 :     return state;
     490              : }
     491              : 
     492              : Tuplesortstate *
     493          412 : tuplesort_begin_index_gist(Relation heapRel,
     494              :                            Relation indexRel,
     495              :                            int workMem,
     496              :                            SortCoordinate coordinate,
     497              :                            int sortopt)
     498              : {
     499          412 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     500              :                                                    sortopt);
     501          412 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     502              :     MemoryContext oldcontext;
     503              :     TuplesortIndexBTreeArg *arg;
     504              :     int         i;
     505              : 
     506          412 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     507          412 :     arg = palloc_object(TuplesortIndexBTreeArg);
     508              : 
     509          412 :     if (trace_sort)
     510            0 :         elog(LOG,
     511              :              "begin index sort: workMem = %d, randomAccess = %c",
     512              :              workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     513              : 
     514          412 :     base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
     515              : 
     516          412 :     base->removeabbrev = removeabbrev_index;
     517          412 :     base->comparetup = comparetup_index_btree;
     518          412 :     base->comparetup_tiebreak = comparetup_index_btree_tiebreak;
     519          412 :     base->writetup = writetup_index;
     520          412 :     base->readtup = readtup_index;
     521          412 :     base->haveDatum1 = true;
     522          412 :     base->arg = arg;
     523              : 
     524          412 :     arg->index.heapRel = heapRel;
     525          412 :     arg->index.indexRel = indexRel;
     526          412 :     arg->enforceUnique = false;
     527          412 :     arg->uniqueNullsNotDistinct = false;
     528              : 
     529              :     /* Prepare SortSupport data for each column */
     530          412 :     base->sortKeys = (SortSupport) palloc0(base->nKeys *
     531              :                                            sizeof(SortSupportData));
     532              : 
     533         1131 :     for (i = 0; i < base->nKeys; i++)
     534              :     {
     535          719 :         SortSupport sortKey = base->sortKeys + i;
     536              : 
     537          719 :         sortKey->ssup_cxt = CurrentMemoryContext;
     538          719 :         sortKey->ssup_collation = indexRel->rd_indcollation[i];
     539          719 :         sortKey->ssup_nulls_first = false;
     540          719 :         sortKey->ssup_attno = i + 1;
     541              :         /* Convey if abbreviation optimization is applicable in principle */
     542          719 :         sortKey->abbreviate = (i == 0 && base->haveDatum1);
     543              : 
     544              :         Assert(sortKey->ssup_attno != 0);
     545              : 
     546              :         /* Look for a sort support function */
     547          719 :         PrepareSortSupportFromGistIndexRel(indexRel, sortKey);
     548              :     }
     549              : 
     550          412 :     MemoryContextSwitchTo(oldcontext);
     551              : 
     552          412 :     return state;
     553              : }
     554              : 
     555              : Tuplesortstate *
     556           14 : tuplesort_begin_index_brin(int workMem,
     557              :                            SortCoordinate coordinate,
     558              :                            int sortopt)
     559              : {
     560           14 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     561              :                                                    sortopt);
     562           14 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     563              : 
     564           14 :     if (trace_sort)
     565            0 :         elog(LOG,
     566              :              "begin index sort: workMem = %d, randomAccess = %c",
     567              :              workMem,
     568              :              sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     569              : 
     570           14 :     base->nKeys = 1;         /* Only one sort column, the block number */
     571              : 
     572           14 :     base->removeabbrev = removeabbrev_index_brin;
     573           14 :     base->comparetup = comparetup_index_brin;
     574           14 :     base->writetup = writetup_index_brin;
     575           14 :     base->readtup = readtup_index_brin;
     576           14 :     base->haveDatum1 = true;
     577           14 :     base->arg = NULL;
     578              : 
     579           14 :     return state;
     580              : }
     581              : 
     582              : Tuplesortstate *
     583           91 : tuplesort_begin_index_gin(Relation heapRel,
     584              :                           Relation indexRel,
     585              :                           int workMem, SortCoordinate coordinate,
     586              :                           int sortopt)
     587              : {
     588           91 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     589              :                                                    sortopt);
     590           91 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     591              :     MemoryContext oldcontext;
     592              :     int         i;
     593           91 :     TupleDesc   desc = RelationGetDescr(indexRel);
     594              : 
     595           91 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     596              : 
     597              : #ifdef TRACE_SORT
     598              :     if (trace_sort)
     599              :         elog(LOG,
     600              :              "begin index sort: workMem = %d, randomAccess = %c",
     601              :              workMem,
     602              :              sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     603              : #endif
     604              : 
     605              :     /*
     606              :      * Multi-column GIN indexes expand the row into a separate index entry for
     607              :      * attribute, and that's what we write into the tuplesort. But we still
     608              :      * need to initialize sortsupport for all the attributes.
     609              :      */
     610           91 :     base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
     611              : 
     612              :     /* Prepare SortSupport data for each column */
     613           91 :     base->sortKeys = (SortSupport) palloc0(base->nKeys *
     614              :                                            sizeof(SortSupportData));
     615              : 
     616          182 :     for (i = 0; i < base->nKeys; i++)
     617              :     {
     618           91 :         SortSupport sortKey = base->sortKeys + i;
     619           91 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     620              :         Oid         cmpFunc;
     621              : 
     622           91 :         sortKey->ssup_cxt = CurrentMemoryContext;
     623           91 :         sortKey->ssup_collation = indexRel->rd_indcollation[i];
     624           91 :         sortKey->ssup_nulls_first = false;
     625           91 :         sortKey->ssup_attno = i + 1;
     626           91 :         sortKey->abbreviate = false;
     627              : 
     628              :         Assert(sortKey->ssup_attno != 0);
     629              : 
     630           91 :         if (!OidIsValid(sortKey->ssup_collation))
     631           91 :             sortKey->ssup_collation = DEFAULT_COLLATION_OID;
     632              : 
     633              :         /*
     634              :          * If the compare proc isn't specified in the opclass definition, look
     635              :          * up the index key type's default btree comparator.
     636              :          */
     637           91 :         cmpFunc = index_getprocid(indexRel, i + 1, GIN_COMPARE_PROC);
     638           91 :         if (cmpFunc == InvalidOid)
     639              :         {
     640              :             TypeCacheEntry *typentry;
     641              : 
     642            0 :             typentry = lookup_type_cache(att->atttypid,
     643              :                                          TYPECACHE_CMP_PROC_FINFO);
     644            0 :             if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
     645            0 :                 ereport(ERROR,
     646              :                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
     647              :                          errmsg("could not identify a comparison function for type %s",
     648              :                                 format_type_be(att->atttypid))));
     649              : 
     650            0 :             cmpFunc = typentry->cmp_proc_finfo.fn_oid;
     651              :         }
     652              : 
     653           91 :         PrepareSortSupportComparisonShim(cmpFunc, sortKey);
     654              :     }
     655              : 
     656           91 :     base->removeabbrev = removeabbrev_index_gin;
     657           91 :     base->comparetup = comparetup_index_gin;
     658           91 :     base->writetup = writetup_index_gin;
     659           91 :     base->readtup = readtup_index_gin;
     660           91 :     base->haveDatum1 = false;
     661           91 :     base->arg = NULL;
     662              : 
     663           91 :     MemoryContextSwitchTo(oldcontext);
     664              : 
     665           91 :     return state;
     666              : }
     667              : 
     668              : Tuplesortstate *
     669        32317 : tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation,
     670              :                       bool nullsFirstFlag, int workMem,
     671              :                       SortCoordinate coordinate, int sortopt)
     672              : {
     673        32317 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     674              :                                                    sortopt);
     675        32317 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     676              :     TuplesortDatumArg *arg;
     677              :     MemoryContext oldcontext;
     678              :     int16       typlen;
     679              :     bool        typbyval;
     680              : 
     681        32317 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     682        32317 :     arg = palloc_object(TuplesortDatumArg);
     683              : 
     684        32317 :     if (trace_sort)
     685            0 :         elog(LOG,
     686              :              "begin datum sort: workMem = %d, randomAccess = %c",
     687              :              workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     688              : 
     689        32317 :     base->nKeys = 1;         /* always a one-column sort */
     690              : 
     691              :     TRACE_POSTGRESQL_SORT_START(DATUM_SORT,
     692              :                                 false,  /* no unique check */
     693              :                                 1,
     694              :                                 workMem,
     695              :                                 sortopt & TUPLESORT_RANDOMACCESS,
     696              :                                 PARALLEL_SORT(coordinate));
     697              : 
     698        32317 :     base->removeabbrev = removeabbrev_datum;
     699        32317 :     base->comparetup = comparetup_datum;
     700        32317 :     base->comparetup_tiebreak = comparetup_datum_tiebreak;
     701        32317 :     base->writetup = writetup_datum;
     702        32317 :     base->readtup = readtup_datum;
     703        32317 :     base->haveDatum1 = true;
     704        32317 :     base->arg = arg;
     705              : 
     706        32317 :     arg->datumType = datumType;
     707              : 
     708              :     /* lookup necessary attributes of the datum type */
     709        32317 :     get_typlenbyval(datumType, &typlen, &typbyval);
     710        32317 :     arg->datumTypeLen = typlen;
     711        32317 :     base->tuples = !typbyval;
     712              : 
     713              :     /* Prepare SortSupport data */
     714        32317 :     base->sortKeys = palloc0_object(SortSupportData);
     715              : 
     716        32317 :     base->sortKeys->ssup_cxt = CurrentMemoryContext;
     717        32317 :     base->sortKeys->ssup_collation = sortCollation;
     718        32317 :     base->sortKeys->ssup_nulls_first = nullsFirstFlag;
     719              : 
     720              :     /*
     721              :      * Abbreviation is possible here only for by-reference types.  In theory,
     722              :      * a pass-by-value datatype could have an abbreviated form that is cheaper
     723              :      * to compare.  In a tuple sort, we could support that, because we can
     724              :      * always extract the original datum from the tuple as needed.  Here, we
     725              :      * can't, because a datum sort only stores a single copy of the datum; the
     726              :      * "tuple" field of each SortTuple is NULL.
     727              :      */
     728        32317 :     base->sortKeys->abbreviate = !typbyval;
     729              : 
     730        32317 :     PrepareSortSupportFromOrderingOp(sortOperator, base->sortKeys);
     731              : 
     732              :     /*
     733              :      * The "onlyKey" optimization cannot be used with abbreviated keys, since
     734              :      * tie-breaker comparisons may be required.  Typically, the optimization
     735              :      * is only of value to pass-by-value types anyway, whereas abbreviated
     736              :      * keys are typically only of value to pass-by-reference types.
     737              :      */
     738        32317 :     if (!base->sortKeys->abbrev_converter)
     739        31889 :         base->onlyKey = base->sortKeys;
     740              : 
     741        32317 :     MemoryContextSwitchTo(oldcontext);
     742              : 
     743        32317 :     return state;
     744              : }
     745              : 
     746              : /*
     747              :  * Accept one tuple while collecting input data for sort.
     748              :  *
     749              :  * Note that the input data is always copied; the caller need not save it.
     750              :  */
     751              : void
     752      7236899 : tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
     753              : {
     754      7236899 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     755      7236899 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
     756      7236899 :     TupleDesc   tupDesc = (TupleDesc) base->arg;
     757              :     SortTuple   stup;
     758              :     MinimalTuple tuple;
     759              :     HeapTupleData htup;
     760              :     Size        tuplen;
     761              : 
     762              :     /* copy the tuple into sort storage */
     763      7236899 :     tuple = ExecCopySlotMinimalTuple(slot);
     764      7236899 :     stup.tuple = tuple;
     765              :     /* set up first-column key value */
     766      7236899 :     htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
     767      7236899 :     htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
     768     14473798 :     stup.datum1 = heap_getattr(&htup,
     769      7236899 :                                base->sortKeys[0].ssup_attno,
     770              :                                tupDesc,
     771              :                                &stup.isnull1);
     772              : 
     773              :     /* GetMemoryChunkSpace is not supported for bump contexts */
     774      7236899 :     if (TupleSortUseBumpTupleCxt(base->sortopt))
     775      5485606 :         tuplen = MAXALIGN(tuple->t_len);
     776              :     else
     777      1751293 :         tuplen = GetMemoryChunkSpace(tuple);
     778              : 
     779      7236899 :     tuplesort_puttuple_common(state, &stup,
     780      7799687 :                               base->sortKeys->abbrev_converter &&
     781      7799687 :                               !stup.isnull1, tuplen);
     782              : 
     783      7236899 :     MemoryContextSwitchTo(oldcontext);
     784      7236899 : }
     785              : 
     786              : /*
     787              :  * Accept one tuple while collecting input data for sort.
     788              :  *
     789              :  * Note that the input data is always copied; the caller need not save it.
     790              :  */
     791              : void
     792       273708 : tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup)
     793              : {
     794              :     SortTuple   stup;
     795       273708 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     796       273708 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
     797       273708 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
     798              :     Size        tuplen;
     799              : 
     800              :     /* copy the tuple into sort storage */
     801       273708 :     tup = heap_copytuple(tup);
     802       273708 :     stup.tuple = tup;
     803              : 
     804              :     /*
     805              :      * set up first-column key value, and potentially abbreviate, if it's a
     806              :      * simple column
     807              :      */
     808       273708 :     if (base->haveDatum1)
     809              :     {
     810       272895 :         stup.datum1 = heap_getattr(tup,
     811       272895 :                                    arg->indexInfo->ii_IndexAttrNumbers[0],
     812              :                                    arg->tupDesc,
     813              :                                    &stup.isnull1);
     814              :     }
     815              : 
     816              :     /* GetMemoryChunkSpace is not supported for bump contexts */
     817       273708 :     if (TupleSortUseBumpTupleCxt(base->sortopt))
     818       273708 :         tuplen = MAXALIGN(HEAPTUPLESIZE + tup->t_len);
     819              :     else
     820            0 :         tuplen = GetMemoryChunkSpace(tup);
     821              : 
     822       273708 :     tuplesort_puttuple_common(state, &stup,
     823       546603 :                               base->haveDatum1 &&
     824       455252 :                               base->sortKeys->abbrev_converter &&
     825       455252 :                               !stup.isnull1, tuplen);
     826              : 
     827       273708 :     MemoryContextSwitchTo(oldcontext);
     828       273708 : }
     829              : 
     830              : /*
     831              :  * Collect one index tuple while collecting input data for sort, building
     832              :  * it from caller-supplied values.
     833              :  */
     834              : void
     835      6674569 : tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel,
     836              :                               const ItemPointerData *self, const Datum *values,
     837              :                               const bool *isnull)
     838              : {
     839              :     SortTuple   stup;
     840              :     IndexTuple  tuple;
     841      6674569 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     842      6674569 :     TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
     843              :     Size        tuplen;
     844              : 
     845      6674569 :     stup.tuple = index_form_tuple_context(RelationGetDescr(rel), values,
     846              :                                           isnull, base->tuplecontext);
     847      6674569 :     tuple = ((IndexTuple) stup.tuple);
     848      6674569 :     tuple->t_tid = *self;
     849              :     /* set up first-column key value */
     850     13349138 :     stup.datum1 = index_getattr(tuple,
     851              :                                 1,
     852      6674569 :                                 RelationGetDescr(arg->indexRel),
     853              :                                 &stup.isnull1);
     854              : 
     855              :     /* GetMemoryChunkSpace is not supported for bump contexts */
     856      6674569 :     if (TupleSortUseBumpTupleCxt(base->sortopt))
     857      6674569 :         tuplen = MAXALIGN(tuple->t_info & INDEX_SIZE_MASK);
     858              :     else
     859            0 :         tuplen = GetMemoryChunkSpace(tuple);
     860              : 
     861      6674569 :     tuplesort_puttuple_common(state, &stup,
     862     13288638 :                               base->sortKeys &&
     863      7736091 :                               base->sortKeys->abbrev_converter &&
     864      7736091 :                               !stup.isnull1, tuplen);
     865      6674569 : }
     866              : 
     867              : /*
     868              :  * Collect one BRIN tuple while collecting input data for sort.
     869              :  */
     870              : void
     871           20 : tuplesort_putbrintuple(Tuplesortstate *state, BrinTuple *tuple, Size size)
     872              : {
     873              :     SortTuple   stup;
     874              :     BrinSortTuple *bstup;
     875           20 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     876           20 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
     877              :     Size        tuplen;
     878              : 
     879              :     /* allocate space for the whole BRIN sort tuple */
     880           20 :     bstup = palloc(BRINSORTTUPLE_SIZE(size));
     881              : 
     882           20 :     bstup->tuplen = size;
     883           20 :     memcpy(&bstup->tuple, tuple, size);
     884              : 
     885           20 :     stup.tuple = bstup;
     886           20 :     stup.datum1 = UInt32GetDatum(tuple->bt_blkno);
     887           20 :     stup.isnull1 = false;
     888              : 
     889              :     /* GetMemoryChunkSpace is not supported for bump contexts */
     890           20 :     if (TupleSortUseBumpTupleCxt(base->sortopt))
     891           20 :         tuplen = MAXALIGN(BRINSORTTUPLE_SIZE(size));
     892              :     else
     893            0 :         tuplen = GetMemoryChunkSpace(bstup);
     894              : 
     895           20 :     tuplesort_puttuple_common(state, &stup,
     896           20 :                               base->sortKeys &&
     897           20 :                               base->sortKeys->abbrev_converter &&
     898           20 :                               !stup.isnull1, tuplen);
     899              : 
     900           20 :     MemoryContextSwitchTo(oldcontext);
     901           20 : }
     902              : 
     903              : void
     904        34350 : tuplesort_putgintuple(Tuplesortstate *state, GinTuple *tuple, Size size)
     905              : {
     906              :     SortTuple   stup;
     907              :     GinTuple   *ctup;
     908        34350 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     909        34350 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
     910              :     Size        tuplen;
     911              : 
     912              :     /* copy the GinTuple into the right memory context */
     913        34350 :     ctup = palloc(size);
     914        34350 :     memcpy(ctup, tuple, size);
     915              : 
     916        34350 :     stup.tuple = ctup;
     917        34350 :     stup.datum1 = (Datum) 0;
     918        34350 :     stup.isnull1 = false;
     919              : 
     920              :     /* GetMemoryChunkSpace is not supported for bump contexts */
     921        34350 :     if (TupleSortUseBumpTupleCxt(base->sortopt))
     922        34350 :         tuplen = MAXALIGN(size);
     923              :     else
     924            0 :         tuplen = GetMemoryChunkSpace(ctup);
     925              : 
     926        34350 :     tuplesort_puttuple_common(state, &stup,
     927        68700 :                               base->sortKeys &&
     928        34350 :                               base->sortKeys->abbrev_converter &&
     929        34350 :                               !stup.isnull1, tuplen);
     930              : 
     931        34350 :     MemoryContextSwitchTo(oldcontext);
     932        34350 : }
     933              : 
     934              : /*
     935              :  * Accept one Datum while collecting input data for sort.
     936              :  *
     937              :  * If the Datum is pass-by-ref type, the value will be copied.
     938              :  */
     939              : void
     940      1995693 : tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
     941              : {
     942      1995693 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     943      1995693 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
     944      1995693 :     TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
     945              :     SortTuple   stup;
     946              : 
     947              :     /*
     948              :      * Pass-by-value types or null values are just stored directly in
     949              :      * stup.datum1 (and stup.tuple is not used and set to NULL).
     950              :      *
     951              :      * Non-null pass-by-reference values need to be copied into memory we
     952              :      * control, and possibly abbreviated. The copied value is pointed to by
     953              :      * stup.tuple and is treated as the canonical copy (e.g. to return via
     954              :      * tuplesort_getdatum or when writing to tape); stup.datum1 gets the
     955              :      * abbreviated value if abbreviation is happening, otherwise it's
     956              :      * identical to stup.tuple.
     957              :      */
     958              : 
     959      1995693 :     if (isNull || !base->tuples)
     960              :     {
     961              :         /*
     962              :          * Set datum1 to zeroed representation for NULLs (to be consistent,
     963              :          * and to support cheap inequality tests for NULL abbreviated keys).
     964              :          */
     965      1117120 :         stup.datum1 = !isNull ? val : (Datum) 0;
     966      1117120 :         stup.isnull1 = isNull;
     967      1117120 :         stup.tuple = NULL;      /* no separate storage */
     968              :     }
     969              :     else
     970              :     {
     971       878573 :         stup.isnull1 = false;
     972       878573 :         stup.datum1 = datumCopy(val, false, arg->datumTypeLen);
     973       878573 :         stup.tuple = DatumGetPointer(stup.datum1);
     974              :     }
     975              : 
     976      1995693 :     tuplesort_puttuple_common(state, &stup,
     977      2874697 :                               base->tuples &&
     978      1995693 :                               base->sortKeys->abbrev_converter && !isNull, 0);
     979              : 
     980      1995693 :     MemoryContextSwitchTo(oldcontext);
     981      1995693 : }
     982              : 
     983              : /*
     984              :  * Fetch the next tuple in either forward or back direction.
     985              :  * If successful, put tuple in slot and return true; else, clear the slot
     986              :  * and return false.
     987              :  *
     988              :  * Caller may optionally be passed back abbreviated value (on true return
     989              :  * value) when abbreviation was used, which can be used to cheaply avoid
     990              :  * equality checks that might otherwise be required.  Caller can safely make a
     991              :  * determination of "non-equal tuple" based on simple binary inequality.  A
     992              :  * NULL value in leading attribute will set abbreviated value to zeroed
     993              :  * representation, which caller may rely on in abbreviated inequality check.
     994              :  *
     995              :  * If copy is true, the slot receives a tuple that's been copied into the
     996              :  * caller's memory context, so that it will stay valid regardless of future
     997              :  * manipulations of the tuplesort's state (up to and including deleting the
     998              :  * tuplesort).  If copy is false, the slot will just receive a pointer to a
     999              :  * tuple held within the tuplesort, which is more efficient, but only safe for
    1000              :  * callers that are prepared to have any subsequent manipulation of the
    1001              :  * tuplesort's state invalidate slot contents.
    1002              :  */
    1003              : bool
    1004      6532325 : tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy,
    1005              :                        TupleTableSlot *slot, Datum *abbrev)
    1006              : {
    1007      6532325 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1008      6532325 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1009              :     SortTuple   stup;
    1010              : 
    1011      6532325 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1012        63461 :         stup.tuple = NULL;
    1013              : 
    1014      6532325 :     MemoryContextSwitchTo(oldcontext);
    1015              : 
    1016      6532325 :     if (stup.tuple)
    1017              :     {
    1018              :         /* Record abbreviated key for caller */
    1019      6468864 :         if (base->sortKeys->abbrev_converter && abbrev)
    1020            0 :             *abbrev = stup.datum1;
    1021              : 
    1022      6468864 :         if (copy)
    1023         2278 :             stup.tuple = heap_copy_minimal_tuple((MinimalTuple) stup.tuple, 0);
    1024              : 
    1025      6468864 :         ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, copy);
    1026      6468864 :         return true;
    1027              :     }
    1028              :     else
    1029              :     {
    1030        63461 :         ExecClearTuple(slot);
    1031        63461 :         return false;
    1032              :     }
    1033              : }
    1034              : 
    1035              : /*
    1036              :  * Fetch the next tuple in either forward or back direction.
    1037              :  * Returns NULL if no more tuples.  Returned tuple belongs to tuplesort memory
    1038              :  * context, and must not be freed by caller.  Caller may not rely on tuple
    1039              :  * remaining valid after any further manipulation of tuplesort.
    1040              :  */
    1041              : HeapTuple
    1042       273766 : tuplesort_getheaptuple(Tuplesortstate *state, bool forward)
    1043              : {
    1044       273766 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1045       273766 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1046              :     SortTuple   stup;
    1047              : 
    1048       273766 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1049           58 :         stup.tuple = NULL;
    1050              : 
    1051       273766 :     MemoryContextSwitchTo(oldcontext);
    1052              : 
    1053       273766 :     return stup.tuple;
    1054              : }
    1055              : 
    1056              : /*
    1057              :  * Fetch the next index tuple in either forward or back direction.
    1058              :  * Returns NULL if no more tuples.  Returned tuple belongs to tuplesort memory
    1059              :  * context, and must not be freed by caller.  Caller may not rely on tuple
    1060              :  * remaining valid after any further manipulation of tuplesort.
    1061              :  */
    1062              : IndexTuple
    1063      6701166 : tuplesort_getindextuple(Tuplesortstate *state, bool forward)
    1064              : {
    1065      6701166 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1066      6701166 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1067              :     SortTuple   stup;
    1068              : 
    1069      6701166 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1070        26786 :         stup.tuple = NULL;
    1071              : 
    1072      6701166 :     MemoryContextSwitchTo(oldcontext);
    1073              : 
    1074      6701166 :     return (IndexTuple) stup.tuple;
    1075              : }
    1076              : 
    1077              : /*
    1078              :  * Fetch the next BRIN tuple in either forward or back direction.
    1079              :  * Returns NULL if no more tuples.  Returned tuple belongs to tuplesort memory
    1080              :  * context, and must not be freed by caller.  Caller may not rely on tuple
    1081              :  * remaining valid after any further manipulation of tuplesort.
    1082              :  */
    1083              : BrinTuple *
    1084           24 : tuplesort_getbrintuple(Tuplesortstate *state, Size *len, bool forward)
    1085              : {
    1086           24 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1087           24 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1088              :     SortTuple   stup;
    1089              :     BrinSortTuple *btup;
    1090              : 
    1091           24 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1092            4 :         stup.tuple = NULL;
    1093              : 
    1094           24 :     MemoryContextSwitchTo(oldcontext);
    1095              : 
    1096           24 :     if (!stup.tuple)
    1097            4 :         return NULL;
    1098              : 
    1099           20 :     btup = (BrinSortTuple *) stup.tuple;
    1100              : 
    1101           20 :     *len = btup->tuplen;
    1102              : 
    1103           20 :     return &btup->tuple;
    1104              : }
    1105              : 
    1106              : GinTuple *
    1107        34402 : tuplesort_getgintuple(Tuplesortstate *state, Size *len, bool forward)
    1108              : {
    1109        34402 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1110        34402 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1111              :     SortTuple   stup;
    1112              :     GinTuple   *tup;
    1113              : 
    1114        34402 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1115           52 :         stup.tuple = NULL;
    1116              : 
    1117        34402 :     MemoryContextSwitchTo(oldcontext);
    1118              : 
    1119        34402 :     if (!stup.tuple)
    1120           52 :         return NULL;
    1121              : 
    1122        34350 :     tup = (GinTuple *) stup.tuple;
    1123              : 
    1124        34350 :     *len = tup->tuplen;
    1125              : 
    1126        34350 :     return tup;
    1127              : }
    1128              : 
    1129              : /*
    1130              :  * Fetch the next Datum in either forward or back direction.
    1131              :  * Returns false if no more datums.
    1132              :  *
    1133              :  * If the Datum is pass-by-ref type, the returned value is freshly palloc'd
    1134              :  * in caller's context, and is now owned by the caller (this differs from
    1135              :  * similar routines for other types of tuplesorts).
    1136              :  *
    1137              :  * Caller may optionally be passed back abbreviated value (on true return
    1138              :  * value) when abbreviation was used, which can be used to cheaply avoid
    1139              :  * equality checks that might otherwise be required.  Caller can safely make a
    1140              :  * determination of "non-equal tuple" based on simple binary inequality.  A
    1141              :  * NULL value will have a zeroed abbreviated value representation, which caller
    1142              :  * may rely on in abbreviated inequality check.
    1143              :  *
    1144              :  * For byref Datums, if copy is true, *val is set to a copy of the Datum
    1145              :  * copied into the caller's memory context, so that it will stay valid
    1146              :  * regardless of future manipulations of the tuplesort's state (up to and
    1147              :  * including deleting the tuplesort).  If copy is false, *val will just be
    1148              :  * set to a pointer to the Datum held within the tuplesort, which is more
    1149              :  * efficient, but only safe for callers that are prepared to have any
    1150              :  * subsequent manipulation of the tuplesort's state invalidate slot contents.
    1151              :  * For byval Datums, the value of the 'copy' parameter has no effect.
    1152              :  */
    1153              : bool
    1154      1307936 : tuplesort_getdatum(Tuplesortstate *state, bool forward, bool copy,
    1155              :                    Datum *val, bool *isNull, Datum *abbrev)
    1156              : {
    1157      1307936 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1158      1307936 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1159      1307936 :     TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
    1160              :     SortTuple   stup;
    1161              : 
    1162      1307936 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1163              :     {
    1164        31632 :         MemoryContextSwitchTo(oldcontext);
    1165        31632 :         return false;
    1166              :     }
    1167              : 
    1168              :     /* Ensure we copy into caller's memory context */
    1169      1276304 :     MemoryContextSwitchTo(oldcontext);
    1170              : 
    1171              :     /* Record abbreviated key for caller */
    1172      1276304 :     if (base->sortKeys->abbrev_converter && abbrev)
    1173        27512 :         *abbrev = stup.datum1;
    1174              : 
    1175      1276304 :     if (stup.isnull1 || !base->tuples)
    1176              :     {
    1177       704571 :         *val = stup.datum1;
    1178       704571 :         *isNull = stup.isnull1;
    1179              :     }
    1180              :     else
    1181              :     {
    1182              :         /* use stup.tuple because stup.datum1 may be an abbreviation */
    1183       571733 :         if (copy)
    1184        30024 :             *val = datumCopy(PointerGetDatum(stup.tuple), false,
    1185              :                              arg->datumTypeLen);
    1186              :         else
    1187       541709 :             *val = PointerGetDatum(stup.tuple);
    1188       571733 :         *isNull = false;
    1189              :     }
    1190              : 
    1191      1276304 :     return true;
    1192              : }
    1193              : 
    1194              : 
    1195              : /*
    1196              :  * Routines specialized for HeapTuple (actually MinimalTuple) case
    1197              :  */
    1198              : 
    1199              : static void
    1200            6 : removeabbrev_heap(Tuplesortstate *state, SortTuple *stups, int count)
    1201              : {
    1202              :     int         i;
    1203            6 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1204              : 
    1205        61446 :     for (i = 0; i < count; i++)
    1206              :     {
    1207              :         HeapTupleData htup;
    1208              : 
    1209        61440 :         htup.t_len = ((MinimalTuple) stups[i].tuple)->t_len +
    1210              :             MINIMAL_TUPLE_OFFSET;
    1211        61440 :         htup.t_data = (HeapTupleHeader) ((char *) stups[i].tuple -
    1212              :                                          MINIMAL_TUPLE_OFFSET);
    1213        61440 :         stups[i].datum1 = heap_getattr(&htup,
    1214        61440 :                                        base->sortKeys[0].ssup_attno,
    1215        61440 :                                        (TupleDesc) base->arg,
    1216        61440 :                                        &stups[i].isnull1);
    1217              :     }
    1218            6 : }
    1219              : 
    1220              : static int
    1221     31544728 : comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
    1222              : {
    1223     31544728 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1224     31544728 :     SortSupport sortKey = base->sortKeys;
    1225              :     int32       compare;
    1226              : 
    1227              : 
    1228              :     /* Compare the leading sort key */
    1229     31544728 :     compare = ApplySortComparator(a->datum1, a->isnull1,
    1230     31544728 :                                   b->datum1, b->isnull1,
    1231              :                                   sortKey);
    1232     31544728 :     if (compare != 0)
    1233     10641359 :         return compare;
    1234              : 
    1235              :     /* Compare additional sort keys */
    1236     20903369 :     return comparetup_heap_tiebreak(a, b, state);
    1237              : }
    1238              : 
    1239              : static int
    1240     21823482 : comparetup_heap_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
    1241              : {
    1242     21823482 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1243     21823482 :     SortSupport sortKey = base->sortKeys;
    1244              :     HeapTupleData ltup;
    1245              :     HeapTupleData rtup;
    1246              :     TupleDesc   tupDesc;
    1247              :     int         nkey;
    1248              :     int32       compare;
    1249              :     AttrNumber  attno;
    1250              :     Datum       datum1,
    1251              :                 datum2;
    1252              :     bool        isnull1,
    1253              :                 isnull2;
    1254              : 
    1255     21823482 :     ltup.t_len = ((MinimalTuple) a->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
    1256     21823482 :     ltup.t_data = (HeapTupleHeader) ((char *) a->tuple - MINIMAL_TUPLE_OFFSET);
    1257     21823482 :     rtup.t_len = ((MinimalTuple) b->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
    1258     21823482 :     rtup.t_data = (HeapTupleHeader) ((char *) b->tuple - MINIMAL_TUPLE_OFFSET);
    1259     21823482 :     tupDesc = (TupleDesc) base->arg;
    1260              : 
    1261     21823482 :     if (sortKey->abbrev_converter)
    1262              :     {
    1263       500887 :         attno = sortKey->ssup_attno;
    1264              : 
    1265       500887 :         datum1 = heap_getattr(&ltup, attno, tupDesc, &isnull1);
    1266       500887 :         datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
    1267              : 
    1268       500887 :         compare = ApplySortAbbrevFullComparator(datum1, isnull1,
    1269              :                                                 datum2, isnull2,
    1270              :                                                 sortKey);
    1271       500887 :         if (compare != 0)
    1272       416329 :             return compare;
    1273              :     }
    1274              : 
    1275     21407153 :     sortKey++;
    1276     22435402 :     for (nkey = 1; nkey < base->nKeys; nkey++, sortKey++)
    1277              :     {
    1278     21351742 :         attno = sortKey->ssup_attno;
    1279              : 
    1280     21351742 :         datum1 = heap_getattr(&ltup, attno, tupDesc, &isnull1);
    1281     21351742 :         datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
    1282              : 
    1283     21351742 :         compare = ApplySortComparator(datum1, isnull1,
    1284              :                                       datum2, isnull2,
    1285              :                                       sortKey);
    1286     21351742 :         if (compare != 0)
    1287     20323493 :             return compare;
    1288              :     }
    1289              : 
    1290      1083660 :     return 0;
    1291              : }
    1292              : 
    1293              : static void
    1294       545225 : writetup_heap(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    1295              : {
    1296       545225 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1297       545225 :     MinimalTuple tuple = (MinimalTuple) stup->tuple;
    1298              : 
    1299              :     /* the part of the MinimalTuple we'll write: */
    1300       545225 :     char       *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
    1301       545225 :     unsigned int tupbodylen = tuple->t_len - MINIMAL_TUPLE_DATA_OFFSET;
    1302              : 
    1303              :     /* total on-disk footprint: */
    1304       545225 :     unsigned int tuplen = tupbodylen + sizeof(int);
    1305              : 
    1306       545225 :     LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1307       545225 :     LogicalTapeWrite(tape, tupbody, tupbodylen);
    1308       545225 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1309        15000 :         LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1310       545225 : }
    1311              : 
    1312              : static void
    1313       494090 : readtup_heap(Tuplesortstate *state, SortTuple *stup,
    1314              :              LogicalTape *tape, unsigned int len)
    1315              : {
    1316       494090 :     unsigned int tupbodylen = len - sizeof(int);
    1317       494090 :     unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
    1318       494090 :     MinimalTuple tuple = (MinimalTuple) tuplesort_readtup_alloc(state, tuplen);
    1319       494090 :     char       *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
    1320       494090 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1321              :     HeapTupleData htup;
    1322              : 
    1323              :     /* read in the tuple proper */
    1324       494090 :     tuple->t_len = tuplen;
    1325       494090 :     LogicalTapeReadExact(tape, tupbody, tupbodylen);
    1326       494090 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1327        23892 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    1328       494090 :     stup->tuple = tuple;
    1329              :     /* set up first-column key value */
    1330       494090 :     htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
    1331       494090 :     htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
    1332       988180 :     stup->datum1 = heap_getattr(&htup,
    1333       494090 :                                 base->sortKeys[0].ssup_attno,
    1334       494090 :                                 (TupleDesc) base->arg,
    1335              :                                 &stup->isnull1);
    1336       494090 : }
    1337              : 
    1338              : /*
    1339              :  * Routines specialized for the CLUSTER case (HeapTuple data, with
    1340              :  * comparisons per a btree index definition)
    1341              :  */
    1342              : 
    1343              : static void
    1344            6 : removeabbrev_cluster(Tuplesortstate *state, SortTuple *stups, int count)
    1345              : {
    1346              :     int         i;
    1347            6 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1348            6 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
    1349              : 
    1350        61446 :     for (i = 0; i < count; i++)
    1351              :     {
    1352              :         HeapTuple   tup;
    1353              : 
    1354        61440 :         tup = (HeapTuple) stups[i].tuple;
    1355        61440 :         stups[i].datum1 = heap_getattr(tup,
    1356        61440 :                                        arg->indexInfo->ii_IndexAttrNumbers[0],
    1357              :                                        arg->tupDesc,
    1358        61440 :                                        &stups[i].isnull1);
    1359              :     }
    1360            6 : }
    1361              : 
    1362              : static int
    1363      3088612 : comparetup_cluster(const SortTuple *a, const SortTuple *b,
    1364              :                    Tuplesortstate *state)
    1365              : {
    1366      3088612 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1367      3088612 :     SortSupport sortKey = base->sortKeys;
    1368              :     int32       compare;
    1369              : 
    1370              :     /* Compare the leading sort key, if it's simple */
    1371      3088612 :     if (base->haveDatum1)
    1372              :     {
    1373      3082717 :         compare = ApplySortComparator(a->datum1, a->isnull1,
    1374      3082717 :                                       b->datum1, b->isnull1,
    1375              :                                       sortKey);
    1376      3082717 :         if (compare != 0)
    1377      2952149 :             return compare;
    1378              :     }
    1379              : 
    1380       136463 :     return comparetup_cluster_tiebreak(a, b, state);
    1381              : }
    1382              : 
    1383              : static int
    1384       276317 : comparetup_cluster_tiebreak(const SortTuple *a, const SortTuple *b,
    1385              :                             Tuplesortstate *state)
    1386              : {
    1387       276317 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1388       276317 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
    1389       276317 :     SortSupport sortKey = base->sortKeys;
    1390              :     HeapTuple   ltup;
    1391              :     HeapTuple   rtup;
    1392              :     TupleDesc   tupDesc;
    1393              :     int         nkey;
    1394       276317 :     int32       compare = 0;
    1395              :     Datum       datum1,
    1396              :                 datum2;
    1397              :     bool        isnull1,
    1398              :                 isnull2;
    1399              : 
    1400       276317 :     ltup = (HeapTuple) a->tuple;
    1401       276317 :     rtup = (HeapTuple) b->tuple;
    1402       276317 :     tupDesc = arg->tupDesc;
    1403              : 
    1404              :     /* Compare the leading sort key, if it's simple */
    1405       276317 :     if (base->haveDatum1)
    1406              :     {
    1407       270422 :         if (sortKey->abbrev_converter)
    1408              :         {
    1409        60034 :             AttrNumber  leading = arg->indexInfo->ii_IndexAttrNumbers[0];
    1410              : 
    1411        60034 :             datum1 = heap_getattr(ltup, leading, tupDesc, &isnull1);
    1412        60034 :             datum2 = heap_getattr(rtup, leading, tupDesc, &isnull2);
    1413              : 
    1414        60034 :             compare = ApplySortAbbrevFullComparator(datum1, isnull1,
    1415              :                                                     datum2, isnull2,
    1416              :                                                     sortKey);
    1417              :         }
    1418       270422 :         if (compare != 0 || base->nKeys == 1)
    1419        61676 :             return compare;
    1420              :         /* Compare additional columns the hard way */
    1421       208746 :         sortKey++;
    1422       208746 :         nkey = 1;
    1423              :     }
    1424              :     else
    1425              :     {
    1426              :         /* Must compare all keys the hard way */
    1427         5895 :         nkey = 0;
    1428              :     }
    1429              : 
    1430       214641 :     if (arg->indexInfo->ii_Expressions == NULL)
    1431              :     {
    1432              :         /* If not expression index, just compare the proper heap attrs */
    1433              : 
    1434       291651 :         for (; nkey < base->nKeys; nkey++, sortKey++)
    1435              :         {
    1436       291651 :             AttrNumber  attno = arg->indexInfo->ii_IndexAttrNumbers[nkey];
    1437              : 
    1438       291651 :             datum1 = heap_getattr(ltup, attno, tupDesc, &isnull1);
    1439       291651 :             datum2 = heap_getattr(rtup, attno, tupDesc, &isnull2);
    1440              : 
    1441       291651 :             compare = ApplySortComparator(datum1, isnull1,
    1442              :                                           datum2, isnull2,
    1443              :                                           sortKey);
    1444       291651 :             if (compare != 0)
    1445       208746 :                 return compare;
    1446              :         }
    1447              :     }
    1448              :     else
    1449              :     {
    1450              :         /*
    1451              :          * In the expression index case, compute the whole index tuple and
    1452              :          * then compare values.  It would perhaps be faster to compute only as
    1453              :          * many columns as we need to compare, but that would require
    1454              :          * duplicating all the logic in FormIndexDatum.
    1455              :          */
    1456              :         Datum       l_index_values[INDEX_MAX_KEYS];
    1457              :         bool        l_index_isnull[INDEX_MAX_KEYS];
    1458              :         Datum       r_index_values[INDEX_MAX_KEYS];
    1459              :         bool        r_index_isnull[INDEX_MAX_KEYS];
    1460              :         TupleTableSlot *ecxt_scantuple;
    1461              : 
    1462              :         /* Reset context each time to prevent memory leakage */
    1463         5895 :         ResetPerTupleExprContext(arg->estate);
    1464              : 
    1465         5895 :         ecxt_scantuple = GetPerTupleExprContext(arg->estate)->ecxt_scantuple;
    1466              : 
    1467         5895 :         ExecStoreHeapTuple(ltup, ecxt_scantuple, false);
    1468         5895 :         FormIndexDatum(arg->indexInfo, ecxt_scantuple, arg->estate,
    1469              :                        l_index_values, l_index_isnull);
    1470              : 
    1471         5895 :         ExecStoreHeapTuple(rtup, ecxt_scantuple, false);
    1472         5895 :         FormIndexDatum(arg->indexInfo, ecxt_scantuple, arg->estate,
    1473              :                        r_index_values, r_index_isnull);
    1474              : 
    1475         6357 :         for (; nkey < base->nKeys; nkey++, sortKey++)
    1476              :         {
    1477         6357 :             compare = ApplySortComparator(l_index_values[nkey],
    1478         6357 :                                           l_index_isnull[nkey],
    1479              :                                           r_index_values[nkey],
    1480         6357 :                                           r_index_isnull[nkey],
    1481              :                                           sortKey);
    1482         6357 :             if (compare != 0)
    1483         5895 :                 return compare;
    1484              :         }
    1485              :     }
    1486              : 
    1487            0 :     return 0;
    1488              : }
    1489              : 
    1490              : static void
    1491        30000 : writetup_cluster(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    1492              : {
    1493        30000 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1494        30000 :     HeapTuple   tuple = (HeapTuple) stup->tuple;
    1495        30000 :     unsigned int tuplen = tuple->t_len + sizeof(ItemPointerData) + sizeof(int);
    1496              : 
    1497              :     /* We need to store t_self, but not other fields of HeapTupleData */
    1498        30000 :     LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1499        30000 :     LogicalTapeWrite(tape, &tuple->t_self, sizeof(ItemPointerData));
    1500        30000 :     LogicalTapeWrite(tape, tuple->t_data, tuple->t_len);
    1501        30000 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1502            0 :         LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1503        30000 : }
    1504              : 
    1505              : static void
    1506        30000 : readtup_cluster(Tuplesortstate *state, SortTuple *stup,
    1507              :                 LogicalTape *tape, unsigned int tuplen)
    1508              : {
    1509        30000 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1510        30000 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
    1511        30000 :     unsigned int t_len = tuplen - sizeof(ItemPointerData) - sizeof(int);
    1512        30000 :     HeapTuple   tuple = (HeapTuple) tuplesort_readtup_alloc(state,
    1513              :                                                             t_len + HEAPTUPLESIZE);
    1514              : 
    1515              :     /* Reconstruct the HeapTupleData header */
    1516        30000 :     tuple->t_data = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
    1517        30000 :     tuple->t_len = t_len;
    1518        30000 :     LogicalTapeReadExact(tape, &tuple->t_self, sizeof(ItemPointerData));
    1519              :     /* We don't currently bother to reconstruct t_tableOid */
    1520        30000 :     tuple->t_tableOid = InvalidOid;
    1521              :     /* Read in the tuple body */
    1522        30000 :     LogicalTapeReadExact(tape, tuple->t_data, tuple->t_len);
    1523        30000 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1524            0 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    1525        30000 :     stup->tuple = tuple;
    1526              :     /* set up first-column key value, if it's a simple column */
    1527        30000 :     if (base->haveDatum1)
    1528        30000 :         stup->datum1 = heap_getattr(tuple,
    1529        30000 :                                     arg->indexInfo->ii_IndexAttrNumbers[0],
    1530              :                                     arg->tupDesc,
    1531              :                                     &stup->isnull1);
    1532        30000 : }
    1533              : 
    1534              : static void
    1535           58 : freestate_cluster(Tuplesortstate *state)
    1536              : {
    1537           58 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1538           58 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
    1539              : 
    1540              :     /* Free any execution state created for CLUSTER case */
    1541           58 :     if (arg->estate != NULL)
    1542              :     {
    1543           12 :         ExprContext *econtext = GetPerTupleExprContext(arg->estate);
    1544              : 
    1545           12 :         ExecDropSingleTupleTableSlot(econtext->ecxt_scantuple);
    1546           12 :         FreeExecutorState(arg->estate);
    1547              :     }
    1548           58 : }
    1549              : 
    1550              : /*
    1551              :  * Routines specialized for IndexTuple case
    1552              :  *
    1553              :  * The btree and hash cases require separate comparison functions, but the
    1554              :  * IndexTuple representation is the same so the copy/write/read support
    1555              :  * functions can be shared.
    1556              :  */
    1557              : 
    1558              : static void
    1559           30 : removeabbrev_index(Tuplesortstate *state, SortTuple *stups, int count)
    1560              : {
    1561           30 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1562           30 :     TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
    1563              :     int         i;
    1564              : 
    1565       307230 :     for (i = 0; i < count; i++)
    1566              :     {
    1567              :         IndexTuple  tuple;
    1568              : 
    1569       307200 :         tuple = stups[i].tuple;
    1570       307200 :         stups[i].datum1 = index_getattr(tuple,
    1571              :                                         1,
    1572       307200 :                                         RelationGetDescr(arg->indexRel),
    1573       307200 :                                         &stups[i].isnull1);
    1574              :     }
    1575           30 : }
    1576              : 
    1577              : static int
    1578     33226651 : comparetup_index_btree(const SortTuple *a, const SortTuple *b,
    1579              :                        Tuplesortstate *state)
    1580              : {
    1581              :     /*
    1582              :      * This is similar to comparetup_heap(), but expects index tuples.  There
    1583              :      * is also special handling for enforcing uniqueness, and special
    1584              :      * treatment for equal keys at the end.
    1585              :      */
    1586     33226651 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1587     33226651 :     SortSupport sortKey = base->sortKeys;
    1588              :     int32       compare;
    1589              : 
    1590              :     /* Compare the leading sort key */
    1591     33226651 :     compare = ApplySortComparator(a->datum1, a->isnull1,
    1592     33226651 :                                   b->datum1, b->isnull1,
    1593              :                                   sortKey);
    1594     33226651 :     if (compare != 0)
    1595     29878791 :         return compare;
    1596              : 
    1597              :     /* Compare additional sort keys */
    1598      3347860 :     return comparetup_index_btree_tiebreak(a, b, state);
    1599              : }
    1600              : 
    1601              : static int
    1602      9531297 : comparetup_index_btree_tiebreak(const SortTuple *a, const SortTuple *b,
    1603              :                                 Tuplesortstate *state)
    1604              : {
    1605      9531297 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1606      9531297 :     TuplesortIndexBTreeArg *arg = (TuplesortIndexBTreeArg *) base->arg;
    1607      9531297 :     SortSupport sortKey = base->sortKeys;
    1608              :     IndexTuple  tuple1;
    1609              :     IndexTuple  tuple2;
    1610              :     int         keysz;
    1611              :     TupleDesc   tupDes;
    1612      9531297 :     bool        equal_hasnull = false;
    1613              :     int         nkey;
    1614              :     int32       compare;
    1615              :     Datum       datum1,
    1616              :                 datum2;
    1617              :     bool        isnull1,
    1618              :                 isnull2;
    1619              : 
    1620      9531297 :     tuple1 = (IndexTuple) a->tuple;
    1621      9531297 :     tuple2 = (IndexTuple) b->tuple;
    1622      9531297 :     keysz = base->nKeys;
    1623      9531297 :     tupDes = RelationGetDescr(arg->index.indexRel);
    1624              : 
    1625      9531297 :     if (sortKey->abbrev_converter)
    1626              :     {
    1627       343016 :         datum1 = index_getattr(tuple1, 1, tupDes, &isnull1);
    1628       343016 :         datum2 = index_getattr(tuple2, 1, tupDes, &isnull2);
    1629              : 
    1630       343016 :         compare = ApplySortAbbrevFullComparator(datum1, isnull1,
    1631              :                                                 datum2, isnull2,
    1632              :                                                 sortKey);
    1633       343016 :         if (compare != 0)
    1634       315728 :             return compare;
    1635              :     }
    1636              : 
    1637              :     /* they are equal, so we only need to examine one null flag */
    1638      9215569 :     if (a->isnull1)
    1639         7519 :         equal_hasnull = true;
    1640              : 
    1641      9215569 :     sortKey++;
    1642     10513524 :     for (nkey = 2; nkey <= keysz; nkey++, sortKey++)
    1643              :     {
    1644      3803092 :         datum1 = index_getattr(tuple1, nkey, tupDes, &isnull1);
    1645      3803092 :         datum2 = index_getattr(tuple2, nkey, tupDes, &isnull2);
    1646              : 
    1647      3803092 :         compare = ApplySortComparator(datum1, isnull1,
    1648              :                                       datum2, isnull2,
    1649              :                                       sortKey);
    1650      3803092 :         if (compare != 0)
    1651      2505137 :             return compare;     /* done when we find unequal attributes */
    1652              : 
    1653              :         /* they are equal, so we only need to examine one null flag */
    1654      1297955 :         if (isnull1)
    1655        12996 :             equal_hasnull = true;
    1656              :     }
    1657              : 
    1658              :     /*
    1659              :      * If btree has asked us to enforce uniqueness, complain if two equal
    1660              :      * tuples are detected (unless there was at least one NULL field and NULLS
    1661              :      * NOT DISTINCT was not set).
    1662              :      *
    1663              :      * It is sufficient to make the test here, because if two tuples are equal
    1664              :      * they *must* get compared at some stage of the sort --- otherwise the
    1665              :      * sort algorithm wouldn't have checked whether one must appear before the
    1666              :      * other.
    1667              :      */
    1668      6710432 :     if (arg->enforceUnique && !(!arg->uniqueNullsNotDistinct && equal_hasnull))
    1669              :     {
    1670              :         Datum       values[INDEX_MAX_KEYS];
    1671              :         bool        isnull[INDEX_MAX_KEYS];
    1672              :         char       *key_desc;
    1673              : 
    1674              :         /*
    1675              :          * Some rather brain-dead implementations of qsort (such as the one in
    1676              :          * QNX 4) will sometimes call the comparison routine to compare a
    1677              :          * value to itself, but we always use our own implementation, which
    1678              :          * does not.
    1679              :          */
    1680              :         Assert(tuple1 != tuple2);
    1681              : 
    1682           42 :         index_deform_tuple(tuple1, tupDes, values, isnull);
    1683              : 
    1684           42 :         key_desc = BuildIndexValueDescription(arg->index.indexRel, values, isnull);
    1685              : 
    1686           42 :         ereport(ERROR,
    1687              :                 (errcode(ERRCODE_UNIQUE_VIOLATION),
    1688              :                  errmsg("could not create unique index \"%s\"",
    1689              :                         RelationGetRelationName(arg->index.indexRel)),
    1690              :                  key_desc ? errdetail("Key %s is duplicated.", key_desc) :
    1691              :                  errdetail("Duplicate keys exist."),
    1692              :                  errtableconstraint(arg->index.heapRel,
    1693              :                                     RelationGetRelationName(arg->index.indexRel))));
    1694              :     }
    1695              : 
    1696              :     /*
    1697              :      * If key values are equal, we sort on ItemPointer.  This is required for
    1698              :      * btree indexes, since heap TID is treated as an implicit last key
    1699              :      * attribute in order to ensure that all keys in the index are physically
    1700              :      * unique.
    1701              :      */
    1702              :     {
    1703      6710390 :         BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
    1704      6710390 :         BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
    1705              : 
    1706      6710390 :         if (blk1 != blk2)
    1707      6095973 :             return (blk1 < blk2) ? -1 : 1;
    1708              :     }
    1709              :     {
    1710       614417 :         OffsetNumber pos1 = ItemPointerGetOffsetNumber(&tuple1->t_tid);
    1711       614417 :         OffsetNumber pos2 = ItemPointerGetOffsetNumber(&tuple2->t_tid);
    1712              : 
    1713       614417 :         if (pos1 != pos2)
    1714       614417 :             return (pos1 < pos2) ? -1 : 1;
    1715              :     }
    1716              : 
    1717              :     /* ItemPointer values should never be equal */
    1718              :     Assert(false);
    1719              : 
    1720            0 :     return 0;
    1721              : }
    1722              : 
    1723              : static int
    1724       913962 : comparetup_index_hash(const SortTuple *a, const SortTuple *b,
    1725              :                       Tuplesortstate *state)
    1726              : {
    1727              :     Bucket      bucket1;
    1728              :     Bucket      bucket2;
    1729              :     uint32      hash1;
    1730              :     uint32      hash2;
    1731              :     IndexTuple  tuple1;
    1732              :     IndexTuple  tuple2;
    1733       913962 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1734       913962 :     TuplesortIndexHashArg *arg = (TuplesortIndexHashArg *) base->arg;
    1735              : 
    1736              :     /*
    1737              :      * Fetch hash keys and mask off bits we don't want to sort by, so that the
    1738              :      * initial sort is just on the bucket number.  We know that the first
    1739              :      * column of the index tuple is the hash key.
    1740              :      */
    1741              :     Assert(!a->isnull1);
    1742       913962 :     bucket1 = _hash_hashkey2bucket(DatumGetUInt32(a->datum1),
    1743              :                                    arg->max_buckets, arg->high_mask,
    1744              :                                    arg->low_mask);
    1745              :     Assert(!b->isnull1);
    1746       913962 :     bucket2 = _hash_hashkey2bucket(DatumGetUInt32(b->datum1),
    1747              :                                    arg->max_buckets, arg->high_mask,
    1748              :                                    arg->low_mask);
    1749       913962 :     if (bucket1 > bucket2)
    1750       270487 :         return 1;
    1751       643475 :     else if (bucket1 < bucket2)
    1752       253917 :         return -1;
    1753              : 
    1754              :     /*
    1755              :      * If bucket values are equal, sort by hash values.  This allows us to
    1756              :      * insert directly onto bucket/overflow pages, where the index tuples are
    1757              :      * stored in hash order to allow fast binary search within each page.
    1758              :      */
    1759       389558 :     hash1 = DatumGetUInt32(a->datum1);
    1760       389558 :     hash2 = DatumGetUInt32(b->datum1);
    1761       389558 :     if (hash1 > hash2)
    1762        97508 :         return 1;
    1763       292050 :     else if (hash1 < hash2)
    1764        87091 :         return -1;
    1765              : 
    1766              :     /*
    1767              :      * If hash values are equal, we sort on ItemPointer.  This does not affect
    1768              :      * validity of the finished index, but it may be useful to have index
    1769              :      * scans in physical order.
    1770              :      */
    1771       204959 :     tuple1 = (IndexTuple) a->tuple;
    1772       204959 :     tuple2 = (IndexTuple) b->tuple;
    1773              : 
    1774              :     {
    1775       204959 :         BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
    1776       204959 :         BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
    1777              : 
    1778       204959 :         if (blk1 != blk2)
    1779       136543 :             return (blk1 < blk2) ? -1 : 1;
    1780              :     }
    1781              :     {
    1782        68416 :         OffsetNumber pos1 = ItemPointerGetOffsetNumber(&tuple1->t_tid);
    1783        68416 :         OffsetNumber pos2 = ItemPointerGetOffsetNumber(&tuple2->t_tid);
    1784              : 
    1785        68416 :         if (pos1 != pos2)
    1786        68416 :             return (pos1 < pos2) ? -1 : 1;
    1787              :     }
    1788              : 
    1789              :     /* ItemPointer values should never be equal */
    1790              :     Assert(false);
    1791              : 
    1792            0 :     return 0;
    1793              : }
    1794              : 
    1795              : /*
    1796              :  * Sorting for hash indexes only uses one sort key, so this shouldn't ever be
    1797              :  * called. It's only here for consistency.
    1798              :  */
    1799              : static int
    1800            0 : comparetup_index_hash_tiebreak(const SortTuple *a, const SortTuple *b,
    1801              :                                Tuplesortstate *state)
    1802              : {
    1803              :     Assert(false);
    1804              : 
    1805            0 :     return 0;
    1806              : }
    1807              : 
    1808              : static void
    1809      1855043 : writetup_index(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    1810              : {
    1811      1855043 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1812      1855043 :     IndexTuple  tuple = (IndexTuple) stup->tuple;
    1813              :     unsigned int tuplen;
    1814              : 
    1815      1855043 :     tuplen = IndexTupleSize(tuple) + sizeof(tuplen);
    1816      1855043 :     LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1817      1855043 :     LogicalTapeWrite(tape, tuple, IndexTupleSize(tuple));
    1818      1855043 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1819            0 :         LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1820      1855043 : }
    1821              : 
    1822              : static void
    1823      1855043 : readtup_index(Tuplesortstate *state, SortTuple *stup,
    1824              :               LogicalTape *tape, unsigned int len)
    1825              : {
    1826      1855043 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1827      1855043 :     TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
    1828      1855043 :     unsigned int tuplen = len - sizeof(unsigned int);
    1829      1855043 :     IndexTuple  tuple = (IndexTuple) tuplesort_readtup_alloc(state, tuplen);
    1830              : 
    1831      1855043 :     LogicalTapeReadExact(tape, tuple, tuplen);
    1832      1855043 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1833            0 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    1834      1855043 :     stup->tuple = tuple;
    1835              :     /* set up first-column key value */
    1836      3710086 :     stup->datum1 = index_getattr(tuple,
    1837              :                                  1,
    1838      1855043 :                                  RelationGetDescr(arg->indexRel),
    1839              :                                  &stup->isnull1);
    1840      1855043 : }
    1841              : 
    1842              : /*
    1843              :  * Routines specialized for BrinTuple case
    1844              :  */
    1845              : 
    1846              : static void
    1847            0 : removeabbrev_index_brin(Tuplesortstate *state, SortTuple *stups, int count)
    1848              : {
    1849              :     int         i;
    1850              : 
    1851            0 :     for (i = 0; i < count; i++)
    1852              :     {
    1853              :         BrinSortTuple *tuple;
    1854              : 
    1855            0 :         tuple = stups[i].tuple;
    1856            0 :         stups[i].datum1 = UInt32GetDatum(tuple->tuple.bt_blkno);
    1857              :     }
    1858            0 : }
    1859              : 
    1860              : static int
    1861           19 : comparetup_index_brin(const SortTuple *a, const SortTuple *b,
    1862              :                       Tuplesortstate *state)
    1863              : {
    1864              :     Assert(TuplesortstateGetPublic(state)->haveDatum1);
    1865              : 
    1866           19 :     if (DatumGetUInt32(a->datum1) > DatumGetUInt32(b->datum1))
    1867            0 :         return 1;
    1868              : 
    1869           19 :     if (DatumGetUInt32(a->datum1) < DatumGetUInt32(b->datum1))
    1870           19 :         return -1;
    1871              : 
    1872              :     /* silence compilers */
    1873            0 :     return 0;
    1874              : }
    1875              : 
    1876              : static void
    1877           20 : writetup_index_brin(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    1878              : {
    1879           20 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1880           20 :     BrinSortTuple *tuple = (BrinSortTuple *) stup->tuple;
    1881           20 :     unsigned int tuplen = tuple->tuplen;
    1882              : 
    1883           20 :     tuplen = tuplen + sizeof(tuplen);
    1884           20 :     LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1885           20 :     LogicalTapeWrite(tape, &tuple->tuple, tuple->tuplen);
    1886           20 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1887            0 :         LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1888           20 : }
    1889              : 
    1890              : static void
    1891           20 : readtup_index_brin(Tuplesortstate *state, SortTuple *stup,
    1892              :                    LogicalTape *tape, unsigned int len)
    1893              : {
    1894              :     BrinSortTuple *tuple;
    1895           20 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1896           20 :     unsigned int tuplen = len - sizeof(unsigned int);
    1897              : 
    1898              :     /*
    1899              :      * Allocate space for the BRIN sort tuple, which is BrinTuple with an
    1900              :      * extra length field.
    1901              :      */
    1902           20 :     tuple = (BrinSortTuple *) tuplesort_readtup_alloc(state,
    1903              :                                                       BRINSORTTUPLE_SIZE(tuplen));
    1904              : 
    1905           20 :     tuple->tuplen = tuplen;
    1906              : 
    1907           20 :     LogicalTapeReadExact(tape, &tuple->tuple, tuplen);
    1908           20 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1909            0 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    1910           20 :     stup->tuple = tuple;
    1911              : 
    1912              :     /* set up first-column key value, which is block number */
    1913           20 :     stup->datum1 = UInt32GetDatum(tuple->tuple.bt_blkno);
    1914           20 : }
    1915              : 
    1916              : /*
    1917              :  * Routines specialized for GIN case
    1918              :  */
    1919              : 
    1920              : static void
    1921            0 : removeabbrev_index_gin(Tuplesortstate *state, SortTuple *stups, int count)
    1922              : {
    1923              :     Assert(false);
    1924            0 :     elog(ERROR, "removeabbrev_index_gin not implemented");
    1925              : }
    1926              : 
    1927              : static int
    1928        55765 : comparetup_index_gin(const SortTuple *a, const SortTuple *b,
    1929              :                      Tuplesortstate *state)
    1930              : {
    1931        55765 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1932              : 
    1933              :     Assert(!TuplesortstateGetPublic(state)->haveDatum1);
    1934              : 
    1935       111530 :     return _gin_compare_tuples((GinTuple *) a->tuple,
    1936        55765 :                                (GinTuple *) b->tuple,
    1937              :                                base->sortKeys);
    1938              : }
    1939              : 
    1940              : static void
    1941        17175 : writetup_index_gin(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    1942              : {
    1943        17175 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1944        17175 :     GinTuple   *tuple = (GinTuple *) stup->tuple;
    1945        17175 :     unsigned int tuplen = tuple->tuplen;
    1946              : 
    1947        17175 :     tuplen = tuplen + sizeof(tuplen);
    1948        17175 :     LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1949        17175 :     LogicalTapeWrite(tape, tuple, tuple->tuplen);
    1950        17175 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1951            0 :         LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1952        17175 : }
    1953              : 
    1954              : static void
    1955        17175 : readtup_index_gin(Tuplesortstate *state, SortTuple *stup,
    1956              :                   LogicalTape *tape, unsigned int len)
    1957              : {
    1958              :     GinTuple   *tuple;
    1959        17175 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1960        17175 :     unsigned int tuplen = len - sizeof(unsigned int);
    1961              : 
    1962              :     /*
    1963              :      * Allocate space for the GIN sort tuple, which already has the proper
    1964              :      * length included in the header.
    1965              :      */
    1966        17175 :     tuple = (GinTuple *) tuplesort_readtup_alloc(state, tuplen);
    1967              : 
    1968        17175 :     tuple->tuplen = tuplen;
    1969              : 
    1970        17175 :     LogicalTapeReadExact(tape, tuple, tuplen);
    1971        17175 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1972            0 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    1973        17175 :     stup->tuple = tuple;
    1974              : 
    1975              :     /* no abbreviations (FIXME maybe use attrnum for this?) */
    1976        17175 :     stup->datum1 = (Datum) 0;
    1977        17175 : }
    1978              : 
    1979              : /*
    1980              :  * Routines specialized for DatumTuple case
    1981              :  */
    1982              : 
    1983              : static void
    1984            6 : removeabbrev_datum(Tuplesortstate *state, SortTuple *stups, int count)
    1985              : {
    1986              :     int         i;
    1987              : 
    1988        61446 :     for (i = 0; i < count; i++)
    1989        61440 :         stups[i].datum1 = PointerGetDatum(stups[i].tuple);
    1990            6 : }
    1991              : 
    1992              : static int
    1993      4012591 : comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
    1994              : {
    1995      4012591 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1996              :     int         compare;
    1997              : 
    1998      4012591 :     compare = ApplySortComparator(a->datum1, a->isnull1,
    1999      4012591 :                                   b->datum1, b->isnull1,
    2000              :                                   base->sortKeys);
    2001      4012591 :     if (compare != 0)
    2002      3710233 :         return compare;
    2003              : 
    2004       302358 :     return comparetup_datum_tiebreak(a, b, state);
    2005              : }
    2006              : 
    2007              : static int
    2008      1479504 : comparetup_datum_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
    2009              : {
    2010      1479504 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    2011      1479504 :     int32       compare = 0;
    2012              : 
    2013              :     /* if we have abbreviations, then "tuple" has the original value */
    2014      1479504 :     if (base->sortKeys->abbrev_converter)
    2015      1264009 :         compare = ApplySortAbbrevFullComparator(PointerGetDatum(a->tuple), a->isnull1,
    2016      1264009 :                                                 PointerGetDatum(b->tuple), b->isnull1,
    2017              :                                                 base->sortKeys);
    2018              : 
    2019      1479504 :     return compare;
    2020              : }
    2021              : 
    2022              : static void
    2023       590261 : writetup_datum(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    2024              : {
    2025       590261 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    2026       590261 :     TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
    2027              :     void       *waddr;
    2028              :     unsigned int tuplen;
    2029              :     unsigned int writtenlen;
    2030              : 
    2031       590261 :     if (stup->isnull1)
    2032              :     {
    2033           33 :         waddr = NULL;
    2034           33 :         tuplen = 0;
    2035              :     }
    2036       590228 :     else if (!base->tuples)
    2037              :     {
    2038       200066 :         waddr = &stup->datum1;
    2039       200066 :         tuplen = sizeof(Datum);
    2040              :     }
    2041              :     else
    2042              :     {
    2043       390162 :         waddr = stup->tuple;
    2044       390162 :         tuplen = datumGetSize(PointerGetDatum(stup->tuple), false, arg->datumTypeLen);
    2045              :         Assert(tuplen != 0);
    2046              :     }
    2047              : 
    2048       590261 :     writtenlen = tuplen + sizeof(unsigned int);
    2049              : 
    2050       590261 :     LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
    2051       590261 :     LogicalTapeWrite(tape, waddr, tuplen);
    2052       590261 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    2053       260132 :         LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
    2054       590261 : }
    2055              : 
    2056              : static void
    2057       535276 : readtup_datum(Tuplesortstate *state, SortTuple *stup,
    2058              :               LogicalTape *tape, unsigned int len)
    2059              : {
    2060       535276 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    2061       535276 :     unsigned int tuplen = len - sizeof(unsigned int);
    2062              : 
    2063       535276 :     if (tuplen == 0)
    2064              :     {
    2065              :         /* it's NULL */
    2066           45 :         stup->datum1 = (Datum) 0;
    2067           45 :         stup->isnull1 = true;
    2068           45 :         stup->tuple = NULL;
    2069              :     }
    2070       535231 :     else if (!base->tuples)
    2071              :     {
    2072              :         Assert(tuplen == sizeof(Datum));
    2073       205069 :         LogicalTapeReadExact(tape, &stup->datum1, tuplen);
    2074       205069 :         stup->isnull1 = false;
    2075       205069 :         stup->tuple = NULL;
    2076              :     }
    2077              :     else
    2078              :     {
    2079       330162 :         void       *raddr = tuplesort_readtup_alloc(state, tuplen);
    2080              : 
    2081       330162 :         LogicalTapeReadExact(tape, raddr, tuplen);
    2082       330162 :         stup->datum1 = PointerGetDatum(raddr);
    2083       330162 :         stup->isnull1 = false;
    2084       330162 :         stup->tuple = raddr;
    2085              :     }
    2086              : 
    2087       535276 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    2088       265156 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    2089       535276 : }
        

Generated by: LCOV version 2.0-1