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

Generated by: LCOV version 1.14