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