]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/nodeTidscan.c
Make some small planner API cleanups.
[postgresql] / src / backend / executor / nodeTidscan.c
index 28244a1a3d072a4c9035593277ed648fdb6000a6..8daf09c785a5e30fce6d69ee113bdb953f253f4a 100644 (file)
@@ -3,7 +3,7 @@
  * nodeTidscan.c
  *       Routines to support direct tid scans of relations
  *
- * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
@@ -19,8 +19,6 @@
  *             ExecInitTidScan         creates and initializes state info.
  *             ExecReScanTidScan       rescans the tid relation.
  *             ExecEndTidScan          releases all storage.
- *             ExecTidMarkPos          marks scan position.
- *             ExecTidRestrPos         restores scan position.
  */
 #include "postgres.h"
 
@@ -29,7 +27,8 @@
 #include "catalog/pg_type.h"
 #include "executor/execdebug.h"
 #include "executor/nodeTidscan.h"
-#include "optimizer/clauses.h"
+#include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
 #include "storage/bufmgr.h"
 #include "utils/array.h"
 #include "utils/rel.h"
         ((Var *) (node))->varattno == SelfItemPointerAttributeNumber && \
         ((Var *) (node))->varlevelsup == 0)
 
-static void TidListCreate(TidScanState *tidstate);
+/* one element in tss_tidexprs */
+typedef struct TidExpr
+{
+       ExprState  *exprstate;          /* ExprState for a TID-yielding subexpr */
+       bool            isarray;                /* if true, it yields tid[] not just tid */
+       CurrentOfExpr *cexpr;           /* alternatively, we can have CURRENT OF */
+} TidExpr;
+
+static void TidExprListCreate(TidScanState *tidstate);
+static void TidListEval(TidScanState *tidstate);
 static int     itemptr_comparator(const void *a, const void *b);
 static TupleTableSlot *TidNext(TidScanState *node);
 
 
+/*
+ * Extract the qual subexpressions that yield TIDs to search for,
+ * and compile them into ExprStates if they're ordinary expressions.
+ *
+ * CURRENT OF is a special case that we can't compile usefully;
+ * just drop it into the TidExpr list as-is.
+ */
+static void
+TidExprListCreate(TidScanState *tidstate)
+{
+       TidScan    *node = (TidScan *) tidstate->ss.ps.plan;
+       ListCell   *l;
+
+       tidstate->tss_tidexprs = NIL;
+       tidstate->tss_isCurrentOf = false;
+
+       foreach(l, node->tidquals)
+       {
+               Expr       *expr = (Expr *) lfirst(l);
+               TidExpr    *tidexpr = (TidExpr *) palloc0(sizeof(TidExpr));
+
+               if (is_opclause(expr))
+               {
+                       Node       *arg1;
+                       Node       *arg2;
+
+                       arg1 = get_leftop(expr);
+                       arg2 = get_rightop(expr);
+                       if (IsCTIDVar(arg1))
+                               tidexpr->exprstate = ExecInitExpr((Expr *) arg2,
+                                                                                                 &tidstate->ss.ps);
+                       else if (IsCTIDVar(arg2))
+                               tidexpr->exprstate = ExecInitExpr((Expr *) arg1,
+                                                                                                 &tidstate->ss.ps);
+                       else
+                               elog(ERROR, "could not identify CTID variable");
+                       tidexpr->isarray = false;
+               }
+               else if (expr && IsA(expr, ScalarArrayOpExpr))
+               {
+                       ScalarArrayOpExpr *saex = (ScalarArrayOpExpr *) expr;
+
+                       Assert(IsCTIDVar(linitial(saex->args)));
+                       tidexpr->exprstate = ExecInitExpr(lsecond(saex->args),
+                                                                                         &tidstate->ss.ps);
+                       tidexpr->isarray = true;
+               }
+               else if (expr && IsA(expr, CurrentOfExpr))
+               {
+                       CurrentOfExpr *cexpr = (CurrentOfExpr *) expr;
+
+                       tidexpr->cexpr = cexpr;
+                       tidstate->tss_isCurrentOf = true;
+               }
+               else
+                       elog(ERROR, "could not identify CTID expression");
+
+               tidstate->tss_tidexprs = lappend(tidstate->tss_tidexprs, tidexpr);
+       }
+
+       /* CurrentOfExpr could never appear OR'd with something else */
+       Assert(list_length(tidstate->tss_tidexprs) == 1 ||
+                  !tidstate->tss_isCurrentOf);
+}
+
 /*
  * Compute the list of TIDs to be visited, by evaluating the expressions
  * for them.
@@ -53,9 +126,8 @@ static TupleTableSlot *TidNext(TidScanState *node);
  * (The result is actually an array, not a list.)
  */
 static void
