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