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