|
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 | returnslot; |
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 |
|
|