{
/* Restore state from previous execution */
off = slot->tts_off;
- slow = slot->tts_slow;
+ slow = TTS_SLOW(slot);
}
tp = (char *) tup + tup->t_hoff;
*/
slot->tts_nvalid = attnum;
slot->tts_off = off;
- slot->tts_slow = slow;
+ if (slow)
+ slot->tts_flags |= TTS_FLAG_SLOW;
+ else
+ slot->tts_flags &= ~TTS_FLAG_SLOW;
}
/*
slot = palloc0(sz);
slot->type = T_TupleTableSlot;
- slot->tts_isempty = true;
- slot->tts_shouldFree = false;
- slot->tts_shouldFreeMin = false;
+ slot->tts_flags |= TTS_FLAG_EMPTY;
+ if (tupleDesc != NULL)
+ slot->tts_flags |= TTS_FLAG_FIXED;
slot->tts_tuple = NULL;
- slot->tts_fixedTupleDescriptor = tupleDesc != NULL;
slot->tts_tupleDescriptor = tupleDesc;
slot->tts_mcxt = CurrentMemoryContext;
slot->tts_buffer = InvalidBuffer;
/* If shouldFree, release memory occupied by the slot itself */
if (shouldFree)
{
- if (!slot->tts_fixedTupleDescriptor)
+ if (!TTS_FIXED(slot))
{
if (slot->tts_values)
pfree(slot->tts_values);
ExecClearTuple(slot);
if (slot->tts_tupleDescriptor)
ReleaseTupleDesc(slot->tts_tupleDescriptor);
- if (!slot->tts_fixedTupleDescriptor)
+ if (!TTS_FIXED(slot))
{
if (slot->tts_values)
pfree(slot->tts_values);
ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
TupleDesc tupdesc) /* new tuple descriptor */
{
- Assert(!slot->tts_fixedTupleDescriptor);
+ Assert(!TTS_FIXED(slot));
/* For safety, make sure slot is empty before changing it */
ExecClearTuple(slot);
/*
* Free any old physical tuple belonging to the slot.
*/
- if (slot->tts_shouldFree)
+ if (TTS_SHOULDFREE(slot))
+ {
heap_freetuple(slot->tts_tuple);
- if (slot->tts_shouldFreeMin)
+ slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
+ }
+ if (TTS_SHOULDFREEMIN(slot))
+ {
heap_free_minimal_tuple(slot->tts_mintuple);
+ slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
+ }
/*
* Store the new tuple into the specified slot.
*/
- slot->tts_isempty = false;
- slot->tts_shouldFree = shouldFree;
- slot->tts_shouldFreeMin = false;
+ slot->tts_flags &= ~TTS_FLAG_EMPTY;
+ if (shouldFree)
+ slot->tts_flags |= TTS_FLAG_SHOULDFREE;
slot->tts_tuple = tuple;
slot->tts_mintuple = NULL;
/*
* Free any old physical tuple belonging to the slot.
*/
- if (slot->tts_shouldFree)
+ if (TTS_SHOULDFREE(slot))
+ {
heap_freetuple(slot->tts_tuple);
- if (slot->tts_shouldFreeMin)
+ slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
+ }
+ if (TTS_SHOULDFREEMIN(slot))
+ {
heap_free_minimal_tuple(slot->tts_mintuple);
+ slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
+ }
/*
* Store the new tuple into the specified slot.
*/
- slot->tts_isempty = false;
- slot->tts_shouldFree = false;
- slot->tts_shouldFreeMin = false;
+ slot->tts_flags &= ~TTS_FLAG_EMPTY;
slot->tts_tuple = tuple;
slot->tts_mintuple = NULL;
/*
* Free any old physical tuple belonging to the slot.
*/
- if (slot->tts_shouldFree)
+ if (TTS_SHOULDFREE(slot))
+ {
heap_freetuple(slot->tts_tuple);
- if (slot->tts_shouldFreeMin)
+ slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
+ }
+ if (TTS_SHOULDFREEMIN(slot))
+ {
heap_free_minimal_tuple(slot->tts_mintuple);
+ slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
+ }
/*
* Drop the pin on the referenced buffer, if there is one.
/*
* Store the new tuple into the specified slot.
*/
- slot->tts_isempty = false;
- slot->tts_shouldFree = false;
- slot->tts_shouldFreeMin = shouldFree;
+ slot->tts_flags &= ~TTS_FLAG_EMPTY;
+ if (shouldFree)
+ slot->tts_flags |= TTS_FLAG_SHOULDFREEMIN;
slot->tts_tuple = &slot->tts_minhdr;
slot->tts_mintuple = mtup;
/*
* Free the old physical tuple if necessary.
*/
- if (slot->tts_shouldFree)
+ if (TTS_SHOULDFREE(slot))
+ {
heap_freetuple(slot->tts_tuple);
- if (slot->tts_shouldFreeMin)
+ slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
+ }
+ if (TTS_SHOULDFREEMIN(slot))
+ {
heap_free_minimal_tuple(slot->tts_mintuple);
+ slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
+ }
slot->tts_tuple = NULL;
slot->tts_mintuple = NULL;
- slot->tts_shouldFree = false;
- slot->tts_shouldFreeMin = false;
/*
* Drop the pin on the referenced buffer, if there is one.
/*
* Mark it empty.
*/
- slot->tts_isempty = true;
+ slot->tts_flags |= TTS_FLAG_EMPTY;
slot->tts_nvalid = 0;
return slot;
*/
Assert(slot != NULL);
Assert(slot->tts_tupleDescriptor != NULL);
- Assert(slot->tts_isempty);
+ Assert(TTS_EMPTY(slot));
- slot->tts_isempty = false;
+ slot->tts_flags &= ~TTS_FLAG_EMPTY;
slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
return slot;
* sanity checks
*/
Assert(slot != NULL);
- Assert(!slot->tts_isempty);
+ Assert(!TTS_EMPTY(slot));
/*
* If we have a physical tuple (either format) then just copy it.
* sanity checks
*/
Assert(slot != NULL);
- Assert(!slot->tts_isempty);
+ Assert(!TTS_EMPTY(slot));
/*
* If we have a physical tuple then just copy it. Prefer to copy
* sanity checks
*/
Assert(slot != NULL);
- Assert(!slot->tts_isempty);
+ Assert(!TTS_EMPTY(slot));
/*
* If we have a regular physical tuple then just return it.
* sanity checks
*/
Assert(slot != NULL);
- Assert(!slot->tts_isempty);
+ Assert(!TTS_EMPTY(slot));
+
/*
* If we have a minimal physical tuple (local or not) then just return it.
*/
oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
slot->tts_mintuple = ExecCopySlotMinimalTuple(slot);
- slot->tts_shouldFreeMin = true;
+ slot->tts_flags |= TTS_FLAG_SHOULDFREEMIN;
MemoryContextSwitchTo(oldContext);
/*
* sanity checks
*/
Assert(slot != NULL);
- Assert(!slot->tts_isempty);
+ Assert(!TTS_EMPTY(slot));
/*
* If we have a regular physical tuple, and it's locally palloc'd, we have
* nothing to do.
*/
- if (slot->tts_tuple && slot->tts_shouldFree)
+ if (slot->tts_tuple && TTS_SHOULDFREE(slot))
return slot->tts_tuple;
/*
*/
oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
slot->tts_tuple = ExecCopySlotTuple(slot);
- slot->tts_shouldFree = true;
+ slot->tts_flags |= TTS_FLAG_SHOULDFREE;
MemoryContextSwitchTo(oldContext);
/*
* storage, we must not pfree it now, since callers might have already
* fetched datum pointers referencing it.)
*/
- if (!slot->tts_shouldFreeMin)
+ if (!TTS_SHOULDFREEMIN(slot))
slot->tts_mintuple = NULL;
return slot->tts_tuple;
aggstate->grouped_cols = grouped_cols;
- if (slot->tts_isempty)
+ if (TTS_EMPTY(slot))
{
/*
* Force all values to be NULL if working on an empty input tuple
* RETURNING expressions might reference the tableoid column, so
* initialize t_tableOid before evaluating them.
*/
- if (slot->tts_isempty)
+ if (TTS_EMPTY(slot))
ExecStoreAllNullTuple(slot);
tuple = ExecMaterializeSlot(slot);
tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
LLVMValueRef v_tts_values;
LLVMValueRef v_tts_nulls;
LLVMValueRef v_slotoffp;
- LLVMValueRef v_slowp;
+ LLVMValueRef v_flagsp;
LLVMValueRef v_nvalidp;
LLVMValueRef v_nvalid;
LLVMValueRef v_maxatt;
"tts_ISNULL");
v_slotoffp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_OFF, "");
- v_slowp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_SLOW, "");
+ v_flagsp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_FLAGS, "");
v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, "");
v_tupleheaderp =
{
LLVMValueRef v_off = LLVMBuildLoad(b, v_offp, "");
+ LLVMValueRef v_flags;
LLVMBuildStore(b, l_int16_const(natts), v_nvalidp);
v_off = LLVMBuildTrunc(b, v_off, LLVMInt32Type(), "");
LLVMBuildStore(b, v_off, v_slotoffp);
- LLVMBuildStore(b, l_int8_const(1), v_slowp);
+ v_flags = LLVMBuildLoad(b, v_flagsp, "tts_flags");
+ v_flags = LLVMBuildOr(b, v_flags, l_int16_const(TTS_FLAG_SLOW), "");
+ LLVMBuildStore(b, v_flags, v_flagsp);
LLVMBuildRetVoid(b);
}
if (!desc &&
is &&
is->ps_ResultTupleSlot &&
- is->ps_ResultTupleSlot->tts_fixedTupleDescriptor)
+ TTS_FIXED(is->ps_ResultTupleSlot))
desc = is->ps_ResultTupleSlot->tts_tupleDescriptor;
}
else if (opcode == EEOP_OUTER_FETCHSOME)
if (!desc &&
os &&
os->ps_ResultTupleSlot &&
- os->ps_ResultTupleSlot->tts_fixedTupleDescriptor)
+ TTS_FIXED(os->ps_ResultTupleSlot))
desc = os->ps_ResultTupleSlot->tts_tupleDescriptor;
}
else
* Successfully formed a result row. Mark the result slot as containing a
* valid virtual tuple (inlined version of ExecStoreVirtualTuple()).
*/
- slot->tts_isempty = false;
+ slot->tts_flags &= ~TTS_FLAG_EMPTY;
slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
return slot;
* ie, only as needed. This serves to avoid repeated extraction of data
* from the physical tuple.
*
- * A TupleTableSlot can also be "empty", holding no valid data. This is
- * the only valid state for a freshly-created slot that has not yet had a
- * tuple descriptor assigned to it. In this state, tts_isempty must be
- * true, tts_shouldFree false, tts_tuple NULL, tts_buffer InvalidBuffer,
- * and tts_nvalid zero.
+ * A TupleTableSlot can also be "empty", indicated by flag TTS_EMPTY set in
+ * tts_flags, holding no valid data. This is the only valid state for a
+ * freshly-created slot that has not yet had a tuple descriptor assigned to it.
+ * In this state, TTS_SHOULDFREE should not be set in tts_flag, tts_tuple must
+ * be NULL, tts_buffer InvalidBuffer, and tts_nvalid zero.
*
* The tupleDescriptor is simply referenced, not copied, by the TupleTableSlot
* code. The caller of ExecSetSlotDescriptor() is responsible for providing
* mechanism to do more. However, the slot will increment the tupdesc
* reference count if a reference-counted tupdesc is supplied.)
*
- * When tts_shouldFree is true, the physical tuple is "owned" by the slot
- * and should be freed when the slot's reference to the tuple is dropped.
+ * When TTS_SHOULDFREE is set in tts_flags, the physical tuple is "owned" by
+ * the slot and should be freed when the slot's reference to the tuple is
+ * dropped.
*
* If tts_buffer is not InvalidBuffer, then the slot is holding a pin
* on the indicated buffer page; drop the pin when we release the
* MINIMAL_TUPLE_OFFSET bytes before tts_mintuple. This allows column
* extraction to treat the case identically to regular physical tuples.
*
- * tts_slow/tts_off are saved state for slot_deform_tuple, and should not
- * be touched by any other code.
+ * TTS_SLOW flag in tts_flags and tts_off are saved state for
+ * slot_deform_tuple, and should not be touched by any other code.
*----------
*/
+
+/* true = slot is empty */
+#define TTS_FLAG_EMPTY (1 << 1)
+#define TTS_EMPTY(slot) (((slot)->tts_flags & TTS_FLAG_EMPTY) != 0)
+
+/* should pfree tts_tuple? */
+#define TTS_FLAG_SHOULDFREE (1 << 2)
+#define TTS_SHOULDFREE(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREE) != 0)
+
+/* should pfree tts_mintuple? */
+#define TTS_FLAG_SHOULDFREEMIN (1 << 3)
+#define TTS_SHOULDFREEMIN(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREEMIN) != 0)
+
+/* saved state for slot_deform_tuple */
+#define TTS_FLAG_SLOW (1 << 4)
+#define TTS_SLOW(slot) (((slot)->tts_flags & TTS_FLAG_SLOW) != 0)
+
+/* fixed tuple descriptor */
+#define TTS_FLAG_FIXED (1 << 5)
+#define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0)
+
typedef struct TupleTableSlot
{
NodeTag type;
- bool tts_isempty; /* true = slot is empty */
- bool tts_shouldFree; /* should pfree tts_tuple? */
- bool tts_shouldFreeMin; /* should pfree tts_mintuple? */
-#define FIELDNO_TUPLETABLESLOT_SLOW 4
- bool tts_slow; /* saved state for slot_deform_tuple */
-#define FIELDNO_TUPLETABLESLOT_TUPLE 5
+#define FIELDNO_TUPLETABLESLOT_FLAGS 1
+ uint16 tts_flags; /* Boolean states */
+#define FIELDNO_TUPLETABLESLOT_NVALID 2
+ AttrNumber tts_nvalid; /* # of valid values in tts_values */
+#define FIELDNO_TUPLETABLESLOT_TUPLE 3
HeapTuple tts_tuple; /* physical tuple, or NULL if virtual */
-#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 6
+#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4
TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */
MemoryContext tts_mcxt; /* slot itself is in this context */
Buffer tts_buffer; /* tuple's buffer, or InvalidBuffer */
-#define FIELDNO_TUPLETABLESLOT_NVALID 9
- AttrNumber tts_nvalid; /* # of valid values in tts_values */
-#define FIELDNO_TUPLETABLESLOT_VALUES 10
+#define FIELDNO_TUPLETABLESLOT_OFF 7
+ uint32 tts_off; /* saved state for slot_deform_tuple */
+#define FIELDNO_TUPLETABLESLOT_VALUES 8
Datum *tts_values; /* current per-attribute values */
-#define FIELDNO_TUPLETABLESLOT_ISNULL 11
+#define FIELDNO_TUPLETABLESLOT_ISNULL 9
bool *tts_isnull; /* current per-attribute isnull flags */
MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */
HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */
-#define FIELDNO_TUPLETABLESLOT_OFF 14
- uint32 tts_off; /* saved state for slot_deform_tuple */
- bool tts_fixedTupleDescriptor; /* descriptor can't be changed */
} TupleTableSlot;
#define TTS_HAS_PHYSICAL_TUPLE(slot) \
* TupIsNull -- is a TupleTableSlot empty?
*/
#define TupIsNull(slot) \
- ((slot) == NULL || (slot)->tts_isempty)
+ ((slot) == NULL || TTS_EMPTY(slot))
/* in executor/execTuples.c */
extern TupleTableSlot *MakeTupleTableSlot(TupleDesc desc);