-TidListCreate(TidScanState *tidstate)
+TidListEval(TidScanState *tidstate)
 {
-       List       *evalList = tidstate->tss_tidquals;
        ExprContext *econtext = tidstate->ss.ps.ps_ExprContext;
        BlockNumber nblocks;
        ItemPointerData *tidList;
@@ -76,39 +148,23 @@ TidListCreate(TidScanState *tidstate)
         * are simple OpExprs or CurrentOfExprs.  If there are any
         * ScalarArrayOpExprs, we may have to enlarge the array.
         */
-       numAllocTids = list_length(evalList);
+       numAllocTids = list_length(tidstate->tss_tidexprs);
        tidList = (ItemPointerData *)
                palloc(numAllocTids * sizeof(ItemPointerData));
        numTids = 0;
-       tidstate->tss_isCurrentOf = false;
 
-       foreach(l, evalList)
+       foreach(l, tidstate->tss_tidexprs)
        {
-               ExprState  *exstate = (ExprState *) lfirst(l);
-               Expr       *expr = exstate->expr;
+               TidExpr    *tidexpr = (TidExpr *) lfirst(l);
                ItemPointer itemptr;
                bool            isNull;
 
-               if (is_opclause(expr))
+               if (tidexpr->exprstate && !tidexpr->isarray)
                {
-                       FuncExprState *fexstate = (FuncExprState *) exstate;
-                       Node       *arg1;
-                       Node       *arg2;
-
-                       arg1 = get_leftop(expr);
-                       arg2 = get_rightop(expr);
-                       if (IsCTIDVar(arg1))
-                               exstate = (ExprState *) lsecond(fexstate->args);
-                       else if (IsCTIDVar(arg2))
-                               exstate = (ExprState *) linitial(fexstate->args);
-                       else
-                               elog(ERROR, "could not identify CTID variable");
-
                        itemptr = (ItemPointer)
-                               DatumGetPointer(ExecEvalExprSwitchContext(exstate,
+                               DatumGetPointer(ExecEvalExprSwitchContext(tidexpr->exprstate,
                                                                                                                  econtext,
-                                                                                                                 &isNull,
-                                                                                                                 NULL));
+                                                                                                                 &isNull));
                        if (!isNull &&
                                ItemPointerIsValid(itemptr) &&
                                ItemPointerGetBlockNumber(itemptr) < nblocks)
@@ -123,9 +179,8 @@ TidListCreate(TidScanState *tidstate)
                                tidList[numTids++] = *itemptr;
                        }
                }
-               else if (expr && IsA(expr, ScalarArrayOpExpr))
+               else if (tidexpr->exprstate && tidexpr->isarray)
                {
-                       ScalarArrayOpExprState *saexstate = (ScalarArrayOpExprState *) exstate;
                        Datum           arraydatum;
                        ArrayType  *itemarray;
                        Datum      *ipdatums;
@@ -133,16 +188,14 @@ TidListCreate(TidScanState *tidstate)
                        int                     ndatums;
                        int                     i;
 
-                       exstate = (ExprState *) lsecond(saexstate->fxprstate.args);
-                       arraydatum = ExecEvalExprSwitchContext(exstate,
+                       arraydatum = ExecEvalExprSwitchContext(tidexpr->exprstate,
                                                                                                   econtext,
-                                                                                                  &isNull,
-                                                                                                  NULL);
+                                                                                                  &isNull);
                        if (isNull)
                                continue;
                        itemarray = DatumGetArrayTypeP(arraydatum);
                        deconstruct_array(itemarray,
-                                                         TIDOID, SizeOfIptrData, false, 's',
+                                                         TIDOID, sizeof(ItemPointerData), false, 's',
                                                          &ipdatums, &ipnulls, &ndatums);
                        if (numTids + ndatums > numAllocTids)
                        {
@@ -164,13 +217,13 @@ TidListCreate(TidScanState *tidstate)
                        pfree(ipdatums);
                        pfree(ipnulls);
                }
-               else if (expr && IsA(expr, CurrentOfExpr))
+               else
                {
-                       CurrentOfExpr *cexpr = (CurrentOfExpr *) expr;
                        ItemPointerData cursor_tid;
 
-                       if (execCurrentOf(cexpr, econtext,
-                                                  RelationGetRelid(tidstate->ss.ss_currentRelation),
+                       Assert(tidexpr->cexpr);
+                       if (execCurrentOf(tidexpr->cexpr, econtext,
+                                                         RelationGetRelid(tidstate->ss.ss_currentRelation),
                                                          &cursor_tid))
                        {
                                if (numTids >= numAllocTids)
@@ -181,11 +234,8 @@ TidListCreate(TidScanState *tidstate)
                                                                 numAllocTids * sizeof(ItemPointerData));
                                }
                                tidList[numTids++] = cursor_tid;
-                               tidstate->tss_isCurrentOf = true;
                        }
                }
-               else
-                       elog(ERROR, "could not identify CTID expression");
        }
 
        /*
@@ -277,11 +327,15 @@ TidNext(TidScanState *node)
         * First time through, compute the list of TIDs to be visited
         */
        if (node->tss_TidList == NULL)
-               TidListCreate(node);
+               TidListEval(node);
 
        tidList = node->tss_TidList;
        numTids = node->tss_NumTids;
 
+       /*
+        * We use node->tss_htup as the tuple pointer; note this can't just be a
+        * local variable here, as the scan tuple slot will keep a pointer to it.
+        */
        tuple = &(node->tss_htup);
 
        /*
@@ -324,20 +378,18 @@ TidNext(TidScanState *node)
                if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
                {
                        /*
-                        * store the scanned tuple in the scan tuple slot of the scan
+                        * Store the scanned tuple in the scan tuple slot of the scan
                         * state.  Eventually we will only do this and not return a tuple.
-                        * Note: we pass 'false' because tuples returned by amgetnext are
-                        * pointers onto disk pages and were not created with palloc() and
-                        * so should not be pfree()'d.
                         */
-                       ExecStoreTuple(tuple,           /* tuple to store */
-                                                  slot,        /* slot to store in */
-                                                  buffer,              /* buffer associated with tuple  */
-                                                  false);              /* don't pfree */
+                       ExecStoreBufferHeapTuple(tuple, /* tuple to store */
+                                                                        slot,  /* slot to store in */
+                                                                        buffer);       /* buffer associated with
+                                                                                                * tuple */
 
                        /*
                         * At this point we have an extra pin on the buffer, because
-                        * ExecStoreTuple incremented the pin count. Drop our local pin.
+                        * ExecStoreHeapTuple incremented the pin count. Drop our local
+                        * pin.
                         */
                        ReleaseBuffer(buffer);
 
@@ -348,6 +400,8 @@ TidNext(TidScanState *node)
                        node->tss_TidPtr--;
                else
                        node->tss_TidPtr++;
+
+               CHECK_FOR_INTERRUPTS();
        }
 
        /*
@@ -390,9 +444,11 @@ TidRecheck(TidScanState *node, TupleTableSlot *slot)
  *               -- tidPtr is -1.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
-ExecTidScan(TidScanState *node)
+static TupleTableSlot *
+ExecTidScan(PlanState *pstate)
 {
+       TidScanState *node = castNode(TidScanState, pstate);
+
        return ExecScan(&node->ss,
                                        (ExecScanAccessMtd) TidNext,
                                        (ExecScanRecheckMtd) TidRecheck);
@@ -432,41 +488,9 @@ ExecEndTidScan(TidScanState *node)
        /*
         * clear out tuple table slots
         */
