LCOV - code coverage report
Current view: top level - src/backend/utils/sort - tuplesortvariants.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 95.2 % 786 748
Test Date: 2026-10-05 23:15:49 Functions: 94.1 % 51 48
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 64.9 % 376 244

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

Generated by: LCOV version 2.0-1