5858 * At ExecutorStart()
5959 * ----------------
6060 * - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
61- * ExecInitResultTupleSlot () to construct TupleTableSlots
61+ * ExecInitResultTupleSlotTL () to construct TupleTableSlots
6262 * for the tuples returned by the access methods and the
6363 * tuples resulting from performing target list projections.
6464 *
@@ -104,26 +104,56 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
104104/* --------------------------------
105105 * MakeTupleTableSlot
106106 *
107- * Basic routine to make an empty TupleTableSlot.
107+ * Basic routine to make an empty TupleTableSlot. If tupleDesc is
108+ * specified the slot's descriptor is fixed for it's lifetime, gaining
109+ * some efficiency. If that's undesirable, pass NULL.
108110 * --------------------------------
109111 */
110112TupleTableSlot *
111- MakeTupleTableSlot (void )
113+ MakeTupleTableSlot (TupleDesc tupleDesc )
112114{
113- TupleTableSlot * slot = makeNode (TupleTableSlot );
115+ Size sz ;
116+ TupleTableSlot * slot ;
114117
118+ /*
119+ * When a fixed descriptor is specified, we can reduce overhead by
120+ * allocating the entire slot in one go.
121+ */
122+ if (tupleDesc )
123+ sz = MAXALIGN (sizeof (TupleTableSlot )) +
124+ MAXALIGN (tupleDesc -> natts * sizeof (Datum )) +
125+ MAXALIGN (tupleDesc -> natts * sizeof (bool ));
126+ else
127+ sz = sizeof (TupleTableSlot );
128+
129+ slot = palloc0 (sz );
130+ slot -> type = T_TupleTableSlot ;
115131 slot -> tts_isempty = true;
116132 slot -> tts_shouldFree = false;
117133 slot -> tts_shouldFreeMin = false;
118134 slot -> tts_tuple = NULL ;
119- slot -> tts_tupleDescriptor = NULL ;
135+ slot -> tts_fixedTupleDescriptor = tupleDesc != NULL ;
136+ slot -> tts_tupleDescriptor = tupleDesc ;
120137 slot -> tts_mcxt = CurrentMemoryContext ;
121138 slot -> tts_buffer = InvalidBuffer ;
122139 slot -> tts_nvalid = 0 ;
123140 slot -> tts_values = NULL ;
124141 slot -> tts_isnull = NULL ;
125142 slot -> tts_mintuple = NULL ;
126143
144+ if (tupleDesc != NULL )
145+ {
146+ slot -> tts_values = (Datum * )
147+ (((char * ) slot )
148+ + MAXALIGN (sizeof (TupleTableSlot )));
149+ slot -> tts_isnull = (bool * )
150+ (((char * ) slot )
151+ + MAXALIGN (sizeof (TupleTableSlot ))
152+ + MAXALIGN (tupleDesc -> natts * sizeof (Datum )));
153+
154+ PinTupleDesc (tupleDesc );
155+ }
156+
127157 return slot ;
128158}
129159
@@ -134,9 +164,9 @@ MakeTupleTableSlot(void)
134164 * --------------------------------
135165 */
136166TupleTableSlot *
137- ExecAllocTableSlot (List * * tupleTable )
167+ ExecAllocTableSlot (List * * tupleTable , TupleDesc desc )
138168{
139- TupleTableSlot * slot = MakeTupleTableSlot ();
169+ TupleTableSlot * slot = MakeTupleTableSlot (desc );
140170
141171 * tupleTable = lappend (* tupleTable , slot );
142172
@@ -173,10 +203,13 @@ ExecResetTupleTable(List *tupleTable, /* tuple table */
173203 /* If shouldFree, release memory occupied by the slot itself */
174204 if (shouldFree )
175205 {
176- if (slot -> tts_values )
177- pfree (slot -> tts_values );
178- if (slot -> tts_isnull )
179- pfree (slot -> tts_isnull );
206+ if (!slot -> tts_fixedTupleDescriptor )
207+ {
208+ if (slot -> tts_values )
209+ pfree (slot -> tts_values );
210+ if (slot -> tts_isnull )
211+ pfree (slot -> tts_isnull );
212+ }
180213 pfree (slot );
181214 }
182215 }
@@ -198,9 +231,7 @@ ExecResetTupleTable(List *tupleTable, /* tuple table */
198231TupleTableSlot *
199232MakeSingleTupleTableSlot (TupleDesc tupdesc )
200233{
201- TupleTableSlot * slot = MakeTupleTableSlot ();
202-
203- ExecSetSlotDescriptor (slot , tupdesc );
234+ TupleTableSlot * slot = MakeTupleTableSlot (tupdesc );
204235
205236 return slot ;
206237}
@@ -220,10 +251,13 @@ ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
220251 ExecClearTuple (slot );
221252 if (slot -> tts_tupleDescriptor )
222253 ReleaseTupleDesc (slot -> tts_tupleDescriptor );
223- if (slot -> tts_values )
224- pfree (slot -> tts_values );
225- if (slot -> tts_isnull )
226- pfree (slot -> tts_isnull );
254+ if (!slot -> tts_fixedTupleDescriptor )
255+ {
256+ if (slot -> tts_values )
257+ pfree (slot -> tts_values );
258+ if (slot -> tts_isnull )
259+ pfree (slot -> tts_isnull );
260+ }
227261 pfree (slot );
228262}
229263
247281ExecSetSlotDescriptor (TupleTableSlot * slot , /* slot to change */
248282 TupleDesc tupdesc ) /* new tuple descriptor */
249283{
284+ Assert (!slot -> tts_fixedTupleDescriptor );
285+
250286 /* For safety, make sure slot is empty before changing it */
251287 ExecClearTuple (slot );
252288
@@ -816,7 +852,7 @@ ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
816852 */
817853
818854/* --------------------------------
819- * ExecInit{Result,Scan,Extra}TupleSlot
855+ * ExecInit{Result,Scan,Extra}TupleSlot[TL]
820856 *
821857 * These are convenience routines to initialize the specified slot
822858 * in nodes inheriting the appropriate state. ExecInitExtraTupleSlot
@@ -825,33 +861,55 @@ ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
825861 */
826862
827863/* ----------------
828- * ExecInitResultTupleSlot
864+ * ExecInitResultTupleSlotTL
865+ *
866+ * Initialize result tuple slot, using the plan node's targetlist.
829867 * ----------------
830868 */
831869void
832- ExecInitResultTupleSlot (EState * estate , PlanState * planstate )
870+ ExecInitResultTupleSlotTL (EState * estate , PlanState * planstate )
833871{
834- planstate -> ps_ResultTupleSlot = ExecAllocTableSlot (& estate -> es_tupleTable );
872+ bool hasoid ;
873+ TupleDesc tupDesc ;
874+
875+ if (ExecContextForcesOids (planstate , & hasoid ))
876+ {
877+ /* context forces OID choice; hasoid is now set correctly */
878+ }
879+ else
880+ {
881+ /* given free choice, don't leave space for OIDs in result tuples */
882+ hasoid = false;
883+ }
884+
885+ tupDesc = ExecTypeFromTL (planstate -> plan -> targetlist , hasoid );
886+
887+ planstate -> ps_ResultTupleSlot = ExecAllocTableSlot (& estate -> es_tupleTable , tupDesc );
835888}
836889
837890/* ----------------
838891 * ExecInitScanTupleSlot
839892 * ----------------
840893 */
841894void
842- ExecInitScanTupleSlot (EState * estate , ScanState * scanstate )
895+ ExecInitScanTupleSlot (EState * estate , ScanState * scanstate , TupleDesc tupledesc )
843896{
844- scanstate -> ss_ScanTupleSlot = ExecAllocTableSlot (& estate -> es_tupleTable );
897+ scanstate -> ss_ScanTupleSlot = ExecAllocTableSlot (& estate -> es_tupleTable ,
898+ tupledesc );
845899}
846900
847901/* ----------------
848902 * ExecInitExtraTupleSlot
903+ *
904+ * Return a newly created slot. If tupledesc is non-NULL the slot will have
905+ * that as its fixed tupledesc. Otherwise the caller needs to use
906+ * ExecSetSlotDescriptor() to set the descriptor before use.
849907 * ----------------
850908 */
851909TupleTableSlot *
852- ExecInitExtraTupleSlot (EState * estate )
910+ ExecInitExtraTupleSlot (EState * estate , TupleDesc tupledesc )
853911{
854- return ExecAllocTableSlot (& estate -> es_tupleTable );
912+ return ExecAllocTableSlot (& estate -> es_tupleTable , tupledesc );
855913}
856914
857915/* ----------------
@@ -865,9 +923,7 @@ ExecInitExtraTupleSlot(EState *estate)
865923TupleTableSlot *
866924ExecInitNullTupleSlot (EState * estate , TupleDesc tupType )
867925{
868- TupleTableSlot * slot = ExecInitExtraTupleSlot (estate );
869-
870- ExecSetSlotDescriptor (slot , tupType );
926+ TupleTableSlot * slot = ExecInitExtraTupleSlot (estate , tupType );
871927
872928 return ExecStoreAllNullTuple (slot );
873929}
0 commit comments