LCOV - code coverage report
Current view: top level - src/backend/utils/sort - tuplesortvariants.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 81.4 % 1015 826
Test Date: 2026-01-26 10:56:24 Functions: 74.5 % 51 38
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 53.2 % 410 218

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

Generated by: LCOV version 2.3.2-1