Fix confusion on different kinds of slots in IndexOnlyScans.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 6 Jun 2019 06:46:52 +0000 (09:46 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 6 Jun 2019 06:46:52 +0000 (09:46 +0300)
We used the same slot to store a tuple from the index, and to store a
tuple from the table. That's not OK. It worked with the heap, because
heapam_getnextslot() stores a HeapTuple to the slot, and doesn't care how
large the tts_values/nulls arrays are. But when I played with a toy table
AM implementation that used a virtual tuple, it caused memory overruns.

In the passing, tidy up comments on the ioss_PscanLen fields.

src/backend/executor/nodeIndexonlyscan.c
src/include/nodes/execnodes.h

index ee5b1c493b7e9a81a06a7ad72fa740136f76738d..8a4d795d1a9fe91515bd8b2f097a8c3bf155acca 100644 (file)
@@ -166,10 +166,10 @@ IndexOnlyNext(IndexOnlyScanState *node)
             * Rats, we have to visit the heap to check visibility.
             */
            InstrCountTuples2(node, 1);
-           if (!index_fetch_heap(scandesc, slot))
+           if (!index_fetch_heap(scandesc, node->ioss_TableSlot))
                continue;       /* no visible tuple, try next index entry */
 
-           ExecClearTuple(slot);
+           ExecClearTuple(node->ioss_TableSlot);
 
            /*
             * Only MVCC snapshots are supported here, so there should be no
@@ -528,7 +528,17 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
     */
    tupDesc = ExecTypeFromTL(node->indextlist);
    ExecInitScanTupleSlot(estate, &indexstate->ss, tupDesc,
-                         table_slot_callbacks(currentRelation));
+                         &TTSOpsVirtual);
+
+   /*
+    * We need another slot, in a format that's suitable for the table AM,
+    * for when we need to fetch a tuple from the table for rechecking
+    * visibility.
+    */
+   indexstate->ioss_TableSlot =
+       ExecAllocTableSlot(&estate->es_tupleTable,
+                          RelationGetDescr(currentRelation),
+                          table_slot_callbacks(currentRelation));
 
    /*
     * Initialize result type and projection info.  The node's targetlist will
index 112a9a53683f197b4f5cebcf45ff5bec1523f629..99b9fa414f138678b74a639cd249169b5dc2d122 100644 (file)
@@ -1359,7 +1359,7 @@ typedef struct
  *     SortSupport        for reordering ORDER BY exprs
  *     OrderByTypByVals   is the datatype of order by expression pass-by-value?
  *     OrderByTypLens     typlens of the datatypes of order by expressions
- *     pscan_len          size of parallel index scan descriptor
+ *     PscanLen           size of parallel index scan descriptor
  * ----------------
  */
 typedef struct IndexScanState
@@ -1403,8 +1403,9 @@ typedef struct IndexScanState
  *     RuntimeContext     expr context for evaling runtime Skeys
  *     RelationDesc       index relation descriptor
  *     ScanDesc           index scan descriptor
+ *     TableSlot          slot for holding tuples fetched from the table
  *     VMBuffer           buffer in use for visibility map testing, if any
- *     ioss_PscanLen      Size of parallel index-only scan descriptor
+ *     PscanLen           size of parallel index-only scan descriptor
  * ----------------
  */
 typedef struct IndexOnlyScanState
@@ -1421,6 +1422,7 @@ typedef struct IndexOnlyScanState
    ExprContext *ioss_RuntimeContext;
    Relation    ioss_RelationDesc;
    struct IndexScanDescData *ioss_ScanDesc;
+   TupleTableSlot *ioss_TableSlot;
    Buffer      ioss_VMBuffer;
    Size        ioss_PscanLen;
 } IndexOnlyScanState;