LCOV - code coverage report
Current view: top level - src/backend/utils/sort - tuplesortvariants.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 665 695 95.7 %
Date: 2024-04-26 19:11:10 Functions: 42 44 95.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14