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/rel.h"
35 : #include "utils/tuplesort.h"
36 :
37 :
38 : /* sort-type codes for sort__start probes */
39 : #define HEAP_SORT 0
40 : #define INDEX_SORT 1
41 : #define DATUM_SORT 2
42 : #define CLUSTER_SORT 3
43 :
44 : static void removeabbrev_heap(Tuplesortstate *state, SortTuple *stups,
45 : int count);
46 : static void removeabbrev_cluster(Tuplesortstate *state, SortTuple *stups,
47 : int count);
48 : static void removeabbrev_index(Tuplesortstate *state, SortTuple *stups,
49 : int count);
50 : static void removeabbrev_index_brin(Tuplesortstate *state, SortTuple *stups,
51 : int count);
52 : static void removeabbrev_index_gin(Tuplesortstate *state, SortTuple *stups,
53 : int count);
54 : static void removeabbrev_datum(Tuplesortstate *state, SortTuple *stups,
55 : int count);
56 : static int comparetup_heap(const SortTuple *a, const SortTuple *b,
57 : Tuplesortstate *state);
58 : static int comparetup_heap_tiebreak(const SortTuple *a, const SortTuple *b,
59 : Tuplesortstate *state);
60 : static void writetup_heap(Tuplesortstate *state, LogicalTape *tape,
61 : SortTuple *stup);
62 : static void readtup_heap(Tuplesortstate *state, SortTuple *stup,
63 : LogicalTape *tape, unsigned int len);
64 : static int comparetup_cluster(const SortTuple *a, const SortTuple *b,
65 : Tuplesortstate *state);
66 : static int comparetup_cluster_tiebreak(const SortTuple *a, const SortTuple *b,
67 : Tuplesortstate *state);
68 : static void writetup_cluster(Tuplesortstate *state, LogicalTape *tape,
69 : SortTuple *stup);
70 : static void readtup_cluster(Tuplesortstate *state, SortTuple *stup,
71 : LogicalTape *tape, unsigned int tuplen);
72 : static int comparetup_index_btree(const SortTuple *a, const SortTuple *b,
73 : Tuplesortstate *state);
74 : static int comparetup_index_btree_tiebreak(const SortTuple *a, const SortTuple *b,
75 : Tuplesortstate *state);
76 : static int comparetup_index_hash(const SortTuple *a, const SortTuple *b,
77 : Tuplesortstate *state);
78 : static int comparetup_index_hash_tiebreak(const SortTuple *a, const SortTuple *b,
79 : Tuplesortstate *state);
80 : static int comparetup_index_brin(const SortTuple *a, const SortTuple *b,
81 : Tuplesortstate *state);
82 : static int comparetup_index_gin(const SortTuple *a, const SortTuple *b,
83 : Tuplesortstate *state);
84 : static void writetup_index(Tuplesortstate *state, LogicalTape *tape,
85 : SortTuple *stup);
86 : static void readtup_index(Tuplesortstate *state, SortTuple *stup,
87 : LogicalTape *tape, unsigned int len);
88 : static void writetup_index_brin(Tuplesortstate *state, LogicalTape *tape,
89 : SortTuple *stup);
90 : static void readtup_index_brin(Tuplesortstate *state, SortTuple *stup,
91 : LogicalTape *tape, unsigned int len);
92 : static void writetup_index_gin(Tuplesortstate *state, LogicalTape *tape,
93 : SortTuple *stup);
94 : static void readtup_index_gin(Tuplesortstate *state, SortTuple *stup,
95 : LogicalTape *tape, unsigned int len);
96 : static int comparetup_datum(const SortTuple *a, const SortTuple *b,
97 : Tuplesortstate *state);
98 : static int comparetup_datum_tiebreak(const SortTuple *a, const SortTuple *b,
99 : Tuplesortstate *state);
100 : static void writetup_datum(Tuplesortstate *state, LogicalTape *tape,
101 : SortTuple *stup);
102 : static void readtup_datum(Tuplesortstate *state, SortTuple *stup,
103 : LogicalTape *tape, unsigned int len);
104 : static void freestate_cluster(Tuplesortstate *state);
105 :
106 : /*
107 : * Data structure pointed by "TuplesortPublic.arg" for the CLUSTER case. Set by
108 : * the tuplesort_begin_cluster.
109 : */
110 : typedef struct
111 : {
112 : TupleDesc tupDesc;
113 :
114 : IndexInfo *indexInfo; /* info about index being used for reference */
115 : EState *estate; /* for evaluating index expressions */
116 : } TuplesortClusterArg;
117 :
118 : /*
119 : * Data structure pointed by "TuplesortPublic.arg" for the IndexTuple case.
120 : * Set by tuplesort_begin_index_xxx and used only by the IndexTuple routines.
121 : */
122 : typedef struct
123 : {
124 : Relation heapRel; /* table the index is being built on */
125 : Relation indexRel; /* index being built */
126 : } TuplesortIndexArg;
127 :
128 : /*
129 : * Data structure pointed by "TuplesortPublic.arg" for the index_btree subcase.
130 : */
131 : typedef struct
132 : {
133 : TuplesortIndexArg index;
134 :
135 : bool enforceUnique; /* complain if we find duplicate tuples */
136 : bool uniqueNullsNotDistinct; /* unique constraint null treatment */
137 : } TuplesortIndexBTreeArg;
138 :
139 : /*
140 : * Data structure pointed by "TuplesortPublic.arg" for the index_hash subcase.
141 : */
142 : typedef struct
143 : {
144 : TuplesortIndexArg index;
145 :
146 : uint32 high_mask; /* masks for sortable part of hash code */
147 : uint32 low_mask;
148 : uint32 max_buckets;
149 : } TuplesortIndexHashArg;
150 :
151 : /*
152 : * Data structure pointed by "TuplesortPublic.arg" for the Datum case.
153 : * Set by tuplesort_begin_datum and used only by the DatumTuple routines.
154 : */
155 : typedef struct
156 : {
157 : /* the datatype oid of Datum's to be sorted */
158 : Oid datumType;
159 : /* we need typelen in order to know how to copy the Datums. */
160 : int datumTypeLen;
161 : } TuplesortDatumArg;
162 :
163 : /*
164 : * Computing BrinTuple size with only the tuple is difficult, so we want to track
165 : * the length referenced by the SortTuple. That's what BrinSortTuple is meant
166 : * to do - it's essentially a BrinTuple prefixed by its length.
167 : */
168 : typedef struct BrinSortTuple
169 : {
170 : Size tuplen;
171 : BrinTuple tuple;
172 : } BrinSortTuple;
173 :
174 : /* Size of the BrinSortTuple, given length of the BrinTuple. */
175 : #define BRINSORTTUPLE_SIZE(len) (offsetof(BrinSortTuple, tuple) + (len))
176 :
177 :
178 : Tuplesortstate *
179 119400 : tuplesort_begin_heap(TupleDesc tupDesc,
180 : int nkeys, AttrNumber *attNums,
181 : Oid *sortOperators, Oid *sortCollations,
182 : bool *nullsFirstFlags,
183 : int workMem, SortCoordinate coordinate, int sortopt)
184 : {
185 119400 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
186 : sortopt);
187 119400 : TuplesortPublic *base = TuplesortstateGetPublic(state);
188 : MemoryContext oldcontext;
189 : int i;
190 :
191 119400 : oldcontext = MemoryContextSwitchTo(base->maincontext);
192 :
193 : Assert(nkeys > 0);
194 :
195 119400 : if (trace_sort)
196 0 : elog(LOG,
197 : "begin tuple sort: nkeys = %d, workMem = %d, randomAccess = %c",
198 : nkeys, workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
199 :
200 119400 : base->nKeys = nkeys;
201 :
202 : TRACE_POSTGRESQL_SORT_START(HEAP_SORT,
203 : false, /* no unique check */
204 : nkeys,
205 : workMem,
206 : sortopt & TUPLESORT_RANDOMACCESS,
207 : PARALLEL_SORT(coordinate));
208 :
209 119400 : base->removeabbrev = removeabbrev_heap;
210 119400 : base->comparetup = comparetup_heap;
211 119400 : base->comparetup_tiebreak = comparetup_heap_tiebreak;
212 119400 : base->writetup = writetup_heap;
213 119400 : base->readtup = readtup_heap;
214 119400 : base->haveDatum1 = true;
215 119400 : base->arg = tupDesc; /* assume we need not copy tupDesc */
216 :
217 : /* Prepare SortSupport data for each column */
218 119400 : base->sortKeys = (SortSupport) palloc0(nkeys * sizeof(SortSupportData));
219 :
220 294368 : for (i = 0; i < nkeys; i++)
221 : {
222 174980 : SortSupport sortKey = base->sortKeys + i;
223 :
224 : Assert(attNums[i] != 0);
225 : Assert(sortOperators[i] != 0);
226 :
227 174980 : sortKey->ssup_cxt = CurrentMemoryContext;
228 174980 : sortKey->ssup_collation = sortCollations[i];
229 174980 : sortKey->ssup_nulls_first = nullsFirstFlags[i];
230 174980 : sortKey->ssup_attno = attNums[i];
231 : /* Convey if abbreviation optimization is applicable in principle */
232 174980 : sortKey->abbreviate = (i == 0 && base->haveDatum1);
233 :
234 174980 : PrepareSortSupportFromOrderingOp(sortOperators[i], sortKey);
235 : }
236 :
237 : /*
238 : * The "onlyKey" optimization cannot be used with abbreviated keys, since
239 : * tie-breaker comparisons may be required. Typically, the optimization
240 : * is only of value to pass-by-value types anyway, whereas abbreviated
241 : * keys are typically only of value to pass-by-reference types.
242 : */
243 119388 : if (nkeys == 1 && !base->sortKeys->abbrev_converter)
244 68406 : base->onlyKey = base->sortKeys;
245 :
246 119388 : MemoryContextSwitchTo(oldcontext);
247 :
248 119388 : return state;
249 : }
250 :
251 : Tuplesortstate *
252 116 : tuplesort_begin_cluster(TupleDesc tupDesc,
253 : Relation indexRel,
254 : int workMem,
255 : SortCoordinate coordinate, int sortopt)
256 : {
257 116 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
258 : sortopt);
259 116 : TuplesortPublic *base = TuplesortstateGetPublic(state);
260 : BTScanInsert indexScanKey;
261 : MemoryContext oldcontext;
262 : TuplesortClusterArg *arg;
263 : int i;
264 :
265 : Assert(indexRel->rd_rel->relam == BTREE_AM_OID);
266 :
267 116 : oldcontext = MemoryContextSwitchTo(base->maincontext);
268 116 : arg = palloc0_object(TuplesortClusterArg);
269 :
270 116 : if (trace_sort)
271 0 : elog(LOG,
272 : "begin tuple sort: nkeys = %d, workMem = %d, randomAccess = %c",
273 : RelationGetNumberOfAttributes(indexRel),
274 : workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
275 :
276 116 : base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
277 :
278 : TRACE_POSTGRESQL_SORT_START(CLUSTER_SORT,
279 : false, /* no unique check */
280 : base->nKeys,
281 : workMem,
282 : sortopt & TUPLESORT_RANDOMACCESS,
283 : PARALLEL_SORT(coordinate));
284 :
285 116 : base->removeabbrev = removeabbrev_cluster;
286 116 : base->comparetup = comparetup_cluster;
287 116 : base->comparetup_tiebreak = comparetup_cluster_tiebreak;
288 116 : base->writetup = writetup_cluster;
289 116 : base->readtup = readtup_cluster;
290 116 : base->freestate = freestate_cluster;
291 116 : base->arg = arg;
292 :
293 116 : arg->indexInfo = BuildIndexInfo(indexRel);
294 :
295 : /*
296 : * If we don't have a simple leading attribute, we don't currently
297 : * initialize datum1, so disable optimizations that require it.
298 : */
299 116 : if (arg->indexInfo->ii_IndexAttrNumbers[0] == 0)
300 24 : base->haveDatum1 = false;
301 : else
302 92 : base->haveDatum1 = true;
303 :
304 116 : arg->tupDesc = tupDesc; /* assume we need not copy tupDesc */
305 :
306 116 : indexScanKey = _bt_mkscankey(indexRel, NULL);
307 :
308 116 : if (arg->indexInfo->ii_Expressions != NULL)
309 : {
310 : TupleTableSlot *slot;
311 : ExprContext *econtext;
312 :
313 : /*
314 : * We will need to use FormIndexDatum to evaluate the index
315 : * expressions. To do that, we need an EState, as well as a
316 : * TupleTableSlot to put the table tuples into. The econtext's
317 : * scantuple has to point to that slot, too.
318 : */
319 24 : arg->estate = CreateExecutorState();
320 24 : slot = MakeSingleTupleTableSlot(tupDesc, &TTSOpsHeapTuple);
321 24 : econtext = GetPerTupleExprContext(arg->estate);
322 24 : econtext->ecxt_scantuple = slot;
323 : }
324 :
325 : /* Prepare SortSupport data for each column */
326 116 : base->sortKeys = (SortSupport) palloc0(base->nKeys *
327 : sizeof(SortSupportData));
328 :
329 256 : for (i = 0; i < base->nKeys; i++)
330 : {
331 140 : SortSupport sortKey = base->sortKeys + i;
332 140 : ScanKey scanKey = indexScanKey->scankeys + i;
333 : bool reverse;
334 :
335 140 : sortKey->ssup_cxt = CurrentMemoryContext;
336 140 : sortKey->ssup_collation = scanKey->sk_collation;
337 140 : sortKey->ssup_nulls_first =
338 140 : (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
339 140 : sortKey->ssup_attno = scanKey->sk_attno;
340 : /* Convey if abbreviation optimization is applicable in principle */
341 140 : sortKey->abbreviate = (i == 0 && base->haveDatum1);
342 :
343 : Assert(sortKey->ssup_attno != 0);
344 :
345 140 : reverse = (scanKey->sk_flags & SK_BT_DESC) != 0;
346 :
347 140 : PrepareSortSupportFromIndexRel(indexRel, reverse, sortKey);
348 : }
349 :
350 116 : pfree(indexScanKey);
351 :
352 116 : MemoryContextSwitchTo(oldcontext);
353 :
354 116 : return state;
355 : }
356 :
357 : Tuplesortstate *
358 95668 : tuplesort_begin_index_btree(Relation heapRel,
359 : Relation indexRel,
360 : bool enforceUnique,
361 : bool uniqueNullsNotDistinct,
362 : int workMem,
363 : SortCoordinate coordinate,
364 : int sortopt)
365 : {
366 95668 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
367 : sortopt);
368 95668 : TuplesortPublic *base = TuplesortstateGetPublic(state);
369 : BTScanInsert indexScanKey;
370 : TuplesortIndexBTreeArg *arg;
371 : MemoryContext oldcontext;
372 : int i;
373 :
374 95668 : oldcontext = MemoryContextSwitchTo(base->maincontext);
375 95668 : arg = palloc_object(TuplesortIndexBTreeArg);
376 :
377 95668 : if (trace_sort)
378 0 : elog(LOG,
379 : "begin index sort: unique = %c, workMem = %d, randomAccess = %c",
380 : enforceUnique ? 't' : 'f',
381 : workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
382 :
383 95668 : base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
384 :
385 : TRACE_POSTGRESQL_SORT_START(INDEX_SORT,
386 : enforceUnique,
387 : base->nKeys,
388 : workMem,
389 : sortopt & TUPLESORT_RANDOMACCESS,
390 : PARALLEL_SORT(coordinate));
391 :
392 95668 : base->removeabbrev = removeabbrev_index;
393 95668 : base->comparetup = comparetup_index_btree;
394 95668 : base->comparetup_tiebreak = comparetup_index_btree_tiebreak;
395 95668 : base->writetup = writetup_index;
396 95668 : base->readtup = readtup_index;
397 95668 : base->haveDatum1 = true;
398 95668 : base->arg = arg;
399 :
400 95668 : arg->index.heapRel = heapRel;
401 95668 : arg->index.indexRel = indexRel;
402 95668 : arg->enforceUnique = enforceUnique;
403 95668 : arg->uniqueNullsNotDistinct = uniqueNullsNotDistinct;
404 :
405 95668 : indexScanKey = _bt_mkscankey(indexRel, NULL);
406 :
407 : /* Prepare SortSupport data for each column */
408 95668 : base->sortKeys = (SortSupport) palloc0(base->nKeys *
409 : sizeof(SortSupportData));
410 :
411 253644 : for (i = 0; i < base->nKeys; i++)
412 : {
413 157976 : SortSupport sortKey = base->sortKeys + i;
414 157976 : ScanKey scanKey = indexScanKey->scankeys + i;
415 : bool reverse;
416 :
417 157976 : sortKey->ssup_cxt = CurrentMemoryContext;
418 157976 : sortKey->ssup_collation = scanKey->sk_collation;
419 157976 : sortKey->ssup_nulls_first =
420 157976 : (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
421 157976 : sortKey->ssup_attno = scanKey->sk_attno;
422 : /* Convey if abbreviation optimization is applicable in principle */
423 157976 : sortKey->abbreviate = (i == 0 && base->haveDatum1);
424 :
425 : Assert(sortKey->ssup_attno != 0);
426 :
427 157976 : reverse = (scanKey->sk_flags & SK_BT_DESC) != 0;
428 :
429 157976 : PrepareSortSupportFromIndexRel(indexRel, reverse, sortKey);
430 : }
431 :
432 95668 : pfree(indexScanKey);
433 :
434 95668 : MemoryContextSwitchTo(oldcontext);
435 :
436 95668 : return state;
437 : }
438 :
439 : Tuplesortstate *
440 8 : tuplesort_begin_index_hash(Relation heapRel,
441 : Relation indexRel,
442 : uint32 high_mask,
443 : uint32 low_mask,
444 : uint32 max_buckets,
445 : int workMem,
446 : SortCoordinate coordinate,
447 : int sortopt)
448 : {
449 8 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
450 : sortopt);
451 8 : TuplesortPublic *base = TuplesortstateGetPublic(state);
452 : MemoryContext oldcontext;
453 : TuplesortIndexHashArg *arg;
454 :
455 8 : oldcontext = MemoryContextSwitchTo(base->maincontext);
456 8 : arg = palloc_object(TuplesortIndexHashArg);
457 :
458 8 : if (trace_sort)
459 0 : elog(LOG,
460 : "begin index sort: high_mask = 0x%x, low_mask = 0x%x, "
461 : "max_buckets = 0x%x, workMem = %d, randomAccess = %c",
462 : high_mask,
463 : low_mask,
464 : max_buckets,
465 : workMem,
466 : sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
467 :
468 8 : base->nKeys = 1; /* Only one sort column, the hash code */
469 :
470 8 : base->removeabbrev = removeabbrev_index;
471 8 : base->comparetup = comparetup_index_hash;
472 8 : base->comparetup_tiebreak = comparetup_index_hash_tiebreak;
473 8 : base->writetup = writetup_index;
474 8 : base->readtup = readtup_index;
475 8 : base->haveDatum1 = true;
476 8 : base->arg = arg;
477 :
478 8 : arg->index.heapRel = heapRel;
479 8 : arg->index.indexRel = indexRel;
480 :
481 8 : arg->high_mask = high_mask;
482 8 : arg->low_mask = low_mask;
483 8 : arg->max_buckets = max_buckets;
484 :
485 8 : MemoryContextSwitchTo(oldcontext);
486 :
487 8 : return state;
488 : }
489 :
490 : Tuplesortstate *
491 824 : tuplesort_begin_index_gist(Relation heapRel,
492 : Relation indexRel,
493 : int workMem,
494 : SortCoordinate coordinate,
495 : int sortopt)
496 : {
497 824 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
498 : sortopt);
499 824 : TuplesortPublic *base = TuplesortstateGetPublic(state);
500 : MemoryContext oldcontext;
501 : TuplesortIndexBTreeArg *arg;
502 : int i;
503 :
504 824 : oldcontext = MemoryContextSwitchTo(base->maincontext);
505 824 : arg = palloc_object(TuplesortIndexBTreeArg);
506 :
507 824 : if (trace_sort)
508 0 : elog(LOG,
509 : "begin index sort: workMem = %d, randomAccess = %c",
510 : workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
511 :
512 824 : base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
513 :
514 824 : base->removeabbrev = removeabbrev_index;
515 824 : base->comparetup = comparetup_index_btree;
516 824 : base->comparetup_tiebreak = comparetup_index_btree_tiebreak;
517 824 : base->writetup = writetup_index;
518 824 : base->readtup = readtup_index;
519 824 : base->haveDatum1 = true;
520 824 : base->arg = arg;
521 :
522 824 : arg->index.heapRel = heapRel;
523 824 : arg->index.indexRel = indexRel;
524 824 : arg->enforceUnique = false;
525 824 : arg->uniqueNullsNotDistinct = false;
526 :
527 : /* Prepare SortSupport data for each column */
528 824 : base->sortKeys = (SortSupport) palloc0(base->nKeys *
529 : sizeof(SortSupportData));
530 :
531 2262 : for (i = 0; i < base->nKeys; i++)
532 : {
533 1438 : SortSupport sortKey = base->sortKeys + i;
534 :
535 1438 : sortKey->ssup_cxt = CurrentMemoryContext;
536 1438 : sortKey->ssup_collation = indexRel->rd_indcollation[i];
537 1438 : sortKey->ssup_nulls_first = false;
538 1438 : sortKey->ssup_attno = i + 1;
539 : /* Convey if abbreviation optimization is applicable in principle */
540 1438 : sortKey->abbreviate = (i == 0 && base->haveDatum1);
541 :
542 : Assert(sortKey->ssup_attno != 0);
543 :
544 : /* Look for a sort support function */
545 1438 : PrepareSortSupportFromGistIndexRel(indexRel, sortKey);
546 : }
547 :
548 824 : MemoryContextSwitchTo(oldcontext);
549 :
550 824 : return state;
551 : }
552 :
553 : Tuplesortstate *
554 28 : tuplesort_begin_index_brin(int workMem,
555 : SortCoordinate coordinate,
556 : int sortopt)
557 : {
558 28 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
559 : sortopt);
560 28 : TuplesortPublic *base = TuplesortstateGetPublic(state);
561 :
562 28 : if (trace_sort)
563 0 : elog(LOG,
564 : "begin index sort: workMem = %d, randomAccess = %c",
565 : workMem,
566 : sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
567 :
568 28 : base->nKeys = 1; /* Only one sort column, the block number */
569 :
570 28 : base->removeabbrev = removeabbrev_index_brin;
571 28 : base->comparetup = comparetup_index_brin;
572 28 : base->writetup = writetup_index_brin;
573 28 : base->readtup = readtup_index_brin;
574 28 : base->haveDatum1 = true;
575 28 : base->arg = NULL;
576 :
577 28 : return state;
578 : }
579 :
580 : Tuplesortstate *
581 0 : tuplesort_begin_index_gin(Relation heapRel,
582 : Relation indexRel,
583 : int workMem, SortCoordinate coordinate,
584 : int sortopt)
585 : {
586 0 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
587 : sortopt);
588 0 : TuplesortPublic *base = TuplesortstateGetPublic(state);
589 : MemoryContext oldcontext;
590 : int i;
591 0 : TupleDesc desc = RelationGetDescr(indexRel);
592 :
593 0 : oldcontext = MemoryContextSwitchTo(base->maincontext);
594 :
595 : #ifdef TRACE_SORT
596 : if (trace_sort)
597 : elog(LOG,
598 : "begin index sort: workMem = %d, randomAccess = %c",
599 : workMem,
600 : sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
601 : #endif
602 :
603 : /*
604 : * Multi-column GIN indexes expand the row into a separate index entry for
605 : * attribute, and that's what we write into the tuplesort. But we still
606 : * need to initialize sortsupport for all the attributes.
607 : */
608 0 : base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
609 :
610 : /* Prepare SortSupport data for each column */
611 0 : base->sortKeys = (SortSupport) palloc0(base->nKeys *
612 : sizeof(SortSupportData));
613 :
614 0 : for (i = 0; i < base->nKeys; i++)
615 : {
616 0 : SortSupport sortKey = base->sortKeys + i;
617 0 : Form_pg_attribute att = TupleDescAttr(desc, i);
618 : TypeCacheEntry *typentry;
619 :
620 0 : sortKey->ssup_cxt = CurrentMemoryContext;
621 0 : sortKey->ssup_collation = indexRel->rd_indcollation[i];
622 0 : sortKey->ssup_nulls_first = false;
623 0 : sortKey->ssup_attno = i + 1;
624 0 : sortKey->abbreviate = false;
625 :
626 : Assert(sortKey->ssup_attno != 0);
627 :
628 0 : if (!OidIsValid(sortKey->ssup_collation))
629 0 : sortKey->ssup_collation = DEFAULT_COLLATION_OID;
630 :
631 : /*
632 : * Look for a ordering for the index key data type, and then the sort
633 : * support function.
634 : */
635 0 : typentry = lookup_type_cache(att->atttypid, TYPECACHE_LT_OPR);
636 0 : PrepareSortSupportFromOrderingOp(typentry->lt_opr, sortKey);
637 : }
638 :
639 0 : base->removeabbrev = removeabbrev_index_gin;
640 0 : base->comparetup = comparetup_index_gin;
641 0 : base->writetup = writetup_index_gin;
642 0 : base->readtup = readtup_index_gin;
643 0 : base->haveDatum1 = false;
644 0 : base->arg = NULL;
645 :
646 0 : MemoryContextSwitchTo(oldcontext);
647 :
648 0 : return state;
649 : }
650 :
651 : Tuplesortstate *
652 61146 : tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation,
653 : bool nullsFirstFlag, int workMem,
654 : SortCoordinate coordinate, int sortopt)
655 : {
656 61146 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
657 : sortopt);
658 61146 : TuplesortPublic *base = TuplesortstateGetPublic(state);
659 : TuplesortDatumArg *arg;
660 : MemoryContext oldcontext;
661 : int16 typlen;
662 : bool typbyval;
663 :
664 61146 : oldcontext = MemoryContextSwitchTo(base->maincontext);
665 61146 : arg = palloc_object(TuplesortDatumArg);
666 :
667 61146 : if (trace_sort)
668 0 : elog(LOG,
669 : "begin datum sort: workMem = %d, randomAccess = %c",
670 : workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
671 :
672 61146 : base->nKeys = 1; /* always a one-column sort */
673 :
674 : TRACE_POSTGRESQL_SORT_START(DATUM_SORT,
675 : false, /* no unique check */
676 : 1,
677 : workMem,
678 : sortopt & TUPLESORT_RANDOMACCESS,
679 : PARALLEL_SORT(coordinate));
680 :
681 61146 : base->removeabbrev = removeabbrev_datum;
682 61146 : base->comparetup = comparetup_datum;
683 61146 : base->comparetup_tiebreak = comparetup_datum_tiebreak;
684 61146 : base->writetup = writetup_datum;
685 61146 : base->readtup = readtup_datum;
686 61146 : base->haveDatum1 = true;
687 61146 : base->arg = arg;
688 :
689 61146 : arg->datumType = datumType;
690 :
691 : /* lookup necessary attributes of the datum type */
692 61146 : get_typlenbyval(datumType, &typlen, &typbyval);
693 61146 : arg->datumTypeLen = typlen;
694 61146 : base->tuples = !typbyval;
695 :
696 : /* Prepare SortSupport data */
697 61146 : base->sortKeys = palloc0_object(SortSupportData);
698 :
699 61146 : base->sortKeys->ssup_cxt = CurrentMemoryContext;
700 61146 : base->sortKeys->ssup_collation = sortCollation;
701 61146 : base->sortKeys->ssup_nulls_first = nullsFirstFlag;
702 :
703 : /*
704 : * Abbreviation is possible here only for by-reference types. In theory,
705 : * a pass-by-value datatype could have an abbreviated form that is cheaper
706 : * to compare. In a tuple sort, we could support that, because we can
707 : * always extract the original datum from the tuple as needed. Here, we
708 : * can't, because a datum sort only stores a single copy of the datum; the
709 : * "tuple" field of each SortTuple is NULL.
710 : */
711 61146 : base->sortKeys->abbreviate = !typbyval;
712 :
713 61146 : PrepareSortSupportFromOrderingOp(sortOperator, base->sortKeys);
714 :
715 : /*
716 : * The "onlyKey" optimization cannot be used with abbreviated keys, since
717 : * tie-breaker comparisons may be required. Typically, the optimization
718 : * is only of value to pass-by-value types anyway, whereas abbreviated
719 : * keys are typically only of value to pass-by-reference types.
720 : */
721 61146 : if (!base->sortKeys->abbrev_converter)
722 60330 : base->onlyKey = base->sortKeys;
723 :
724 61146 : MemoryContextSwitchTo(oldcontext);
725 :
726 61146 : return state;
727 : }
728 :
729 : /*
730 : * Accept one tuple while collecting input data for sort.
731 : *
732 : * Note that the input data is always copied; the caller need not save it.
733 : */
734 : void
735 13289388 : tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
736 : {
737 13289388 : TuplesortPublic *base = TuplesortstateGetPublic(state);
738 13289388 : MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
739 13289388 : TupleDesc tupDesc = (TupleDesc) base->arg;
740 : SortTuple stup;
741 : MinimalTuple tuple;
742 : HeapTupleData htup;
743 : Size tuplen;
744 :
745 : /* copy the tuple into sort storage */
746 13289388 : tuple = ExecCopySlotMinimalTuple(slot);
747 13289388 : stup.tuple = tuple;
748 : /* set up first-column key value */
749 13289388 : htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
750 13289388 : htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
751 26578776 : stup.datum1 = heap_getattr(&htup,
752 13289388 : base->sortKeys[0].ssup_attno,
753 : tupDesc,
754 : &stup.isnull1);
755 :
756 : /* GetMemoryChunkSpace is not supported for bump contexts */
757 13289388 : if (TupleSortUseBumpTupleCxt(base->sortopt))
758 9786854 : tuplen = MAXALIGN(tuple->t_len);
759 : else
760 3502534 : tuplen = GetMemoryChunkSpace(tuple);
761 :
762 13289388 : tuplesort_puttuple_common(state, &stup,
763 14412116 : base->sortKeys->abbrev_converter &&
764 1122728 : !stup.isnull1, tuplen);
765 :
766 13289388 : MemoryContextSwitchTo(oldcontext);
767 13289388 : }
768 :
769 : /*
770 : * Accept one tuple while collecting input data for sort.
771 : *
772 : * Note that the input data is always copied; the caller need not save it.
773 : */
774 : void
775 547414 : tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup)
776 : {
777 : SortTuple stup;
778 547414 : TuplesortPublic *base = TuplesortstateGetPublic(state);
779 547414 : MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
780 547414 : TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
781 : Size tuplen;
782 :
783 : /* copy the tuple into sort storage */
784 547414 : tup = heap_copytuple(tup);
785 547414 : stup.tuple = tup;
786 :
787 : /*
788 : * set up first-column key value, and potentially abbreviate, if it's a
789 : * simple column
790 : */
791 547414 : if (base->haveDatum1)
792 : {
793 545788 : stup.datum1 = heap_getattr(tup,
794 545788 : arg->indexInfo->ii_IndexAttrNumbers[0],
795 : arg->tupDesc,
796 : &stup.isnull1);
797 : }
798 :
799 : /* GetMemoryChunkSpace is not supported for bump contexts */
800 547414 : if (TupleSortUseBumpTupleCxt(base->sortopt))
801 547414 : tuplen = MAXALIGN(HEAPTUPLESIZE + tup->t_len);
802 : else
803 0 : tuplen = GetMemoryChunkSpace(tup);
804 :
805 547414 : tuplesort_puttuple_common(state, &stup,
806 1093202 : base->haveDatum1 &&
807 910502 : base->sortKeys->abbrev_converter &&
808 363088 : !stup.isnull1, tuplen);
809 :
810 547414 : MemoryContextSwitchTo(oldcontext);
811 547414 : }
812 :
813 : /*
814 : * Collect one index tuple while collecting input data for sort, building
815 : * it from caller-supplied values.
816 : */
817 : void
818 13325138 : tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel,
819 : const ItemPointerData *self, const Datum *values,
820 : const bool *isnull)
821 : {
822 : SortTuple stup;
823 : IndexTuple tuple;
824 13325138 : TuplesortPublic *base = TuplesortstateGetPublic(state);
825 13325138 : TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
826 : Size tuplen;
827 :
828 13325138 : stup.tuple = index_form_tuple_context(RelationGetDescr(rel), values,
829 : isnull, base->tuplecontext);
830 13325138 : tuple = ((IndexTuple) stup.tuple);
831 13325138 : tuple->t_tid = *self;
832 : /* set up first-column key value */
833 26650276 : stup.datum1 = index_getattr(tuple,
834 : 1,
835 13325138 : RelationGetDescr(arg->indexRel),
836 : &stup.isnull1);
837 :
838 : /* GetMemoryChunkSpace is not supported for bump contexts */
839 13325138 : if (TupleSortUseBumpTupleCxt(base->sortopt))
840 13325138 : tuplen = MAXALIGN(tuple->t_info & INDEX_SIZE_MASK);
841 : else
842 0 : tuplen = GetMemoryChunkSpace(tuple);
843 :
844 13325138 : tuplesort_puttuple_common(state, &stup,
845 26529276 : base->sortKeys &&
846 15447982 : base->sortKeys->abbrev_converter &&
847 2122844 : !stup.isnull1, tuplen);
848 13325138 : }
849 :
850 : /*
851 : * Collect one BRIN tuple while collecting input data for sort.
852 : */
853 : void
854 40 : tuplesort_putbrintuple(Tuplesortstate *state, BrinTuple *tuple, Size size)
855 : {
856 : SortTuple stup;
857 : BrinSortTuple *bstup;
858 40 : TuplesortPublic *base = TuplesortstateGetPublic(state);
859 40 : MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
860 : Size tuplen;
861 :
862 : /* allocate space for the whole BRIN sort tuple */
863 40 : bstup = palloc(BRINSORTTUPLE_SIZE(size));
864 :
865 40 : bstup->tuplen = size;
866 40 : memcpy(&bstup->tuple, tuple, size);
867 :
868 40 : stup.tuple = bstup;
869 40 : stup.datum1 = UInt32GetDatum(tuple->bt_blkno);
870 40 : stup.isnull1 = false;
871 :
872 : /* GetMemoryChunkSpace is not supported for bump contexts */
873 40 : if (TupleSortUseBumpTupleCxt(base->sortopt))
874 40 : tuplen = MAXALIGN(BRINSORTTUPLE_SIZE(size));
875 : else
876 0 : tuplen = GetMemoryChunkSpace(bstup);
877 :
878 40 : tuplesort_puttuple_common(state, &stup,
879 40 : base->sortKeys &&
880 40 : base->sortKeys->abbrev_converter &&
881 0 : !stup.isnull1, tuplen);
882 :
883 40 : MemoryContextSwitchTo(oldcontext);
884 40 : }
885 :
886 : void
887 0 : tuplesort_putgintuple(Tuplesortstate *state, GinTuple *tuple, Size size)
888 : {
889 : SortTuple stup;
890 : GinTuple *ctup;
891 0 : TuplesortPublic *base = TuplesortstateGetPublic(state);
892 0 : MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
893 : Size tuplen;
894 :
895 : /* copy the GinTuple into the right memory context */
896 0 : ctup = palloc(size);
897 0 : memcpy(ctup, tuple, size);
898 :
899 0 : stup.tuple = ctup;
900 0 : stup.datum1 = (Datum) 0;
901 0 : stup.isnull1 = false;
902 :
903 : /* GetMemoryChunkSpace is not supported for bump contexts */
904 0 : if (TupleSortUseBumpTupleCxt(base->sortopt))
905 0 : tuplen = MAXALIGN(size);
906 : else
907 0 : tuplen = GetMemoryChunkSpace(ctup);
908 :
909 0 : tuplesort_puttuple_common(state, &stup,
910 0 : base->sortKeys &&
911 0 : base->sortKeys->abbrev_converter &&
912 0 : !stup.isnull1, tuplen);
913 :
914 0 : MemoryContextSwitchTo(oldcontext);
915 0 : }
916 :
917 : /*
918 : * Accept one Datum while collecting input data for sort.
919 : *
920 : * If the Datum is pass-by-ref type, the value will be copied.
921 : */
922 : void
923 3967526 : tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
924 : {
925 3967526 : TuplesortPublic *base = TuplesortstateGetPublic(state);
926 3967526 : MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
927 3967526 : TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
928 : SortTuple stup;
929 :
930 : /*
931 : * Pass-by-value types or null values are just stored directly in
932 : * stup.datum1 (and stup.tuple is not used and set to NULL).
933 : *
934 : * Non-null pass-by-reference values need to be copied into memory we
935 : * control, and possibly abbreviated. The copied value is pointed to by
936 : * stup.tuple and is treated as the canonical copy (e.g. to return via
937 : * tuplesort_getdatum or when writing to tape); stup.datum1 gets the
938 : * abbreviated value if abbreviation is happening, otherwise it's
939 : * identical to stup.tuple.
940 : */
941 :
942 3967526 : if (isNull || !base->tuples)
943 : {
944 : /*
945 : * Set datum1 to zeroed representation for NULLs (to be consistent,
946 : * and to support cheap inequality tests for NULL abbreviated keys).
947 : */
948 2211440 : stup.datum1 = !isNull ? val : (Datum) 0;
949 2211440 : stup.isnull1 = isNull;
950 2211440 : stup.tuple = NULL; /* no separate storage */
951 : }
952 : else
953 : {
954 1756086 : stup.isnull1 = false;
955 1756086 : stup.datum1 = datumCopy(val, false, arg->datumTypeLen);
956 1756086 : stup.tuple = DatumGetPointer(stup.datum1);
957 : }
958 :
959 3967526 : tuplesort_puttuple_common(state, &stup,
960 5724438 : base->tuples &&
961 3967526 : base->sortKeys->abbrev_converter && !isNull, 0);
962 :
963 3967526 : MemoryContextSwitchTo(oldcontext);
964 3967526 : }
965 :
966 : /*
967 : * Fetch the next tuple in either forward or back direction.
968 : * If successful, put tuple in slot and return true; else, clear the slot
969 : * and return false.
970 : *
971 : * Caller may optionally be passed back abbreviated value (on true return
972 : * value) when abbreviation was used, which can be used to cheaply avoid
973 : * equality checks that might otherwise be required. Caller can safely make a
974 : * determination of "non-equal tuple" based on simple binary inequality. A
975 : * NULL value in leading attribute will set abbreviated value to zeroed
976 : * representation, which caller may rely on in abbreviated inequality check.
977 : *
978 : * If copy is true, the slot receives a tuple that's been copied into the
979 : * caller's memory context, so that it will stay valid regardless of future
980 : * manipulations of the tuplesort's state (up to and including deleting the
981 : * tuplesort). If copy is false, the slot will just receive a pointer to a
982 : * tuple held within the tuplesort, which is more efficient, but only safe for
983 : * callers that are prepared to have any subsequent manipulation of the
984 : * tuplesort's state invalidate slot contents.
985 : */
986 : bool
987 11870118 : tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy,
988 : TupleTableSlot *slot, Datum *abbrev)
989 : {
990 11870118 : TuplesortPublic *base = TuplesortstateGetPublic(state);
991 11870118 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
992 : SortTuple stup;
993 :
994 11870118 : if (!tuplesort_gettuple_common(state, forward, &stup))
995 122492 : stup.tuple = NULL;
996 :
997 11870118 : MemoryContextSwitchTo(oldcontext);
998 :
999 11870118 : if (stup.tuple)
1000 : {
1001 : /* Record abbreviated key for caller */
1002 11747626 : if (base->sortKeys->abbrev_converter && abbrev)
1003 0 : *abbrev = stup.datum1;
1004 :
1005 11747626 : if (copy)
1006 4556 : stup.tuple = heap_copy_minimal_tuple((MinimalTuple) stup.tuple, 0);
1007 :
1008 11747626 : ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, copy);
1009 11747626 : return true;
1010 : }
1011 : else
1012 : {
1013 122492 : ExecClearTuple(slot);
1014 122492 : return false;
1015 : }
1016 : }
1017 :
1018 : /*
1019 : * Fetch the next tuple in either forward or back direction.
1020 : * Returns NULL if no more tuples. Returned tuple belongs to tuplesort memory
1021 : * context, and must not be freed by caller. Caller may not rely on tuple
1022 : * remaining valid after any further manipulation of tuplesort.
1023 : */
1024 : HeapTuple
1025 547530 : tuplesort_getheaptuple(Tuplesortstate *state, bool forward)
1026 : {
1027 547530 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1028 547530 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1029 : SortTuple stup;
1030 :
1031 547530 : if (!tuplesort_gettuple_common(state, forward, &stup))
1032 116 : stup.tuple = NULL;
1033 :
1034 547530 : MemoryContextSwitchTo(oldcontext);
1035 :
1036 547530 : return stup.tuple;
1037 : }
1038 :
1039 : /*
1040 : * Fetch the next index tuple in either forward or back direction.
1041 : * Returns NULL if no more tuples. Returned tuple belongs to tuplesort memory
1042 : * context, and must not be freed by caller. Caller may not rely on tuple
1043 : * remaining valid after any further manipulation of tuplesort.
1044 : */
1045 : IndexTuple
1046 13378022 : tuplesort_getindextuple(Tuplesortstate *state, bool forward)
1047 : {
1048 13378022 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1049 13378022 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1050 : SortTuple stup;
1051 :
1052 13378022 : if (!tuplesort_gettuple_common(state, forward, &stup))
1053 53262 : stup.tuple = NULL;
1054 :
1055 13378022 : MemoryContextSwitchTo(oldcontext);
1056 :
1057 13378022 : return (IndexTuple) stup.tuple;
1058 : }
1059 :
1060 : /*
1061 : * Fetch the next BRIN tuple in either forward or back direction.
1062 : * Returns NULL if no more tuples. Returned tuple belongs to tuplesort memory
1063 : * context, and must not be freed by caller. Caller may not rely on tuple
1064 : * remaining valid after any further manipulation of tuplesort.
1065 : */
1066 : BrinTuple *
1067 48 : tuplesort_getbrintuple(Tuplesortstate *state, Size *len, bool forward)
1068 : {
1069 48 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1070 48 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1071 : SortTuple stup;
1072 : BrinSortTuple *btup;
1073 :
1074 48 : if (!tuplesort_gettuple_common(state, forward, &stup))
1075 8 : stup.tuple = NULL;
1076 :
1077 48 : MemoryContextSwitchTo(oldcontext);
1078 :
1079 48 : if (!stup.tuple)
1080 8 : return NULL;
1081 :
1082 40 : btup = (BrinSortTuple *) stup.tuple;
1083 :
1084 40 : *len = btup->tuplen;
1085 :
1086 40 : return &btup->tuple;
1087 : }
1088 :
1089 : GinTuple *
1090 0 : tuplesort_getgintuple(Tuplesortstate *state, Size *len, bool forward)
1091 : {
1092 0 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1093 0 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1094 : SortTuple stup;
1095 : GinTuple *tup;
1096 :
1097 0 : if (!tuplesort_gettuple_common(state, forward, &stup))
1098 0 : stup.tuple = NULL;
1099 :
1100 0 : MemoryContextSwitchTo(oldcontext);
1101 :
1102 0 : if (!stup.tuple)
1103 0 : return NULL;
1104 :
1105 0 : tup = (GinTuple *) stup.tuple;
1106 :
1107 0 : *len = tup->tuplen;
1108 :
1109 0 : return tup;
1110 : }
1111 :
1112 : /*
1113 : * Fetch the next Datum in either forward or back direction.
1114 : * Returns false if no more datums.
1115 : *
1116 : * If the Datum is pass-by-ref type, the returned value is freshly palloc'd
1117 : * in caller's context, and is now owned by the caller (this differs from
1118 : * similar routines for other types of tuplesorts).
1119 : *
1120 : * Caller may optionally be passed back abbreviated value (on true return
1121 : * value) when abbreviation was used, which can be used to cheaply avoid
1122 : * equality checks that might otherwise be required. Caller can safely make a
1123 : * determination of "non-equal tuple" based on simple binary inequality. A
1124 : * NULL value will have a zeroed abbreviated value representation, which caller
1125 : * may rely on in abbreviated inequality check.
1126 : *
1127 : * For byref Datums, if copy is true, *val is set to a copy of the Datum
1128 : * copied into the caller's memory context, so that it will stay valid
1129 : * regardless of future manipulations of the tuplesort's state (up to and
1130 : * including deleting the tuplesort). If copy is false, *val will just be
1131 : * set to a pointer to the Datum held within the tuplesort, which is more
1132 : * efficient, but only safe for callers that are prepared to have any
1133 : * subsequent manipulation of the tuplesort's state invalidate slot contents.
1134 : * For byval Datums, the value of the 'copy' parameter has no effect.
1135 : */
1136 : bool
1137 2588636 : tuplesort_getdatum(Tuplesortstate *state, bool forward, bool copy,
1138 : Datum *val, bool *isNull, Datum *abbrev)
1139 : {
1140 2588636 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1141 2588636 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1142 2588636 : TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
1143 : SortTuple stup;
1144 :
1145 2588636 : if (!tuplesort_gettuple_common(state, forward, &stup))
1146 : {
1147 59816 : MemoryContextSwitchTo(oldcontext);
1148 59816 : return false;
1149 : }
1150 :
1151 : /* Ensure we copy into caller's memory context */
1152 2528820 : MemoryContextSwitchTo(oldcontext);
1153 :
1154 : /* Record abbreviated key for caller */
1155 2528820 : if (base->sortKeys->abbrev_converter && abbrev)
1156 55024 : *abbrev = stup.datum1;
1157 :
1158 2528820 : if (stup.isnull1 || !base->tuples)
1159 : {
1160 1386414 : *val = stup.datum1;
1161 1386414 : *isNull = stup.isnull1;
1162 : }
1163 : else
1164 : {
1165 : /* use stup.tuple because stup.datum1 may be an abbreviation */
1166 1142406 : if (copy)
1167 60048 : *val = datumCopy(PointerGetDatum(stup.tuple), false,
1168 : arg->datumTypeLen);
1169 : else
1170 1082358 : *val = PointerGetDatum(stup.tuple);
1171 1142406 : *isNull = false;
1172 : }
1173 :
1174 2528820 : 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 48155740 : comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
1205 : {
1206 48155740 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1207 48155740 : SortSupport sortKey = base->sortKeys;
1208 : int32 compare;
1209 :
1210 :
1211 : /* Compare the leading sort key */
1212 48155740 : compare = ApplySortComparator(a->datum1, a->isnull1,
1213 48155740 : b->datum1, b->isnull1,
1214 : sortKey);
1215 48155740 : if (compare != 0)
1216 17887378 : return compare;
1217 :
1218 : /* Compare additional sort keys */
1219 30268362 : return comparetup_heap_tiebreak(a, b, state);
1220 : }
1221 :
1222 : static int
1223 33397962 : comparetup_heap_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
1224 : {
1225 33397962 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1226 33397962 : 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 33397962 : ltup.t_len = ((MinimalTuple) a->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
1239 33397962 : ltup.t_data = (HeapTupleHeader) ((char *) a->tuple - MINIMAL_TUPLE_OFFSET);
1240 33397962 : rtup.t_len = ((MinimalTuple) b->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
1241 33397962 : rtup.t_data = (HeapTupleHeader) ((char *) b->tuple - MINIMAL_TUPLE_OFFSET);
1242 33397962 : tupDesc = (TupleDesc) base->arg;
1243 :
1244 33397962 : if (sortKey->abbrev_converter)
1245 : {
1246 1055758 : attno = sortKey->ssup_attno;
1247 :
1248 1055758 : datum1 = heap_getattr(<up, attno, tupDesc, &isnull1);
1249 1055758 : datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
1250 :
1251 1055758 : compare = ApplySortAbbrevFullComparator(datum1, isnull1,
1252 : datum2, isnull2,
1253 : sortKey);
1254 1055758 : if (compare != 0)
1255 882698 : return compare;
1256 : }
1257 :
1258 32515264 : sortKey++;
1259 34315396 : for (nkey = 1; nkey < base->nKeys; nkey++, sortKey++)
1260 : {
1261 32735386 : attno = sortKey->ssup_attno;
1262 :
1263 32735386 : datum1 = heap_getattr(<up, attno, tupDesc, &isnull1);
1264 32735386 : datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
1265 :
1266 32735386 : compare = ApplySortComparator(datum1, isnull1,
1267 : datum2, isnull2,
1268 : sortKey);
1269 32735386 : if (compare != 0)
1270 30935254 : return compare;
1271 : }
1272 :
1273 1580010 : return 0;
1274 : }
1275 :
1276 : static void
1277 1090450 : writetup_heap(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
1278 : {
1279 1090450 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1280 1090450 : MinimalTuple tuple = (MinimalTuple) stup->tuple;
1281 :
1282 : /* the part of the MinimalTuple we'll write: */
1283 1090450 : char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1284 1090450 : unsigned int tupbodylen = tuple->t_len - MINIMAL_TUPLE_DATA_OFFSET;
1285 :
1286 : /* total on-disk footprint: */
1287 1090450 : unsigned int tuplen = tupbodylen + sizeof(int);
1288 :
1289 1090450 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1290 1090450 : LogicalTapeWrite(tape, tupbody, tupbodylen);
1291 1090450 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1292 30000 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1293 1090450 : }
1294 :
1295 : static void
1296 988180 : readtup_heap(Tuplesortstate *state, SortTuple *stup,
1297 : LogicalTape *tape, unsigned int len)
1298 : {
1299 988180 : unsigned int tupbodylen = len - sizeof(int);
1300 988180 : unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
1301 988180 : MinimalTuple tuple = (MinimalTuple) tuplesort_readtup_alloc(state, tuplen);
1302 988180 : char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1303 988180 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1304 : HeapTupleData htup;
1305 :
1306 : /* read in the tuple proper */
1307 988180 : tuple->t_len = tuplen;
1308 988180 : LogicalTapeReadExact(tape, tupbody, tupbodylen);
1309 988180 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1310 47784 : LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1311 988180 : stup->tuple = tuple;
1312 : /* set up first-column key value */
1313 988180 : htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
1314 988180 : htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
1315 1976360 : stup->datum1 = heap_getattr(&htup,
1316 988180 : base->sortKeys[0].ssup_attno,
1317 988180 : (TupleDesc) base->arg,
1318 : &stup->isnull1);
1319 988180 : }
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 5996944 : comparetup_cluster(const SortTuple *a, const SortTuple *b,
1347 : Tuplesortstate *state)
1348 : {
1349 5996944 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1350 5996944 : SortSupport sortKey = base->sortKeys;
1351 : int32 compare;
1352 :
1353 : /* Compare the leading sort key, if it's simple */
1354 5996944 : if (base->haveDatum1)
1355 : {
1356 5985154 : compare = ApplySortComparator(a->datum1, a->isnull1,
1357 5985154 : b->datum1, b->isnull1,
1358 : sortKey);
1359 5985154 : if (compare != 0)
1360 5844052 : return compare;
1361 : }
1362 :
1363 152892 : return comparetup_cluster_tiebreak(a, b, state);
1364 : }
1365 :
1366 : static int
1367 587134 : comparetup_cluster_tiebreak(const SortTuple *a, const SortTuple *b,
1368 : Tuplesortstate *state)
1369 : {
1370 587134 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1371 587134 : TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
1372 587134 : SortSupport sortKey = base->sortKeys;
1373 : HeapTuple ltup;
1374 : HeapTuple rtup;
1375 : TupleDesc tupDesc;
1376 : int nkey;
1377 587134 : int32 compare = 0;
1378 : Datum datum1,
1379 : datum2;
1380 : bool isnull1,
1381 : isnull2;
1382 :
1383 587134 : ltup = (HeapTuple) a->tuple;
1384 587134 : rtup = (HeapTuple) b->tuple;
1385 587134 : tupDesc = arg->tupDesc;
1386 :
1387 : /* Compare the leading sort key, if it's simple */
1388 587134 : if (base->haveDatum1)
1389 : {
1390 575344 : 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 575344 : if (compare != 0 || base->nKeys == 1)
1402 147784 : 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 116 : freestate_cluster(Tuplesortstate *state)
1519 : {
1520 116 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1521 116 : TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
1522 :
1523 : /* Free any execution state created for CLUSTER case */
1524 116 : 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 116 : }
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 59655956 : 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 59655956 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1570 59655956 : SortSupport sortKey = base->sortKeys;
1571 : int32 compare;
1572 :
1573 : /* Compare the leading sort key */
1574 59655956 : compare = ApplySortComparator(a->datum1, a->isnull1,
1575 59655956 : b->datum1, b->isnull1,
1576 : sortKey);
1577 59655956 : if (compare != 0)
1578 53805746 : return compare;
1579 :
1580 : /* Compare additional sort keys */
1581 5850210 : return comparetup_index_btree_tiebreak(a, b, state);
1582 : }
1583 :
1584 : static int
1585 18137572 : comparetup_index_btree_tiebreak(const SortTuple *a, const SortTuple *b,
1586 : Tuplesortstate *state)
1587 : {
1588 18137572 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1589 18137572 : TuplesortIndexBTreeArg *arg = (TuplesortIndexBTreeArg *) base->arg;
1590 18137572 : SortSupport sortKey = base->sortKeys;
1591 : IndexTuple tuple1;
1592 : IndexTuple tuple2;
1593 : int keysz;
1594 : TupleDesc tupDes;
1595 18137572 : bool equal_hasnull = false;
1596 : int nkey;
1597 : int32 compare;
1598 : Datum datum1,
1599 : datum2;
1600 : bool isnull1,
1601 : isnull2;
1602 :
1603 18137572 : tuple1 = (IndexTuple) a->tuple;
1604 18137572 : tuple2 = (IndexTuple) b->tuple;
1605 18137572 : keysz = base->nKeys;
1606 18137572 : tupDes = RelationGetDescr(arg->index.indexRel);
1607 :
1608 18137572 : if (sortKey->abbrev_converter)
1609 : {
1610 862774 : datum1 = index_getattr(tuple1, 1, tupDes, &isnull1);
1611 862774 : datum2 = index_getattr(tuple2, 1, tupDes, &isnull2);
1612 :
1613 862774 : compare = ApplySortAbbrevFullComparator(datum1, isnull1,
1614 : datum2, isnull2,
1615 : sortKey);
1616 862774 : if (compare != 0)
1617 804294 : return compare;
1618 : }
1619 :
1620 : /* they are equal, so we only need to examine one null flag */
1621 17333278 : if (a->isnull1)
1622 15038 : equal_hasnull = true;
1623 :
1624 17333278 : sortKey++;
1625 20017848 : for (nkey = 2; nkey <= keysz; nkey++, sortKey++)
1626 : {
1627 7717798 : datum1 = index_getattr(tuple1, nkey, tupDes, &isnull1);
1628 7717798 : datum2 = index_getattr(tuple2, nkey, tupDes, &isnull2);
1629 :
1630 7717798 : compare = ApplySortComparator(datum1, isnull1,
1631 : datum2, isnull2,
1632 : sortKey);
1633 7717798 : if (compare != 0)
1634 5033228 : return compare; /* done when we find unequal attributes */
1635 :
1636 : /* they are equal, so we only need to examine one null flag */
1637 2684570 : 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 12300050 : 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 12299966 : BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
1687 12299966 : BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
1688 :
1689 12299966 : if (blk1 != blk2)
1690 11229278 : return (blk1 < blk2) ? -1 : 1;
1691 : }
1692 : {
1693 1070688 : OffsetNumber pos1 = ItemPointerGetOffsetNumber(&tuple1->t_tid);
1694 1070688 : OffsetNumber pos2 = ItemPointerGetOffsetNumber(&tuple2->t_tid);
1695 :
1696 1070688 : if (pos1 != pos2)
1697 1070688 : 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 3704014 : writetup_index(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
1793 : {
1794 3704014 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1795 3704014 : IndexTuple tuple = (IndexTuple) stup->tuple;
1796 : unsigned int tuplen;
1797 :
1798 3704014 : tuplen = IndexTupleSize(tuple) + sizeof(tuplen);
1799 3704014 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1800 3704014 : LogicalTapeWrite(tape, tuple, IndexTupleSize(tuple));
1801 3704014 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1802 0 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1803 3704014 : }
1804 :
1805 : static void
1806 3704014 : readtup_index(Tuplesortstate *state, SortTuple *stup,
1807 : LogicalTape *tape, unsigned int len)
1808 : {
1809 3704014 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1810 3704014 : TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
1811 3704014 : unsigned int tuplen = len - sizeof(unsigned int);
1812 3704014 : IndexTuple tuple = (IndexTuple) tuplesort_readtup_alloc(state, tuplen);
1813 :
1814 3704014 : LogicalTapeReadExact(tape, tuple, tuplen);
1815 3704014 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1816 0 : LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1817 3704014 : stup->tuple = tuple;
1818 : /* set up first-column key value */
1819 7408028 : stup->datum1 = index_getattr(tuple,
1820 : 1,
1821 3704014 : RelationGetDescr(arg->indexRel),
1822 : &stup->isnull1);
1823 3704014 : }
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 = UInt32GetDatum(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 = UInt32GetDatum(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 = 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 6834572 : comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
1977 : {
1978 6834572 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1979 : int compare;
1980 :
1981 6834572 : compare = ApplySortComparator(a->datum1, a->isnull1,
1982 6834572 : b->datum1, b->isnull1,
1983 : base->sortKeys);
1984 6834572 : if (compare != 0)
1985 6634298 : return compare;
1986 :
1987 200274 : return comparetup_datum_tiebreak(a, b, state);
1988 : }
1989 :
1990 : static int
1991 2704264 : comparetup_datum_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
1992 : {
1993 2704264 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1994 2704264 : int32 compare = 0;
1995 :
1996 : /* if we have abbreviations, then "tuple" has the original value */
1997 2704264 : if (base->sortKeys->abbrev_converter)
1998 2504012 : compare = ApplySortAbbrevFullComparator(PointerGetDatum(a->tuple), a->isnull1,
1999 2504012 : PointerGetDatum(b->tuple), b->isnull1,
2000 : base->sortKeys);
2001 :
2002 2704264 : return compare;
2003 : }
2004 :
2005 : static void
2006 1180522 : writetup_datum(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
2007 : {
2008 1180522 : TuplesortPublic *base = TuplesortstateGetPublic(state);
2009 1180522 : TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
2010 : void *waddr;
2011 : unsigned int tuplen;
2012 : unsigned int writtenlen;
2013 :
2014 1180522 : if (stup->isnull1)
2015 : {
2016 66 : waddr = NULL;
2017 66 : tuplen = 0;
2018 : }
2019 1180456 : else if (!base->tuples)
2020 : {
2021 400132 : waddr = &stup->datum1;
2022 400132 : 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 1180522 : writtenlen = tuplen + sizeof(unsigned int);
2032 :
2033 1180522 : LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
2034 1180522 : LogicalTapeWrite(tape, waddr, tuplen);
2035 1180522 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
2036 520264 : LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
2037 1180522 : }
2038 :
2039 : static void
2040 1070552 : readtup_datum(Tuplesortstate *state, SortTuple *stup,
2041 : LogicalTape *tape, unsigned int len)
2042 : {
2043 1070552 : TuplesortPublic *base = TuplesortstateGetPublic(state);
2044 1070552 : unsigned int tuplen = len - sizeof(unsigned int);
2045 :
2046 1070552 : 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 1070462 : else if (!base->tuples)
2054 : {
2055 : Assert(tuplen == sizeof(Datum));
2056 410138 : LogicalTapeReadExact(tape, &stup->datum1, tuplen);
2057 410138 : stup->isnull1 = false;
2058 410138 : 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 1070552 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
2071 530312 : LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
2072 1070552 : }
|