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