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

Generated by: LCOV version 1.16