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-18 20:16:10 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        72222 : 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        72222 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     188              :                                                    sortopt);
     189        72222 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     190              :     MemoryContext oldcontext;
     191              :     int         i;
     192              : 
     193        72222 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     194              : 
     195              :     Assert(nkeys > 0);
     196              : 
     197        72222 :     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        72222 :     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        72222 :     base->removeabbrev = removeabbrev_heap;
     212        72222 :     base->comparetup = comparetup_heap;
     213        72222 :     base->comparetup_tiebreak = comparetup_heap_tiebreak;
     214        72222 :     base->writetup = writetup_heap;
     215        72222 :     base->readtup = readtup_heap;
     216        72222 :     base->haveDatum1 = true;
     217        72222 :     base->arg = tupDesc;     /* assume we need not copy tupDesc */
     218              : 
     219              :     /* Prepare SortSupport data for each column */
     220        72222 :     base->sortKeys = (SortSupport) palloc0(nkeys * sizeof(SortSupportData));
     221              : 
     222       181437 :     for (i = 0; i < nkeys; i++)
     223              :     {
     224       109223 :         SortSupport sortKey = base->sortKeys + i;
     225              : 
     226              :         Assert(attNums[i] != 0);
     227              :         Assert(sortOperators[i] != 0);
     228              : 
     229       109223 :         sortKey->ssup_cxt = CurrentMemoryContext;
     230       109223 :         sortKey->ssup_collation = sortCollations[i];
     231       109223 :         sortKey->ssup_nulls_first = nullsFirstFlags[i];
     232       109223 :         sortKey->ssup_attno = attNums[i];
     233              :         /* Convey if abbreviation optimization is applicable in principle */
     234       109223 :         sortKey->abbreviate = (i == 0 && base->haveDatum1);
     235              : 
     236       109223 :         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        72214 :     if (nkeys == 1 && !base->sortKeys->abbrev_converter)
     246        40459 :         base->onlyKey = base->sortKeys;
     247              : 
     248        72214 :     MemoryContextSwitchTo(oldcontext);
     249              : 
     250        72214 :     return state;
     251              : }
     252              : 
     253              : Tuplesortstate *
     254           90 : tuplesort_begin_cluster(TupleDesc tupDesc,
     255              :                         Relation indexRel,
     256              :                         int workMem,
     257              :                         SortCoordinate coordinate, int sortopt)
     258              : {
     259           90 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     260              :                                                    sortopt);
     261           90 :     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           90 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     270           90 :     arg = palloc0_object(TuplesortClusterArg);
     271              : 
     272           90 :     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           90 :     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           90 :     base->removeabbrev = removeabbrev_cluster;
     288           90 :     base->comparetup = comparetup_cluster;
     289           90 :     base->comparetup_tiebreak = comparetup_cluster_tiebreak;
     290           90 :     base->writetup = writetup_cluster;
     291           90 :     base->readtup = readtup_cluster;
     292           90 :     base->freestate = freestate_cluster;
     293           90 :     base->arg = arg;
     294              : 
     295           90 :     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           90 :     if (arg->indexInfo->ii_IndexAttrNumbers[0] == 0)
     302           16 :         base->haveDatum1 = false;
     303              :     else
     304           74 :         base->haveDatum1 = true;
     305              : 
     306           90 :     arg->tupDesc = tupDesc;      /* assume we need not copy tupDesc */
     307              : 
     308           90 :     indexScanKey = _bt_mkscankey(indexRel, NULL);
     309              : 
     310           90 :     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           16 :         arg->estate = CreateExecutorState();
     322           16 :         slot = MakeSingleTupleTableSlot(tupDesc, &TTSOpsHeapTuple);
     323           16 :         econtext = GetPerTupleExprContext(arg->estate);
     324           16 :         econtext->ecxt_scantuple = slot;
     325              :     }
     326              : 
     327              :     /* Prepare SortSupport data for each column */
     328           90 :     base->sortKeys = (SortSupport) palloc0(base->nKeys *
     329              :                                            sizeof(SortSupportData));
     330              : 
     331          196 :     for (i = 0; i < base->nKeys; i++)
     332              :     {
     333          106 :         SortSupport sortKey = base->sortKeys + i;
     334          106 :         ScanKey     scanKey = indexScanKey->scankeys + i;
     335              :         bool        reverse;
     336              : 
     337          106 :         sortKey->ssup_cxt = CurrentMemoryContext;
     338          106 :         sortKey->ssup_collation = scanKey->sk_collation;
     339          106 :         sortKey->ssup_nulls_first =
     340          106 :             (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
     341          106 :         sortKey->ssup_attno = scanKey->sk_attno;
     342              :         /* Convey if abbreviation optimization is applicable in principle */
     343          106 :         sortKey->abbreviate = (i == 0 && base->haveDatum1);
     344              : 
     345              :         Assert(sortKey->ssup_attno != 0);
     346              : 
     347          106 :         reverse = (scanKey->sk_flags & SK_BT_DESC) != 0;
     348              : 
     349          106 :         PrepareSortSupportFromIndexRel(indexRel, reverse, sortKey);
     350              :     }
     351              : 
     352           90 :     pfree(indexScanKey);
     353              : 
     354           90 :     MemoryContextSwitchTo(oldcontext);
     355              : 
     356           90 :     return state;
     357              : }
     358              : 
     359              : Tuplesortstate *
     360        56358 : 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        56358 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     369              :                                                    sortopt);
     370        56358 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     371              :     BTScanInsert indexScanKey;
     372              :     TuplesortIndexBTreeArg *arg;
     373              :     MemoryContext oldcontext;
     374              :     int         i;
     375              : 
     376        56358 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     377        56358 :     arg = palloc_object(TuplesortIndexBTreeArg);
     378              : 
     379        56358 :     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        56358 :     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        56358 :     base->removeabbrev = removeabbrev_index;
     395        56358 :     base->comparetup = comparetup_index_btree;
     396        56358 :     base->comparetup_tiebreak = comparetup_index_btree_tiebreak;
     397        56358 :     base->writetup = writetup_index;
     398        56358 :     base->readtup = readtup_index;
     399        56358 :     base->haveDatum1 = true;
     400        56358 :     base->arg = arg;
     401              : 
     402        56358 :     arg->index.heapRel = heapRel;
     403        56358 :     arg->index.indexRel = indexRel;
     404        56358 :     arg->enforceUnique = enforceUnique;
     405        56358 :     arg->uniqueNullsNotDistinct = uniqueNullsNotDistinct;
     406              : 
     407        56358 :     indexScanKey = _bt_mkscankey(indexRel, NULL);
     408              : 
     409              :     /* Prepare SortSupport data for each column */
     410        56358 :     base->sortKeys = (SortSupport) palloc0(base->nKeys *
     411              :                                            sizeof(SortSupportData));
     412              : 
     413       148914 :     for (i = 0; i < base->nKeys; i++)
     414              :     {
     415        92556 :         SortSupport sortKey = base->sortKeys + i;
     416        92556 :         ScanKey     scanKey = indexScanKey->scankeys + i;
     417              :         bool        reverse;
     418              : 
     419        92556 :         sortKey->ssup_cxt = CurrentMemoryContext;
     420        92556 :         sortKey->ssup_collation = scanKey->sk_collation;
     421        92556 :         sortKey->ssup_nulls_first =
     422        92556 :             (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
     423        92556 :         sortKey->ssup_attno = scanKey->sk_attno;
     424              :         /* Convey if abbreviation optimization is applicable in principle */
     425        92556 :         sortKey->abbreviate = (i == 0 && base->haveDatum1);
     426              : 
     427              :         Assert(sortKey->ssup_attno != 0);
     428              : 
     429        92556 :         reverse = (scanKey->sk_flags & SK_BT_DESC) != 0;
     430              : 
     431        92556 :         PrepareSortSupportFromIndexRel(indexRel, reverse, sortKey);
     432              :     }
     433              : 
     434        56358 :     pfree(indexScanKey);
     435              : 
     436        56358 :     MemoryContextSwitchTo(oldcontext);
     437              : 
     438        56358 :     return state;
     439              : }
     440              : 
     441              : Tuplesortstate *
     442            5 : 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            5 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     452              :                                                    sortopt);
     453            5 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     454              :     MemoryContext oldcontext;
     455              :     TuplesortIndexHashArg *arg;
     456              : 
     457            5 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     458            5 :     arg = palloc_object(TuplesortIndexHashArg);
     459              : 
     460            5 :     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            5 :     base->nKeys = 1;         /* Only one sort column, the hash code */
     471              : 
     472            5 :     base->removeabbrev = removeabbrev_index;
     473            5 :     base->comparetup = comparetup_index_hash;
     474            5 :     base->comparetup_tiebreak = comparetup_index_hash_tiebreak;
     475            5 :     base->writetup = writetup_index;
     476            5 :     base->readtup = readtup_index;
     477            5 :     base->haveDatum1 = true;
     478            5 :     base->arg = arg;
     479              : 
     480            5 :     arg->index.heapRel = heapRel;
     481            5 :     arg->index.indexRel = indexRel;
     482              : 
     483            5 :     arg->high_mask = high_mask;
     484            5 :     arg->low_mask = low_mask;
     485            5 :     arg->max_buckets = max_buckets;
     486              : 
     487            5 :     MemoryContextSwitchTo(oldcontext);
     488              : 
     489            5 :     return state;
     490              : }
     491              : 
     492              : Tuplesortstate *
     493          508 : tuplesort_begin_index_gist(Relation heapRel,
     494              :                            Relation indexRel,
     495              :                            int workMem,
     496              :                            SortCoordinate coordinate,
     497              :                            int sortopt)
     498              : {
     499          508 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     500              :                                                    sortopt);
     501          508 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     502              :     MemoryContext oldcontext;
     503              :     TuplesortIndexBTreeArg *arg;
     504              :     int         i;
     505              : 
     506          508 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     507          508 :     arg = palloc_object(TuplesortIndexBTreeArg);
     508              : 
     509          508 :     if (trace_sort)
     510            0 :         elog(LOG,
     511              :              "begin index sort: workMem = %d, randomAccess = %c",
     512              :              workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     513              : 
     514          508 :     base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
     515              : 
     516          508 :     base->removeabbrev = removeabbrev_index;
     517          508 :     base->comparetup = comparetup_index_btree;
     518          508 :     base->comparetup_tiebreak = comparetup_index_btree_tiebreak;
     519          508 :     base->writetup = writetup_index;
     520          508 :     base->readtup = readtup_index;
     521          508 :     base->haveDatum1 = true;
     522          508 :     base->arg = arg;
     523              : 
     524          508 :     arg->index.heapRel = heapRel;
     525          508 :     arg->index.indexRel = indexRel;
     526          508 :     arg->enforceUnique = false;
     527          508 :     arg->uniqueNullsNotDistinct = false;
     528              : 
     529              :     /* Prepare SortSupport data for each column */
     530          508 :     base->sortKeys = (SortSupport) palloc0(base->nKeys *
     531              :                                            sizeof(SortSupportData));
     532              : 
     533         1409 :     for (i = 0; i < base->nKeys; i++)
     534              :     {
     535          901 :         SortSupport sortKey = base->sortKeys + i;
     536              : 
     537          901 :         sortKey->ssup_cxt = CurrentMemoryContext;
     538          901 :         sortKey->ssup_collation = indexRel->rd_indcollation[i];
     539          901 :         sortKey->ssup_nulls_first = false;
     540          901 :         sortKey->ssup_attno = i + 1;
     541              :         /* Convey if abbreviation optimization is applicable in principle */
     542          901 :         sortKey->abbreviate = (i == 0 && base->haveDatum1);
     543              : 
     544              :         Assert(sortKey->ssup_attno != 0);
     545              : 
     546              :         /* Look for a sort support function */
     547          901 :         PrepareSortSupportFromGistIndexRel(indexRel, sortKey);
     548              :     }
     549              : 
     550          508 :     MemoryContextSwitchTo(oldcontext);
     551              : 
     552          508 :     return state;
     553              : }
     554              : 
     555              : Tuplesortstate *
     556           17 : tuplesort_begin_index_brin(int workMem,
     557              :                            SortCoordinate coordinate,
     558              :                            int sortopt)
     559              : {
     560           17 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     561              :                                                    sortopt);
     562           17 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     563              : 
     564           17 :     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           17 :     base->nKeys = 1;         /* Only one sort column, the block number */
     571              : 
     572           17 :     base->removeabbrev = removeabbrev_index_brin;
     573           17 :     base->comparetup = comparetup_index_brin;
     574           17 :     base->writetup = writetup_index_brin;
     575           17 :     base->readtup = readtup_index_brin;
     576           17 :     base->haveDatum1 = true;
     577           17 :     base->arg = NULL;
     578              : 
     579           17 :     return state;
     580              : }
     581              : 
     582              : Tuplesortstate *
     583          119 : tuplesort_begin_index_gin(Relation heapRel,
     584              :                           Relation indexRel,
     585              :                           int workMem, SortCoordinate coordinate,
     586              :                           int sortopt)
     587              : {
     588          119 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     589              :                                                    sortopt);
     590          119 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     591              :     MemoryContext oldcontext;
     592              :     int         i;
     593          119 :     TupleDesc   desc = RelationGetDescr(indexRel);
     594              : 
     595          119 :     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          119 :     base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
     611              : 
     612              :     /* Prepare SortSupport data for each column */
     613          119 :     base->sortKeys = (SortSupport) palloc0(base->nKeys *
     614              :                                            sizeof(SortSupportData));
     615              : 
     616          238 :     for (i = 0; i < base->nKeys; i++)
     617              :     {
     618          119 :         SortSupport sortKey = base->sortKeys + i;
     619          119 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     620              :         Oid         cmpFunc;
     621              : 
     622          119 :         sortKey->ssup_cxt = CurrentMemoryContext;
     623          119 :         sortKey->ssup_collation = indexRel->rd_indcollation[i];
     624          119 :         sortKey->ssup_nulls_first = false;
     625          119 :         sortKey->ssup_attno = i + 1;
     626          119 :         sortKey->abbreviate = false;
     627              : 
     628              :         Assert(sortKey->ssup_attno != 0);
     629              : 
     630          119 :         if (!OidIsValid(sortKey->ssup_collation))
     631          119 :             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          119 :         cmpFunc = index_getprocid(indexRel, i + 1, GIN_COMPARE_PROC);
     638          119 :         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          119 :         PrepareSortSupportComparisonShim(cmpFunc, sortKey);
     654              :     }
     655              : 
     656          119 :     base->removeabbrev = removeabbrev_index_gin;
     657          119 :     base->comparetup = comparetup_index_gin;
     658          119 :     base->writetup = writetup_index_gin;
     659          119 :     base->readtup = readtup_index_gin;
     660          119 :     base->haveDatum1 = false;
     661          119 :     base->arg = NULL;
     662              : 
     663          119 :     MemoryContextSwitchTo(oldcontext);
     664              : 
     665          119 :     return state;
     666              : }
     667              : 
     668              : Tuplesortstate *
     669        42414 : tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation,
     670              :                       bool nullsFirstFlag, int workMem,
     671              :                       SortCoordinate coordinate, int sortopt)
     672              : {
     673        42414 :     Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
     674              :                                                    sortopt);
     675        42414 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     676              :     TuplesortDatumArg *arg;
     677              :     MemoryContext oldcontext;
     678              :     int16       typlen;
     679              :     bool        typbyval;
     680              : 
     681        42414 :     oldcontext = MemoryContextSwitchTo(base->maincontext);
     682        42414 :     arg = palloc_object(TuplesortDatumArg);
     683              : 
     684        42414 :     if (trace_sort)
     685            0 :         elog(LOG,
     686              :              "begin datum sort: workMem = %d, randomAccess = %c",
     687              :              workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
     688              : 
     689        42414 :     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        42414 :     base->removeabbrev = removeabbrev_datum;
     699        42414 :     base->comparetup = comparetup_datum;
     700        42414 :     base->comparetup_tiebreak = comparetup_datum_tiebreak;
     701        42414 :     base->writetup = writetup_datum;
     702        42414 :     base->readtup = readtup_datum;
     703        42414 :     base->haveDatum1 = true;
     704        42414 :     base->arg = arg;
     705              : 
     706        42414 :     arg->datumType = datumType;
     707              : 
     708              :     /* lookup necessary attributes of the datum type */
     709        42414 :     get_typlenbyval(datumType, &typlen, &typbyval);
     710        42414 :     arg->datumTypeLen = typlen;
     711        42414 :     base->tuples = !typbyval;
     712              : 
     713              :     /* Prepare SortSupport data */
     714        42414 :     base->sortKeys = palloc0_object(SortSupportData);
     715              : 
     716        42414 :     base->sortKeys->ssup_cxt = CurrentMemoryContext;
     717        42414 :     base->sortKeys->ssup_collation = sortCollation;
     718        42414 :     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        42414 :     base->sortKeys->abbreviate = !typbyval;
     729              : 
     730        42414 :     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        42414 :     if (!base->sortKeys->abbrev_converter)
     739        41888 :         base->onlyKey = base->sortKeys;
     740              : 
     741        42414 :     MemoryContextSwitchTo(oldcontext);
     742              : 
     743        42414 :     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      8425497 : tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
     753              : {
     754      8425497 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     755      8425497 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
     756      8425497 :     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      8425497 :     tuple = ExecCopySlotMinimalTuple(slot);
     764      8425497 :     stup.tuple = tuple;
     765              :     /* set up first-column key value */
     766      8425497 :     htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
     767      8425497 :     htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
     768     16850994 :     stup.datum1 = heap_getattr(&htup,
     769      8425497 :                                base->sortKeys[0].ssup_attno,
     770              :                                tupDesc,
     771              :                                &stup.isnull1);
     772              : 
     773              :     /* GetMemoryChunkSpace is not supported for bump contexts */
     774      8425497 :     if (TupleSortUseBumpTupleCxt(base->sortopt))
     775      6445699 :         tuplen = MAXALIGN(tuple->t_len);
     776              :     else
     777      1979798 :         tuplen = GetMemoryChunkSpace(tuple);
     778              : 
     779      8425497 :     tuplesort_puttuple_common(state, &stup,
     780      9154375 :                               base->sortKeys->abbrev_converter &&
     781      9154375 :                               !stup.isnull1, tuplen);
     782              : 
     783      8425497 :     MemoryContextSwitchTo(oldcontext);
     784      8425497 : }
     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       364352 : tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup)
     793              : {
     794              :     SortTuple   stup;
     795       364352 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     796       364352 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
     797       364352 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
     798              :     Size        tuplen;
     799              : 
     800              :     /* copy the tuple into sort storage */
     801       364352 :     tup = heap_copytuple(tup);
     802       364352 :     stup.tuple = tup;
     803              : 
     804              :     /*
     805              :      * set up first-column key value, and potentially abbreviate, if it's a
     806              :      * simple column
     807              :      */
     808       364352 :     if (base->haveDatum1)
     809              :     {
     810       363268 :         stup.datum1 = heap_getattr(tup,
     811       363268 :                                    arg->indexInfo->ii_IndexAttrNumbers[0],
     812              :                                    arg->tupDesc,
     813              :                                    &stup.isnull1);
     814              :     }
     815              : 
     816              :     /* GetMemoryChunkSpace is not supported for bump contexts */
     817       364352 :     if (TupleSortUseBumpTupleCxt(base->sortopt))
     818       364352 :         tuplen = MAXALIGN(HEAPTUPLESIZE + tup->t_len);
     819              :     else
     820            0 :         tuplen = GetMemoryChunkSpace(tup);
     821              : 
     822       364352 :     tuplesort_puttuple_common(state, &stup,
     823       727620 :                               base->haveDatum1 &&
     824       606432 :                               base->sortKeys->abbrev_converter &&
     825       606432 :                               !stup.isnull1, tuplen);
     826              : 
     827       364352 :     MemoryContextSwitchTo(oldcontext);
     828       364352 : }
     829              : 
     830              : /*
     831              :  * Collect one index tuple while collecting input data for sort, building
     832              :  * it from caller-supplied values.
     833              :  */
     834              : void
     835      7890780 : 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      7890780 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     842      7890780 :     TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
     843              :     Size        tuplen;
     844              : 
     845      7890780 :     stup.tuple = index_form_tuple_context(RelationGetDescr(rel), values,
     846              :                                           isnull, base->tuplecontext);
     847      7890780 :     tuple = ((IndexTuple) stup.tuple);
     848      7890780 :     tuple->t_tid = *self;
     849              :     /* set up first-column key value */
     850     15781560 :     stup.datum1 = index_getattr(tuple,
     851              :                                 1,
     852      7890780 :                                 RelationGetDescr(arg->indexRel),
     853              :                                 &stup.isnull1);
     854              : 
     855              :     /* GetMemoryChunkSpace is not supported for bump contexts */
     856      7890780 :     if (TupleSortUseBumpTupleCxt(base->sortopt))
     857      7890780 :         tuplen = MAXALIGN(tuple->t_info & INDEX_SIZE_MASK);
     858              :     else
     859            0 :         tuplen = GetMemoryChunkSpace(tuple);
     860              : 
     861      7890780 :     tuplesort_puttuple_common(state, &stup,
     862     15711060 :                               base->sortKeys &&
     863      9297572 :                               base->sortKeys->abbrev_converter &&
     864      9297572 :                               !stup.isnull1, tuplen);
     865      7890780 : }
     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        46028 : tuplesort_putgintuple(Tuplesortstate *state, GinTuple *tuple, Size size)
     905              : {
     906              :     SortTuple   stup;
     907              :     GinTuple   *ctup;
     908        46028 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     909        46028 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
     910              :     Size        tuplen;
     911              : 
     912              :     /* copy the GinTuple into the right memory context */
     913        46028 :     ctup = palloc(size);
     914        46028 :     memcpy(ctup, tuple, size);
     915              : 
     916        46028 :     stup.tuple = ctup;
     917        46028 :     stup.datum1 = (Datum) 0;
     918        46028 :     stup.isnull1 = false;
     919              : 
     920              :     /* GetMemoryChunkSpace is not supported for bump contexts */
     921        46028 :     if (TupleSortUseBumpTupleCxt(base->sortopt))
     922        46028 :         tuplen = MAXALIGN(size);
     923              :     else
     924            0 :         tuplen = GetMemoryChunkSpace(ctup);
     925              : 
     926        46028 :     tuplesort_puttuple_common(state, &stup,
     927        92056 :                               base->sortKeys &&
     928        46028 :                               base->sortKeys->abbrev_converter &&
     929        46028 :                               !stup.isnull1, tuplen);
     930              : 
     931        46028 :     MemoryContextSwitchTo(oldcontext);
     932        46028 : }
     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      2613827 : tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
     941              : {
     942      2613827 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
     943      2613827 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
     944      2613827 :     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      2613827 :     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      1451486 :         stup.datum1 = !isNull ? val : (Datum) 0;
     966      1451486 :         stup.isnull1 = isNull;
     967      1451486 :         stup.tuple = NULL;      /* no separate storage */
     968              :     }
     969              :     else
     970              :     {
     971      1162341 :         stup.isnull1 = false;
     972      1162341 :         stup.datum1 = datumCopy(val, false, arg->datumTypeLen);
     973      1162341 :         stup.tuple = DatumGetPointer(stup.datum1);
     974              :     }
     975              : 
     976      2613827 :     tuplesort_puttuple_common(state, &stup,
     977      3776628 :                               base->tuples &&
     978      2613827 :                               base->sortKeys->abbrev_converter && !isNull, 0);
     979              : 
     980      2613827 :     MemoryContextSwitchTo(oldcontext);
     981      2613827 : }
     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      7578326 : tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy,
    1005              :                        TupleTableSlot *slot, Datum *abbrev)
    1006              : {
    1007      7578326 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1008      7578326 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1009              :     SortTuple   stup;
    1010              : 
    1011      7578326 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1012        73786 :         stup.tuple = NULL;
    1013              : 
    1014      7578326 :     MemoryContextSwitchTo(oldcontext);
    1015              : 
    1016      7578326 :     if (stup.tuple)
    1017              :     {
    1018              :         /* Record abbreviated key for caller */
    1019      7504540 :         if (base->sortKeys->abbrev_converter && abbrev)
    1020            0 :             *abbrev = stup.datum1;
    1021              : 
    1022      7504540 :         if (copy)
    1023         2967 :             stup.tuple = heap_copy_minimal_tuple((MinimalTuple) stup.tuple, 0);
    1024              : 
    1025      7504540 :         ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, copy);
    1026      7504540 :         return true;
    1027              :     }
    1028              :     else
    1029              :     {
    1030        73786 :         ExecClearTuple(slot);
    1031        73786 :         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       364442 : tuplesort_getheaptuple(Tuplesortstate *state, bool forward)
    1043              : {
    1044       364442 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1045       364442 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1046              :     SortTuple   stup;
    1047              : 
    1048       364442 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1049           90 :         stup.tuple = NULL;
    1050              : 
    1051       364442 :     MemoryContextSwitchTo(oldcontext);
    1052              : 
    1053       364442 :     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      7922129 : tuplesort_getindextuple(Tuplesortstate *state, bool forward)
    1064              : {
    1065      7922129 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1066      7922129 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1067              :     SortTuple   stup;
    1068              : 
    1069      7922129 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1070        31601 :         stup.tuple = NULL;
    1071              : 
    1072      7922129 :     MemoryContextSwitchTo(oldcontext);
    1073              : 
    1074      7922129 :     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           25 : tuplesort_getbrintuple(Tuplesortstate *state, Size *len, bool forward)
    1085              : {
    1086           25 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1087           25 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1088              :     SortTuple   stup;
    1089              :     BrinSortTuple *btup;
    1090              : 
    1091           25 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1092            5 :         stup.tuple = NULL;
    1093              : 
    1094           25 :     MemoryContextSwitchTo(oldcontext);
    1095              : 
    1096           25 :     if (!stup.tuple)
    1097            5 :         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        46096 : tuplesort_getgintuple(Tuplesortstate *state, Size *len, bool forward)
    1108              : {
    1109        46096 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1110        46096 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1111              :     SortTuple   stup;
    1112              :     GinTuple   *tup;
    1113              : 
    1114        46096 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1115           68 :         stup.tuple = NULL;
    1116              : 
    1117        46096 :     MemoryContextSwitchTo(oldcontext);
    1118              : 
    1119        46096 :     if (!stup.tuple)
    1120           68 :         return NULL;
    1121              : 
    1122        46028 :     tup = (GinTuple *) stup.tuple;
    1123              : 
    1124        46028 :     *len = tup->tuplen;
    1125              : 
    1126        46028 :     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      1695006 : tuplesort_getdatum(Tuplesortstate *state, bool forward, bool copy,
    1155              :                    Datum *val, bool *isNull, Datum *abbrev)
    1156              : {
    1157      1695006 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1158      1695006 :     MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
    1159      1695006 :     TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
    1160              :     SortTuple   stup;
    1161              : 
    1162      1695006 :     if (!tuplesort_gettuple_common(state, forward, &stup))
    1163              :     {
    1164        41559 :         MemoryContextSwitchTo(oldcontext);
    1165        41559 :         return false;
    1166              :     }
    1167              : 
    1168              :     /* Ensure we copy into caller's memory context */
    1169      1653447 :     MemoryContextSwitchTo(oldcontext);
    1170              : 
    1171              :     /* Record abbreviated key for caller */
    1172      1653447 :     if (base->sortKeys->abbrev_converter && abbrev)
    1173        27512 :         *abbrev = stup.datum1;
    1174              : 
    1175      1653447 :     if (stup.isnull1 || !base->tuples)
    1176              :     {
    1177       900225 :         *val = stup.datum1;
    1178       900225 :         *isNull = stup.isnull1;
    1179              :     }
    1180              :     else
    1181              :     {
    1182              :         /* use stup.tuple because stup.datum1 may be an abbreviation */
    1183       753222 :         if (copy)
    1184        40032 :             *val = datumCopy(PointerGetDatum(stup.tuple), false,
    1185              :                              arg->datumTypeLen);
    1186              :         else
    1187       713190 :             *val = PointerGetDatum(stup.tuple);
    1188       753222 :         *isNull = false;
    1189              :     }
    1190              : 
    1191      1653447 :     return true;
    1192              : }
    1193              : 
    1194              : 
    1195              : /*
    1196              :  * Routines specialized for HeapTuple (actually MinimalTuple) case
    1197              :  */
    1198              : 
    1199              : static void
    1200            8 : removeabbrev_heap(Tuplesortstate *state, SortTuple *stups, int count)
    1201              : {
    1202              :     int         i;
    1203            8 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1204              : 
    1205        81928 :     for (i = 0; i < count; i++)
    1206              :     {
    1207              :         HeapTupleData htup;
    1208              : 
    1209        81920 :         htup.t_len = ((MinimalTuple) stups[i].tuple)->t_len +
    1210              :             MINIMAL_TUPLE_OFFSET;
    1211        81920 :         htup.t_data = (HeapTupleHeader) ((char *) stups[i].tuple -
    1212              :                                          MINIMAL_TUPLE_OFFSET);
    1213        81920 :         stups[i].datum1 = heap_getattr(&htup,
    1214        81920 :                                        base->sortKeys[0].ssup_attno,
    1215        81920 :                                        (TupleDesc) base->arg,
    1216        81920 :                                        &stups[i].isnull1);
    1217              :     }
    1218            8 : }
    1219              : 
    1220              : static int
    1221     34788783 : comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
    1222              : {
    1223     34788783 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1224     34788783 :     SortSupport sortKey = base->sortKeys;
    1225              :     int32       compare;
    1226              : 
    1227              : 
    1228              :     /* Compare the leading sort key */
    1229     34788783 :     compare = ApplySortComparator(a->datum1, a->isnull1,
    1230     34788783 :                                   b->datum1, b->isnull1,
    1231              :                                   sortKey);
    1232     34788783 :     if (compare != 0)
    1233     12841709 :         return compare;
    1234              : 
    1235              :     /* Compare additional sort keys */
    1236     21947074 :     return comparetup_heap_tiebreak(a, b, state);
    1237              : }
    1238              : 
    1239              : static int
    1240     23226191 : comparetup_heap_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
    1241              : {
    1242     23226191 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1243     23226191 :     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     23226191 :     ltup.t_len = ((MinimalTuple) a->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
    1256     23226191 :     ltup.t_data = (HeapTupleHeader) ((char *) a->tuple - MINIMAL_TUPLE_OFFSET);
    1257     23226191 :     rtup.t_len = ((MinimalTuple) b->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
    1258     23226191 :     rtup.t_data = (HeapTupleHeader) ((char *) b->tuple - MINIMAL_TUPLE_OFFSET);
    1259     23226191 :     tupDesc = (TupleDesc) base->arg;
    1260              : 
    1261     23226191 :     if (sortKey->abbrev_converter)
    1262              :     {
    1263       645222 :         attno = sortKey->ssup_attno;
    1264              : 
    1265       645222 :         datum1 = heap_getattr(&ltup, attno, tupDesc, &isnull1);
    1266       645222 :         datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
    1267              : 
    1268       645222 :         compare = ApplySortAbbrevFullComparator(datum1, isnull1,
    1269              :                                                 datum2, isnull2,
    1270              :                                                 sortKey);
    1271       645222 :         if (compare != 0)
    1272       553306 :             return compare;
    1273              :     }
    1274              : 
    1275     22672885 :     sortKey++;
    1276     23958104 :     for (nkey = 1; nkey < base->nKeys; nkey++, sortKey++)
    1277              :     {
    1278     22611982 :         attno = sortKey->ssup_attno;
    1279              : 
    1280     22611982 :         datum1 = heap_getattr(&ltup, attno, tupDesc, &isnull1);
    1281     22611982 :         datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
    1282              : 
    1283     22611982 :         compare = ApplySortComparator(datum1, isnull1,
    1284              :                                       datum2, isnull2,
    1285              :                                       sortKey);
    1286     22611982 :         if (compare != 0)
    1287     21326763 :             return compare;
    1288              :     }
    1289              : 
    1290      1346122 :     return 0;
    1291              : }
    1292              : 
    1293              : static void
    1294       725300 : writetup_heap(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    1295              : {
    1296       725300 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1297       725300 :     MinimalTuple tuple = (MinimalTuple) stup->tuple;
    1298              : 
    1299              :     /* the part of the MinimalTuple we'll write: */
    1300       725300 :     char       *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
    1301       725300 :     unsigned int tupbodylen = tuple->t_len - MINIMAL_TUPLE_DATA_OFFSET;
    1302              : 
    1303              :     /* total on-disk footprint: */
    1304       725300 :     unsigned int tuplen = tupbodylen + sizeof(int);
    1305              : 
    1306       725300 :     LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1307       725300 :     LogicalTapeWrite(tape, tupbody, tupbodylen);
    1308       725300 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1309        20000 :         LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1310       725300 : }
    1311              : 
    1312              : static void
    1313       657120 : readtup_heap(Tuplesortstate *state, SortTuple *stup,
    1314              :              LogicalTape *tape, unsigned int len)
    1315              : {
    1316       657120 :     unsigned int tupbodylen = len - sizeof(int);
    1317       657120 :     unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
    1318       657120 :     MinimalTuple tuple = (MinimalTuple) tuplesort_readtup_alloc(state, tuplen);
    1319       657120 :     char       *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
    1320       657120 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1321              :     HeapTupleData htup;
    1322              : 
    1323              :     /* read in the tuple proper */
    1324       657120 :     tuple->t_len = tuplen;
    1325       657120 :     LogicalTapeReadExact(tape, tupbody, tupbodylen);
    1326       657120 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1327        31856 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    1328       657120 :     stup->tuple = tuple;
    1329              :     /* set up first-column key value */
    1330       657120 :     htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
    1331       657120 :     htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
    1332      1314240 :     stup->datum1 = heap_getattr(&htup,
    1333       657120 :                                 base->sortKeys[0].ssup_attno,
    1334       657120 :                                 (TupleDesc) base->arg,
    1335              :                                 &stup->isnull1);
    1336       657120 : }
    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            8 : removeabbrev_cluster(Tuplesortstate *state, SortTuple *stups, int count)
    1345              : {
    1346              :     int         i;
    1347            8 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1348            8 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
    1349              : 
    1350        81928 :     for (i = 0; i < count; i++)
    1351              :     {
    1352              :         HeapTuple   tup;
    1353              : 
    1354        81920 :         tup = (HeapTuple) stups[i].tuple;
    1355        81920 :         stups[i].datum1 = heap_getattr(tup,
    1356        81920 :                                        arg->indexInfo->ii_IndexAttrNumbers[0],
    1357              :                                        arg->tupDesc,
    1358        81920 :                                        &stups[i].isnull1);
    1359              :     }
    1360            8 : }
    1361              : 
    1362              : static int
    1363      4107873 : comparetup_cluster(const SortTuple *a, const SortTuple *b,
    1364              :                    Tuplesortstate *state)
    1365              : {
    1366      4107873 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1367      4107873 :     SortSupport sortKey = base->sortKeys;
    1368              :     int32       compare;
    1369              : 
    1370              :     /* Compare the leading sort key, if it's simple */
    1371      4107873 :     if (base->haveDatum1)
    1372              :     {
    1373      4100013 :         compare = ApplySortComparator(a->datum1, a->isnull1,
    1374      4100013 :                                       b->datum1, b->isnull1,
    1375              :                                       sortKey);
    1376      4100013 :         if (compare != 0)
    1377      3926179 :             return compare;
    1378              :     }
    1379              : 
    1380       181694 :     return comparetup_cluster_tiebreak(a, b, state);
    1381              : }
    1382              : 
    1383              : static int
    1384       368166 : comparetup_cluster_tiebreak(const SortTuple *a, const SortTuple *b,
    1385              :                             Tuplesortstate *state)
    1386              : {
    1387       368166 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1388       368166 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
    1389       368166 :     SortSupport sortKey = base->sortKeys;
    1390              :     HeapTuple   ltup;
    1391              :     HeapTuple   rtup;
    1392              :     TupleDesc   tupDesc;
    1393              :     int         nkey;
    1394       368166 :     int32       compare = 0;
    1395              :     Datum       datum1,
    1396              :                 datum2;
    1397              :     bool        isnull1,
    1398              :                 isnull2;
    1399              : 
    1400       368166 :     ltup = (HeapTuple) a->tuple;
    1401       368166 :     rtup = (HeapTuple) b->tuple;
    1402       368166 :     tupDesc = arg->tupDesc;
    1403              : 
    1404              :     /* Compare the leading sort key, if it's simple */
    1405       368166 :     if (base->haveDatum1)
    1406              :     {
    1407       360306 :         if (sortKey->abbrev_converter)
    1408              :         {
    1409        80046 :             AttrNumber  leading = arg->indexInfo->ii_IndexAttrNumbers[0];
    1410              : 
    1411        80046 :             datum1 = heap_getattr(ltup, leading, tupDesc, &isnull1);
    1412        80046 :             datum2 = heap_getattr(rtup, leading, tupDesc, &isnull2);
    1413              : 
    1414        80046 :             compare = ApplySortAbbrevFullComparator(datum1, isnull1,
    1415              :                                                     datum2, isnull2,
    1416              :                                                     sortKey);
    1417              :         }
    1418       360306 :         if (compare != 0 || base->nKeys == 1)
    1419        81978 :             return compare;
    1420              :         /* Compare additional columns the hard way */
    1421       278328 :         sortKey++;
    1422       278328 :         nkey = 1;
    1423              :     }
    1424              :     else
    1425              :     {
    1426              :         /* Must compare all keys the hard way */
    1427         7860 :         nkey = 0;
    1428              :     }
    1429              : 
    1430       286188 :     if (arg->indexInfo->ii_Expressions == NULL)
    1431              :     {
    1432              :         /* If not expression index, just compare the proper heap attrs */
    1433              : 
    1434       388868 :         for (; nkey < base->nKeys; nkey++, sortKey++)
    1435              :         {
    1436       388868 :             AttrNumber  attno = arg->indexInfo->ii_IndexAttrNumbers[nkey];
    1437              : 
    1438       388868 :             datum1 = heap_getattr(ltup, attno, tupDesc, &isnull1);
    1439       388868 :             datum2 = heap_getattr(rtup, attno, tupDesc, &isnull2);
    1440              : 
    1441       388868 :             compare = ApplySortComparator(datum1, isnull1,
    1442              :                                           datum2, isnull2,
    1443              :                                           sortKey);
    1444       388868 :             if (compare != 0)
    1445       278328 :                 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         7860 :         ResetPerTupleExprContext(arg->estate);
    1464              : 
    1465         7860 :         ecxt_scantuple = GetPerTupleExprContext(arg->estate)->ecxt_scantuple;
    1466              : 
    1467         7860 :         ExecStoreHeapTuple(ltup, ecxt_scantuple, false);
    1468         7860 :         FormIndexDatum(arg->indexInfo, ecxt_scantuple, arg->estate,
    1469              :                        l_index_values, l_index_isnull);
    1470              : 
    1471         7860 :         ExecStoreHeapTuple(rtup, ecxt_scantuple, false);
    1472         7860 :         FormIndexDatum(arg->indexInfo, ecxt_scantuple, arg->estate,
    1473              :                        r_index_values, r_index_isnull);
    1474              : 
    1475         8476 :         for (; nkey < base->nKeys; nkey++, sortKey++)
    1476              :         {
    1477         8476 :             compare = ApplySortComparator(l_index_values[nkey],
    1478         8476 :                                           l_index_isnull[nkey],
    1479              :                                           r_index_values[nkey],
    1480         8476 :                                           r_index_isnull[nkey],
    1481              :                                           sortKey);
    1482         8476 :             if (compare != 0)
    1483         7860 :                 return compare;
    1484              :         }
    1485              :     }
    1486              : 
    1487            0 :     return 0;
    1488              : }
    1489              : 
    1490              : static void
    1491        40000 : writetup_cluster(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    1492              : {
    1493        40000 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1494        40000 :     HeapTuple   tuple = (HeapTuple) stup->tuple;
    1495        40000 :     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        40000 :     LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1499        40000 :     LogicalTapeWrite(tape, &tuple->t_self, sizeof(ItemPointerData));
    1500        40000 :     LogicalTapeWrite(tape, tuple->t_data, tuple->t_len);
    1501        40000 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1502            0 :         LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1503        40000 : }
    1504              : 
    1505              : static void
    1506        40000 : readtup_cluster(Tuplesortstate *state, SortTuple *stup,
    1507              :                 LogicalTape *tape, unsigned int tuplen)
    1508              : {
    1509        40000 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1510        40000 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
    1511        40000 :     unsigned int t_len = tuplen - sizeof(ItemPointerData) - sizeof(int);
    1512        40000 :     HeapTuple   tuple = (HeapTuple) tuplesort_readtup_alloc(state,
    1513              :                                                             t_len + HEAPTUPLESIZE);
    1514              : 
    1515              :     /* Reconstruct the HeapTupleData header */
    1516        40000 :     tuple->t_data = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
    1517        40000 :     tuple->t_len = t_len;
    1518        40000 :     LogicalTapeReadExact(tape, &tuple->t_self, sizeof(ItemPointerData));
    1519              :     /* We don't currently bother to reconstruct t_tableOid */
    1520        40000 :     tuple->t_tableOid = InvalidOid;
    1521              :     /* Read in the tuple body */
    1522        40000 :     LogicalTapeReadExact(tape, tuple->t_data, tuple->t_len);
    1523        40000 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1524            0 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    1525        40000 :     stup->tuple = tuple;
    1526              :     /* set up first-column key value, if it's a simple column */
    1527        40000 :     if (base->haveDatum1)
    1528        40000 :         stup->datum1 = heap_getattr(tuple,
    1529        40000 :                                     arg->indexInfo->ii_IndexAttrNumbers[0],
    1530              :                                     arg->tupDesc,
    1531              :                                     &stup->isnull1);
    1532        40000 : }
    1533              : 
    1534              : static void
    1535           90 : freestate_cluster(Tuplesortstate *state)
    1536              : {
    1537           90 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1538           90 :     TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
    1539              : 
    1540              :     /* Free any execution state created for CLUSTER case */
    1541           90 :     if (arg->estate != NULL)
    1542              :     {
    1543           16 :         ExprContext *econtext = GetPerTupleExprContext(arg->estate);
    1544              : 
    1545           16 :         ExecDropSingleTupleTableSlot(econtext->ecxt_scantuple);
    1546           16 :         FreeExecutorState(arg->estate);
    1547              :     }
    1548           90 : }
    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           40 : removeabbrev_index(Tuplesortstate *state, SortTuple *stups, int count)
    1560              : {
    1561           40 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1562           40 :     TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
    1563              :     int         i;
    1564              : 
    1565       409640 :     for (i = 0; i < count; i++)
    1566              :     {
    1567              :         IndexTuple  tuple;
    1568              : 
    1569       409600 :         tuple = stups[i].tuple;
    1570       409600 :         stups[i].datum1 = index_getattr(tuple,
    1571              :                                         1,
    1572       409600 :                                         RelationGetDescr(arg->indexRel),
    1573       409600 :                                         &stups[i].isnull1);
    1574              :     }
    1575           40 : }
    1576              : 
    1577              : static int
    1578     38133868 : 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     38133868 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1587     38133868 :     SortSupport sortKey = base->sortKeys;
    1588              :     int32       compare;
    1589              : 
    1590              :     /* Compare the leading sort key */
    1591     38133868 :     compare = ApplySortComparator(a->datum1, a->isnull1,
    1592     38133868 :                                   b->datum1, b->isnull1,
    1593              :                                   sortKey);
    1594     38133868 :     if (compare != 0)
    1595     34396783 :         return compare;
    1596              : 
    1597              :     /* Compare additional sort keys */
    1598      3737085 :     return comparetup_index_btree_tiebreak(a, b, state);
    1599              : }
    1600              : 
    1601              : static int
    1602     13394011 : comparetup_index_btree_tiebreak(const SortTuple *a, const SortTuple *b,
    1603              :                                 Tuplesortstate *state)
    1604              : {
    1605     13394011 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1606     13394011 :     TuplesortIndexBTreeArg *arg = (TuplesortIndexBTreeArg *) base->arg;
    1607     13394011 :     SortSupport sortKey = base->sortKeys;
    1608              :     IndexTuple  tuple1;
    1609              :     IndexTuple  tuple2;
    1610              :     int         keysz;
    1611              :     TupleDesc   tupDes;
    1612     13394011 :     bool        equal_hasnull = false;
    1613              :     int         nkey;
    1614              :     int32       compare;
    1615              :     Datum       datum1,
    1616              :                 datum2;
    1617              :     bool        isnull1,
    1618              :                 isnull2;
    1619              : 
    1620     13394011 :     tuple1 = (IndexTuple) a->tuple;
    1621     13394011 :     tuple2 = (IndexTuple) b->tuple;
    1622     13394011 :     keysz = base->nKeys;
    1623     13394011 :     tupDes = RelationGetDescr(arg->index.indexRel);
    1624              : 
    1625     13394011 :     if (sortKey->abbrev_converter)
    1626              :     {
    1627       444847 :         datum1 = index_getattr(tuple1, 1, tupDes, &isnull1);
    1628       444847 :         datum2 = index_getattr(tuple2, 1, tupDes, &isnull2);
    1629              : 
    1630       444847 :         compare = ApplySortAbbrevFullComparator(datum1, isnull1,
    1631              :                                                 datum2, isnull2,
    1632              :                                                 sortKey);
    1633       444847 :         if (compare != 0)
    1634       416250 :             return compare;
    1635              :     }
    1636              : 
    1637              :     /* they are equal, so we only need to examine one null flag */
    1638     12977761 :     if (a->isnull1)
    1639         7604 :         equal_hasnull = true;
    1640              : 
    1641     12977761 :     sortKey++;
    1642     14443365 :     for (nkey = 2; nkey <= keysz; nkey++, sortKey++)
    1643              :     {
    1644      4212505 :         datum1 = index_getattr(tuple1, nkey, tupDes, &isnull1);
    1645      4212505 :         datum2 = index_getattr(tuple2, nkey, tupDes, &isnull2);
    1646              : 
    1647      4212505 :         compare = ApplySortComparator(datum1, isnull1,
    1648              :                                       datum2, isnull2,
    1649              :                                       sortKey);
    1650      4212505 :         if (compare != 0)
    1651      2746901 :             return compare;     /* done when we find unequal attributes */
    1652              : 
    1653              :         /* they are equal, so we only need to examine one null flag */
    1654      1465604 :         if (isnull1)
    1655        13995 :             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     10230860 :     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           56 :         index_deform_tuple(tuple1, tupDes, values, isnull);
    1683              : 
    1684           56 :         key_desc = BuildIndexValueDescription(arg->index.indexRel, values, isnull);
    1685              : 
    1686           56 :         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     10230804 :         BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
    1704     10230804 :         BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
    1705              : 
    1706     10230804 :         if (blk1 != blk2)
    1707      8838200 :             return (blk1 < blk2) ? -1 : 1;
    1708              :     }
    1709              :     {
    1710      1392604 :         OffsetNumber pos1 = ItemPointerGetOffsetNumber(&tuple1->t_tid);
    1711      1392604 :         OffsetNumber pos2 = ItemPointerGetOffsetNumber(&tuple2->t_tid);
    1712              : 
    1713      1392604 :         if (pos1 != pos2)
    1714      1392604 :             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      1052005 : 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      1052005 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1734      1052005 :     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      1052005 :     bucket1 = _hash_hashkey2bucket(DatumGetUInt32(a->datum1),
    1743              :                                    arg->max_buckets, arg->high_mask,
    1744              :                                    arg->low_mask);
    1745              :     Assert(!b->isnull1);
    1746      1052005 :     bucket2 = _hash_hashkey2bucket(DatumGetUInt32(b->datum1),
    1747              :                                    arg->max_buckets, arg->high_mask,
    1748              :                                    arg->low_mask);
    1749      1052005 :     if (bucket1 > bucket2)
    1750       310086 :         return 1;
    1751       741919 :     else if (bucket1 < bucket2)
    1752       295549 :         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       446370 :     hash1 = DatumGetUInt32(a->datum1);
    1760       446370 :     hash2 = DatumGetUInt32(b->datum1);
    1761       446370 :     if (hash1 > hash2)
    1762       108223 :         return 1;
    1763       338147 :     else if (hash1 < hash2)
    1764        97451 :         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       240696 :     tuple1 = (IndexTuple) a->tuple;
    1772       240696 :     tuple2 = (IndexTuple) b->tuple;
    1773              : 
    1774              :     {
    1775       240696 :         BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
    1776       240696 :         BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
    1777              : 
    1778       240696 :         if (blk1 != blk2)
    1779       172077 :             return (blk1 < blk2) ? -1 : 1;
    1780              :     }
    1781              :     {
    1782        68619 :         OffsetNumber pos1 = ItemPointerGetOffsetNumber(&tuple1->t_tid);
    1783        68619 :         OffsetNumber pos2 = ItemPointerGetOffsetNumber(&tuple2->t_tid);
    1784              : 
    1785        68619 :         if (pos1 != pos2)
    1786        68619 :             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      2106057 : writetup_index(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    1810              : {
    1811      2106057 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1812      2106057 :     IndexTuple  tuple = (IndexTuple) stup->tuple;
    1813              :     unsigned int tuplen;
    1814              : 
    1815      2106057 :     tuplen = IndexTupleSize(tuple) + sizeof(tuplen);
    1816      2106057 :     LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1817      2106057 :     LogicalTapeWrite(tape, tuple, IndexTupleSize(tuple));
    1818      2106057 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1819            0 :         LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1820      2106057 : }
    1821              : 
    1822              : static void
    1823      2106057 : readtup_index(Tuplesortstate *state, SortTuple *stup,
    1824              :               LogicalTape *tape, unsigned int len)
    1825              : {
    1826      2106057 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1827      2106057 :     TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
    1828      2106057 :     unsigned int tuplen = len - sizeof(unsigned int);
    1829      2106057 :     IndexTuple  tuple = (IndexTuple) tuplesort_readtup_alloc(state, tuplen);
    1830              : 
    1831      2106057 :     LogicalTapeReadExact(tape, tuple, tuplen);
    1832      2106057 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1833            0 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    1834      2106057 :     stup->tuple = tuple;
    1835              :     /* set up first-column key value */
    1836      4212114 :     stup->datum1 = index_getattr(tuple,
    1837              :                                  1,
    1838      2106057 :                                  RelationGetDescr(arg->indexRel),
    1839              :                                  &stup->isnull1);
    1840      2106057 : }
    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        75668 : comparetup_index_gin(const SortTuple *a, const SortTuple *b,
    1929              :                      Tuplesortstate *state)
    1930              : {
    1931        75668 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1932              : 
    1933              :     Assert(!TuplesortstateGetPublic(state)->haveDatum1);
    1934              : 
    1935       151336 :     return _gin_compare_tuples((GinTuple *) a->tuple,
    1936        75668 :                                (GinTuple *) b->tuple,
    1937              :                                base->sortKeys);
    1938              : }
    1939              : 
    1940              : static void
    1941        23014 : writetup_index_gin(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    1942              : {
    1943        23014 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1944        23014 :     GinTuple   *tuple = (GinTuple *) stup->tuple;
    1945        23014 :     unsigned int tuplen = tuple->tuplen;
    1946              : 
    1947        23014 :     tuplen = tuplen + sizeof(tuplen);
    1948        23014 :     LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1949        23014 :     LogicalTapeWrite(tape, tuple, tuple->tuplen);
    1950        23014 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1951            0 :         LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
    1952        23014 : }
    1953              : 
    1954              : static void
    1955        23014 : readtup_index_gin(Tuplesortstate *state, SortTuple *stup,
    1956              :                   LogicalTape *tape, unsigned int len)
    1957              : {
    1958              :     GinTuple   *tuple;
    1959        23014 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1960        23014 :     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        23014 :     tuple = (GinTuple *) tuplesort_readtup_alloc(state, tuplen);
    1967              : 
    1968        23014 :     tuple->tuplen = tuplen;
    1969              : 
    1970        23014 :     LogicalTapeReadExact(tape, tuple, tuplen);
    1971        23014 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    1972            0 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    1973        23014 :     stup->tuple = tuple;
    1974              : 
    1975              :     /* no abbreviations (FIXME maybe use attrnum for this?) */
    1976        23014 :     stup->datum1 = (Datum) 0;
    1977        23014 : }
    1978              : 
    1979              : /*
    1980              :  * Routines specialized for DatumTuple case
    1981              :  */
    1982              : 
    1983              : static void
    1984            8 : removeabbrev_datum(Tuplesortstate *state, SortTuple *stups, int count)
    1985              : {
    1986              :     int         i;
    1987              : 
    1988        81928 :     for (i = 0; i < count; i++)
    1989        81920 :         stups[i].datum1 = PointerGetDatum(stups[i].tuple);
    1990            8 : }
    1991              : 
    1992              : static int
    1993      5252661 : comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
    1994              : {
    1995      5252661 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    1996              :     int         compare;
    1997              : 
    1998      5252661 :     compare = ApplySortComparator(a->datum1, a->isnull1,
    1999      5252661 :                                   b->datum1, b->isnull1,
    2000              :                                   base->sortKeys);
    2001      5252661 :     if (compare != 0)
    2002      4851953 :         return compare;
    2003              : 
    2004       400708 :     return comparetup_datum_tiebreak(a, b, state);
    2005              : }
    2006              : 
    2007              : static int
    2008      1968244 : comparetup_datum_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
    2009              : {
    2010      1968244 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    2011      1968244 :     int32       compare = 0;
    2012              : 
    2013              :     /* if we have abbreviations, then "tuple" has the original value */
    2014      1968244 :     if (base->sortKeys->abbrev_converter)
    2015      1680279 :         compare = ApplySortAbbrevFullComparator(PointerGetDatum(a->tuple), a->isnull1,
    2016      1680279 :                                                 PointerGetDatum(b->tuple), b->isnull1,
    2017              :                                                 base->sortKeys);
    2018              : 
    2019      1968244 :     return compare;
    2020              : }
    2021              : 
    2022              : static void
    2023       770348 : writetup_datum(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
    2024              : {
    2025       770348 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    2026       770348 :     TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
    2027              :     void       *waddr;
    2028              :     unsigned int tuplen;
    2029              :     unsigned int writtenlen;
    2030              : 
    2031       770348 :     if (stup->isnull1)
    2032              :     {
    2033           44 :         waddr = NULL;
    2034           44 :         tuplen = 0;
    2035              :     }
    2036       770304 :     else if (!base->tuples)
    2037              :     {
    2038       250088 :         waddr = &stup->datum1;
    2039       250088 :         tuplen = sizeof(Datum);
    2040              :     }
    2041              :     else
    2042              :     {
    2043       520216 :         waddr = stup->tuple;
    2044       520216 :         tuplen = datumGetSize(PointerGetDatum(stup->tuple), false, arg->datumTypeLen);
    2045              :         Assert(tuplen != 0);
    2046              :     }
    2047              : 
    2048       770348 :     writtenlen = tuplen + sizeof(unsigned int);
    2049              : 
    2050       770348 :     LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
    2051       770348 :     LogicalTapeWrite(tape, waddr, tuplen);
    2052       770348 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    2053       340176 :         LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
    2054       770348 : }
    2055              : 
    2056              : static void
    2057       695368 : readtup_datum(Tuplesortstate *state, SortTuple *stup,
    2058              :               LogicalTape *tape, unsigned int len)
    2059              : {
    2060       695368 :     TuplesortPublic *base = TuplesortstateGetPublic(state);
    2061       695368 :     unsigned int tuplen = len - sizeof(unsigned int);
    2062              : 
    2063       695368 :     if (tuplen == 0)
    2064              :     {
    2065              :         /* it's NULL */
    2066           60 :         stup->datum1 = (Datum) 0;
    2067           60 :         stup->isnull1 = true;
    2068           60 :         stup->tuple = NULL;
    2069              :     }
    2070       695308 :     else if (!base->tuples)
    2071              :     {
    2072              :         Assert(tuplen == sizeof(Datum));
    2073       255092 :         LogicalTapeReadExact(tape, &stup->datum1, tuplen);
    2074       255092 :         stup->isnull1 = false;
    2075       255092 :         stup->tuple = NULL;
    2076              :     }
    2077              :     else
    2078              :     {
    2079       440216 :         void       *raddr = tuplesort_readtup_alloc(state, tuplen);
    2080              : 
    2081       440216 :         LogicalTapeReadExact(tape, raddr, tuplen);
    2082       440216 :         stup->datum1 = PointerGetDatum(raddr);
    2083       440216 :         stup->isnull1 = false;
    2084       440216 :         stup->tuple = raddr;
    2085              :     }
    2086              : 
    2087       695368 :     if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
    2088       345208 :         LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
    2089       695368 : }
        

Generated by: LCOV version 2.0-1