PostgreSQL Source Code  git master
tuplesortvariants.c
Go to the documentation of this file.
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);
44  int count);
46  int count);
48  int count);
50  int count);
51 static int comparetup_heap(const SortTuple *a, const SortTuple *b,
53 static int comparetup_heap_tiebreak(const SortTuple *a, const SortTuple *b,
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,
61 static int comparetup_cluster_tiebreak(const SortTuple *a, const SortTuple *b,
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,
69 static int comparetup_index_btree_tiebreak(const SortTuple *a, const SortTuple *b,
71 static int comparetup_index_hash(const SortTuple *a, const SortTuple *b,
73 static int comparetup_index_hash_tiebreak(const SortTuple *a, const SortTuple *b,
75 static int comparetup_index_brin(const SortTuple *a, const SortTuple *b,
78  SortTuple *stup);
79 static void readtup_index(Tuplesortstate *state, SortTuple *stup,
80  LogicalTape *tape, unsigned int len);
82  SortTuple *stup);
84  LogicalTape *tape, unsigned int len);
85 static int comparetup_datum(const SortTuple *a, const SortTuple *b,
87 static int comparetup_datum_tiebreak(const SortTuple *a, const SortTuple *b,
90  SortTuple *stup);
91 static void readtup_datum(Tuplesortstate *state, SortTuple *stup,
92  LogicalTape *tape, unsigned int len);
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 {
102 
103  IndexInfo *indexInfo; /* info about index being used for reference */
104  EState *estate; /* for evaluating index expressions */
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 */
116 
117 /*
118  * Data structure pointed by "TuplesortPublic.arg" for the index_btree subcase.
119  */
120 typedef struct
121 {
123 
124  bool enforceUnique; /* complain if we find duplicate tuples */
125  bool uniqueNullsNotDistinct; /* unique constraint null treatment */
127 
128 /*
129  * Data structure pointed by "TuplesortPublic.arg" for the index_hash subcase.
130  */
131 typedef struct
132 {
134 
135  uint32 high_mask; /* masks for sortable part of hash code */
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 */
148  /* we need typelen in order to know how to copy the Datums. */
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 {
162 
163 /* Size of the BrinSortTuple, given length of the BrinTuple. */
164 #define BRINSORTTUPLE_SIZE(len) (offsetof(BrinSortTuple, tuple) + (len))
165 
166 
169  int nkeys, AttrNumber *attNums,
170  Oid *sortOperators, Oid *sortCollations,
171  bool *nullsFirstFlags,
172  int workMem, SortCoordinate coordinate, int sortopt)
173 {
174  Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
175  sortopt);
177  MemoryContext oldcontext;
178  int i;
179 
180  oldcontext = MemoryContextSwitchTo(base->maincontext);
181 
182  Assert(nkeys > 0);
183 
184 #ifdef TRACE_SORT
185  if (trace_sort)
186  elog(LOG,
187  "begin tuple sort: nkeys = %d, workMem = %d, randomAccess = %c",
188  nkeys, workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
189 #endif
190 
191  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 
201  base->comparetup = comparetup_heap;
203  base->writetup = writetup_heap;
204  base->readtup = readtup_heap;
205  base->haveDatum1 = true;
206  base->arg = tupDesc; /* assume we need not copy tupDesc */
207 
208  /* Prepare SortSupport data for each column */
209  base->sortKeys = (SortSupport) palloc0(nkeys * sizeof(SortSupportData));
210 
211  for (i = 0; i < nkeys; i++)
212  {
213  SortSupport sortKey = base->sortKeys + i;
214 
215  Assert(attNums[i] != 0);
216  Assert(sortOperators[i] != 0);
217 
218  sortKey->ssup_cxt = CurrentMemoryContext;
219  sortKey->ssup_collation = sortCollations[i];
220  sortKey->ssup_nulls_first = nullsFirstFlags[i];
221  sortKey->ssup_attno = attNums[i];
222  /* Convey if abbreviation optimization is applicable in principle */
223  sortKey->abbreviate = (i == 0 && base->haveDatum1);
224 
225  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  if (nkeys == 1 && !base->sortKeys->abbrev_converter)
235  base->onlyKey = base->sortKeys;
236 
237  MemoryContextSwitchTo(oldcontext);
238 
239  return state;
240 }
241 
244  Relation indexRel,
245  int workMem,
246  SortCoordinate coordinate, int sortopt)
247 {
248  Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
249  sortopt);
251  BTScanInsert indexScanKey;
252  MemoryContext oldcontext;
254  int i;
255 
256  Assert(indexRel->rd_rel->relam == BTREE_AM_OID);
257 
258  oldcontext = MemoryContextSwitchTo(base->maincontext);
260 
261 #ifdef TRACE_SORT
262  if (trace_sort)
263  elog(LOG,
264  "begin tuple sort: nkeys = %d, workMem = %d, randomAccess = %c",
266  workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
267 #endif
268 
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 
281  base->writetup = writetup_cluster;
282  base->readtup = readtup_cluster;
284  base->arg = arg;
285 
286  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  if (arg->indexInfo->ii_IndexAttrNumbers[0] == 0)
293  base->haveDatum1 = false;
294  else
295  base->haveDatum1 = true;
296 
297  arg->tupDesc = tupDesc; /* assume we need not copy tupDesc */
298 
299  indexScanKey = _bt_mkscankey(indexRel, NULL);
300 
301  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  arg->estate = CreateExecutorState();
313  slot = MakeSingleTupleTableSlot(tupDesc, &TTSOpsHeapTuple);
314  econtext = GetPerTupleExprContext(arg->estate);
315  econtext->ecxt_scantuple = slot;
316  }
317 
318  /* Prepare SortSupport data for each column */
319  base->sortKeys = (SortSupport) palloc0(base->nKeys *
320  sizeof(SortSupportData));
321 
322  for (i = 0; i < base->nKeys; i++)
323  {
324  SortSupport sortKey = base->sortKeys + i;
325  ScanKey scanKey = indexScanKey->scankeys + i;
326  int16 strategy;
327 
328  sortKey->ssup_cxt = CurrentMemoryContext;
329  sortKey->ssup_collation = scanKey->sk_collation;
330  sortKey->ssup_nulls_first =
331  (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
332  sortKey->ssup_attno = scanKey->sk_attno;
333  /* Convey if abbreviation optimization is applicable in principle */
334  sortKey->abbreviate = (i == 0 && base->haveDatum1);
335 
336  Assert(sortKey->ssup_attno != 0);
337 
338  strategy = (scanKey->sk_flags & SK_BT_DESC) != 0 ?
340 
341  PrepareSortSupportFromIndexRel(indexRel, strategy, sortKey);
342  }
343 
344  pfree(indexScanKey);
345 
346  MemoryContextSwitchTo(oldcontext);
347 
348  return state;
349 }
350 
353  Relation indexRel,
354  bool enforceUnique,
355  bool uniqueNullsNotDistinct,
356  int workMem,
357  SortCoordinate coordinate,
358  int sortopt)
359 {
360  Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
361  sortopt);
363  BTScanInsert indexScanKey;
365  MemoryContext oldcontext;
366  int i;
367 
368  oldcontext = MemoryContextSwitchTo(base->maincontext);
370 
371 #ifdef TRACE_SORT
372  if (trace_sort)
373  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 
380 
381  TRACE_POSTGRESQL_SORT_START(INDEX_SORT,
382  enforceUnique,
383  base->nKeys,
384  workMem,
385  sortopt & TUPLESORT_RANDOMACCESS,
386  PARALLEL_SORT(coordinate));
387 
391  base->writetup = writetup_index;
392  base->readtup = readtup_index;
393  base->haveDatum1 = true;
394  base->arg = arg;
395 
396  arg->index.heapRel = heapRel;
397  arg->index.indexRel = indexRel;
398  arg->enforceUnique = enforceUnique;
399  arg->uniqueNullsNotDistinct = uniqueNullsNotDistinct;
400 
401  indexScanKey = _bt_mkscankey(indexRel, NULL);
402 
403  /* Prepare SortSupport data for each column */
404  base->sortKeys = (SortSupport) palloc0(base->nKeys *
405  sizeof(SortSupportData));
406 
407  for (i = 0; i < base->nKeys; i++)
408  {
409  SortSupport sortKey = base->sortKeys + i;
410  ScanKey scanKey = indexScanKey->scankeys + i;
411  int16 strategy;
412 
413  sortKey->ssup_cxt = CurrentMemoryContext;
414  sortKey->ssup_collation = scanKey->sk_collation;
415  sortKey->ssup_nulls_first =
416  (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
417  sortKey->ssup_attno = scanKey->sk_attno;
418  /* Convey if abbreviation optimization is applicable in principle */
419  sortKey->abbreviate = (i == 0 && base->haveDatum1);
420 
421  Assert(sortKey->ssup_attno != 0);
422 
423  strategy = (scanKey->sk_flags & SK_BT_DESC) != 0 ?
425 
426  PrepareSortSupportFromIndexRel(indexRel, strategy, sortKey);
427  }
428 
429  pfree(indexScanKey);
430 
431  MemoryContextSwitchTo(oldcontext);
432 
433  return state;
434 }
435 
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  Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
447  sortopt);
449  MemoryContext oldcontext;
451 
452  oldcontext = MemoryContextSwitchTo(base->maincontext);
454 
455 #ifdef TRACE_SORT
456  if (trace_sort)
457  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  base->nKeys = 1; /* Only one sort column, the hash code */
468 
472  base->writetup = writetup_index;
473  base->readtup = readtup_index;
474  base->haveDatum1 = true;
475  base->arg = arg;
476 
477  arg->index.heapRel = heapRel;
478  arg->index.indexRel = indexRel;
479 
480  arg->high_mask = high_mask;
481  arg->low_mask = low_mask;
482  arg->max_buckets = max_buckets;
483 
484  MemoryContextSwitchTo(oldcontext);
485 
486  return state;
487 }
488 
491  Relation indexRel,
492  int workMem,
493  SortCoordinate coordinate,
494  int sortopt)
495 {
496  Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
497  sortopt);
499  MemoryContext oldcontext;
501  int i;
502 
503  oldcontext = MemoryContextSwitchTo(base->maincontext);
505 
506 #ifdef TRACE_SORT
507  if (trace_sort)
508  elog(LOG,
509  "begin index sort: workMem = %d, randomAccess = %c",
510  workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
511 #endif
512 
514 
518  base->writetup = writetup_index;
519  base->readtup = readtup_index;
520  base->haveDatum1 = true;
521  base->arg = arg;
522 
523  arg->index.heapRel = heapRel;
524  arg->index.indexRel = indexRel;
525  arg->enforceUnique = false;
526  arg->uniqueNullsNotDistinct = false;
527 
528  /* Prepare SortSupport data for each column */
529  base->sortKeys = (SortSupport) palloc0(base->nKeys *
530  sizeof(SortSupportData));
531 
532  for (i = 0; i < base->nKeys; i++)
533  {
534  SortSupport sortKey = base->sortKeys + i;
535 
536  sortKey->ssup_cxt = CurrentMemoryContext;
537  sortKey->ssup_collation = indexRel->rd_indcollation[i];
538  sortKey->ssup_nulls_first = false;
539  sortKey->ssup_attno = i + 1;
540  /* Convey if abbreviation optimization is applicable in principle */
541  sortKey->abbreviate = (i == 0 && base->haveDatum1);
542 
543  Assert(sortKey->ssup_attno != 0);
544 
545  /* Look for a sort support function */
546  PrepareSortSupportFromGistIndexRel(indexRel, sortKey);
547  }
548 
549  MemoryContextSwitchTo(oldcontext);
550 
551  return state;
552 }
553 
556  SortCoordinate coordinate,
557  int sortopt)
558 {
559  Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
560  sortopt);
562 
563 #ifdef TRACE_SORT
564  if (trace_sort)
565  elog(LOG,
566  "begin index sort: workMem = %d, randomAccess = %c",
567  workMem,
568  sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
569 #endif
570 
571  base->nKeys = 1; /* Only one sort column, the block number */
572 
576  base->readtup = readtup_index_brin;
577  base->haveDatum1 = true;
578  base->arg = NULL;
579 
580  return state;
581 }
582 
584 tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation,
585  bool nullsFirstFlag, int workMem,
586  SortCoordinate coordinate, int sortopt)
587 {
588  Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
589  sortopt);
592  MemoryContext oldcontext;
593  int16 typlen;
594  bool typbyval;
595 
596  oldcontext = MemoryContextSwitchTo(base->maincontext);
598 
599 #ifdef TRACE_SORT
600  if (trace_sort)
601  elog(LOG,
602  "begin datum sort: workMem = %d, randomAccess = %c",
603  workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
604 #endif
605 
606  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 
618  base->writetup = writetup_datum;
619  base->readtup = readtup_datum;
620  base->haveDatum1 = true;
621  base->arg = arg;
622 
623  arg->datumType = datumType;
624 
625  /* lookup necessary attributes of the datum type */
626  get_typlenbyval(datumType, &typlen, &typbyval);
627  arg->datumTypeLen = typlen;
628  base->tuples = !typbyval;
629 
630  /* Prepare SortSupport data */
631  base->sortKeys = (SortSupport) palloc0(sizeof(SortSupportData));
632 
634  base->sortKeys->ssup_collation = sortCollation;
635  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  base->sortKeys->abbreviate = !typbyval;
646 
647  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  if (!base->sortKeys->abbrev_converter)
656  base->onlyKey = base->sortKeys;
657 
658  MemoryContextSwitchTo(oldcontext);
659 
660  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
670 {
673  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  tuple = ExecCopySlotMinimalTuple(slot);
681  stup.tuple = (void *) tuple;
682  /* set up first-column key value */
683  htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
684  htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
685  stup.datum1 = heap_getattr(&htup,
686  base->sortKeys[0].ssup_attno,
687  tupDesc,
688  &stup.isnull1);
689 
690  /* GetMemoryChunkSpace is not supported for bump contexts */
692  tuplen = MAXALIGN(tuple->t_len);
693  else
694  tuplen = GetMemoryChunkSpace(tuple);
695 
697  base->sortKeys->abbrev_converter &&
698  !stup.isnull1, tuplen);
699 
700  MemoryContextSwitchTo(oldcontext);
701 }
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
710 {
711  SortTuple stup;
715  Size tuplen;
716 
717  /* copy the tuple into sort storage */
718  tup = heap_copytuple(tup);
719  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  if (base->haveDatum1)
726  {
727  stup.datum1 = heap_getattr(tup,
728  arg->indexInfo->ii_IndexAttrNumbers[0],
729  arg->tupDesc,
730  &stup.isnull1);
731  }
732 
733  /* GetMemoryChunkSpace is not supported for bump contexts */
735  tuplen = MAXALIGN(HEAPTUPLESIZE + tup->t_len);
736  else
737  tuplen = GetMemoryChunkSpace(tup);
738 
740  base->haveDatum1 &&
741  base->sortKeys->abbrev_converter &&
742  !stup.isnull1, tuplen);
743 
744  MemoryContextSwitchTo(oldcontext);
745 }
746 
747 /*
748  * Collect one index tuple while collecting input data for sort, building
749  * it from caller-supplied values.
750  */
751 void
753  ItemPointer self, const Datum *values,
754  const bool *isnull)
755 {
756  SortTuple stup;
757  IndexTuple tuple;
760  Size tuplen;
761 
763  isnull, base->tuplecontext);
764  tuple = ((IndexTuple) stup.tuple);
765  tuple->t_tid = *self;
766  /* set up first-column key value */
767  stup.datum1 = index_getattr(tuple,
768  1,
769  RelationGetDescr(arg->indexRel),
770  &stup.isnull1);
771 
772  /* GetMemoryChunkSpace is not supported for bump contexts */
774  tuplen = MAXALIGN(tuple->t_info & INDEX_SIZE_MASK);
775  else
776  tuplen = GetMemoryChunkSpace(tuple);
777 
779  base->sortKeys &&
780  base->sortKeys->abbrev_converter &&
781  !stup.isnull1, tuplen);
782 }
783 
784 /*
785  * Collect one BRIN tuple while collecting input data for sort.
786  */
787 void
789 {
790  SortTuple stup;
791  BrinSortTuple *bstup;
794  Size tuplen;
795 
796  /* allocate space for the whole BRIN sort tuple */
797  bstup = palloc(BRINSORTTUPLE_SIZE(size));
798 
799  bstup->tuplen = size;
800  memcpy(&bstup->tuple, tuple, size);
801 
802  stup.tuple = bstup;
803  stup.datum1 = tuple->bt_blkno;
804  stup.isnull1 = false;
805 
806  /* GetMemoryChunkSpace is not supported for bump contexts */
808  tuplen = MAXALIGN(BRINSORTTUPLE_SIZE(size));
809  else
810  tuplen = GetMemoryChunkSpace(bstup);
811 
813  base->sortKeys &&
814  base->sortKeys->abbrev_converter &&
815  !stup.isnull1, tuplen);
816 
817  MemoryContextSwitchTo(oldcontext);
818 }
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
827 {
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  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  stup.datum1 = !isNull ? val : (Datum) 0;
852  stup.isnull1 = isNull;
853  stup.tuple = NULL; /* no separate storage */
854  }
855  else
856  {
857  stup.isnull1 = false;
858  stup.datum1 = datumCopy(val, false, arg->datumTypeLen);
859  stup.tuple = DatumGetPointer(stup.datum1);
860  }
861 
863  base->tuples &&
864  base->sortKeys->abbrev_converter && !isNull, 0);
865 
866  MemoryContextSwitchTo(oldcontext);
867 }
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 tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy,
891  TupleTableSlot *slot, Datum *abbrev)
892 {
894  MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
895  SortTuple stup;
896 
897  if (!tuplesort_gettuple_common(state, forward, &stup))
898  stup.tuple = NULL;
899 
900  MemoryContextSwitchTo(oldcontext);
901 
902  if (stup.tuple)
903  {
904  /* Record abbreviated key for caller */
905  if (base->sortKeys->abbrev_converter && abbrev)
906  *abbrev = stup.datum1;
907 
908  if (copy)
910 
911  ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, copy);
912  return true;
913  }
914  else
915  {
916  ExecClearTuple(slot);
917  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
929 {
931  MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
932  SortTuple stup;
933 
934  if (!tuplesort_gettuple_common(state, forward, &stup))
935  stup.tuple = NULL;
936 
937  MemoryContextSwitchTo(oldcontext);
938 
939  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  */
950 {
952  MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
953  SortTuple stup;
954 
955  if (!tuplesort_gettuple_common(state, forward, &stup))
956  stup.tuple = NULL;
957 
958  MemoryContextSwitchTo(oldcontext);
959 
960  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 *
971 {
973  MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
974  SortTuple stup;
975  BrinSortTuple *btup;
976 
977  if (!tuplesort_gettuple_common(state, forward, &stup))
978  stup.tuple = NULL;
979 
980  MemoryContextSwitchTo(oldcontext);
981 
982  if (!stup.tuple)
983  return NULL;
984 
985  btup = (BrinSortTuple *) stup.tuple;
986 
987  *len = btup->tuplen;
988 
989  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 tuplesort_getdatum(Tuplesortstate *state, bool forward, bool copy,
1019  Datum *val, bool *isNull, Datum *abbrev)
1020 {
1022  MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1024  SortTuple stup;
1025 
1026  if (!tuplesort_gettuple_common(state, forward, &stup))
1027  {
1028  MemoryContextSwitchTo(oldcontext);
1029  return false;
1030  }
1031 
1032  /* Ensure we copy into caller's memory context */
1033  MemoryContextSwitchTo(oldcontext);
1034 
1035  /* Record abbreviated key for caller */
1036  if (base->sortKeys->abbrev_converter && abbrev)
1037  *abbrev = stup.datum1;
1038 
1039  if (stup.isnull1 || !base->tuples)
1040  {
1041  *val = stup.datum1;
1042  *isNull = stup.isnull1;
1043  }
1044  else
1045  {
1046  /* use stup.tuple because stup.datum1 may be an abbreviation */
1047  if (copy)
1048  *val = datumCopy(PointerGetDatum(stup.tuple), false,
1049  arg->datumTypeLen);
1050  else
1051  *val = PointerGetDatum(stup.tuple);
1052  *isNull = false;
1053  }
1054 
1055  return true;
1056 }
1057 
1058 
1059 /*
1060  * Routines specialized for HeapTuple (actually MinimalTuple) case
1061  */
1062 
1063 static void
1065 {
1066  int i;
1068 
1069  for (i = 0; i < count; i++)
1070  {
1071  HeapTupleData htup;
1072 
1073  htup.t_len = ((MinimalTuple) stups[i].tuple)->t_len +
1075  htup.t_data = (HeapTupleHeader) ((char *) stups[i].tuple -
1077  stups[i].datum1 = heap_getattr(&htup,
1078  base->sortKeys[0].ssup_attno,
1079  (TupleDesc) base->arg,
1080  &stups[i].isnull1);
1081  }
1082 }
1083 
1084 static int
1086 {
1088  SortSupport sortKey = base->sortKeys;
1089  int32 compare;
1090 
1091 
1092  /* Compare the leading sort key */
1093  compare = ApplySortComparator(a->datum1, a->isnull1,
1094  b->datum1, b->isnull1,
1095  sortKey);
1096  if (compare != 0)
1097  return compare;
1098 
1099  /* Compare additional sort keys */
1100  return comparetup_heap_tiebreak(a, b, state);
1101 }
1102 
1103 static int
1105 {
1107  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  ltup.t_len = ((MinimalTuple) a->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
1120  ltup.t_data = (HeapTupleHeader) ((char *) a->tuple - MINIMAL_TUPLE_OFFSET);
1121  rtup.t_len = ((MinimalTuple) b->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
1122  rtup.t_data = (HeapTupleHeader) ((char *) b->tuple - MINIMAL_TUPLE_OFFSET);
1123  tupDesc = (TupleDesc) base->arg;
1124 
1125  if (sortKey->abbrev_converter)
1126  {
1127  attno = sortKey->ssup_attno;
1128 
1129  datum1 = heap_getattr(&ltup, attno, tupDesc, &isnull1);
1130  datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
1131 
1132  compare = ApplySortAbbrevFullComparator(datum1, isnull1,
1133  datum2, isnull2,
1134  sortKey);
1135  if (compare != 0)
1136  return compare;
1137  }
1138 
1139  sortKey++;
1140  for (nkey = 1; nkey < base->nKeys; nkey++, sortKey++)
1141  {
1142  attno = sortKey->ssup_attno;
1143 
1144  datum1 = heap_getattr(&ltup, attno, tupDesc, &isnull1);
1145  datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
1146 
1147  compare = ApplySortComparator(datum1, isnull1,
1148  datum2, isnull2,
1149  sortKey);
1150  if (compare != 0)
1151  return compare;
1152  }
1153 
1154  return 0;
1155 }
1156 
1157 static void
1159 {
1161  MinimalTuple tuple = (MinimalTuple) stup->tuple;
1162 
1163  /* the part of the MinimalTuple we'll write: */
1164  char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1165  unsigned int tupbodylen = tuple->t_len - MINIMAL_TUPLE_DATA_OFFSET;
1166 
1167  /* total on-disk footprint: */
1168  unsigned int tuplen = tupbodylen + sizeof(int);
1169 
1170  LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1171  LogicalTapeWrite(tape, tupbody, tupbodylen);
1172  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1173  LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1174 }
1175 
1176 static void
1178  LogicalTape *tape, unsigned int len)
1179 {
1180  unsigned int tupbodylen = len - sizeof(int);
1181  unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
1183  char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1185  HeapTupleData htup;
1186 
1187  /* read in the tuple proper */
1188  tuple->t_len = tuplen;
1189  LogicalTapeReadExact(tape, tupbody, tupbodylen);
1190  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1191  LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1192  stup->tuple = (void *) tuple;
1193  /* set up first-column key value */
1194  htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
1195  htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
1196  stup->datum1 = heap_getattr(&htup,
1197  base->sortKeys[0].ssup_attno,
1198  (TupleDesc) base->arg,
1199  &stup->isnull1);
1200 }
1201 
1202 /*
1203  * Routines specialized for the CLUSTER case (HeapTuple data, with
1204  * comparisons per a btree index definition)
1205  */
1206 
1207 static void
1209 {
1210  int i;
1213 
1214  for (i = 0; i < count; i++)
1215  {
1216  HeapTuple tup;
1217 
1218  tup = (HeapTuple) stups[i].tuple;
1219  stups[i].datum1 = heap_getattr(tup,
1220  arg->indexInfo->ii_IndexAttrNumbers[0],
1221  arg->tupDesc,
1222  &stups[i].isnull1);
1223  }
1224 }
1225 
1226 static int
1229 {
1231  SortSupport sortKey = base->sortKeys;
1232  int32 compare;
1233 
1234  /* Compare the leading sort key, if it's simple */
1235  if (base->haveDatum1)
1236  {
1237  compare = ApplySortComparator(a->datum1, a->isnull1,
1238  b->datum1, b->isnull1,
1239  sortKey);
1240  if (compare != 0)
1241  return compare;
1242  }
1243 
1245 }
1246 
1247 static int
1250 {
1253  SortSupport sortKey = base->sortKeys;
1254  HeapTuple ltup;
1255  HeapTuple rtup;
1256  TupleDesc tupDesc;
1257  int nkey;
1258  int32 compare = 0;
1259  Datum datum1,
1260  datum2;
1261  bool isnull1,
1262  isnull2;
1263 
1264  ltup = (HeapTuple) a->tuple;
1265  rtup = (HeapTuple) b->tuple;
1266  tupDesc = arg->tupDesc;
1267 
1268  /* Compare the leading sort key, if it's simple */
1269  if (base->haveDatum1)
1270  {
1271  if (sortKey->abbrev_converter)
1272  {
1273  AttrNumber leading = arg->indexInfo->ii_IndexAttrNumbers[0];
1274 
1275  datum1 = heap_getattr(ltup, leading, tupDesc, &isnull1);
1276  datum2 = heap_getattr(rtup, leading, tupDesc, &isnull2);
1277 
1278  compare = ApplySortAbbrevFullComparator(datum1, isnull1,
1279  datum2, isnull2,
1280  sortKey);
1281  }
1282  if (compare != 0 || base->nKeys == 1)
1283  return compare;
1284  /* Compare additional columns the hard way */
1285  sortKey++;
1286  nkey = 1;
1287  }
1288  else
1289  {
1290  /* Must compare all keys the hard way */
1291  nkey = 0;
1292  }
1293 
1294  if (arg->indexInfo->ii_Expressions == NULL)
1295  {
1296  /* If not expression index, just compare the proper heap attrs */
1297 
1298  for (; nkey < base->nKeys; nkey++, sortKey++)
1299  {
1300  AttrNumber attno = arg->indexInfo->ii_IndexAttrNumbers[nkey];
1301 
1302  datum1 = heap_getattr(ltup, attno, tupDesc, &isnull1);
1303  datum2 = heap_getattr(rtup, attno, tupDesc, &isnull2);
1304 
1305  compare = ApplySortComparator(datum1, isnull1,
1306  datum2, isnull2,
1307  sortKey);
1308  if (compare != 0)
1309  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  ResetPerTupleExprContext(arg->estate);
1328 
1329  ecxt_scantuple = GetPerTupleExprContext(arg->estate)->ecxt_scantuple;
1330 
1331  ExecStoreHeapTuple(ltup, ecxt_scantuple, false);
1332  FormIndexDatum(arg->indexInfo, ecxt_scantuple, arg->estate,
1333  l_index_values, l_index_isnull);
1334 
1335  ExecStoreHeapTuple(rtup, ecxt_scantuple, false);
1336  FormIndexDatum(arg->indexInfo, ecxt_scantuple, arg->estate,
1337  r_index_values, r_index_isnull);
1338 
1339  for (; nkey < base->nKeys; nkey++, sortKey++)
1340  {
1341  compare = ApplySortComparator(l_index_values[nkey],
1342  l_index_isnull[nkey],
1343  r_index_values[nkey],
1344  r_index_isnull[nkey],
1345  sortKey);
1346  if (compare != 0)
1347  return compare;
1348  }
1349  }
1350 
1351  return 0;
1352 }
1353 
1354 static void
1356 {
1358  HeapTuple tuple = (HeapTuple) stup->tuple;
1359  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  LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1363  LogicalTapeWrite(tape, &tuple->t_self, sizeof(ItemPointerData));
1364  LogicalTapeWrite(tape, tuple->t_data, tuple->t_len);
1365  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1366  LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1367 }
1368 
1369 static void
1371  LogicalTape *tape, unsigned int tuplen)
1372 {
1375  unsigned int t_len = tuplen - sizeof(ItemPointerData) - sizeof(int);
1377  t_len + HEAPTUPLESIZE);
1378 
1379  /* Reconstruct the HeapTupleData header */
1380  tuple->t_data = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
1381  tuple->t_len = t_len;
1382  LogicalTapeReadExact(tape, &tuple->t_self, sizeof(ItemPointerData));
1383  /* We don't currently bother to reconstruct t_tableOid */
1384  tuple->t_tableOid = InvalidOid;
1385  /* Read in the tuple body */
1386  LogicalTapeReadExact(tape, tuple->t_data, tuple->t_len);
1387  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1388  LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1389  stup->tuple = (void *) tuple;
1390  /* set up first-column key value, if it's a simple column */
1391  if (base->haveDatum1)
1392  stup->datum1 = heap_getattr(tuple,
1393  arg->indexInfo->ii_IndexAttrNumbers[0],
1394  arg->tupDesc,
1395  &stup->isnull1);
1396 }
1397 
1398 static void
1400 {
1403 
1404  /* Free any execution state created for CLUSTER case */
1405  if (arg->estate != NULL)
1406  {
1407  ExprContext *econtext = GetPerTupleExprContext(arg->estate);
1408 
1410  FreeExecutorState(arg->estate);
1411  }
1412 }
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
1424 {
1427  int i;
1428 
1429  for (i = 0; i < count; i++)
1430  {
1431  IndexTuple tuple;
1432 
1433  tuple = stups[i].tuple;
1434  stups[i].datum1 = index_getattr(tuple,
1435  1,
1436  RelationGetDescr(arg->indexRel),
1437  &stups[i].isnull1);
1438  }
1439 }
1440 
1441 static int
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  */
1451  SortSupport sortKey = base->sortKeys;
1452  int32 compare;
1453 
1454  /* Compare the leading sort key */
1455  compare = ApplySortComparator(a->datum1, a->isnull1,
1456  b->datum1, b->isnull1,
1457  sortKey);
1458  if (compare != 0)
1459  return compare;
1460 
1461  /* Compare additional sort keys */
1463 }
1464 
1465 static int
1468 {
1471  SortSupport sortKey = base->sortKeys;
1472  IndexTuple tuple1;
1473  IndexTuple tuple2;
1474  int keysz;
1475  TupleDesc tupDes;
1476  bool equal_hasnull = false;
1477  int nkey;
1478  int32 compare;
1479  Datum datum1,
1480  datum2;
1481  bool isnull1,
1482  isnull2;
1483 
1484  tuple1 = (IndexTuple) a->tuple;
1485  tuple2 = (IndexTuple) b->tuple;
1486  keysz = base->nKeys;
1487  tupDes = RelationGetDescr(arg->index.indexRel);
1488 
1489  if (sortKey->abbrev_converter)
1490  {
1491  datum1 = index_getattr(tuple1, 1, tupDes, &isnull1);
1492  datum2 = index_getattr(tuple2, 1, tupDes, &isnull2);
1493 
1494  compare = ApplySortAbbrevFullComparator(datum1, isnull1,
1495  datum2, isnull2,
1496  sortKey);
1497  if (compare != 0)
1498  return compare;
1499  }
1500 
1501  /* they are equal, so we only need to examine one null flag */
1502  if (a->isnull1)
1503  equal_hasnull = true;
1504 
1505  sortKey++;
1506  for (nkey = 2; nkey <= keysz; nkey++, sortKey++)
1507  {
1508  datum1 = index_getattr(tuple1, nkey, tupDes, &isnull1);
1509  datum2 = index_getattr(tuple2, nkey, tupDes, &isnull2);
1510 
1511  compare = ApplySortComparator(datum1, isnull1,
1512  datum2, isnull2,
1513  sortKey);
1514  if (compare != 0)
1515  return compare; /* done when we find unequal attributes */
1516 
1517  /* they are equal, so we only need to examine one null flag */
1518  if (isnull1)
1519  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  if (arg->enforceUnique && !(!arg->uniqueNullsNotDistinct && equal_hasnull))
1533  {
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  index_deform_tuple(tuple1, tupDes, values, isnull);
1547 
1548  key_desc = BuildIndexValueDescription(arg->index.indexRel, values, isnull);
1549 
1550  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  BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
1568  BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
1569 
1570  if (blk1 != blk2)
1571  return (blk1 < blk2) ? -1 : 1;
1572  }
1573  {
1574  OffsetNumber pos1 = ItemPointerGetOffsetNumber(&tuple1->t_tid);
1575  OffsetNumber pos2 = ItemPointerGetOffsetNumber(&tuple2->t_tid);
1576 
1577  if (pos1 != pos2)
1578  return (pos1 < pos2) ? -1 : 1;
1579  }
1580 
1581  /* ItemPointer values should never be equal */
1582  Assert(false);
1583 
1584  return 0;
1585 }
1586 
1587 static int
1590 {
1591  Bucket bucket1;
1592  Bucket bucket2;
1593  uint32 hash1;
1594  uint32 hash2;
1595  IndexTuple tuple1;
1596  IndexTuple tuple2;
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  bucket1 = _hash_hashkey2bucket(DatumGetUInt32(a->datum1),
1607  arg->max_buckets, arg->high_mask,
1608  arg->low_mask);
1609  Assert(!b->isnull1);
1610  bucket2 = _hash_hashkey2bucket(DatumGetUInt32(b->datum1),
1611  arg->max_buckets, arg->high_mask,
1612  arg->low_mask);
1613  if (bucket1 > bucket2)
1614  return 1;
1615  else if (bucket1 < bucket2)
1616  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  hash1 = DatumGetUInt32(a->datum1);
1624  hash2 = DatumGetUInt32(b->datum1);
1625  if (hash1 > hash2)
1626  return 1;
1627  else if (hash1 < hash2)
1628  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  tuple1 = (IndexTuple) a->tuple;
1636  tuple2 = (IndexTuple) b->tuple;
1637 
1638  {
1639  BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
1640  BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
1641 
1642  if (blk1 != blk2)
1643  return (blk1 < blk2) ? -1 : 1;
1644  }
1645  {
1648 
1649  if (pos1 != pos2)
1650  return (pos1 < pos2) ? -1 : 1;
1651  }
1652 
1653  /* ItemPointer values should never be equal */
1654  Assert(false);
1655 
1656  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
1666 {
1667  Assert(false);
1668 
1669  return 0;
1670 }
1671 
1672 static void
1674 {
1676  IndexTuple tuple = (IndexTuple) stup->tuple;
1677  unsigned int tuplen;
1678 
1679  tuplen = IndexTupleSize(tuple) + sizeof(tuplen);
1680  LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1681  LogicalTapeWrite(tape, tuple, IndexTupleSize(tuple));
1682  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1683  LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1684 }
1685 
1686 static void
1688  LogicalTape *tape, unsigned int len)
1689 {
1692  unsigned int tuplen = len - sizeof(unsigned int);
1694 
1695  LogicalTapeReadExact(tape, tuple, tuplen);
1696  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1697  LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1698  stup->tuple = (void *) tuple;
1699  /* set up first-column key value */
1700  stup->datum1 = index_getattr(tuple,
1701  1,
1702  RelationGetDescr(arg->indexRel),
1703  &stup->isnull1);
1704 }
1705 
1706 /*
1707  * Routines specialized for BrinTuple case
1708  */
1709 
1710 static void
1712 {
1713  int i;
1714 
1715  for (i = 0; i < count; i++)
1716  {
1717  BrinSortTuple *tuple;
1718 
1719  tuple = stups[i].tuple;
1720  stups[i].datum1 = tuple->tuple.bt_blkno;
1721  }
1722 }
1723 
1724 static int
1727 {
1728  Assert(TuplesortstateGetPublic(state)->haveDatum1);
1729 
1730  if (DatumGetUInt32(a->datum1) > DatumGetUInt32(b->datum1))
1731  return 1;
1732 
1733  if (DatumGetUInt32(a->datum1) < DatumGetUInt32(b->datum1))
1734  return -1;
1735 
1736  /* silence compilers */
1737  return 0;
1738 }
1739 
1740 static void
1742 {
1744  BrinSortTuple *tuple = (BrinSortTuple *) stup->tuple;
1745  unsigned int tuplen = tuple->tuplen;
1746 
1747  tuplen = tuplen + sizeof(tuplen);
1748  LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1749  LogicalTapeWrite(tape, &tuple->tuple, tuple->tuplen);
1750  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1751  LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1752 }
1753 
1754 static void
1756  LogicalTape *tape, unsigned int len)
1757 {
1758  BrinSortTuple *tuple;
1760  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  */
1767  BRINSORTTUPLE_SIZE(tuplen));
1768 
1769  tuple->tuplen = tuplen;
1770 
1771  LogicalTapeReadExact(tape, &tuple->tuple, tuplen);
1772  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1773  LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1774  stup->tuple = (void *) tuple;
1775 
1776  /* set up first-column key value, which is block number */
1777  stup->datum1 = tuple->tuple.bt_blkno;
1778 }
1779 
1780 /*
1781  * Routines specialized for DatumTuple case
1782  */
1783 
1784 static void
1786 {
1787  int i;
1788 
1789  for (i = 0; i < count; i++)
1790  stups[i].datum1 = PointerGetDatum(stups[i].tuple);
1791 }
1792 
1793 static int
1795 {
1797  int compare;
1798 
1799  compare = ApplySortComparator(a->datum1, a->isnull1,
1800  b->datum1, b->isnull1,
1801  base->sortKeys);
1802  if (compare != 0)
1803  return compare;
1804 
1805  return comparetup_datum_tiebreak(a, b, state);
1806 }
1807 
1808 static int
1810 {
1812  int32 compare = 0;
1813 
1814  /* if we have abbreviations, then "tuple" has the original value */
1815  if (base->sortKeys->abbrev_converter)
1817  PointerGetDatum(b->tuple), b->isnull1,
1818  base->sortKeys);
1819 
1820  return compare;
1821 }
1822 
1823 static void
1825 {
1828  void *waddr;
1829  unsigned int tuplen;
1830  unsigned int writtenlen;
1831 
1832  if (stup->isnull1)
1833  {
1834  waddr = NULL;
1835  tuplen = 0;
1836  }
1837  else if (!base->tuples)
1838  {
1839  waddr = &stup->datum1;
1840  tuplen = sizeof(Datum);
1841  }
1842  else
1843  {
1844  waddr = stup->tuple;
1845  tuplen = datumGetSize(PointerGetDatum(stup->tuple), false, arg->datumTypeLen);
1846  Assert(tuplen != 0);
1847  }
1848 
1849  writtenlen = tuplen + sizeof(unsigned int);
1850 
1851  LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
1852  LogicalTapeWrite(tape, waddr, tuplen);
1853  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1854  LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
1855 }
1856 
1857 static void
1859  LogicalTape *tape, unsigned int len)
1860 {
1862  unsigned int tuplen = len - sizeof(unsigned int);
1863 
1864  if (tuplen == 0)
1865  {
1866  /* it's NULL */
1867  stup->datum1 = (Datum) 0;
1868  stup->isnull1 = true;
1869  stup->tuple = NULL;
1870  }
1871  else if (!base->tuples)
1872  {
1873  Assert(tuplen == sizeof(Datum));
1874  LogicalTapeReadExact(tape, &stup->datum1, tuplen);
1875  stup->isnull1 = false;
1876  stup->tuple = NULL;
1877  }
1878  else
1879  {
1880  void *raddr = tuplesort_readtup_alloc(state, tuplen);
1881 
1882  LogicalTapeReadExact(tape, raddr, tuplen);
1883  stup->datum1 = PointerGetDatum(raddr);
1884  stup->isnull1 = false;
1885  stup->tuple = raddr;
1886  }
1887 
1888  if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1889  LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1890 }
int16 AttrNumber
Definition: attnum.h:21
uint32 BlockNumber
Definition: block.h:31
static Datum values[MAXATTR]
Definition: bootstrap.c:152
unsigned int uint32
Definition: c.h:506
signed short int16
Definition: c.h:493
#define MAXALIGN(LEN)
Definition: c.h:811
signed int int32
Definition: c.h:494
#define Assert(condition)
Definition: c.h:858
size_t Size
Definition: c.h:605
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
Size datumGetSize(Datum value, bool typByVal, int typLen)
Definition: datum.c:65
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define LOG
Definition: elog.h:31
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1533
TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1325
EState * CreateExecutorState(void)
Definition: execUtils.c:88
void FreeExecutorState(EState *estate)
Definition: execUtils.c:189
#define ResetPerTupleExprContext(estate)
Definition: executor.h:559
#define GetPerTupleExprContext(estate)
Definition: executor.h:550
char * BuildIndexValueDescription(Relation indexRelation, const Datum *values, const bool *isnull)
Definition: genam.c:174
static int compare(const void *arg1, const void *arg2)
Definition: geqo_pool.c:145
uint32 Bucket
Definition: hash.h:35
for(;;)
Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket, uint32 highmask, uint32 lowmask)
Definition: hashutil.c:125
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup)
Definition: heaptuple.c:1535
#define HEAPTUPLESIZE
Definition: htup.h:73
HeapTupleData * HeapTuple
Definition: htup.h:71
MinimalTupleData * MinimalTuple
Definition: htup.h:27
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define MINIMAL_TUPLE_OFFSET
Definition: htup_details.h:617
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
#define MINIMAL_TUPLE_DATA_OFFSET
Definition: htup_details.h:621
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2705
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2407
void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:456
IndexTuple index_form_tuple_context(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull, MemoryContext context)
Definition: indextuple.c:65
long val
Definition: informix.c:670
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition: itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexTupleSize(itup)
Definition: itup.h:70
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: itup.h:117
#define INDEX_SIZE_MASK
Definition: itup.h:65
void LogicalTapeWrite(LogicalTape *lt, const void *ptr, size_t size)
Definition: logtape.c:761
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2251
void pfree(void *pointer)
Definition: mcxt.c:1520
Size GetMemoryChunkSpace(void *pointer)
Definition: mcxt.c:721
void * palloc0(Size size)
Definition: mcxt.c:1346
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void * palloc(Size size)
Definition: mcxt.c:1316
#define SK_BT_NULLS_FIRST
Definition: nbtree.h:1128
#define SK_BT_DESC
Definition: nbtree.h:1127
BTScanInsert _bt_mkscankey(Relation rel, IndexTuple itup)
Definition: nbtutils.c:129
uint16 OffsetNumber
Definition: off.h:24
void * arg
#define INDEX_MAX_KEYS
const void size_t len
static uint32 DatumGetUInt32(Datum X)
Definition: postgres.h:222
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContextSwitchTo(old_ctx)
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:5999
static pg_noinline void Size size
Definition: slab.c:607
void PrepareSortSupportFromGistIndexRel(Relation indexRel, SortSupport ssup)
Definition: sortsupport.c:188
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:134
void PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy, SortSupport ssup)
Definition: sortsupport.c:161
static int ApplySortAbbrevFullComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
Definition: sortsupport.h:341
struct SortSupportData * SortSupport
Definition: sortsupport.h:58
static int ApplySortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
Definition: sortsupport.h:200
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define BTLessStrategyNumber
Definition: stratnum.h:29
ScanKeyData scankeys[INDEX_MAX_KEYS]
Definition: nbtree.h:793
BlockNumber bt_blkno
Definition: brin_tuple.h:66
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:255
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
ItemPointerData t_tid
Definition: itup.h:37
unsigned short t_info
Definition: itup.h:49
Oid * rd_indcollation
Definition: rel.h:217
Form_pg_class rd_rel
Definition: rel.h:111
int sk_flags
Definition: skey.h:66
Oid sk_collation
Definition: skey.h:70
AttrNumber sk_attno
Definition: skey.h:67
AttrNumber ssup_attno
Definition: sortsupport.h:81
bool ssup_nulls_first
Definition: sortsupport.h:75
Datum(* abbrev_converter)(Datum original, SortSupport ssup)
Definition: sortsupport.h:172
MemoryContext ssup_cxt
Definition: sortsupport.h:66
bool isnull1
Definition: tuplesort.h:151
void * tuple
Definition: tuplesort.h:149
Datum datum1
Definition: tuplesort.h:150
TuplesortIndexArg index
TuplesortIndexArg index
SortSupport onlyKey
Definition: tuplesort.h:245
MemoryContext maincontext
Definition: tuplesort.h:218
void(* writetup)(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
Definition: tuplesort.h:194
void(* removeabbrev)(Tuplesortstate *state, SortTuple *stups, int count)
Definition: tuplesort.h:187
void(* freestate)(Tuplesortstate *state)
Definition: tuplesort.h:212
MemoryContext tuplecontext
Definition: tuplesort.h:221
MemoryContext sortcontext
Definition: tuplesort.h:220
void(* readtup)(Tuplesortstate *state, SortTuple *stup, LogicalTape *tape, unsigned int len)
Definition: tuplesort.h:203
SortTupleComparator comparetup
Definition: tuplesort.h:174
SortSupport sortKeys
Definition: tuplesort.h:235
SortTupleComparator comparetup_tiebreak
Definition: tuplesort.h:181
Definition: regguts.h:323
struct TupleDescData * TupleDesc
Definition: tupdesc.h:89
Tuplesortstate * tuplesort_begin_common(int workMem, SortCoordinate coordinate, int sortopt)
Definition: tuplesort.c:645
void tuplesort_puttuple_common(Tuplesortstate *state, SortTuple *tuple, bool useAbbrev, Size tuplen)
Definition: tuplesort.c:1189
bool tuplesort_gettuple_common(Tuplesortstate *state, bool forward, SortTuple *stup)
Definition: tuplesort.c:1496
bool trace_sort
Definition: tuplesort.c:124
void * tuplesort_readtup_alloc(Tuplesortstate *state, Size tuplen)
Definition: tuplesort.c:2921
#define TupleSortUseBumpTupleCxt(opt)
Definition: tuplesort.h:108
#define PARALLEL_SORT(coordinate)
Definition: tuplesort.h:255
#define TUPLESORT_RANDOMACCESS
Definition: tuplesort.h:96
#define LogicalTapeReadExact(tape, ptr, len)
Definition: tuplesort.h:262
#define TuplesortstateGetPublic(state)
Definition: tuplesort.h:259
IndexTuple tuplesort_getindextuple(Tuplesortstate *state, bool forward)
static void writetup_index_brin(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
HeapTuple tuplesort_getheaptuple(Tuplesortstate *state, bool forward)
static void removeabbrev_datum(Tuplesortstate *state, SortTuple *stups, int count)
static int comparetup_index_btree_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Tuplesortstate * tuplesort_begin_index_hash(Relation heapRel, Relation indexRel, uint32 high_mask, uint32 low_mask, uint32 max_buckets, int workMem, SortCoordinate coordinate, int sortopt)
static int comparetup_index_btree(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
void tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel, ItemPointer self, const Datum *values, const bool *isnull)
static void readtup_index(Tuplesortstate *state, SortTuple *stup, LogicalTape *tape, unsigned int len)
static int comparetup_cluster_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
static int comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
Tuplesortstate * tuplesort_begin_index_gist(Relation heapRel, Relation indexRel, int workMem, SortCoordinate coordinate, int sortopt)
Tuplesortstate * tuplesort_begin_index_btree(Relation heapRel, Relation indexRel, bool enforceUnique, bool uniqueNullsNotDistinct, int workMem, SortCoordinate coordinate, int sortopt)
static void removeabbrev_index(Tuplesortstate *state, SortTuple *stups, int count)
static int comparetup_datum_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
Tuplesortstate * tuplesort_begin_index_brin(int workMem, SortCoordinate coordinate, int sortopt)
static void readtup_datum(Tuplesortstate *state, SortTuple *stup, LogicalTape *tape, unsigned int len)
#define INDEX_SORT
static void readtup_heap(Tuplesortstate *state, SortTuple *stup, LogicalTape *tape, unsigned int len)
static void readtup_cluster(Tuplesortstate *state, SortTuple *stup, LogicalTape *tape, unsigned int tuplen)
static void writetup_datum(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
struct BrinSortTuple BrinSortTuple
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, int sortopt)
#define CLUSTER_SORT
static int comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
static void removeabbrev_index_brin(Tuplesortstate *state, SortTuple *stups, int count)
#define BRINSORTTUPLE_SIZE(len)
#define DATUM_SORT
static int comparetup_index_hash(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
static void readtup_index_brin(Tuplesortstate *state, SortTuple *stup, LogicalTape *tape, unsigned int len)
Tuplesortstate * tuplesort_begin_cluster(TupleDesc tupDesc, Relation indexRel, int workMem, SortCoordinate coordinate, int sortopt)
void tuplesort_putbrintuple(Tuplesortstate *state, BrinTuple *tuple, Size size)
static void writetup_heap(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
static void writetup_index(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
static int comparetup_heap_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
static void freestate_cluster(Tuplesortstate *state)
static void removeabbrev_heap(Tuplesortstate *state, SortTuple *stups, int count)
void tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup)
static int comparetup_cluster(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
static int comparetup_index_brin(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
static int comparetup_index_hash_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, bool copy, Datum *val, bool *isNull, Datum *abbrev)
BrinTuple * tuplesort_getbrintuple(Tuplesortstate *state, Size *len, bool forward)
static void writetup_cluster(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
static void removeabbrev_cluster(Tuplesortstate *state, SortTuple *stups, int count)
#define HEAP_SORT
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, SortCoordinate coordinate, int sortopt)
static MinimalTuple ExecCopySlotMinimalTuple(TupleTableSlot *slot)
Definition: tuptable.h:492
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454