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