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