/* support functions */
static void CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype);
+static void CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot);
static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
TupleDesc *cache_field, ExprContext *econtext);
static void ShutdownTupleDescRef(Datum arg);
EEO_CASE(EEOP_INNER_FETCHSOME)
{
+ CheckOpSlotCompatibility(op, innerslot);
+
/* XXX: worthwhile to check tts_nvalid inline first? */
slot_getsomeattrs(innerslot, op->d.fetch.last_var);
EEO_CASE(EEOP_OUTER_FETCHSOME)
{
+ CheckOpSlotCompatibility(op, outerslot);
+
slot_getsomeattrs(outerslot, op->d.fetch.last_var);
EEO_NEXT();
EEO_CASE(EEOP_SCAN_FETCHSOME)
{
+ CheckOpSlotCompatibility(op, scanslot);
+
slot_getsomeattrs(scanslot, op->d.fetch.last_var);
EEO_NEXT();
}
}
+/*
+ * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation.
+ */
+static void
+CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot)
+{
+#ifdef USE_ASSERT_CHECKING
+ /* there's nothing to check */
+ if (!op->d.fetch.fixed)
+ return;
+
+ /*
+ * Should probably fixed at some point, but for now it's easier to allow
+ * buffer and heap tuples to be used interchangably.
+ */
+ if (slot->tts_ops == &TTSOpsBufferTuple &&
+ op->d.fetch.kind == &TTSOpsHeapTuple)
+ return;
+ if (slot->tts_ops == &TTSOpsHeapTuple &&
+ op->d.fetch.kind == &TTSOpsBufferTuple)
+ return;
+
+ /*
+ * At the moment we consider it OK if a virtual slot is used instead of a
+ * specific type of slot, as a virtual slot never needs to be deformed.
+ */
+ if (slot->tts_ops == &TTSOpsVirtual)
+ return;
+
+ Assert(op->d.fetch.kind == slot->tts_ops);
+#endif
+}
+
/*
* get_cached_rowtype: utility function to lookup a rowtype tupdesc
*
int attnum = op->d.var.attnum + 1;
TupleTableSlot *slot = econtext->ecxt_innertuple;
+ CheckOpSlotCompatibility(&state->steps[0], slot);
+
/*
* Since we use slot_getattr(), we don't need to implement the FETCHSOME
* step explicitly, and we also needn't Assert that the attnum is in range
int attnum = op->d.var.attnum + 1;
TupleTableSlot *slot = econtext->ecxt_outertuple;
+ CheckOpSlotCompatibility(&state->steps[0], slot);
+
/* See comments in ExecJustInnerVar */
return slot_getattr(slot, attnum, isnull);
}
int attnum = op->d.var.attnum + 1;
TupleTableSlot *slot = econtext->ecxt_scantuple;
+ CheckOpSlotCompatibility(&state->steps[0], slot);
+
/* See comments in ExecJustInnerVar */
return slot_getattr(slot, attnum, isnull);
}
TupleTableSlot *inslot = econtext->ecxt_innertuple;
TupleTableSlot *outslot = state->resultslot;
+ CheckOpSlotCompatibility(&state->steps[0], inslot);
+
/*
* We do not need CheckVarSlotCompatibility here; that was taken care of
* at compilation time.
TupleTableSlot *inslot = econtext->ecxt_outertuple;
TupleTableSlot *outslot = state->resultslot;
+ CheckOpSlotCompatibility(&state->steps[0], inslot);
+
/* See comments in ExecJustAssignInnerVar */
outslot->tts_values[resultnum] =
slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
TupleTableSlot *inslot = econtext->ecxt_scantuple;
TupleTableSlot *outslot = state->resultslot;
+ CheckOpSlotCompatibility(&state->steps[0], inslot);
+
/* See comments in ExecJustAssignInnerVar */
outslot->tts_values[resultnum] =
slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);