tableam: introduce slot based table getnext and use where necessary.
authorAndres Freund <andres@anarazel.de>
Wed, 6 Mar 2019 01:07:53 +0000 (17:07 -0800)
committerAndres Freund <andres@anarazel.de>
Wed, 6 Mar 2019 06:59:31 +0000 (22:59 -0800)
Author:
Reviewed-By:
Discussion: https://postgr.es/m/
Backpatch:

src/backend/access/heap/heapam_handler.c
src/backend/access/index/genam.c
src/backend/catalog/index.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/executor/execReplication.c
src/backend/executor/nodeSeqscan.c
src/backend/partitioning/partbounds.c
src/backend/rewrite/rewriteDefine.c
src/include/access/tableam.h

index 9d06ba55b5edc07cf5ce8d98ae50d5ae98efd0bd..7ace8e7d25183a51f855d40bf1dec200859c622b 100644 (file)
@@ -170,6 +170,7 @@ static const TableAmRoutine heapam_methods = {
    .scan_end = heap_endscan,
    .scan_rescan = heap_rescan,
    .scan_update_snapshot = heap_update_snapshot,
+   .scan_getnextslot = heap_getnextslot,
 
    .parallelscan_estimate = table_block_parallelscan_estimate,
    .parallelscan_initialize = table_block_parallelscan_initialize,
index 1b57e0f85d0739de7aad52b374a76636b00d9457..5d0700744a85af5c788c8163d91f42a0c1df4b6b 100644 (file)
@@ -430,7 +430,7 @@ systable_getnext(SysScanDesc sysscan)
    }
    else
    {
-       if (heap_getnextslot(sysscan->scan, ForwardScanDirection, sysscan->slot))
+       if (table_scan_getnextslot(sysscan->scan, ForwardScanDirection, sysscan->slot))
        {
            bool        shouldFree;
 
index ae68e010980d33c1283d8f617ebca4b10de30ada..ae522b663dfc001841bfeac2e7279485075e800c 100644 (file)
@@ -2969,9 +2969,7 @@ IndexCheckExclusion(Relation heapRelation,
                    Relation indexRelation,
                    IndexInfo *indexInfo)
 {
-   HeapTuple   heapTuple;
    TableScanDesc scan;
-   HeapScanDesc hscan;
    Datum       values[INDEX_MAX_KEYS];
    bool        isnull[INDEX_MAX_KEYS];
    ExprState  *predicate;
@@ -3012,17 +3010,11 @@ IndexCheckExclusion(Relation heapRelation,
                                 NULL,  /* scan key */
                                 true,  /* buffer access strategy OK */
                                 true); /* syncscan OK */
-   hscan = (HeapScanDesc) scan;
 
-   while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+   while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
    {
        CHECK_FOR_INTERRUPTS();
 
-       MemoryContextReset(econtext->ecxt_per_tuple_memory);
-
-       /* Set up for predicate or expression evaluation */
-       ExecStoreBufferHeapTuple(heapTuple, slot, hscan->rs_cbuf);
-
        /*
         * In a partial index, ignore tuples that don't satisfy the predicate.
         */
@@ -3046,8 +3038,10 @@ IndexCheckExclusion(Relation heapRelation,
         */
        check_exclusion_constraint(heapRelation,
                                   indexRelation, indexInfo,
-                                  &(heapTuple->t_self), values, isnull,
+                                  &(slot->tts_tid), values, isnull,
                                   estate, true);
+
+       MemoryContextReset(econtext->ecxt_per_tuple_memory);
    }
 
    table_endscan(scan);
index 81ff6a59eedae51c48abaaae5176f56459d77f80..3a04a26f01a8455d520035a1b3aee41d4b7ed469 100644 (file)
@@ -4732,11 +4732,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
    if (newrel || needscan)
    {
        ExprContext *econtext;
-       Datum      *values;
-       bool       *isnull;
        TupleTableSlot *oldslot;
        TupleTableSlot *newslot;
-       HeapTuple   tuple;
        TableScanDesc scan;
        MemoryContext oldCxt;
        List       *dropped_attrs = NIL;
@@ -4765,19 +4762,32 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
        econtext = GetPerTupleExprContext(estate);
 
        /*
-        * Make tuple slots for old and new tuples.  Note that even when the
-        * tuples are the same, the tupDescs might not be (consider ADD COLUMN
-        * without a default).
+        * Create necessary tuple slots. When rewriting, two slots are needed,
+        * otherwise one suffices. In the case where one slot suffices, we
+        * need to use the new tuple descriptor, otherwise some constraints
+        * can't be evaluated.  Note that even when the tuple layout is the
+        * same and no rewrite is required, the tupDescs might not be
+        * (consider ADD COLUMN without a default).
         */
-       oldslot = MakeSingleTupleTableSlot(oldTupDesc, &TTSOpsHeapTuple);
-       newslot = MakeSingleTupleTableSlot(newTupDesc, &TTSOpsHeapTuple);
+       if (tab->rewrite)
+       {
+           Assert(newrel != NULL);
+           oldslot = MakeSingleTupleTableSlot(oldTupDesc,
+                                              table_slot_callbacks(oldrel));
+           newslot = MakeSingleTupleTableSlot(newTupDesc,
+                                              table_slot_callbacks(newrel));
 
-       /* Preallocate values/isnull arrays */
-       i = Max(newTupDesc->natts, oldTupDesc->natts);
-       values = (Datum *) palloc(i * sizeof(Datum));
-       isnull = (bool *) palloc(i * sizeof(bool));
-       memset(values, 0, i * sizeof(Datum));
-       memset(isnull, true, i * sizeof(bool));
+           memset(newslot->tts_values, 0,
+                  sizeof(Datum) * newTupDesc->natts);
+           memset(newslot->tts_isnull, 0,
+                  sizeof(bool) * newTupDesc->natts);
+       }
+       else
+       {
+           oldslot = MakeSingleTupleTableSlot(newTupDesc,
+                                              table_slot_callbacks(oldrel));
+           newslot = NULL;
+       }
 
        /*
         * Any attributes that are dropped according to the new tuple
@@ -4803,55 +4813,69 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
         */
        oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
 
-       while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+       while (table_scan_getnextslot(scan, ForwardScanDirection, oldslot))
        {
+           TupleTableSlot *insertslot;
+
            if (tab->rewrite > 0)
            {
                /* Extract data from old tuple */
-               heap_deform_tuple(tuple, oldTupDesc, values, isnull);
+               slot_getallattrs(oldslot);
+               ExecClearTuple(newslot);
+
+               /* copy attributes */
+               memcpy(newslot->tts_values, oldslot->tts_values,
+                      sizeof(Datum) * oldslot->tts_nvalid);
+               memcpy(newslot->tts_isnull, oldslot->tts_isnull,
+                      sizeof(bool) * oldslot->tts_nvalid);
 
                /* Set dropped attributes to null in new tuple */
                foreach(lc, dropped_attrs)
-                   isnull[lfirst_int(lc)] = true;
+                   newslot->tts_isnull[lfirst_int(lc)] = true;
 
                /*
                 * Process supplied expressions to replace selected columns.
                 * Expression inputs come from the old tuple.
                 */
-               ExecStoreHeapTuple(tuple, oldslot, false);
                econtext->ecxt_scantuple = oldslot;
 
                foreach(l, tab->newvals)
                {
                    NewColumnValue *ex = lfirst(l);
 
-                   values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate,
-                                                         econtext,
-                                                         &isnull[ex->attnum - 1]);
+                   newslot->tts_values[ex->attnum - 1]
+                       = ExecEvalExpr(ex->exprstate,
+                                      econtext,
+                                      &newslot->tts_isnull[ex->attnum - 1]);
                }
 
-               /*
-                * Form the new tuple. Note that we don't explicitly pfree it,
-                * since the per-tuple memory context will be reset shortly.
-                */
-               tuple = heap_form_tuple(newTupDesc, values, isnull);
+               ExecStoreVirtualTuple(newslot);
 
                /*
                 * Constraints might reference the tableoid column, so
                 * initialize t_tableOid before evaluating them.
                 */
-               tuple->t_tableOid = RelationGetRelid(oldrel);
+               newslot->tts_tableOid = RelationGetRelid(oldrel);
+               insertslot = newslot;
+           }
+           else
+           {
+               /*
+                * If there's no rewrite, old and new table are guaranteed to
+                * have the same AM, so we can just use the old slot to
+                * verify new constraints etc.
+                */
+               insertslot = oldslot;
            }
 
            /* Now check any constraints on the possibly-changed tuple */
-           ExecStoreHeapTuple(tuple, newslot, false);
-           econtext->ecxt_scantuple = newslot;
+           econtext->ecxt_scantuple = insertslot;
 
            foreach(l, notnull_attrs)
            {
                int         attn = lfirst_int(l);
 
-               if (heap_attisnull(tuple, attn + 1, newTupDesc))
+               if (slot_attisnull(insertslot, attn + 1))
                {
                    Form_pg_attribute attr = TupleDescAttr(newTupDesc, attn);
 
@@ -4901,6 +4925,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
            /* Write the tuple out to the new relation */
            if (newrel)
            {
+               HeapTuple   tuple;
+
+               tuple = ExecFetchSlotHeapTuple(newslot, true, NULL);
                heap_insert(newrel, tuple, mycid, hi_options, bistate);
                ItemPointerCopy(&tuple->t_self, &newslot->tts_tid);
            }
@@ -4915,7 +4942,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
        UnregisterSnapshot(snapshot);
 
        ExecDropSingleTupleTableSlot(oldslot);
-       ExecDropSingleTupleTableSlot(newslot);
+       if (newslot)
+           ExecDropSingleTupleTableSlot(newslot);
    }
 
    FreeExecutorState(estate);
@@ -8818,9 +8846,7 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
    char       *conbin;
    Expr       *origexpr;
    ExprState  *exprstate;
-   HeapTuple   tuple;
    TableScanDesc scan;
-   HeapScanDesc hscan;
    ExprContext *econtext;
    MemoryContext oldcxt;
    TupleTableSlot *slot;
@@ -8860,7 +8886,6 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
 
    snapshot = RegisterSnapshot(GetLatestSnapshot());
    scan = table_beginscan(rel, snapshot, 0, NULL);
-   hscan = (HeapScanDesc) scan;
 
    /*
     * Switch to per-tuple memory context and reset it for each tuple
@@ -8868,11 +8893,8 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
     */
    oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
 
-   while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+   while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
    {
-       ExecStoreBufferHeapTuple(tuple, slot, hscan->rs_cbuf);
-
-
        if (!ExecCheck(exprstate, econtext))
            ereport(ERROR,
                    (errcode(ERRCODE_CHECK_VIOLATION),
@@ -8903,7 +8925,7 @@ validateForeignKeyConstraint(char *conname,
                             Oid pkindOid,
                             Oid constraintOid)
 {
-   HeapTuple   tuple;
+   TupleTableSlot *slot;
    TableScanDesc scan;
    Trigger     trig;
    Snapshot    snapshot;
@@ -8939,9 +8961,10 @@ validateForeignKeyConstraint(char *conname,
     * ereport(ERROR) and that's that.
     */
    snapshot = RegisterSnapshot(GetLatestSnapshot());
+   slot = table_gimmegimmeslot(rel, NULL);
    scan = table_beginscan(rel, snapshot, 0, NULL);
 
-   while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+   while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
    {
        LOCAL_FCINFO(fcinfo, 0);
        TriggerData trigdata;
@@ -8959,7 +8982,8 @@ validateForeignKeyConstraint(char *conname,
        trigdata.type = T_TriggerData;
        trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
        trigdata.tg_relation = rel;
-       trigdata.tg_trigtuple = tuple;
+       trigdata.tg_trigtuple = ExecFetchSlotHeapTuple(slot, true, NULL);
+       trigdata.tg_trigslot = slot;
        trigdata.tg_newtuple = NULL;
        trigdata.tg_trigger = &trig;
 
@@ -8970,6 +8994,7 @@ validateForeignKeyConstraint(char *conname,
 
    table_endscan(scan);
    UnregisterSnapshot(snapshot);
+   ExecDropSingleTupleTableSlot(slot);
 }
 
 static void
index e0c17d10b9544b2e7f4700100afdab4d74b7a127..ad77acb596ceb840cc51b172e143f0834e1636e2 100644 (file)
@@ -2363,14 +2363,15 @@ AlterDomainNotNull(List *names, bool notNull)
            RelToCheck *rtc = (RelToCheck *) lfirst(rt);
            Relation    testrel = rtc->rel;
            TupleDesc   tupdesc = RelationGetDescr(testrel);
-           HeapTuple   tuple;
+           TupleTableSlot *slot;
            TableScanDesc scan;
            Snapshot    snapshot;
 
            /* Scan all tuples in this relation */
            snapshot = RegisterSnapshot(GetLatestSnapshot());
            scan = table_beginscan(testrel, snapshot, 0, NULL);
-           while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+           slot = table_gimmegimmeslot(testrel, NULL);
+           while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
            {
                int         i;
 
@@ -2380,7 +2381,7 @@ AlterDomainNotNull(List *names, bool notNull)
                    int         attnum = rtc->atts[i];
                    Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
 
-                   if (heap_attisnull(tuple, attnum, tupdesc))
+                   if (slot_attisnull(slot, attnum))
                    {
                        /*
                         * In principle the auxiliary information for this
@@ -2399,6 +2400,7 @@ AlterDomainNotNull(List *names, bool notNull)
                    }
                }
            }
+           ExecDropSingleTupleTableSlot(slot);
            table_endscan(scan);
            UnregisterSnapshot(snapshot);
 
@@ -2777,14 +2779,15 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
        RelToCheck *rtc = (RelToCheck *) lfirst(rt);
        Relation    testrel = rtc->rel;
        TupleDesc   tupdesc = RelationGetDescr(testrel);
-       HeapTuple   tuple;
+       TupleTableSlot *slot;
        TableScanDesc scan;
        Snapshot    snapshot;
 
        /* Scan all tuples in this relation */
        snapshot = RegisterSnapshot(GetLatestSnapshot());
        scan = table_beginscan(testrel, snapshot, 0, NULL);
-       while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+       slot = table_gimmegimmeslot(testrel, NULL);
+       while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
        {
            int         i;
 
@@ -2797,7 +2800,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
                Datum       conResult;
                Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
 
-               d = heap_getattr(tuple, attnum, tupdesc, &isNull);
+               d = slot_getattr(slot, attnum, &isNull);
 
                econtext->domainValue_datum = d;
                econtext->domainValue_isNull = isNull;
@@ -2827,6 +2830,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
 
            ResetExprContext(econtext);
        }
+       ExecDropSingleTupleTableSlot(slot);
        table_endscan(scan);
        UnregisterSnapshot(snapshot);
 
index 275b927cb3319701226c738913d881047faed8bc..311d2aadc09c79b263d44580bb0e066e09bed24b 100644 (file)
@@ -221,19 +221,21 @@ retry:
 }
 
 /*
- * Compare the tuple and slot and check if they have equal values.
+ * Compare the tuples in the slots by checking if they have equal values.
  */
 static bool
-tuple_equals_slot(TupleDesc desc, HeapTuple tup, TupleTableSlot *slot)
+tuples_equal(TupleTableSlot *slot1, TupleTableSlot *slot2)
 {
-   Datum       values[MaxTupleAttributeNumber];
-   bool        isnull[MaxTupleAttributeNumber];
-   int         attrnum;
+   int         attrnum;
 
-   heap_deform_tuple(tup, desc, values, isnull);
+   Assert(slot1->tts_tupleDescriptor->natts ==
+          slot2->tts_tupleDescriptor->natts);
+
+   slot_getallattrs(slot1);
+   slot_getallattrs(slot2);
 
    /* Check equality of the attributes. */
-   for (attrnum = 0; attrnum < desc->natts; attrnum++)
+   for (attrnum = 0; attrnum < slot1->tts_tupleDescriptor->natts; attrnum++)
    {
        Form_pg_attribute att;
        TypeCacheEntry *typentry;
@@ -242,16 +244,16 @@ tuple_equals_slot(TupleDesc desc, HeapTuple tup, TupleTableSlot *slot)
         * If one value is NULL and other is not, then they are certainly not
         * equal
         */
-       if (isnull[attrnum] != slot->tts_isnull[attrnum])
+       if (slot1->tts_isnull[attrnum] != slot2->tts_isnull[attrnum])
            return false;
 
        /*
         * If both are NULL, they can be considered equal.
         */
-       if (isnull[attrnum])
+       if (slot1->tts_isnull[attrnum] || slot2->tts_isnull[attrnum])
            continue;
 
-       att = TupleDescAttr(desc, attrnum);
+       att = TupleDescAttr(slot1->tts_tupleDescriptor, attrnum);
 
        typentry = lookup_type_cache(att->atttypid, TYPECACHE_EQ_OPR_FINFO);
        if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
@@ -261,8 +263,8 @@ tuple_equals_slot(TupleDesc desc, HeapTuple tup, TupleTableSlot *slot)
                            format_type_be(att->atttypid))));
 
        if (!DatumGetBool(FunctionCall2(&typentry->eq_opr_finfo,
-                                       values[attrnum],
-                                       slot->tts_values[attrnum])))
+                                       slot1->tts_values[attrnum],
+                                       slot2->tts_values[attrnum])))
            return false;
    }
 
@@ -283,18 +285,19 @@ bool
 RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode,
                         TupleTableSlot *searchslot, TupleTableSlot *outslot)
 {
-   HeapTuple   scantuple;
+   TupleTableSlot *scanslot;
    TableScanDesc scan;
    SnapshotData snap;
    TransactionId xwait;
    bool        found;
-   TupleDesc   desc = RelationGetDescr(rel);
+   TupleDesc   desc PG_USED_FOR_ASSERTS_ONLY = RelationGetDescr(rel);
 
    Assert(equalTupleDescs(desc, outslot->tts_tupleDescriptor));
 
    /* Start a heap scan. */
    InitDirtySnapshot(snap);
    scan = table_beginscan(rel, &snap, 0, NULL);
+   scanslot = table_gimmegimmeslot(rel, NULL);
 
 retry:
    found = false;
@@ -302,16 +305,13 @@ retry:
    table_rescan(scan, NULL);
 
    /* Try to find the tuple */
-   while ((scantuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+   while (table_scan_getnextslot(scan, ForwardScanDirection, scanslot))
    {
-       HeapScanDesc hscan = (HeapScanDesc) scan;
-
-       if (!tuple_equals_slot(desc, scantuple, searchslot))
+       if (!tuples_equal(scanslot, searchslot))
            continue;
 
        found = true;
-       ExecStoreBufferHeapTuple(scantuple, outslot, hscan->rs_cbuf);
-       ExecMaterializeSlot(outslot);
+       ExecCopySlot(outslot, scanslot);
 
        xwait = TransactionIdIsValid(snap.xmin) ?
            snap.xmin : snap.xmax;
@@ -377,6 +377,7 @@ retry:
    }
 
    table_endscan(scan);
+   ExecDropSingleTupleTableSlot(scanslot);
 
    return found;
 }
index 2272f93b09d10506ccd0662f0c26771e6de5a482..525e84c0476ee7d40f0118a2a19cac8b2cf36a3e 100644 (file)
@@ -27,7 +27,6 @@
  */
 #include "postgres.h"
 
-#include "access/heapam.h"
 #include "access/relscan.h"
 #include "access/tableam.h"
 #include "executor/execdebug.h"
@@ -50,9 +49,7 @@ static TupleTableSlot *SeqNext(SeqScanState *node);
 static TupleTableSlot *
 SeqNext(SeqScanState *node)
 {
-   HeapTuple   tuple;
    TableScanDesc scandesc;
-   HeapScanDesc hscandesc;
    EState     *estate;
    ScanDirection direction;
    TupleTableSlot *slot;
@@ -77,30 +74,10 @@ SeqNext(SeqScanState *node)
        node->ss.ss_currentScanDesc = scandesc;
    }
 
-   hscandesc = (HeapScanDesc) scandesc;
-
    /*
     * get the next tuple from the table
     */
-   tuple = heap_getnext(scandesc, direction);
-
-   /*
-    * save the tuple and the buffer returned to us by the access methods in
-    * our scan tuple slot and return the slot.  Note: we pass 'false' because
-    * tuples returned by heap_getnext() are pointers onto disk pages and were
-    * not created with palloc() and so should not be pfree()'d.  Note also
-    * that ExecStoreHeapTuple will increment the refcount of the buffer; the
-    * refcount will not be dropped until the tuple table slot is cleared.
-    */
-   if (tuple)
-       ExecStoreBufferHeapTuple(tuple, /* tuple to store */
-                                slot,  /* slot to store in */
-                                hscandesc->rs_cbuf);   /* buffer associated
-                                                        * with this tuple */
-   else
-       ExecClearTuple(slot);
-
-   return slot;
+   return table_scan_getnextslot(scandesc, direction, slot);
 }
 
 /*
index 5d9e4dc17165065fdcf025a509e9fb6a38729456..30b0d15895433331c2d123686aebc8ab5b2110ba 100644 (file)
@@ -14,7 +14,8 @@
 
 #include "postgres.h"
 
-#include "access/heapam.h"
+#include "access/relation.h"
+#include "access/table.h"
 #include "access/tableam.h"
 #include "catalog/partition.h"
 #include "catalog/pg_inherits.h"
@@ -1203,12 +1204,10 @@ check_default_partition_contents(Relation parent, Relation default_rel,
        Expr       *constr;
        Expr       *partition_constraint;
        EState     *estate;
-       HeapTuple   tuple;
        ExprState  *partqualstate = NULL;
        Snapshot    snapshot;
        ExprContext *econtext;
        TableScanDesc scan;
-       HeapScanDesc hscan;
        MemoryContext oldCxt;
        TupleTableSlot *tupslot;
 
@@ -1268,7 +1267,6 @@ check_default_partition_contents(Relation parent, Relation default_rel,
        snapshot = RegisterSnapshot(GetLatestSnapshot());
        tupslot = table_gimmegimmeslot(part_rel, &estate->es_tupleTable);
        scan = table_beginscan(part_rel, snapshot, 0, NULL);
-       hscan = (HeapScanDesc) scan;
 
        /*
         * Switch to per-tuple memory context and reset it for each tuple
@@ -1276,9 +1274,8 @@ check_default_partition_contents(Relation parent, Relation default_rel,
         */
        oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
 
-       while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+       while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
        {
-           ExecStoreBufferHeapTuple(tuple, tupslot, hscan->rs_cbuf);
            econtext->ecxt_scantuple = tupslot;
 
            if (!ExecCheck(partqualstate, econtext))
index a83f4cd26cc43cdb98c90689315f0456c5ad25e6..599f98be4d02f6e56aef5bbb4a472b40de218236 100644 (file)
@@ -426,6 +426,7 @@ DefineQueryRewrite(const char *rulename,
        {
            TableScanDesc scanDesc;
            Snapshot    snapshot;
+           TupleTableSlot *slot;
 
            if (event_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
                ereport(ERROR,
@@ -441,11 +442,13 @@ DefineQueryRewrite(const char *rulename,
 
            snapshot = RegisterSnapshot(GetLatestSnapshot());
            scanDesc = table_beginscan(event_relation, snapshot, 0, NULL);
-           if (heap_getnext(scanDesc, ForwardScanDirection) != NULL)
+           slot = table_gimmegimmeslot(event_relation, NULL);
+           if (table_scan_getnextslot(scanDesc, ForwardScanDirection, slot))
                ereport(ERROR,
                        (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                         errmsg("could not convert table \"%s\" to a view because it is not empty",
                                RelationGetRelationName(event_relation))));
+           ExecDropSingleTupleTableSlot(slot);
            table_endscan(scanDesc);
            UnregisterSnapshot(snapshot);
 
index 3e422f84b057a88d42370815ad8b1c0370802748..8f500e55d19afc09eb1361f7dc0386a509ccb414 100644 (file)
@@ -62,6 +62,8 @@ typedef struct TableAmRoutine
    void        (*scan_rescan) (TableScanDesc scan, struct ScanKeyData *key, bool set_params,
                                bool allow_strat, bool allow_sync, bool allow_pagemode);
    void        (*scan_update_snapshot) (TableScanDesc scan, Snapshot snapshot);
+   TupleTableSlot *(*scan_getnextslot) (TableScanDesc scan,
+                                        ScanDirection direction, TupleTableSlot *slot);
 
 
    /* ------------------------------------------------------------------------
@@ -231,6 +233,13 @@ table_scan_update_snapshot(TableScanDesc scan, Snapshot snapshot)
    scan->rs_rd->rd_tableam->scan_update_snapshot(scan, snapshot);
 }
 
+static inline TupleTableSlot *
+table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
+{
+   slot->tts_tableOid = RelationGetRelid(sscan->rs_rd);
+   return sscan->rs_rd->rd_tableam->scan_getnextslot(sscan, direction, slot);
+}
+
 
 /* ----------------------------------------------------------------------------
  * Parallel table scan related functions.