@@ -143,6 +143,7 @@ static void ExecInitInterpreter(void);
143143
144144/* support functions */
145145static void CheckVarSlotCompatibility (TupleTableSlot * slot , int attnum , Oid vartype );
146+ static void CheckOpSlotCompatibility (ExprEvalStep * op , TupleTableSlot * slot );
146147static TupleDesc get_cached_rowtype (Oid type_id , int32 typmod ,
147148 TupleDesc * cache_field , ExprContext * econtext );
148149static void ShutdownTupleDescRef (Datum arg );
@@ -425,6 +426,8 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
425426
426427 EEO_CASE (EEOP_INNER_FETCHSOME )
427428 {
429+ CheckOpSlotCompatibility (op , innerslot );
430+
428431 /* XXX: worthwhile to check tts_nvalid inline first? */
429432 slot_getsomeattrs (innerslot , op -> d .fetch .last_var );
430433
@@ -433,13 +436,17 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
433436
434437 EEO_CASE (EEOP_OUTER_FETCHSOME )
435438 {
439+ CheckOpSlotCompatibility (op , outerslot );
440+
436441 slot_getsomeattrs (outerslot , op -> d .fetch .last_var );
437442
438443 EEO_NEXT ();
439444 }
440445
441446 EEO_CASE (EEOP_SCAN_FETCHSOME )
442447 {
448+ CheckOpSlotCompatibility (op , scanslot );
449+
443450 slot_getsomeattrs (scanslot , op -> d .fetch .last_var );
444451
445452 EEO_NEXT ();
@@ -1854,6 +1861,39 @@ CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype)
18541861 }
18551862}
18561863
1864+ /*
1865+ * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation.
1866+ */
1867+ static void
1868+ CheckOpSlotCompatibility (ExprEvalStep * op , TupleTableSlot * slot )
1869+ {
1870+ #ifdef USE_ASSERT_CHECKING
1871+ /* there's nothing to check */
1872+ if (!op -> d .fetch .fixed )
1873+ return ;
1874+
1875+ /*
1876+ * Should probably fixed at some point, but for now it's easier to allow
1877+ * buffer and heap tuples to be used interchangably.
1878+ */
1879+ if (slot -> tts_ops == & TTSOpsBufferTuple &&
1880+ op -> d .fetch .kind == & TTSOpsHeapTuple )
1881+ return ;
1882+ if (slot -> tts_ops == & TTSOpsHeapTuple &&
1883+ op -> d .fetch .kind == & TTSOpsBufferTuple )
1884+ return ;
1885+
1886+ /*
1887+ * At the moment we consider it OK if a virtual slot is used instead of a
1888+ * specific type of slot, as a virtual slot never needs to be deformed.
1889+ */
1890+ if (slot -> tts_ops == & TTSOpsVirtual )
1891+ return ;
1892+
1893+ Assert (op -> d .fetch .kind == slot -> tts_ops );
1894+ #endif
1895+ }
1896+
18571897/*
18581898 * get_cached_rowtype: utility function to lookup a rowtype tupdesc
18591899 *
@@ -1921,6 +1961,8 @@ ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
19211961 int attnum = op -> d .var .attnum + 1 ;
19221962 TupleTableSlot * slot = econtext -> ecxt_innertuple ;
19231963
1964+ CheckOpSlotCompatibility (& state -> steps [0 ], slot );
1965+
19241966 /*
19251967 * Since we use slot_getattr(), we don't need to implement the FETCHSOME
19261968 * step explicitly, and we also needn't Assert that the attnum is in range
@@ -1937,6 +1979,8 @@ ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
19371979 int attnum = op -> d .var .attnum + 1 ;
19381980 TupleTableSlot * slot = econtext -> ecxt_outertuple ;
19391981
1982+ CheckOpSlotCompatibility (& state -> steps [0 ], slot );
1983+
19401984 /* See comments in ExecJustInnerVar */
19411985 return slot_getattr (slot , attnum , isnull );
19421986}
@@ -1949,6 +1993,8 @@ ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
19491993 int attnum = op -> d .var .attnum + 1 ;
19501994 TupleTableSlot * slot = econtext -> ecxt_scantuple ;
19511995
1996+ CheckOpSlotCompatibility (& state -> steps [0 ], slot );
1997+
19521998 /* See comments in ExecJustInnerVar */
19531999 return slot_getattr (slot , attnum , isnull );
19542000}
@@ -1973,6 +2019,8 @@ ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
19732019 TupleTableSlot * inslot = econtext -> ecxt_innertuple ;
19742020 TupleTableSlot * outslot = state -> resultslot ;
19752021
2022+ CheckOpSlotCompatibility (& state -> steps [0 ], inslot );
2023+
19762024 /*
19772025 * We do not need CheckVarSlotCompatibility here; that was taken care of
19782026 * at compilation time.
@@ -1996,6 +2044,8 @@ ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
19962044 TupleTableSlot * inslot = econtext -> ecxt_outertuple ;
19972045 TupleTableSlot * outslot = state -> resultslot ;
19982046
2047+ CheckOpSlotCompatibility (& state -> steps [0 ], inslot );
2048+
19992049 /* See comments in ExecJustAssignInnerVar */
20002050 outslot -> tts_values [resultnum ] =
20012051 slot_getattr (inslot , attnum , & outslot -> tts_isnull [resultnum ]);
@@ -2012,6 +2062,8 @@ ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
20122062 TupleTableSlot * inslot = econtext -> ecxt_scantuple ;
20132063 TupleTableSlot * outslot = state -> resultslot ;
20142064
2065+ CheckOpSlotCompatibility (& state -> steps [0 ], inslot );
2066+
20152067 /* See comments in ExecJustAssignInnerVar */
20162068 outslot -> tts_values [resultnum ] =
20172069 slot_getattr (inslot , attnum , & outslot -> tts_isnull [resultnum ]);
0 commit comments