Verify that attribute counts match in ExecCopySlot
authorDavid Rowley <[email protected]>
Thu, 7 Dec 2023 08:28:24 +0000 (21:28 +1300)
committerDavid Rowley <[email protected]>
Thu, 7 Dec 2023 08:28:24 +0000 (21:28 +1300)
tts_virtual_copyslot() contained an Assert that checked that the srcslot
contained <= attributes than the dstslot.  This seems to be backwards as
if the srcslot contained fewer attributes then the dstslot could be left
with stale Datum values from the previously stored tuple.  It might make
more sense to allow the source to contain additional attributes and only
copy the leading ones that also exist in the destination, however, that's
not what we're doing here.

Here we just remove the Assert from tts_virtual_copyslot() and add an
Assert to ExecCopySlot() to verify the attribute counts match.  There
does not seem to be any places where the destination contains fewer
attributes, so instead of going to the trouble of making the code
properly handle this, let's just ensure the attribute counts match.  If
this Assert fails then that will indicate that we do have cases that
require us to handle the srcslot with more attributes than the dstslot.
It seems better to only write this code if there's a genuine requirement
for it rather than write it now only to leave it untested.

Thanks to Andres Freund for helping with the analysis of this.

Discussion: https://postgr.es/m/CAApHDvpMAvBL0T+TRORquyx1iqFQKMVTXtqNocOw0Pa2uh1heg@mail.gmail.com

src/backend/executor/execTuples.c
src/include/executor/tuptable.h

index 2c2712ceac365836f35e553e2ae08309c637cc4c..5a2db83987ed2afd133bba3b3b1a760043bf04bf 100644 (file)
@@ -253,8 +253,6 @@ tts_virtual_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
 {
    TupleDesc   srcdesc = srcslot->tts_tupleDescriptor;
 
-   Assert(srcdesc->natts <= dstslot->tts_tupleDescriptor->natts);
-
    tts_virtual_clear(dstslot);
 
    slot_getallattrs(srcslot);
index 4210d6d838fa7aaee2b6a23a929741610553fc32..5250be52d3351d646683e475aac79f45ac4e5174 100644 (file)
@@ -174,7 +174,8 @@ struct TupleTableSlotOps
 
    /*
     * Copy the contents of the source slot into the destination slot's own
-    * context. Invoked using callback of the destination slot.
+    * context. Invoked using callback of the destination slot.  'dstslot' and
+    * 'srcslot' can be assumed to have the same number of attributes.
     */
    void        (*copyslot) (TupleTableSlot *dstslot, TupleTableSlot *srcslot);
 
@@ -477,12 +478,19 @@ ExecCopySlotMinimalTuple(TupleTableSlot *slot)
  *
  * If a source's system attributes are supposed to be accessed in the target
  * slot, the target slot and source slot types need to match.
+ *
+ * Currently, 'dstslot' and 'srcslot' must have the same number of attributes.
+ * Future work could see this relaxed to allow the source to contain
+ * additional attributes and have the code here only copy over the leading
+ * attributes.
  */
 static inline TupleTableSlot *
 ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
 {
    Assert(!TTS_EMPTY(srcslot));
    Assert(srcslot != dstslot);
+   Assert(dstslot->tts_tupleDescriptor->natts ==
+          srcslot->tts_tupleDescriptor->natts);
 
    dstslot->tts_ops->copyslot(dstslot, srcslot);