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