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