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 : 72247 : 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 : 72247 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
188 : : sortopt);
189 : 72247 : TuplesortPublic *base = TuplesortstateGetPublic(state);
190 : : MemoryContext oldcontext;
191 : : int i;
192 : :
193 : 72247 : oldcontext = MemoryContextSwitchTo(base->maincontext);
194 : :
195 : : Assert(nkeys > 0);
196 : :
197 [ - + ]: 72247 : 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 : 72247 : 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 : 72247 : base->removeabbrev = removeabbrev_heap;
212 : 72247 : base->comparetup = comparetup_heap;
213 : 72247 : base->comparetup_tiebreak = comparetup_heap_tiebreak;
214 : 72247 : base->writetup = writetup_heap;
215 : 72247 : base->readtup = readtup_heap;
216 : 72247 : base->haveDatum1 = true;
217 : 72247 : base->arg = tupDesc; /* assume we need not copy tupDesc */
218 : :
219 : : /* Prepare SortSupport data for each column */
220 : 72247 : base->sortKeys = (SortSupport) palloc0_array(SortSupportData, nkeys);
221 : :
222 [ + + ]: 180900 : for (i = 0; i < nkeys; i++)
223 : : {
224 : 108661 : SortSupport sortKey = base->sortKeys + i;
225 : :
226 : : Assert(attNums[i] != 0);
227 : : Assert(sortOperators[i] != 0);
228 : :
229 : 108661 : sortKey->ssup_cxt = CurrentMemoryContext;
230 : 108661 : sortKey->ssup_collation = sortCollations[i];
231 : 108661 : sortKey->ssup_nulls_first = nullsFirstFlags[i];
232 : 108661 : sortKey->ssup_attno = attNums[i];
233 : : /* Convey if abbreviation optimization is applicable in principle */
234 [ + + + - ]: 108661 : sortKey->abbreviate = (i == 0 && base->haveDatum1);
235 : :
236 : 108661 : 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 [ + + + + ]: 72239 : if (nkeys == 1 && !base->sortKeys->abbrev_converter)
246 : 40788 : base->onlyKey = base->sortKeys;
247 : :
248 : 72239 : MemoryContextSwitchTo(oldcontext);
249 : :
250 : 72239 : 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 : 59008 : 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 : 59008 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
368 : : sortopt);
369 : 59008 : TuplesortPublic *base = TuplesortstateGetPublic(state);
370 : : BTScanInsert indexScanKey;
371 : : TuplesortIndexBTreeArg *arg;
372 : : MemoryContext oldcontext;
373 : : int i;
374 : :
375 : 59008 : oldcontext = MemoryContextSwitchTo(base->maincontext);
376 : 59008 : arg = palloc_object(TuplesortIndexBTreeArg);
377 : :
378 [ - + ]: 59008 : 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 : 59008 : 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 : 59008 : base->removeabbrev = removeabbrev_index;
394 : 59008 : base->comparetup = comparetup_index_btree;
395 : 59008 : base->comparetup_tiebreak = comparetup_index_btree_tiebreak;
396 : 59008 : base->writetup = writetup_index;
397 : 59008 : base->readtup = readtup_index;
398 : 59008 : base->haveDatum1 = true;
399 : 59008 : base->arg = arg;
400 : :
401 : 59008 : arg->index.heapRel = heapRel;
402 : 59008 : arg->index.indexRel = indexRel;
403 : 59008 : arg->enforceUnique = enforceUnique;
404 : 59008 : arg->uniqueNullsNotDistinct = uniqueNullsNotDistinct;
405 : :
406 : 59008 : indexScanKey = _bt_mkscankey(indexRel, NULL);
407 : :
408 : : /* Prepare SortSupport data for each column */
409 : 59008 : base->sortKeys = (SortSupport) palloc0_array(SortSupportData, base->nKeys);
410 : :
411 [ + + ]: 156399 : for (i = 0; i < base->nKeys; i++)
412 : : {
413 : 97391 : SortSupport sortKey = base->sortKeys + i;
414 : 97391 : ScanKey scanKey = indexScanKey->scankeys + i;
415 : : bool reverse;
416 : :
417 : 97391 : sortKey->ssup_cxt = CurrentMemoryContext;
418 : 97391 : sortKey->ssup_collation = scanKey->sk_collation;
419 : 97391 : sortKey->ssup_nulls_first =
420 : 97391 : (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
421 : 97391 : sortKey->ssup_attno = scanKey->sk_attno;
422 : : /* Convey if abbreviation optimization is applicable in principle */
423 [ + + + - ]: 97391 : sortKey->abbreviate = (i == 0 && base->haveDatum1);
424 : :
425 : : Assert(sortKey->ssup_attno != 0);
426 : :
427 : 97391 : reverse = (scanKey->sk_flags & SK_BT_DESC) != 0;
428 : :
429 : 97391 : PrepareSortSupportFromIndexRel(indexRel, reverse, sortKey);
430 : : }
431 : :
432 : 59008 : pfree(indexScanKey);
433 : :
434 : 59008 : MemoryContextSwitchTo(oldcontext);
435 : :
436 : 59008 : 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 : 728 : tuplesort_begin_index_gist(Relation heapRel,
492 : : Relation indexRel,
493 : : int workMem,
494 : : SortCoordinate coordinate,
495 : : int sortopt)
496 : : {
497 : 728 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
498 : : sortopt);
499 : 728 : TuplesortPublic *base = TuplesortstateGetPublic(state);
500 : : MemoryContext oldcontext;
501 : : TuplesortIndexBTreeArg *arg;
502 : : int i;
503 : :
504 : 728 : oldcontext = MemoryContextSwitchTo(base->maincontext);
505 : 728 : arg = palloc_object(TuplesortIndexBTreeArg);
506 : :
507 [ - + ]: 728 : if (trace_sort)
508 [ # # # # ]: 0 : elog(LOG,
509 : : "begin index sort: workMem = %d, randomAccess = %c",
510 : : workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
511 : :
512 : 728 : base->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
513 : :
514 : 728 : base->removeabbrev = removeabbrev_index;
515 : 728 : base->comparetup = comparetup_index_btree;
516 : 728 : base->comparetup_tiebreak = comparetup_index_btree_tiebreak;
517 : 728 : base->writetup = writetup_index;
518 : 728 : base->readtup = readtup_index;
519 : 728 : base->haveDatum1 = true;
520 : 728 : base->arg = arg;
521 : :
522 : 728 : arg->index.heapRel = heapRel;
523 : 728 : arg->index.indexRel = indexRel;
524 : 728 : arg->enforceUnique = false;
525 : 728 : arg->uniqueNullsNotDistinct = false;
526 : :
527 : : /* Prepare SortSupport data for each column */
528 : 728 : base->sortKeys = (SortSupport) palloc0_array(SortSupportData, base->nKeys);
529 : :
530 [ + + ]: 2063 : for (i = 0; i < base->nKeys; i++)
531 : : {
532 : 1335 : SortSupport sortKey = base->sortKeys + i;
533 : :
534 : 1335 : sortKey->ssup_cxt = CurrentMemoryContext;
535 : 1335 : sortKey->ssup_collation = indexRel->rd_indcollation[i];
536 : 1335 : sortKey->ssup_nulls_first = false;
537 : 1335 : sortKey->ssup_attno = i + 1;
538 : : /* Convey if abbreviation optimization is applicable in principle */
539 [ + + + - ]: 1335 : sortKey->abbreviate = (i == 0 && base->haveDatum1);
540 : :
541 : : Assert(sortKey->ssup_attno != 0);
542 : :
543 : : /* Look for a sort support function */
544 : 1335 : PrepareSortSupportFromGistIndexRel(indexRel, sortKey);
545 : : }
546 : :
547 : 728 : MemoryContextSwitchTo(oldcontext);
548 : :
549 : 728 : 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 : 42204 : tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation,
666 : : bool nullsFirstFlag, int workMem,
667 : : SortCoordinate coordinate, int sortopt)
668 : : {
669 : 42204 : Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
670 : : sortopt);
671 : 42204 : TuplesortPublic *base = TuplesortstateGetPublic(state);
672 : : TuplesortDatumArg *arg;
673 : : MemoryContext oldcontext;
674 : : int16 typlen;
675 : : bool typbyval;
676 : :
677 : 42204 : oldcontext = MemoryContextSwitchTo(base->maincontext);
678 : 42204 : arg = palloc_object(TuplesortDatumArg);
679 : :
680 [ - + ]: 42204 : if (trace_sort)
681 [ # # # # ]: 0 : elog(LOG,
682 : : "begin datum sort: workMem = %d, randomAccess = %c",
683 : : workMem, sortopt & TUPLESORT_RANDOMACCESS ? 't' : 'f');
684 : :
685 : 42204 : 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 : 42204 : base->removeabbrev = removeabbrev_datum;
695 : 42204 : base->comparetup = comparetup_datum;
696 : 42204 : base->comparetup_tiebreak = comparetup_datum_tiebreak;
697 : 42204 : base->writetup = writetup_datum;
698 : 42204 : base->readtup = readtup_datum;
699 : 42204 : base->haveDatum1 = true;
700 : 42204 : base->arg = arg;
701 : :
702 : 42204 : arg->datumType = datumType;
703 : :
704 : : /* lookup necessary attributes of the datum type */
705 : 42204 : get_typlenbyval(datumType, &typlen, &typbyval);
706 : 42204 : arg->datumTypeLen = typlen;
707 : 42204 : base->tuples = !typbyval;
708 : :
709 : : /* Prepare SortSupport data */
710 : 42204 : base->sortKeys = palloc0_object(SortSupportData);
711 : :
712 : 42204 : base->sortKeys->ssup_cxt = CurrentMemoryContext;
713 : 42204 : base->sortKeys->ssup_collation = sortCollation;
714 : 42204 : 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 : 42204 : base->sortKeys->abbreviate = !typbyval;
725 : :
726 : 42204 : 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 [ + + ]: 42204 : if (!base->sortKeys->abbrev_converter)
735 : 41652 : base->onlyKey = base->sortKeys;
736 : :
737 : 42204 : MemoryContextSwitchTo(oldcontext);
738 : :
739 : 42204 : 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 : 7941974 : tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
749 : : {
750 : 7941974 : TuplesortPublic *base = TuplesortstateGetPublic(state);
751 : 7941974 : MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
752 : 7941974 : 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 : 7941974 : tuple = ExecCopySlotMinimalTuple(slot);
760 : 7941974 : stup.tuple = tuple;
761 : : /* set up first-column key value */
762 : 7941974 : htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
763 : 7941974 : htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
764 : 15883948 : stup.datum1 = heap_getattr(&htup,
765 : 7941974 : base->sortKeys[0].ssup_attno,
766 : : tupDesc,
767 : : &stup.isnull1);
768 : :
769 : : /* GetMemoryChunkSpace is not supported for bump contexts */
770 [ + + ]: 7941974 : if (TupleSortUseBumpTupleCxt(base->sortopt))
771 : 5958149 : tuplen = MAXALIGN(tuple->t_len);
772 : : else
773 : 1983825 : tuplen = GetMemoryChunkSpace(tuple);
774 : :
775 : 7941974 : tuplesort_puttuple_common(state, &stup,
776 [ + + ]: 8672703 : base->sortKeys->abbrev_converter &&
777 [ + + ]: 8672703 : !stup.isnull1, tuplen);
778 : :
779 : 7941974 : MemoryContextSwitchTo(oldcontext);
780 : 7941974 : }
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 : 363318 : tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup)
789 : : {
790 : : SortTuple stup;
791 : 363318 : TuplesortPublic *base = TuplesortstateGetPublic(state);
792 : 363318 : MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
793 : 363318 : TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
794 : : Size tuplen;
795 : :
796 : : /* copy the tuple into sort storage */
797 : 363318 : tup = heap_copytuple(tup);
798 : 363318 : stup.tuple = tup;
799 : :
800 : : /*
801 : : * set up first-column key value, and potentially abbreviate, if it's a
802 : : * simple column
803 : : */
804 [ + + ]: 363318 : if (base->haveDatum1)
805 : : {
806 : 363298 : stup.datum1 = heap_getattr(tup,
807 : 363298 : arg->indexInfo->ii_IndexAttrNumbers[0],
808 : : arg->tupDesc,
809 : : &stup.isnull1);
810 : : }
811 : :
812 : : /* GetMemoryChunkSpace is not supported for bump contexts */
813 [ + - ]: 363318 : if (TupleSortUseBumpTupleCxt(base->sortopt))
814 : 363318 : tuplen = MAXALIGN(HEAPTUPLESIZE + tup->t_len);
815 : : else
816 : 0 : tuplen = GetMemoryChunkSpace(tup);
817 : :
818 : 363318 : tuplesort_puttuple_common(state, &stup,
819 : 726616 : base->haveDatum1 &&
820 [ + + + + ]: 605398 : base->sortKeys->abbrev_converter &&
821 [ + + ]: 605398 : !stup.isnull1, tuplen);
822 : :
823 : 363318 : MemoryContextSwitchTo(oldcontext);
824 : 363318 : }
825 : :
826 : : /*
827 : : * Collect one index tuple while collecting input data for sort, building
828 : : * it from caller-supplied values.
829 : : */
830 : : void
831 : 8188183 : 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 : 8188183 : TuplesortPublic *base = TuplesortstateGetPublic(state);
838 : 8188183 : TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
839 : : Size tuplen;
840 : :
841 : 8188183 : stup.tuple = index_form_tuple_context(RelationGetDescr(rel), values,
842 : : isnull, base->tuplecontext);
843 : 8188183 : tuple = ((IndexTuple) stup.tuple);
844 : 8188183 : tuple->t_tid = *self;
845 : : /* set up first-column key value */
846 : 16376366 : stup.datum1 = index_getattr(tuple,
847 : : 1,
848 : 8188183 : RelationGetDescr(arg->indexRel),
849 : : &stup.isnull1);
850 : :
851 : : /* GetMemoryChunkSpace is not supported for bump contexts */
852 [ + - ]: 8188183 : if (TupleSortUseBumpTupleCxt(base->sortopt))
853 : 8188183 : tuplen = MAXALIGN(tuple->t_info & INDEX_SIZE_MASK);
854 : : else
855 : 0 : tuplen = GetMemoryChunkSpace(tuple);
856 : :
857 : 8188183 : tuplesort_puttuple_common(state, &stup,
858 : 16305866 : base->sortKeys &&
859 [ + + + + ]: 9594915 : base->sortKeys->abbrev_converter &&
860 [ + + ]: 9594915 : !stup.isnull1, tuplen);
861 : 8188183 : }
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 : 47318 : tuplesort_putgintuple(Tuplesortstate *state, GinTuple *tuple, Size size)
901 : : {
902 : : SortTuple stup;
903 : : GinTuple *ctup;
904 : 47318 : TuplesortPublic *base = TuplesortstateGetPublic(state);
905 : 47318 : MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
906 : : Size tuplen;
907 : :
908 : : /* copy the GinTuple into the right memory context */
909 : 47318 : ctup = palloc(size);
910 : 47318 : memcpy(ctup, tuple, size);
911 : :
912 : 47318 : stup.tuple = ctup;
913 : 47318 : stup.datum1 = (Datum) 0;
914 : 47318 : stup.isnull1 = false;
915 : :
916 : : /* GetMemoryChunkSpace is not supported for bump contexts */
917 [ + - ]: 47318 : if (TupleSortUseBumpTupleCxt(base->sortopt))
918 : 47318 : tuplen = MAXALIGN(size);
919 : : else
920 : 0 : tuplen = GetMemoryChunkSpace(ctup);
921 : :
922 : 47318 : tuplesort_puttuple_common(state, &stup,
923 : 94636 : base->sortKeys &&
924 [ + - - + ]: 47318 : base->sortKeys->abbrev_converter &&
925 [ - - ]: 47318 : !stup.isnull1, tuplen);
926 : :
927 : 47318 : MemoryContextSwitchTo(oldcontext);
928 : 47318 : }
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 : 2542342 : tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
937 : : {
938 : 2542342 : TuplesortPublic *base = TuplesortstateGetPublic(state);
939 : 2542342 : MemoryContext oldcontext = MemoryContextSwitchTo(base->tuplecontext);
940 : 2542342 : TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
941 : : SortTuple stup;
942 : :
943 : : /*
944 : : * Pass-by-value types or null values are just stored directly in
945 : : * stup.datum1 (and stup.tuple is not used and set to NULL).
946 : : *
947 : : * Non-null pass-by-reference values need to be copied into memory we
948 : : * control, and possibly abbreviated. The copied value is pointed to by
949 : : * stup.tuple and is treated as the canonical copy (e.g. to return via
950 : : * tuplesort_getdatum or when writing to tape); stup.datum1 gets the
951 : : * abbreviated value if abbreviation is happening, otherwise it's
952 : : * identical to stup.tuple.
953 : : */
954 : :
955 [ + + + + ]: 2542342 : if (isNull || !base->tuples)
956 : : {
957 : : /*
958 : : * Set datum1 to zeroed representation for NULLs (to be consistent,
959 : : * and to support cheap inequality tests for NULL abbreviated keys).
960 : : */
961 [ + + ]: 1417447 : stup.datum1 = !isNull ? val : (Datum) 0;
962 : 1417447 : stup.isnull1 = isNull;
963 : 1417447 : stup.tuple = NULL; /* no separate storage */
964 : : }
965 : : else
966 : : {
967 : 1124895 : stup.isnull1 = false;
968 : 1124895 : stup.datum1 = datumCopy(val, false, arg->datumTypeLen);
969 : 1124895 : stup.tuple = DatumGetPointer(stup.datum1);
970 : : }
971 : :
972 : 2542342 : tuplesort_puttuple_common(state, &stup,
973 : 3667518 : base->tuples &&
974 [ + + + + : 2542342 : base->sortKeys->abbrev_converter && !isNull, 0);
+ + ]
975 : :
976 : 2542342 : MemoryContextSwitchTo(oldcontext);
977 : 2542342 : }
978 : :
979 : : /*
980 : : * Fetch the next tuple in either forward or back direction.
981 : : * If successful, put tuple in slot and return true; else, clear the slot
982 : : * and return false.
983 : : *
984 : : * Caller may optionally be passed back abbreviated value (on true return
985 : : * value) when abbreviation was used, which can be used to cheaply avoid
986 : : * equality checks that might otherwise be required. Caller can safely make a
987 : : * determination of "non-equal tuple" based on simple binary inequality. A
988 : : * NULL value in leading attribute will set abbreviated value to zeroed
989 : : * representation, which caller may rely on in abbreviated inequality check.
990 : : *
991 : : * If copy is true, the slot receives a tuple that's been copied into the
992 : : * caller's memory context, so that it will stay valid regardless of future
993 : : * manipulations of the tuplesort's state (up to and including deleting the
994 : : * tuplesort). If copy is false, the slot will just receive a pointer to a
995 : : * tuple held within the tuplesort, which is more efficient, but only safe for
996 : : * callers that are prepared to have any subsequent manipulation of the
997 : : * tuplesort's state invalidate slot contents.
998 : : */
999 : : bool
1000 : 7094809 : tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy,
1001 : : TupleTableSlot *slot, Datum *abbrev)
1002 : : {
1003 : 7094809 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1004 : 7094809 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1005 : : SortTuple stup;
1006 : :
1007 [ + + ]: 7094809 : if (!tuplesort_gettuple_common(state, forward, &stup))
1008 : 73902 : stup.tuple = NULL;
1009 : :
1010 : 7094809 : MemoryContextSwitchTo(oldcontext);
1011 : :
1012 [ + + ]: 7094809 : if (stup.tuple)
1013 : : {
1014 : : /* Record abbreviated key for caller */
1015 [ + + - + ]: 7020907 : if (base->sortKeys->abbrev_converter && abbrev)
1016 : 0 : *abbrev = stup.datum1;
1017 : :
1018 [ + + ]: 7020907 : if (copy)
1019 : 2967 : stup.tuple = heap_copy_minimal_tuple((MinimalTuple) stup.tuple, 0);
1020 : :
1021 : 7020907 : ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, copy);
1022 : 7020907 : return true;
1023 : : }
1024 : : else
1025 : : {
1026 : 73902 : ExecClearTuple(slot);
1027 : 73902 : return false;
1028 : : }
1029 : : }
1030 : :
1031 : : /*
1032 : : * Fetch the next tuple in either forward or back direction.
1033 : : * Returns NULL if no more tuples. Returned tuple belongs to tuplesort memory
1034 : : * context, and must not be freed by caller. Caller may not rely on tuple
1035 : : * remaining valid after any further manipulation of tuplesort.
1036 : : */
1037 : : HeapTuple
1038 : 363404 : tuplesort_getheaptuple(Tuplesortstate *state, bool forward)
1039 : : {
1040 : 363404 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1041 : 363404 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1042 : : SortTuple stup;
1043 : :
1044 [ + + ]: 363404 : if (!tuplesort_gettuple_common(state, forward, &stup))
1045 : 86 : stup.tuple = NULL;
1046 : :
1047 : 363404 : MemoryContextSwitchTo(oldcontext);
1048 : :
1049 : 363404 : return stup.tuple;
1050 : : }
1051 : :
1052 : : /*
1053 : : * Fetch the next index tuple in either forward or back direction.
1054 : : * Returns NULL if no more tuples. Returned tuple belongs to tuplesort memory
1055 : : * context, and must not be freed by caller. Caller may not rely on tuple
1056 : : * remaining valid after any further manipulation of tuplesort.
1057 : : */
1058 : : IndexTuple
1059 : 8221083 : tuplesort_getindextuple(Tuplesortstate *state, bool forward)
1060 : : {
1061 : 8221083 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1062 : 8221083 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1063 : : SortTuple stup;
1064 : :
1065 [ + + ]: 8221083 : if (!tuplesort_gettuple_common(state, forward, &stup))
1066 : 33156 : stup.tuple = NULL;
1067 : :
1068 : 8221083 : MemoryContextSwitchTo(oldcontext);
1069 : :
1070 : 8221083 : return (IndexTuple) stup.tuple;
1071 : : }
1072 : :
1073 : : /*
1074 : : * Fetch the next BRIN tuple in either forward or back direction.
1075 : : * Returns NULL if no more tuples. Returned tuple belongs to tuplesort memory
1076 : : * context, and must not be freed by caller. Caller may not rely on tuple
1077 : : * remaining valid after any further manipulation of tuplesort.
1078 : : */
1079 : : BrinTuple *
1080 : 25 : tuplesort_getbrintuple(Tuplesortstate *state, Size *len, bool forward)
1081 : : {
1082 : 25 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1083 : 25 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1084 : : SortTuple stup;
1085 : : BrinSortTuple *btup;
1086 : :
1087 [ + + ]: 25 : if (!tuplesort_gettuple_common(state, forward, &stup))
1088 : 5 : stup.tuple = NULL;
1089 : :
1090 : 25 : MemoryContextSwitchTo(oldcontext);
1091 : :
1092 [ + + ]: 25 : if (!stup.tuple)
1093 : 5 : return NULL;
1094 : :
1095 : 20 : btup = (BrinSortTuple *) stup.tuple;
1096 : :
1097 : 20 : *len = btup->tuplen;
1098 : :
1099 : 20 : return &btup->tuple;
1100 : : }
1101 : :
1102 : : GinTuple *
1103 : 47386 : tuplesort_getgintuple(Tuplesortstate *state, Size *len, bool forward)
1104 : : {
1105 : 47386 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1106 : 47386 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1107 : : SortTuple stup;
1108 : : GinTuple *tup;
1109 : :
1110 [ + + ]: 47386 : if (!tuplesort_gettuple_common(state, forward, &stup))
1111 : 68 : stup.tuple = NULL;
1112 : :
1113 : 47386 : MemoryContextSwitchTo(oldcontext);
1114 : :
1115 [ + + ]: 47386 : if (!stup.tuple)
1116 : 68 : return NULL;
1117 : :
1118 : 47318 : tup = (GinTuple *) stup.tuple;
1119 : :
1120 : 47318 : *len = tup->tuplen;
1121 : :
1122 : 47318 : return tup;
1123 : : }
1124 : :
1125 : : /*
1126 : : * Fetch the next Datum in either forward or back direction.
1127 : : * Returns false if no more datums.
1128 : : *
1129 : : * If the Datum is pass-by-ref type, the returned value is freshly palloc'd
1130 : : * in caller's context, and is now owned by the caller (this differs from
1131 : : * similar routines for other types of tuplesorts).
1132 : : *
1133 : : * Caller may optionally be passed back abbreviated value (on true return
1134 : : * value) when abbreviation was used, which can be used to cheaply avoid
1135 : : * equality checks that might otherwise be required. Caller can safely make a
1136 : : * determination of "non-equal tuple" based on simple binary inequality. A
1137 : : * NULL value will have a zeroed abbreviated value representation, which caller
1138 : : * may rely on in abbreviated inequality check.
1139 : : *
1140 : : * For byref Datums, if copy is true, *val is set to a copy of the Datum
1141 : : * copied into the caller's memory context, so that it will stay valid
1142 : : * regardless of future manipulations of the tuplesort's state (up to and
1143 : : * including deleting the tuplesort). If copy is false, *val will just be
1144 : : * set to a pointer to the Datum held within the tuplesort, which is more
1145 : : * efficient, but only safe for callers that are prepared to have any
1146 : : * subsequent manipulation of the tuplesort's state invalidate slot contents.
1147 : : * For byval Datums, the value of the 'copy' parameter has no effect.
1148 : : */
1149 : : bool
1150 : 1624721 : tuplesort_getdatum(Tuplesortstate *state, bool forward, bool copy,
1151 : : Datum *val, bool *isNull, Datum *abbrev)
1152 : : {
1153 : 1624721 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1154 : 1624721 : MemoryContext oldcontext = MemoryContextSwitchTo(base->sortcontext);
1155 : 1624721 : TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
1156 : : SortTuple stup;
1157 : :
1158 [ + + ]: 1624721 : if (!tuplesort_gettuple_common(state, forward, &stup))
1159 : : {
1160 : 41359 : MemoryContextSwitchTo(oldcontext);
1161 : 41359 : return false;
1162 : : }
1163 : :
1164 : : /* Ensure we copy into caller's memory context */
1165 : 1583362 : MemoryContextSwitchTo(oldcontext);
1166 : :
1167 : : /* Record abbreviated key for caller */
1168 [ + + + + ]: 1583362 : if (base->sortKeys->abbrev_converter && abbrev)
1169 : 27512 : *abbrev = stup.datum1;
1170 : :
1171 [ + + + + ]: 1583362 : if (stup.isnull1 || !base->tuples)
1172 : : {
1173 : 867586 : *val = stup.datum1;
1174 : 867586 : *isNull = stup.isnull1;
1175 : : }
1176 : : else
1177 : : {
1178 : : /* use stup.tuple because stup.datum1 may be an abbreviation */
1179 [ + + ]: 715776 : if (copy)
1180 : 40032 : *val = datumCopy(PointerGetDatum(stup.tuple), false,
1181 : : arg->datumTypeLen);
1182 : : else
1183 : 675744 : *val = PointerGetDatum(stup.tuple);
1184 : 715776 : *isNull = false;
1185 : : }
1186 : :
1187 : 1583362 : return true;
1188 : : }
1189 : :
1190 : :
1191 : : /*
1192 : : * Routines specialized for HeapTuple (actually MinimalTuple) case
1193 : : */
1194 : :
1195 : : static void
1196 : 8 : removeabbrev_heap(Tuplesortstate *state, SortTuple *stups, int count)
1197 : : {
1198 : : int i;
1199 : 8 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1200 : :
1201 [ + + ]: 81928 : for (i = 0; i < count; i++)
1202 : : {
1203 : : HeapTupleData htup;
1204 : :
1205 : 81920 : htup.t_len = ((MinimalTuple) stups[i].tuple)->t_len +
1206 : : MINIMAL_TUPLE_OFFSET;
1207 : 81920 : htup.t_data = (HeapTupleHeader) ((char *) stups[i].tuple -
1208 : : MINIMAL_TUPLE_OFFSET);
1209 : 81920 : stups[i].datum1 = heap_getattr(&htup,
1210 : 81920 : base->sortKeys[0].ssup_attno,
1211 : 81920 : (TupleDesc) base->arg,
1212 : 81920 : &stups[i].isnull1);
1213 : : }
1214 : 8 : }
1215 : :
1216 : : static int
1217 : 10697225 : comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
1218 : : {
1219 : 10697225 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1220 : 10697225 : SortSupport sortKey = base->sortKeys;
1221 : : int32 compare;
1222 : :
1223 : :
1224 : : /* Compare the leading sort key */
1225 : 10697225 : compare = ApplySortComparator(a->datum1, a->isnull1,
1226 : 10697225 : b->datum1, b->isnull1,
1227 : : sortKey);
1228 [ + + ]: 10697225 : if (compare != 0)
1229 : 9620813 : return compare;
1230 : :
1231 : : /* Compare additional sort keys */
1232 : 1076412 : return comparetup_heap_tiebreak(a, b, state);
1233 : : }
1234 : :
1235 : : static int
1236 : 18697924 : comparetup_heap_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
1237 : : {
1238 : 18697924 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1239 : 18697924 : SortSupport sortKey = base->sortKeys;
1240 : : HeapTupleData ltup;
1241 : : HeapTupleData rtup;
1242 : : TupleDesc tupDesc;
1243 : : int nkey;
1244 : : int32 compare;
1245 : : AttrNumber attno;
1246 : : Datum datum1,
1247 : : datum2;
1248 : : bool isnull1,
1249 : : isnull2;
1250 : :
1251 : 18697924 : ltup.t_len = ((MinimalTuple) a->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
1252 : 18697924 : ltup.t_data = (HeapTupleHeader) ((char *) a->tuple - MINIMAL_TUPLE_OFFSET);
1253 : 18697924 : rtup.t_len = ((MinimalTuple) b->tuple)->t_len + MINIMAL_TUPLE_OFFSET;
1254 : 18697924 : rtup.t_data = (HeapTupleHeader) ((char *) b->tuple - MINIMAL_TUPLE_OFFSET);
1255 : 18697924 : tupDesc = (TupleDesc) base->arg;
1256 : :
1257 [ + + ]: 18697924 : if (sortKey->abbrev_converter)
1258 : : {
1259 : 658178 : attno = sortKey->ssup_attno;
1260 : :
1261 : 658178 : datum1 = heap_getattr(<up, attno, tupDesc, &isnull1);
1262 : 658178 : datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
1263 : :
1264 : 658178 : compare = ApplySortAbbrevFullComparator(datum1, isnull1,
1265 : : datum2, isnull2,
1266 : : sortKey);
1267 [ + + ]: 658178 : if (compare != 0)
1268 : 567558 : return compare;
1269 : : }
1270 : :
1271 : 18130366 : sortKey++;
1272 [ + + ]: 19470903 : for (nkey = 1; nkey < base->nKeys; nkey++, sortKey++)
1273 : : {
1274 : 18047353 : attno = sortKey->ssup_attno;
1275 : :
1276 : 18047353 : datum1 = heap_getattr(<up, attno, tupDesc, &isnull1);
1277 : 18047353 : datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
1278 : :
1279 : 18047353 : compare = ApplySortComparator(datum1, isnull1,
1280 : : datum2, isnull2,
1281 : : sortKey);
1282 [ + + ]: 18047353 : if (compare != 0)
1283 : 16706816 : return compare;
1284 : : }
1285 : :
1286 : 1423550 : return 0;
1287 : : }
1288 : :
1289 : : static void
1290 : 725300 : writetup_heap(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
1291 : : {
1292 : 725300 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1293 : 725300 : MinimalTuple tuple = (MinimalTuple) stup->tuple;
1294 : :
1295 : : /* the part of the MinimalTuple we'll write: */
1296 : 725300 : char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1297 : 725300 : unsigned int tupbodylen = tuple->t_len - MINIMAL_TUPLE_DATA_OFFSET;
1298 : :
1299 : : /* total on-disk footprint: */
1300 : 725300 : unsigned int tuplen = tupbodylen + sizeof(int);
1301 : :
1302 : 725300 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1303 : 725300 : LogicalTapeWrite(tape, tupbody, tupbodylen);
1304 [ + + ]: 725300 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1305 : 20000 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1306 : 725300 : }
1307 : :
1308 : : static void
1309 : 657120 : readtup_heap(Tuplesortstate *state, SortTuple *stup,
1310 : : LogicalTape *tape, unsigned int len)
1311 : : {
1312 : 657120 : unsigned int tupbodylen = len - sizeof(int);
1313 : 657120 : unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
1314 : 657120 : MinimalTuple tuple = (MinimalTuple) tuplesort_readtup_alloc(state, tuplen);
1315 : 657120 : char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1316 : 657120 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1317 : : HeapTupleData htup;
1318 : :
1319 : : /* read in the tuple proper */
1320 : 657120 : tuple->t_len = tuplen;
1321 [ - + - - ]: 657120 : LogicalTapeReadExact(tape, tupbody, tupbodylen);
1322 [ + + ]: 657120 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1323 [ - + - - ]: 31856 : LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1324 : 657120 : stup->tuple = tuple;
1325 : : /* set up first-column key value */
1326 : 657120 : htup.t_len = tuple->t_len + MINIMAL_TUPLE_OFFSET;
1327 : 657120 : htup.t_data = (HeapTupleHeader) ((char *) tuple - MINIMAL_TUPLE_OFFSET);
1328 : 1314240 : stup->datum1 = heap_getattr(&htup,
1329 : 657120 : base->sortKeys[0].ssup_attno,
1330 : 657120 : (TupleDesc) base->arg,
1331 : : &stup->isnull1);
1332 : 657120 : }
1333 : :
1334 : : /*
1335 : : * Routines specialized for the CLUSTER case (HeapTuple data, with
1336 : : * comparisons per a btree index definition)
1337 : : */
1338 : :
1339 : : static void
1340 : 8 : removeabbrev_cluster(Tuplesortstate *state, SortTuple *stups, int count)
1341 : : {
1342 : : int i;
1343 : 8 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1344 : 8 : TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
1345 : :
1346 [ + + ]: 81928 : for (i = 0; i < count; i++)
1347 : : {
1348 : : HeapTuple tup;
1349 : :
1350 : 81920 : tup = (HeapTuple) stups[i].tuple;
1351 : 81920 : stups[i].datum1 = heap_getattr(tup,
1352 : 81920 : arg->indexInfo->ii_IndexAttrNumbers[0],
1353 : : arg->tupDesc,
1354 : 81920 : &stups[i].isnull1);
1355 : : }
1356 : 8 : }
1357 : :
1358 : : static int
1359 : 4062286 : comparetup_cluster(const SortTuple *a, const SortTuple *b,
1360 : : Tuplesortstate *state)
1361 : : {
1362 : 4062286 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1363 : 4062286 : SortSupport sortKey = base->sortKeys;
1364 : : int32 compare;
1365 : :
1366 : : /* Compare the leading sort key, if it's simple */
1367 [ + + ]: 4062286 : if (base->haveDatum1)
1368 : : {
1369 : 4062274 : compare = ApplySortComparator(a->datum1, a->isnull1,
1370 : 4062274 : b->datum1, b->isnull1,
1371 : : sortKey);
1372 [ + + ]: 4062274 : if (compare != 0)
1373 : 3889929 : return compare;
1374 : : }
1375 : :
1376 : 172357 : return comparetup_cluster_tiebreak(a, b, state);
1377 : : }
1378 : :
1379 : : static int
1380 : 359054 : comparetup_cluster_tiebreak(const SortTuple *a, const SortTuple *b,
1381 : : Tuplesortstate *state)
1382 : : {
1383 : 359054 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1384 : 359054 : TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
1385 : 359054 : SortSupport sortKey = base->sortKeys;
1386 : : HeapTuple ltup;
1387 : : HeapTuple rtup;
1388 : : TupleDesc tupDesc;
1389 : : int nkey;
1390 : 359054 : int32 compare = 0;
1391 : : Datum datum1,
1392 : : datum2;
1393 : : bool isnull1,
1394 : : isnull2;
1395 : :
1396 : 359054 : ltup = (HeapTuple) a->tuple;
1397 : 359054 : rtup = (HeapTuple) b->tuple;
1398 : 359054 : tupDesc = arg->tupDesc;
1399 : :
1400 : : /* Compare the leading sort key, if it's simple */
1401 [ + + ]: 359054 : if (base->haveDatum1)
1402 : : {
1403 [ + + ]: 359042 : if (sortKey->abbrev_converter)
1404 : : {
1405 : 80046 : AttrNumber leading = arg->indexInfo->ii_IndexAttrNumbers[0];
1406 : :
1407 : 80046 : datum1 = heap_getattr(ltup, leading, tupDesc, &isnull1);
1408 : 80046 : datum2 = heap_getattr(rtup, leading, tupDesc, &isnull2);
1409 : :
1410 : 80046 : compare = ApplySortAbbrevFullComparator(datum1, isnull1,
1411 : : datum2, isnull2,
1412 : : sortKey);
1413 : : }
1414 [ + + + + ]: 359042 : if (compare != 0 || base->nKeys == 1)
1415 : 80714 : return compare;
1416 : : /* Compare additional columns the hard way */
1417 : 278328 : sortKey++;
1418 : 278328 : nkey = 1;
1419 : : }
1420 : : else
1421 : : {
1422 : : /* Must compare all keys the hard way */
1423 : 12 : nkey = 0;
1424 : : }
1425 : :
1426 [ + + ]: 278340 : if (arg->indexInfo->ii_Expressions == NULL)
1427 : : {
1428 : : /* If not expression index, just compare the proper heap attrs */
1429 : :
1430 [ + - ]: 388868 : for (; nkey < base->nKeys; nkey++, sortKey++)
1431 : : {
1432 : 388868 : AttrNumber attno = arg->indexInfo->ii_IndexAttrNumbers[nkey];
1433 : :
1434 : 388868 : datum1 = heap_getattr(ltup, attno, tupDesc, &isnull1);
1435 : 388868 : datum2 = heap_getattr(rtup, attno, tupDesc, &isnull2);
1436 : :
1437 : 388868 : compare = ApplySortComparator(datum1, isnull1,
1438 : : datum2, isnull2,
1439 : : sortKey);
1440 [ + + ]: 388868 : if (compare != 0)
1441 : 278328 : return compare;
1442 : : }
1443 : : }
1444 : : else
1445 : : {
1446 : : /*
1447 : : * In the expression index case, compute the whole index tuple and
1448 : : * then compare values. It would perhaps be faster to compute only as
1449 : : * many columns as we need to compare, but that would require
1450 : : * duplicating all the logic in FormIndexDatum.
1451 : : */
1452 : : Datum l_index_values[INDEX_MAX_KEYS];
1453 : : bool l_index_isnull[INDEX_MAX_KEYS];
1454 : : Datum r_index_values[INDEX_MAX_KEYS];
1455 : : bool r_index_isnull[INDEX_MAX_KEYS];
1456 : : TupleTableSlot *ecxt_scantuple;
1457 : :
1458 : : /* Reset context each time to prevent memory leakage */
1459 [ + - ]: 12 : ResetPerTupleExprContext(arg->estate);
1460 : :
1461 [ + - ]: 12 : ecxt_scantuple = GetPerTupleExprContext(arg->estate)->ecxt_scantuple;
1462 : :
1463 : 12 : ExecStoreHeapTuple(ltup, ecxt_scantuple, false);
1464 : 12 : FormIndexDatum(arg->indexInfo, ecxt_scantuple, arg->estate,
1465 : : l_index_values, l_index_isnull);
1466 : :
1467 : 12 : ExecStoreHeapTuple(rtup, ecxt_scantuple, false);
1468 : 12 : FormIndexDatum(arg->indexInfo, ecxt_scantuple, arg->estate,
1469 : : r_index_values, r_index_isnull);
1470 : :
1471 [ + - ]: 12 : for (; nkey < base->nKeys; nkey++, sortKey++)
1472 : : {
1473 : 12 : compare = ApplySortComparator(l_index_values[nkey],
1474 : 12 : l_index_isnull[nkey],
1475 : : r_index_values[nkey],
1476 : 12 : r_index_isnull[nkey],
1477 : : sortKey);
1478 [ + - ]: 12 : if (compare != 0)
1479 : 12 : return compare;
1480 : : }
1481 : : }
1482 : :
1483 : 0 : return 0;
1484 : : }
1485 : :
1486 : : static void
1487 : 40000 : writetup_cluster(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
1488 : : {
1489 : 40000 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1490 : 40000 : HeapTuple tuple = (HeapTuple) stup->tuple;
1491 : 40000 : unsigned int tuplen = tuple->t_len + sizeof(ItemPointerData) + sizeof(int);
1492 : :
1493 : : /* We need to store t_self, but not other fields of HeapTupleData */
1494 : 40000 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1495 : 40000 : LogicalTapeWrite(tape, &tuple->t_self, sizeof(ItemPointerData));
1496 : 40000 : LogicalTapeWrite(tape, tuple->t_data, tuple->t_len);
1497 [ - + ]: 40000 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1498 : 0 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1499 : 40000 : }
1500 : :
1501 : : static void
1502 : 40000 : readtup_cluster(Tuplesortstate *state, SortTuple *stup,
1503 : : LogicalTape *tape, unsigned int tuplen)
1504 : : {
1505 : 40000 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1506 : 40000 : TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
1507 : 40000 : unsigned int t_len = tuplen - sizeof(ItemPointerData) - sizeof(int);
1508 : 40000 : HeapTuple tuple = (HeapTuple) tuplesort_readtup_alloc(state,
1509 : : t_len + HEAPTUPLESIZE);
1510 : :
1511 : : /* Reconstruct the HeapTupleData header */
1512 : 40000 : tuple->t_data = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
1513 : 40000 : tuple->t_len = t_len;
1514 [ - + - - ]: 40000 : LogicalTapeReadExact(tape, &tuple->t_self, sizeof(ItemPointerData));
1515 : : /* We don't currently bother to reconstruct t_tableOid */
1516 : 40000 : tuple->t_tableOid = InvalidOid;
1517 : : /* Read in the tuple body */
1518 [ - + - - ]: 40000 : LogicalTapeReadExact(tape, tuple->t_data, tuple->t_len);
1519 [ - + ]: 40000 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1520 [ # # # # ]: 0 : LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1521 : 40000 : stup->tuple = tuple;
1522 : : /* set up first-column key value, if it's a simple column */
1523 [ + - ]: 40000 : if (base->haveDatum1)
1524 : 40000 : stup->datum1 = heap_getattr(tuple,
1525 : 40000 : arg->indexInfo->ii_IndexAttrNumbers[0],
1526 : : arg->tupDesc,
1527 : : &stup->isnull1);
1528 : 40000 : }
1529 : :
1530 : : static void
1531 : 86 : freestate_cluster(Tuplesortstate *state)
1532 : : {
1533 : 86 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1534 : 86 : TuplesortClusterArg *arg = (TuplesortClusterArg *) base->arg;
1535 : :
1536 : : /* Free any execution state created for CLUSTER case */
1537 [ + + ]: 86 : if (arg->estate != NULL)
1538 : : {
1539 [ + - ]: 8 : ExprContext *econtext = GetPerTupleExprContext(arg->estate);
1540 : :
1541 : 8 : ExecDropSingleTupleTableSlot(econtext->ecxt_scantuple);
1542 : 8 : FreeExecutorState(arg->estate);
1543 : : }
1544 : 86 : }
1545 : :
1546 : : /*
1547 : : * Routines specialized for IndexTuple case
1548 : : *
1549 : : * The btree and hash cases require separate comparison functions, but the
1550 : : * IndexTuple representation is the same so the copy/write/read support
1551 : : * functions can be shared.
1552 : : */
1553 : :
1554 : : static void
1555 : 40 : removeabbrev_index(Tuplesortstate *state, SortTuple *stups, int count)
1556 : : {
1557 : 40 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1558 : 40 : TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
1559 : : int i;
1560 : :
1561 [ + + ]: 409640 : for (i = 0; i < count; i++)
1562 : : {
1563 : : IndexTuple tuple;
1564 : :
1565 : 409600 : tuple = stups[i].tuple;
1566 : 409600 : stups[i].datum1 = index_getattr(tuple,
1567 : : 1,
1568 : 409600 : RelationGetDescr(arg->indexRel),
1569 : 409600 : &stups[i].isnull1);
1570 : : }
1571 : 40 : }
1572 : :
1573 : : static int
1574 : 26223476 : comparetup_index_btree(const SortTuple *a, const SortTuple *b,
1575 : : Tuplesortstate *state)
1576 : : {
1577 : : /*
1578 : : * This is similar to comparetup_heap(), but expects index tuples. There
1579 : : * is also special handling for enforcing uniqueness, and special
1580 : : * treatment for equal keys at the end.
1581 : : */
1582 : 26223476 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1583 : 26223476 : SortSupport sortKey = base->sortKeys;
1584 : : int32 compare;
1585 : :
1586 : : /* Compare the leading sort key */
1587 : 26223476 : compare = ApplySortComparator(a->datum1, a->isnull1,
1588 : 26223476 : b->datum1, b->isnull1,
1589 : : sortKey);
1590 [ + + ]: 26223476 : if (compare != 0)
1591 : 24441651 : return compare;
1592 : :
1593 : : /* Compare additional sort keys */
1594 : 1781825 : return comparetup_index_btree_tiebreak(a, b, state);
1595 : : }
1596 : :
1597 : : static int
1598 : 13347884 : comparetup_index_btree_tiebreak(const SortTuple *a, const SortTuple *b,
1599 : : Tuplesortstate *state)
1600 : : {
1601 : 13347884 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1602 : 13347884 : TuplesortIndexBTreeArg *arg = (TuplesortIndexBTreeArg *) base->arg;
1603 : 13347884 : SortSupport sortKey = base->sortKeys;
1604 : : IndexTuple tuple1;
1605 : : IndexTuple tuple2;
1606 : : int keysz;
1607 : : TupleDesc tupDes;
1608 : 13347884 : bool equal_hasnull = false;
1609 : : int nkey;
1610 : : int32 compare;
1611 : : Datum datum1,
1612 : : datum2;
1613 : : bool isnull1,
1614 : : isnull2;
1615 : :
1616 : 13347884 : tuple1 = (IndexTuple) a->tuple;
1617 : 13347884 : tuple2 = (IndexTuple) b->tuple;
1618 : 13347884 : keysz = base->nKeys;
1619 : 13347884 : tupDes = RelationGetDescr(arg->index.indexRel);
1620 : :
1621 [ + + ]: 13347884 : if (sortKey->abbrev_converter)
1622 : : {
1623 : 444610 : datum1 = index_getattr(tuple1, 1, tupDes, &isnull1);
1624 : 444610 : datum2 = index_getattr(tuple2, 1, tupDes, &isnull2);
1625 : :
1626 : 444610 : compare = ApplySortAbbrevFullComparator(datum1, isnull1,
1627 : : datum2, isnull2,
1628 : : sortKey);
1629 [ + + ]: 444610 : if (compare != 0)
1630 : 415635 : return compare;
1631 : : }
1632 : :
1633 : : /* they are equal, so we only need to examine one null flag */
1634 [ + + ]: 12932249 : if (a->isnull1)
1635 : 8228 : equal_hasnull = true;
1636 : :
1637 : 12932249 : sortKey++;
1638 [ + + ]: 14414013 : for (nkey = 2; nkey <= keysz; nkey++, sortKey++)
1639 : : {
1640 : 4209865 : datum1 = index_getattr(tuple1, nkey, tupDes, &isnull1);
1641 : 4209865 : datum2 = index_getattr(tuple2, nkey, tupDes, &isnull2);
1642 : :
1643 : 4209865 : compare = ApplySortComparator(datum1, isnull1,
1644 : : datum2, isnull2,
1645 : : sortKey);
1646 [ + + ]: 4209865 : if (compare != 0)
1647 : 2728101 : return compare; /* done when we find unequal attributes */
1648 : :
1649 : : /* they are equal, so we only need to examine one null flag */
1650 [ + + ]: 1481764 : if (isnull1)
1651 : 17770 : equal_hasnull = true;
1652 : : }
1653 : :
1654 : : /*
1655 : : * If btree has asked us to enforce uniqueness, complain if two equal
1656 : : * tuples are detected (unless there was at least one NULL field and NULLS
1657 : : * NOT DISTINCT was not set).
1658 : : *
1659 : : * It is sufficient to make the test here, because if two tuples are equal
1660 : : * they *must* get compared at some stage of the sort --- otherwise the
1661 : : * sort algorithm wouldn't have checked whether one must appear before the
1662 : : * other.
1663 : : */
1664 [ + + + + : 10204148 : if (arg->enforceUnique && !(!arg->uniqueNullsNotDistinct && equal_hasnull))
+ + ]
1665 : : {
1666 : : Datum values[INDEX_MAX_KEYS];
1667 : : bool isnull[INDEX_MAX_KEYS];
1668 : : char *key_desc;
1669 : :
1670 : : /*
1671 : : * Some rather brain-dead implementations of qsort (such as the one in
1672 : : * QNX 4) will sometimes call the comparison routine to compare a
1673 : : * value to itself, but we always use our own implementation, which
1674 : : * does not.
1675 : : */
1676 : : Assert(tuple1 != tuple2);
1677 : :
1678 : 56 : index_deform_tuple(tuple1, tupDes, values, isnull);
1679 : :
1680 : 56 : key_desc = BuildIndexValueDescription(arg->index.indexRel, values, isnull);
1681 : :
1682 [ + - + - ]: 56 : ereport(ERROR,
1683 : : (errcode(ERRCODE_UNIQUE_VIOLATION),
1684 : : errmsg("could not create unique index \"%s\"",
1685 : : RelationGetRelationName(arg->index.indexRel)),
1686 : : key_desc ? errdetail("Key %s is duplicated.", key_desc) :
1687 : : errdetail("Duplicate keys exist."),
1688 : : errtableconstraint(arg->index.heapRel,
1689 : : RelationGetRelationName(arg->index.indexRel))));
1690 : : }
1691 : :
1692 : : /*
1693 : : * If key values are equal, we sort on ItemPointer. This is required for
1694 : : * btree indexes, since heap TID is treated as an implicit last key
1695 : : * attribute in order to ensure that all keys in the index are physically
1696 : : * unique.
1697 : : */
1698 : : {
1699 : 10204092 : BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
1700 : 10204092 : BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
1701 : :
1702 [ + + ]: 10204092 : if (blk1 != blk2)
1703 [ + + ]: 8797203 : return (blk1 < blk2) ? -1 : 1;
1704 : : }
1705 : : {
1706 : 1406889 : OffsetNumber pos1 = ItemPointerGetOffsetNumber(&tuple1->t_tid);
1707 : 1406889 : OffsetNumber pos2 = ItemPointerGetOffsetNumber(&tuple2->t_tid);
1708 : :
1709 [ + - ]: 1406889 : if (pos1 != pos2)
1710 [ + + ]: 1406889 : return (pos1 < pos2) ? -1 : 1;
1711 : : }
1712 : :
1713 : : /* ItemPointer values should never be equal */
1714 : : Assert(false);
1715 : :
1716 : 0 : return 0;
1717 : : }
1718 : :
1719 : : static int
1720 : 1052005 : comparetup_index_hash(const SortTuple *a, const SortTuple *b,
1721 : : Tuplesortstate *state)
1722 : : {
1723 : : Bucket bucket1;
1724 : : Bucket bucket2;
1725 : : uint32 hash1;
1726 : : uint32 hash2;
1727 : : IndexTuple tuple1;
1728 : : IndexTuple tuple2;
1729 : 1052005 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1730 : 1052005 : TuplesortIndexHashArg *arg = (TuplesortIndexHashArg *) base->arg;
1731 : :
1732 : : /*
1733 : : * Fetch hash keys and mask off bits we don't want to sort by, so that the
1734 : : * initial sort is just on the bucket number. We know that the first
1735 : : * column of the index tuple is the hash key.
1736 : : */
1737 : : Assert(!a->isnull1);
1738 : 1052005 : bucket1 = _hash_hashkey2bucket(DatumGetUInt32(a->datum1),
1739 : : arg->max_buckets, arg->high_mask,
1740 : : arg->low_mask);
1741 : : Assert(!b->isnull1);
1742 : 1052005 : bucket2 = _hash_hashkey2bucket(DatumGetUInt32(b->datum1),
1743 : : arg->max_buckets, arg->high_mask,
1744 : : arg->low_mask);
1745 [ + + ]: 1052005 : if (bucket1 > bucket2)
1746 : 310086 : return 1;
1747 [ + + ]: 741919 : else if (bucket1 < bucket2)
1748 : 295549 : return -1;
1749 : :
1750 : : /*
1751 : : * If bucket values are equal, sort by hash values. This allows us to
1752 : : * insert directly onto bucket/overflow pages, where the index tuples are
1753 : : * stored in hash order to allow fast binary search within each page.
1754 : : */
1755 : 446370 : hash1 = DatumGetUInt32(a->datum1);
1756 : 446370 : hash2 = DatumGetUInt32(b->datum1);
1757 [ + + ]: 446370 : if (hash1 > hash2)
1758 : 108223 : return 1;
1759 [ + + ]: 338147 : else if (hash1 < hash2)
1760 : 97451 : return -1;
1761 : :
1762 : : /*
1763 : : * If hash values are equal, we sort on ItemPointer. This does not affect
1764 : : * validity of the finished index, but it may be useful to have index
1765 : : * scans in physical order.
1766 : : */
1767 : 240696 : tuple1 = (IndexTuple) a->tuple;
1768 : 240696 : tuple2 = (IndexTuple) b->tuple;
1769 : :
1770 : : {
1771 : 240696 : BlockNumber blk1 = ItemPointerGetBlockNumber(&tuple1->t_tid);
1772 : 240696 : BlockNumber blk2 = ItemPointerGetBlockNumber(&tuple2->t_tid);
1773 : :
1774 [ + + ]: 240696 : if (blk1 != blk2)
1775 [ + + ]: 172077 : return (blk1 < blk2) ? -1 : 1;
1776 : : }
1777 : : {
1778 : 68619 : OffsetNumber pos1 = ItemPointerGetOffsetNumber(&tuple1->t_tid);
1779 : 68619 : OffsetNumber pos2 = ItemPointerGetOffsetNumber(&tuple2->t_tid);
1780 : :
1781 [ + - ]: 68619 : if (pos1 != pos2)
1782 [ + + ]: 68619 : return (pos1 < pos2) ? -1 : 1;
1783 : : }
1784 : :
1785 : : /* ItemPointer values should never be equal */
1786 : : Assert(false);
1787 : :
1788 : 0 : return 0;
1789 : : }
1790 : :
1791 : : /*
1792 : : * Sorting for hash indexes only uses one sort key, so this shouldn't ever be
1793 : : * called. It's only here for consistency.
1794 : : */
1795 : : static int
1796 : 0 : comparetup_index_hash_tiebreak(const SortTuple *a, const SortTuple *b,
1797 : : Tuplesortstate *state)
1798 : : {
1799 : : Assert(false);
1800 : :
1801 : 0 : return 0;
1802 : : }
1803 : :
1804 : : static void
1805 : 2106057 : writetup_index(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
1806 : : {
1807 : 2106057 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1808 : 2106057 : IndexTuple tuple = (IndexTuple) stup->tuple;
1809 : : unsigned int tuplen;
1810 : :
1811 : 2106057 : tuplen = IndexTupleSize(tuple) + sizeof(tuplen);
1812 : 2106057 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1813 : 2106057 : LogicalTapeWrite(tape, tuple, IndexTupleSize(tuple));
1814 [ - + ]: 2106057 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1815 : 0 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1816 : 2106057 : }
1817 : :
1818 : : static void
1819 : 2106057 : readtup_index(Tuplesortstate *state, SortTuple *stup,
1820 : : LogicalTape *tape, unsigned int len)
1821 : : {
1822 : 2106057 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1823 : 2106057 : TuplesortIndexArg *arg = (TuplesortIndexArg *) base->arg;
1824 : 2106057 : unsigned int tuplen = len - sizeof(unsigned int);
1825 : 2106057 : IndexTuple tuple = (IndexTuple) tuplesort_readtup_alloc(state, tuplen);
1826 : :
1827 [ - + - - ]: 2106057 : LogicalTapeReadExact(tape, tuple, tuplen);
1828 [ - + ]: 2106057 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1829 [ # # # # ]: 0 : LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1830 : 2106057 : stup->tuple = tuple;
1831 : : /* set up first-column key value */
1832 : 4212114 : stup->datum1 = index_getattr(tuple,
1833 : : 1,
1834 : 2106057 : RelationGetDescr(arg->indexRel),
1835 : : &stup->isnull1);
1836 : 2106057 : }
1837 : :
1838 : : /*
1839 : : * Routines specialized for BrinTuple case
1840 : : */
1841 : :
1842 : : static void
1843 : 0 : removeabbrev_index_brin(Tuplesortstate *state, SortTuple *stups, int count)
1844 : : {
1845 : : int i;
1846 : :
1847 [ # # ]: 0 : for (i = 0; i < count; i++)
1848 : : {
1849 : : BrinSortTuple *tuple;
1850 : :
1851 : 0 : tuple = stups[i].tuple;
1852 : 0 : stups[i].datum1 = UInt32GetDatum(tuple->tuple.bt_blkno);
1853 : : }
1854 : 0 : }
1855 : :
1856 : : static int
1857 : 19 : comparetup_index_brin(const SortTuple *a, const SortTuple *b,
1858 : : Tuplesortstate *state)
1859 : : {
1860 : : Assert(TuplesortstateGetPublic(state)->haveDatum1);
1861 : :
1862 [ - + ]: 19 : if (DatumGetUInt32(a->datum1) > DatumGetUInt32(b->datum1))
1863 : 0 : return 1;
1864 : :
1865 [ + - ]: 19 : if (DatumGetUInt32(a->datum1) < DatumGetUInt32(b->datum1))
1866 : 19 : return -1;
1867 : :
1868 : : /* silence compilers */
1869 : 0 : return 0;
1870 : : }
1871 : :
1872 : : static void
1873 : 20 : writetup_index_brin(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
1874 : : {
1875 : 20 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1876 : 20 : BrinSortTuple *tuple = (BrinSortTuple *) stup->tuple;
1877 : 20 : unsigned int tuplen = tuple->tuplen;
1878 : :
1879 : 20 : tuplen = tuplen + sizeof(tuplen);
1880 : 20 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1881 : 20 : LogicalTapeWrite(tape, &tuple->tuple, tuple->tuplen);
1882 [ - + ]: 20 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1883 : 0 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1884 : 20 : }
1885 : :
1886 : : static void
1887 : 20 : readtup_index_brin(Tuplesortstate *state, SortTuple *stup,
1888 : : LogicalTape *tape, unsigned int len)
1889 : : {
1890 : : BrinSortTuple *tuple;
1891 : 20 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1892 : 20 : unsigned int tuplen = len - sizeof(unsigned int);
1893 : :
1894 : : /*
1895 : : * Allocate space for the BRIN sort tuple, which is BrinTuple with an
1896 : : * extra length field.
1897 : : */
1898 : 20 : tuple = (BrinSortTuple *) tuplesort_readtup_alloc(state,
1899 : : BRINSORTTUPLE_SIZE(tuplen));
1900 : :
1901 : 20 : tuple->tuplen = tuplen;
1902 : :
1903 [ - + - - ]: 20 : LogicalTapeReadExact(tape, &tuple->tuple, tuplen);
1904 [ - + ]: 20 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1905 [ # # # # ]: 0 : LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1906 : 20 : stup->tuple = tuple;
1907 : :
1908 : : /* set up first-column key value, which is block number */
1909 : 20 : stup->datum1 = UInt32GetDatum(tuple->tuple.bt_blkno);
1910 : 20 : }
1911 : :
1912 : : /*
1913 : : * Routines specialized for GIN case
1914 : : */
1915 : :
1916 : : static void
1917 : 0 : removeabbrev_index_gin(Tuplesortstate *state, SortTuple *stups, int count)
1918 : : {
1919 : : Assert(false);
1920 [ # # ]: 0 : elog(ERROR, "removeabbrev_index_gin not implemented");
1921 : : }
1922 : :
1923 : : static int
1924 : 79071 : comparetup_index_gin(const SortTuple *a, const SortTuple *b,
1925 : : Tuplesortstate *state)
1926 : : {
1927 : 79071 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1928 : :
1929 : : Assert(!TuplesortstateGetPublic(state)->haveDatum1);
1930 : :
1931 : 158142 : return _gin_compare_tuples((GinTuple *) a->tuple,
1932 : 79071 : (GinTuple *) b->tuple,
1933 : : base->sortKeys);
1934 : : }
1935 : :
1936 : : static void
1937 : 23659 : writetup_index_gin(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
1938 : : {
1939 : 23659 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1940 : 23659 : GinTuple *tuple = (GinTuple *) stup->tuple;
1941 : 23659 : unsigned int tuplen = tuple->tuplen;
1942 : :
1943 : 23659 : tuplen = tuplen + sizeof(tuplen);
1944 : 23659 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1945 : 23659 : LogicalTapeWrite(tape, tuple, tuple->tuplen);
1946 [ - + ]: 23659 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1947 : 0 : LogicalTapeWrite(tape, &tuplen, sizeof(tuplen));
1948 : 23659 : }
1949 : :
1950 : : static void
1951 : 23659 : readtup_index_gin(Tuplesortstate *state, SortTuple *stup,
1952 : : LogicalTape *tape, unsigned int len)
1953 : : {
1954 : : GinTuple *tuple;
1955 : 23659 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1956 : 23659 : unsigned int tuplen = len - sizeof(unsigned int);
1957 : :
1958 : : /*
1959 : : * Allocate space for the GIN sort tuple, which already has the proper
1960 : : * length included in the header.
1961 : : */
1962 : 23659 : tuple = (GinTuple *) tuplesort_readtup_alloc(state, tuplen);
1963 : :
1964 : 23659 : tuple->tuplen = tuplen;
1965 : :
1966 [ - + - - ]: 23659 : LogicalTapeReadExact(tape, tuple, tuplen);
1967 [ - + ]: 23659 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
1968 [ # # # # ]: 0 : LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
1969 : 23659 : stup->tuple = tuple;
1970 : :
1971 : : /* no abbreviations (FIXME maybe use attrnum for this?) */
1972 : 23659 : stup->datum1 = (Datum) 0;
1973 : 23659 : }
1974 : :
1975 : : /*
1976 : : * Routines specialized for DatumTuple case
1977 : : */
1978 : :
1979 : : static void
1980 : 8 : removeabbrev_datum(Tuplesortstate *state, SortTuple *stups, int count)
1981 : : {
1982 : : int i;
1983 : :
1984 [ + + ]: 81928 : for (i = 0; i < count; i++)
1985 : 81920 : stups[i].datum1 = PointerGetDatum(stups[i].tuple);
1986 : 8 : }
1987 : :
1988 : : static int
1989 : 5297751 : comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
1990 : : {
1991 : 5297751 : TuplesortPublic *base = TuplesortstateGetPublic(state);
1992 : : int compare;
1993 : :
1994 : 5297751 : compare = ApplySortComparator(a->datum1, a->isnull1,
1995 : 5297751 : b->datum1, b->isnull1,
1996 : : base->sortKeys);
1997 [ + + ]: 5297751 : if (compare != 0)
1998 : 4895088 : return compare;
1999 : :
2000 : 402663 : return comparetup_datum_tiebreak(a, b, state);
2001 : : }
2002 : :
2003 : : static int
2004 : 1970199 : comparetup_datum_tiebreak(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
2005 : : {
2006 : 1970199 : TuplesortPublic *base = TuplesortstateGetPublic(state);
2007 : 1970199 : int32 compare = 0;
2008 : :
2009 : : /* if we have abbreviations, then "tuple" has the original value */
2010 [ + + ]: 1970199 : if (base->sortKeys->abbrev_converter)
2011 : 1680305 : compare = ApplySortAbbrevFullComparator(PointerGetDatum(a->tuple), a->isnull1,
2012 : 1680305 : PointerGetDatum(b->tuple), b->isnull1,
2013 : : base->sortKeys);
2014 : :
2015 : 1970199 : return compare;
2016 : : }
2017 : :
2018 : : static void
2019 : 770348 : writetup_datum(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
2020 : : {
2021 : 770348 : TuplesortPublic *base = TuplesortstateGetPublic(state);
2022 : 770348 : TuplesortDatumArg *arg = (TuplesortDatumArg *) base->arg;
2023 : : void *waddr;
2024 : : unsigned int tuplen;
2025 : : unsigned int writtenlen;
2026 : :
2027 [ + + ]: 770348 : if (stup->isnull1)
2028 : : {
2029 : 44 : waddr = NULL;
2030 : 44 : tuplen = 0;
2031 : : }
2032 [ + + ]: 770304 : else if (!base->tuples)
2033 : : {
2034 : 250088 : waddr = &stup->datum1;
2035 : 250088 : tuplen = sizeof(Datum);
2036 : : }
2037 : : else
2038 : : {
2039 : 520216 : waddr = stup->tuple;
2040 : 520216 : tuplen = datumGetSize(PointerGetDatum(stup->tuple), false, arg->datumTypeLen);
2041 : : Assert(tuplen != 0);
2042 : : }
2043 : :
2044 : 770348 : writtenlen = tuplen + sizeof(unsigned int);
2045 : :
2046 : 770348 : LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
2047 : 770348 : LogicalTapeWrite(tape, waddr, tuplen);
2048 [ + + ]: 770348 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
2049 : 340176 : LogicalTapeWrite(tape, &writtenlen, sizeof(writtenlen));
2050 : 770348 : }
2051 : :
2052 : : static void
2053 : 695368 : readtup_datum(Tuplesortstate *state, SortTuple *stup,
2054 : : LogicalTape *tape, unsigned int len)
2055 : : {
2056 : 695368 : TuplesortPublic *base = TuplesortstateGetPublic(state);
2057 : 695368 : unsigned int tuplen = len - sizeof(unsigned int);
2058 : :
2059 [ + + ]: 695368 : if (tuplen == 0)
2060 : : {
2061 : : /* it's NULL */
2062 : 60 : stup->datum1 = (Datum) 0;
2063 : 60 : stup->isnull1 = true;
2064 : 60 : stup->tuple = NULL;
2065 : : }
2066 [ + + ]: 695308 : else if (!base->tuples)
2067 : : {
2068 : : Assert(tuplen == sizeof(Datum));
2069 [ - + - - ]: 255092 : LogicalTapeReadExact(tape, &stup->datum1, tuplen);
2070 : 255092 : stup->isnull1 = false;
2071 : 255092 : stup->tuple = NULL;
2072 : : }
2073 : : else
2074 : : {
2075 : 440216 : void *raddr = tuplesort_readtup_alloc(state, tuplen);
2076 : :
2077 [ - + - - ]: 440216 : LogicalTapeReadExact(tape, raddr, tuplen);
2078 : 440216 : stup->datum1 = PointerGetDatum(raddr);
2079 : 440216 : stup->isnull1 = false;
2080 : 440216 : stup->tuple = raddr;
2081 : : }
2082 : :
2083 [ + + ]: 695368 : if (base->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */
2084 [ - + - - ]: 345208 : LogicalTapeReadExact(tape, &tuplen, sizeof(tuplen));
2085 : 695368 : }
|