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