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