-       ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+       if (node->ss.ps.ps_ResultTupleSlot)
+               ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
        ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
-       /*
-        * close the heap relation.
-        */
-       ExecCloseScanRelation(node->ss.ss_currentRelation);
-}
-
-/* ----------------------------------------------------------------
- *             ExecTidMarkPos
- *
- *             Marks scan position by marking the current tid.
- *             Returns nothing.
- * ----------------------------------------------------------------
- */
-void
-ExecTidMarkPos(TidScanState *node)
-{
-       node->tss_MarkTidPtr = node->tss_TidPtr;
-}
-
-/* ----------------------------------------------------------------
- *             ExecTidRestrPos
- *
- *             Restores scan position by restoring the current tid.
- *             Returns nothing.
- *
- *             XXX Assumes previously marked scan position belongs to current tid
- * ----------------------------------------------------------------
- */
-void
-ExecTidRestrPos(TidScanState *node)
-{
-       node->tss_TidPtr = node->tss_MarkTidPtr;
 }
 
 /* ----------------------------------------------------------------
@@ -492,6 +516,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
        tidstate = makeNode(TidScanState);
        tidstate->ss.ps.plan = (Plan *) node;
        tidstate->ss.ps.state = estate;
+       tidstate->ss.ps.ExecProcNode = ExecTidScan;
 
        /*
         * Miscellaneous initialization
@@ -500,28 +525,6 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
         */
        ExecAssignExprContext(estate, &tidstate->ss.ps);
 
