|
29 | 29 | * which saves the results in a temporary file or memory. After the |
30 | 30 | * initial call, returns a tuple from the file with each call. |
31 | 31 | * |
| 32 | + * There are two distinct ways that this sort can be performed: |
| 33 | + * |
| 34 | + * 1) When the result is a single column we perform a Datum sort. |
| 35 | + * |
| 36 | + * 2) When the result contains multiple columns we perform a tuple sort. |
| 37 | + * |
| 38 | + * We could do this by always performing a tuple sort, however sorting |
| 39 | + * Datums only can be significantly faster than sorting tuples, |
| 40 | + * especially when the Datums are of a pass-by-value type. |
| 41 | + * |
32 | 42 | * Conditions: |
33 | 43 | * -- none. |
34 | 44 | * |
@@ -86,31 +96,56 @@ ExecSort(PlanState *pstate) |
86 | 96 | outerNode = outerPlanState(node); |
87 | 97 | tupDesc = ExecGetResultType(outerNode); |
88 | 98 |
|
89 | | - tuplesortstate = tuplesort_begin_heap(tupDesc, |
90 | | - plannode->numCols, |
91 | | - plannode->sortColIdx, |
92 | | - plannode->sortOperators, |
93 | | - plannode->collations, |
94 | | - plannode->nullsFirst, |
95 | | - work_mem, |
96 | | - NULL, |
97 | | - node->randomAccess); |
| 99 | + if (node->datumSort) |
| 100 | + tuplesortstate = tuplesort_begin_datum(TupleDescAttr(tupDesc, 0)->atttypid, |
| 101 | + plannode->sortOperators[0], |
| 102 | + plannode->collations[0], |
| 103 | + plannode->nullsFirst[0], |
| 104 | + work_mem, |
| 105 | + NULL, |
| 106 | + node->randomAccess); |
| 107 | + else |
| 108 | + tuplesortstate = tuplesort_begin_heap(tupDesc, |
| 109 | + plannode->numCols, |
| 110 | + plannode->sortColIdx, |
| 111 | + plannode->sortOperators, |
| 112 | + plannode->collations, |
| 113 | + plannode->nullsFirst, |
| 114 | + work_mem, |
| 115 | + NULL, |
| 116 | + node->randomAccess); |
98 | 117 | if (node->bounded) |
99 | 118 | tuplesort_set_bound(tuplesortstate, node->bound); |
100 | 119 | node->tuplesortstate = (void *) tuplesortstate; |
101 | 120 |
|
102 | 121 | /* |
103 | | - * Scan the subplan and feed all the tuples to tuplesort. |
| 122 | + * Scan the subplan and feed all the tuples to tuplesort using the |
| 123 | + * appropriate method based on the type of sort we're doing. |
104 | 124 | */ |
105 | | - |
106 | | - for (;;) |
| 125 | + if (node->datumSort) |
107 | 126 | { |
108 | | - slot = ExecProcNode(outerNode); |
109 | | - |
110 | | - if (TupIsNull(slot)) |
111 | | - break; |
112 | | - |
113 | | - tuplesort_puttupleslot(tuplesortstate, slot); |
| 127 | + for (;;) |
| 128 | + { |
| 129 | + slot = ExecProcNode(outerNode); |
| 130 | + |
| 131 | + if (TupIsNull(slot)) |
| 132 | + break; |
| 133 | + slot_getsomeattrs(slot, 1); |
| 134 | + tuplesort_putdatum(tuplesortstate, |
| 135 | + slot->tts_values[0], |
| 136 | + slot->tts_isnull[0]); |
| 137 | + } |
| 138 | + } |
| 139 | + else |
| 140 | + { |
| 141 | + for (;;) |
| 142 | + { |
| 143 | + slot = ExecProcNode(outerNode); |
| 144 | + |
| 145 | + if (TupIsNull(slot)) |
| 146 | + break; |
| 147 | + tuplesort_puttupleslot(tuplesortstate, slot); |
| 148 | + } |
114 | 149 | } |
115 | 150 |
|
116 | 151 | /* |
@@ -144,15 +179,27 @@ ExecSort(PlanState *pstate) |
144 | 179 | SO1_printf("ExecSort: %s\n", |
145 | 180 | "retrieving tuple from tuplesort"); |
146 | 181 |
|
| 182 | + slot = node->ss.ps.ps_ResultTupleSlot; |
| 183 | + |
147 | 184 | /* |
148 | | - * Get the first or next tuple from tuplesort. Returns NULL if no more |
149 | | - * tuples. Note that we only rely on slot tuple remaining valid until the |
150 | | - * next fetch from the tuplesort. |
| 185 | + * Fetch the next sorted item from the appropriate tuplesort function. For |
| 186 | + * datum sorts we must manage the slot ourselves and leave it clear when |
| 187 | + * tuplesort_getdatum returns false to indicate there are no more datums. |
| 188 | + * For tuple sorts, tuplesort_gettupleslot manages the slot for us and |
| 189 | + * empties the slot when it runs out of tuples. |
151 | 190 | */ |
152 | | - slot = node->ss.ps.ps_ResultTupleSlot; |
153 | | - (void) tuplesort_gettupleslot(tuplesortstate, |
154 | | - ScanDirectionIsForward(dir), |
155 | | - false, slot, NULL); |
| 191 | + if (node->datumSort) |
| 192 | + { |
| 193 | + ExecClearTuple(slot); |
| 194 | + if (tuplesort_getdatum(tuplesortstate, ScanDirectionIsForward(dir), |
| 195 | + &(slot->tts_values[0]), &(slot->tts_isnull[0]), NULL)) |
| 196 | + ExecStoreVirtualTuple(slot); |
| 197 | + } |
| 198 | + else |
| 199 | + (void) tuplesort_gettupleslot(tuplesortstate, |
| 200 | + ScanDirectionIsForward(dir), |
| 201 | + false, slot, NULL); |
| 202 | + |
156 | 203 | return slot; |
157 | 204 | } |
158 | 205 |
|
@@ -221,6 +268,15 @@ ExecInitSort(Sort *node, EState *estate, int eflags) |
221 | 268 | ExecInitResultTupleSlotTL(&sortstate->ss.ps, &TTSOpsMinimalTuple); |
222 | 269 | sortstate->ss.ps.ps_ProjInfo = NULL; |
223 | 270 |
|
| 271 | + /* |
| 272 | + * We perform a Datum sort when we're sorting just a single column, |
| 273 | + * otherwise we perform a tuple sort. |
| 274 | + */ |
| 275 | + if (ExecGetResultType(outerPlanState(sortstate))->natts == 1) |
| 276 | + sortstate->datumSort = true; |
| 277 | + else |
| 278 | + sortstate->datumSort = false; |
| 279 | + |
224 | 280 | SO1_printf("ExecInitSort: %s\n", |
225 | 281 | "sort node initialized"); |
226 | 282 |
|
|
0 commit comments