-       tidstate->ss.ps.ps_TupFromTlist = false;
-
-       /*
-        * initialize child expressions
-        */
-       tidstate->ss.ps.targetlist = (List *)
-               ExecInitExpr((Expr *) node->scan.plan.targetlist,
-                                        (PlanState *) tidstate);
-       tidstate->ss.ps.qual = (List *)
-               ExecInitExpr((Expr *) node->scan.plan.qual,
-                                        (PlanState *) tidstate);
-
-       tidstate->tss_tidquals = (List *)
-               ExecInitExpr((Expr *) node->tidquals,
-                                        (PlanState *) tidstate);
-
-       /*
-        * tuple table initialization
-        */
-       ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
-       ExecInitScanTupleSlot(estate, &tidstate->ss);
-
        /*
         * mark tid list as not computed yet
         */
@@ -530,24 +533,34 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
        tidstate->tss_TidPtr = -1;
 
        /*
-        * open the base relation and acquire appropriate lock on it.
+        * open the scan relation
         */
-       currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
+       currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
 
        tidstate->ss.ss_currentRelation = currentRelation;
-       tidstate->ss.ss_currentScanDesc = NULL;         /* no heap scan here */
+       tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
 
        /*
         * get the scan type from the relation descriptor.
         */
-       ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation));
+       ExecInitScanTupleSlot(estate, &tidstate->ss,
+                                                 RelationGetDescr(currentRelation),
+                                                 &TTSOpsBufferHeapTuple);
 
        /*
-        * Initialize result tuple type and projection info.
+        * Initialize result type and projection.
         */
-       ExecAssignResultTypeFromTL(&tidstate->ss.ps);
+       ExecInitResultTypeTL(&tidstate->ss.ps);
        ExecAssignScanProjectionInfo(&tidstate->ss);
 
+       /*
+        * initialize child expressions
+        */
+       tidstate->ss.ps.qual =
+               ExecInitQual(node->scan.plan.qual, (PlanState *) tidstate);
+
+       TidExprListCreate(tidstate);
+
        /*
         * all done.
         */