* nodeTidscan.c
* Routines to support direct tid scans of relations
*
- * Copyright (c) 1994, Regents of the University of California
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.2 1999/12/16 22:19:44 wieck Exp $
+ * src/backend/executor/nodeTidscan.c
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
*
- * ExecTidScan scans a relation using tids
+ * ExecTidScan scans a relation using tids
* ExecInitTidScan creates and initializes state info.
- * ExecTidReScan rescans the tid relation.
+ * ExecReScanTidScan rescans the tid relation.
* ExecEndTidScan releases all storage.
- * ExecTidMarkPos marks scan position.
- * ExecTidRestrPos restores scan position.
- *
*/
#include "postgres.h"
-#include "executor/executor.h"
+#include "access/heapam.h"
+#include "access/sysattr.h"
+#include "catalog/pg_type.h"
#include "executor/execdebug.h"
#include "executor/nodeTidscan.h"
-#include "optimizer/clauses.h" /* for get_op, get_leftop, get_rightop */
-#include "access/heapam.h"
-#include "parser/parsetree.h"
+#include "miscadmin.h"
+#include "nodes/nodeFuncs.h"
+#include "storage/bufmgr.h"
+#include "utils/array.h"
+#include "utils/rel.h"
-static int TidListCreate(List *, ExprContext *, ItemPointer *);
-static TupleTableSlot *TidNext(TidScan *node);
-static int
-TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList)
+#define IsCTIDVar(node) \
+ ((node) != NULL && \
+ IsA((node), Var) && \
+ ((Var *) (node))->varattno == SelfItemPointerAttributeNumber && \
+ ((Var *) (node))->varlevelsup == 0)
+
+/* one element in tss_tidexprs */
+typedef struct TidExpr
{
- List *lst;
- ItemPointer itemptr;
- bool isNull;
- int numTids = 0;
+ 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 (lst, evalList)
+ foreach(l, node->tidquals)
{
- itemptr = (ItemPointer)ExecEvalExpr(lfirst(lst), econtext,
- &isNull, (bool *)0);
- if (itemptr && ItemPointerIsValid(itemptr))
+ 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))
{
- tidList[numTids] = itemptr;
- numTids++;
+ 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);
}
- return numTids;
+
+ /* 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.
+ *
+ * (The result is actually an array, not a list.)
+ */
+static void
+TidListEval(TidScanState *tidstate)
+{
+ ExprContext *econtext = tidstate->ss.ps.ps_ExprContext;
+ BlockNumber nblocks;
+ ItemPointerData *tidList;
+ int numAllocTids;
+ int numTids;
+ ListCell *l;
+
+ /*
+ * We silently discard any TIDs that are out of range at the time of scan
+ * start. (Since we hold at least AccessShareLock on the table, it won't
+ * be possible for someone to truncate away the blocks we intend to
+ * visit.)
+ */
+ nblocks = RelationGetNumberOfBlocks(tidstate->ss.ss_currentRelation);
+
+ /*
+ * We initialize the array with enough slots for the case that all quals
+ * are simple OpExprs or CurrentOfExprs. If there are any
+ * ScalarArrayOpExprs, we may have to enlarge the array.
+ */
+ numAllocTids = list_length(tidstate->tss_tidexprs);
+ tidList = (ItemPointerData *)
+ palloc(numAllocTids * sizeof(ItemPointerData));
+ numTids = 0;
+
+ foreach(l, tidstate->tss_tidexprs)
+ {
+ TidExpr *tidexpr = (TidExpr *) lfirst(l);
+ ItemPointer itemptr;
+ bool isNull;
+
+ if (tidexpr->exprstate && !tidexpr->isarray)
+ {
+ itemptr = (ItemPointer)
+ DatumGetPointer(ExecEvalExprSwitchContext(tidexpr->exprstate,
+ econtext,
+ &isNull));
+ if (!isNull &&
+ ItemPointerIsValid(itemptr) &&
+ ItemPointerGetBlockNumber(itemptr) < nblocks)
+ {
+ if (numTids >= numAllocTids)
+ {
+ numAllocTids *= 2;
+ tidList = (ItemPointerData *)
+ repalloc(tidList,
+ numAllocTids * sizeof(ItemPointerData));
+ }
+ tidList[numTids++] = *itemptr;
+ }
+ }
+ else if (tidexpr->exprstate && tidexpr->isarray)
+ {
+ Datum arraydatum;
+ ArrayType *itemarray;
+ Datum *ipdatums;
+ bool *ipnulls;
+ int ndatums;
+ int i;
+
+ arraydatum = ExecEvalExprSwitchContext(tidexpr->exprstate,
+ econtext,
+ &isNull);
+ if (isNull)
+ continue;
+ itemarray = DatumGetArrayTypeP(arraydatum);
+ deconstruct_array(itemarray,
+ TIDOID, sizeof(ItemPointerData), false, 's',
+ &ipdatums, &ipnulls, &ndatums);
+ if (numTids + ndatums > numAllocTids)
+ {
+ numAllocTids = numTids + ndatums;
+ tidList = (ItemPointerData *)
+ repalloc(tidList,
+ numAllocTids * sizeof(ItemPointerData));
+ }
+ for (i = 0; i < ndatums; i++)
+ {
+ if (!ipnulls[i])
+ {
+ itemptr = (ItemPointer) DatumGetPointer(ipdatums[i]);
+ if (ItemPointerIsValid(itemptr) &&
+ ItemPointerGetBlockNumber(itemptr) < nblocks)
+ tidList[numTids++] = *itemptr;
+ }
+ }
+ pfree(ipdatums);
+ pfree(ipnulls);
+ }
+ else
+ {
+ ItemPointerData cursor_tid;
+
+ Assert(tidexpr->cexpr);
+ if (execCurrentOf(tidexpr->cexpr, econtext,
+ RelationGetRelid(tidstate->ss.ss_currentRelation),
+ &cursor_tid))
+ {
+ if (numTids >= numAllocTids)
+ {
+ numAllocTids *= 2;
+ tidList = (ItemPointerData *)
+ repalloc(tidList,
+ numAllocTids * sizeof(ItemPointerData));
+ }
+ tidList[numTids++] = cursor_tid;
+ }
+ }
+ }
+
+ /*
+ * Sort the array of TIDs into order, and eliminate duplicates.
+ * Eliminating duplicates is necessary since we want OR semantics across
+ * the list. Sorting makes it easier to detect duplicates, and as a bonus
+ * ensures that we will visit the heap in the most efficient way.
+ */
+ if (numTids > 1)
+ {
+ int lastTid;
+ int i;
+
+ /* CurrentOfExpr could never appear OR'd with something else */
+ Assert(!tidstate->tss_isCurrentOf);
+
+ qsort((void *) tidList, numTids, sizeof(ItemPointerData),
+ itemptr_comparator);
+ lastTid = 0;
+ for (i = 1; i < numTids; i++)
+ {
+ if (!ItemPointerEquals(&tidList[lastTid], &tidList[i]))
+ tidList[++lastTid] = tidList[i];
+ }
+ numTids = lastTid + 1;
+ }
+
+ tidstate->tss_TidList = tidList;
+ tidstate->tss_NumTids = numTids;
+ tidstate->tss_TidPtr = -1;
+}
+
+/*
+ * qsort comparator for ItemPointerData items
+ */
+static int
+itemptr_comparator(const void *a, const void *b)
+{
+ const ItemPointerData *ipa = (const ItemPointerData *) a;
+ const ItemPointerData *ipb = (const ItemPointerData *) b;
+ BlockNumber ba = ItemPointerGetBlockNumber(ipa);
+ BlockNumber bb = ItemPointerGetBlockNumber(ipb);
+ OffsetNumber oa = ItemPointerGetOffsetNumber(ipa);
+ OffsetNumber ob = ItemPointerGetOffsetNumber(ipb);
+
+ if (ba < bb)
+ return -1;
+ if (ba > bb)
+ return 1;
+ if (oa < ob)
+ return -1;
+ if (oa > ob)
+ return 1;
+ return 0;
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
static TupleTableSlot *
-TidNext(TidScan *node)
+TidNext(TidScanState *node)
{
- EState *estate;
- CommonScanState *scanstate;
- TidScanState *tidstate;
- ScanDirection direction;
+ EState *estate;
+ ScanDirection direction;
Snapshot snapshot;
Relation heapRelation;
HeapTuple tuple;
- TupleTableSlot *slot;
+ TupleTableSlot *slot;
Buffer buffer = InvalidBuffer;
- int numTids;
-
+ ItemPointerData *tidList;
+ int numTids;
bool bBackward;
- int tidNumber;
- ItemPointer *tidList, itemptr;
- /* ----------------
- * extract necessary information from tid scan node
- * ----------------
+ /*
+ * extract necessary information from tid scan node
*/
- estate = node->scan.plan.state;
+ estate = node->ss.ps.state;
direction = estate->es_direction;
snapshot = estate->es_snapshot;
- scanstate = node->scan.scanstate;
- tidstate = node->tidstate;
- heapRelation = scanstate->css_currentRelation;
- numTids = tidstate->tss_NumTids;
- tidList = tidstate->tss_TidList;
- slot = scanstate->css_ScanTupleSlot;
+ heapRelation = node->ss.ss_currentRelation;
+ slot = node->ss.ss_ScanTupleSlot;
/*
- * Check if we are evaluating PlanQual for tuple of this relation.
- * Additional checking is not good, but no other way for now. We could
- * introduce new nodes for this case and handle TidScan --> NewNode
- * switching in Init/ReScan plan...
+ * First time through, compute the list of TIDs to be visited
*/
- if (estate->es_evTuple != NULL &&
- estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
- {
- int iptr, numQuals;
-
- ExecClearTuple(slot);
- if (estate->es_evTupleNull[node->scan.scanrelid - 1])
- return slot; /* return empty slot */
-
- slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
- slot->ttc_shouldFree = false;
- /* Flag for the next call that no more tuples */
- estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
- return (slot);
- }
+ if (node->tss_TidList == NULL)
+ TidListEval(node);
+
+ tidList = node->tss_TidList;
+ numTids = node->tss_NumTids;
- tuple = &(tidstate->tss_htup);
+ /*
+ * 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);
- /* ----------------
- * ok, now that we have what we need, fetch an tid tuple.
- * if scanning this tid succeeded then return the
- * appropriate heap tuple.. else return NULL.
- * ----------------
+ /*
+ * Initialize or advance scan position, depending on direction.
*/
bBackward = ScanDirectionIsBackward(direction);
if (bBackward)
{
- tidNumber = numTids - tidstate->tss_TidPtr - 1;
- if (tidNumber < 0)
+ if (node->tss_TidPtr < 0)
{
- tidNumber = 0;
- tidstate->tss_TidPtr = numTids - 1;
+ /* initialize for backward scan */
+ node->tss_TidPtr = numTids - 1;
}
+ else
+ node->tss_TidPtr--;
}
else
{
- if ((tidNumber = tidstate->tss_TidPtr) < 0)
+ if (node->tss_TidPtr < 0)
{
- tidNumber = 0;
- tidstate->tss_TidPtr = 0;
+ /* initialize for forward scan */
+ node->tss_TidPtr = 0;
}
+ else
+ node->tss_TidPtr++;
}
- while (tidNumber < numTids)
+
+ while (node->tss_TidPtr >= 0 && node->tss_TidPtr < numTids)
{
- bool slot_is_valid = false;
+ tuple->t_self = tidList[node->tss_TidPtr];
- itemptr = tidList[tidstate->tss_TidPtr];
- tuple->t_datamcxt = NULL;
- tuple->t_data = NULL;
- if (itemptr)
- {
- tuple->t_self = *(itemptr);
- heap_fetch(heapRelation, snapshot, tuple, &buffer);
- }
- if (tuple->t_data != NULL)
+ /*
+ * For WHERE CURRENT OF, the tuple retrieved from the cursor might
+ * since have been updated; if so, we should fetch the version that is
+ * current according to our snapshot.
+ */
+ if (node->tss_isCurrentOf)
+ heap_get_latest_tid(heapRelation, snapshot, &tuple->t_self);
+
+ if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
{
- bool prev_matches = false;
- int prev_tid;
-
- /* ----------------
- * 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.
- * ----------------
+ /*
+ * Store the scanned tuple in the scan tuple slot of the scan
+ * state. Eventually we will only do this and not return a tuple.
*/
- 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.
- */
- ReleaseBuffer(buffer);
- /*
- * We must check to see if the current tuple would have
- * been matched by an earlier tid, so we don't double
- * report it. We do this by passing the tuple through
- * ExecQual and look for failure with all previous
- * qualifications.
+ * At this point we have an extra pin on the buffer, because
+ * ExecStoreHeapTuple incremented the pin count. Drop our local
+ * pin.
*/
- for (prev_tid = 0; prev_tid < tidstate->tss_TidPtr;
- prev_tid++)
- {
- if (ItemPointerEquals(tidList[prev_tid], &tuple->t_self))
- {
- prev_matches = true;
- break;
- }
- }
- if (!prev_matches)
- slot_is_valid = true;
- else
- ExecClearTuple(slot);
- }
- else if (BufferIsValid(buffer))
ReleaseBuffer(buffer);
- tidNumber++;
+
+ return slot;
+ }
+ /* Bad TID or failed snapshot qual; try next */
if (bBackward)
- tidstate->tss_TidPtr--;
+ node->tss_TidPtr--;
else
- tidstate->tss_TidPtr++;
- if (slot_is_valid)
- return slot;
+ node->tss_TidPtr++;
+
+ CHECK_FOR_INTERRUPTS();
}
- /* ----------------
- * if we get here it means the tid scan failed so we
- * are at the end of the scan..
- * ----------------
+
+ /*
+ * if we get here it means the tid scan failed so we are at the end of the
+ * scan..
*/
return ExecClearTuple(slot);
}
+/*
+ * TidRecheck -- access method routine to recheck a tuple in EvalPlanQual
+ */
+static bool
+TidRecheck(TidScanState *node, TupleTableSlot *slot)
+{
+ /*
+ * XXX shouldn't we check here to make sure tuple matches TID list? In
+ * runtime-key case this is not certain, is it? However, in the WHERE
+ * CURRENT OF case it might not match anyway ...
+ */
+ return true;
+}
+
+
/* ----------------------------------------------------------------
* ExecTidScan(node)
*
* Scans the relation using tids and returns
* the next qualifying tuple in the direction specified.
- * It calls ExecScan() and passes it the access methods which returns
- * the next tuple using the tids.
+ * We call the ExecScan() routine and pass it the appropriate
+ * access method functions.
*
* Conditions:
* -- the "cursor" maintained by the AMI is positioned at the tuple
* Initial States:
* -- the relation indicated is opened for scanning so that the
* "cursor" is positioned before the first qualifying tuple.
- * -- tidPtr points to the first tid.
- * -- state variable ruleFlag = nil.
+ * -- tidPtr is -1.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecTidScan(TidScan *node)
+static TupleTableSlot *
+ExecTidScan(PlanState *pstate)
{
- /* ----------------
- * use TidNext as access method
- * ----------------
- */
- return ExecScan(&node->scan, TidNext);
+ TidScanState *node = castNode(TidScanState, pstate);
+
+ return ExecScan(&node->ss,
+ (ExecScanAccessMtd) TidNext,
+ (ExecScanRecheckMtd) TidRecheck);
}
/* ----------------------------------------------------------------
- * ExecTidReScan(node)
+ * ExecReScanTidScan(node)
* ----------------------------------------------------------------
*/
void
-ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
+ExecReScanTidScan(TidScanState *node)
{
- EState *estate;
- TidScanState *tidstate;
- Plan *outerPlan;
- ItemPointer *tidList;
-
- tidstate = node->tidstate;
- estate = node->scan.plan.state;
- tidstate->tss_TidPtr = -1;
- tidList = tidstate->tss_TidList;
+ if (node->tss_TidList)
+ pfree(node->tss_TidList);
+ node->tss_TidList = NULL;
+ node->tss_NumTids = 0;
+ node->tss_TidPtr = -1;
- if ((outerPlan = outerPlan((Plan *) node)) != NULL)
- {
- /* we are scanning a subplan */
- outerPlan = outerPlan((Plan *) node);
- ExecReScan(outerPlan, exprCtxt, parent);
- }
- else
- /* otherwise, we are scanning a relation */
- {
- /* If this is re-scanning of PlanQual ... */
- if (estate->es_evTuple != NULL &&
- estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
- {
- estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
- return;
- }
-
- /* it's possible in subselects */
- if (exprCtxt == NULL)
- exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;
-
- node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
- tidstate->tss_NumTids = TidListCreate(node->tideval, exprCtxt, tidList);
- }
-
- /* ----------------
- * perhaps return something meaningful
- * ----------------
- */
- return;
+ ExecScanReScan(&node->ss);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
void
-ExecEndTidScan(TidScan *node)
+ExecEndTidScan(TidScanState *node)
{
- CommonScanState *scanstate;
- TidScanState *tidstate;
-
- scanstate = node->scan.scanstate;
- tidstate = node->tidstate;
- if (tidstate && tidstate->tss_TidList)
- pfree(tidstate->tss_TidList);
-
- /* ----------------
- * extract information from the node
- * ----------------
- */
-
- /* ----------------
- * Free the projection info and the scan attribute info
- *
- * Note: we don't ExecFreeResultType(scanstate)
- * because the rule manager depends on the tupType
- * returned by ExecMain(). So for now, this
- * is freed at end-transaction time. -cim 6/2/91
- * ----------------
- */
- ExecFreeProjectionInfo(&scanstate->cstate);
-
- /* ----------------
- * close the heap and tid relations
- * ----------------
+ /*
+ * Free the exprcontext
*/
- ExecCloseR((Plan *) node);
+ ExecFreeExprContext(&node->ss.ps);
- /* ----------------
- * clear out tuple table slots
- * ----------------
+ /*
+ * clear out tuple table slots
*/
- ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
- ExecClearTuple(scanstate->css_ScanTupleSlot);
-/* ExecClearTuple(scanstate->css_RawTupleSlot); */
-}
-
-/* ----------------------------------------------------------------
- * ExecTidMarkPos
- *
- * Marks scan position by marking the current tid.
- * Returns nothing.
- * ----------------------------------------------------------------
- */
-void
-ExecTidMarkPos(TidScan *node)
-{
- TidScanState *tidstate;
-
- tidstate = node->tidstate;
- tidstate->tss_MarkTidPtr = tidstate->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(TidScan *node)
-{
- TidScanState *tidstate;
-
- tidstate = node->tidstate;
- tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
+ if (node->ss.ps.ps_ResultTupleSlot)
+ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+ ExecClearTuple(node->ss.ss_ScanTupleSlot);
}
/* ----------------------------------------------------------------
* estate: the execution state initialized in InitPlan.
* ----------------------------------------------------------------
*/
-bool
-ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
+TidScanState *
+ExecInitTidScan(TidScan *node, EState *estate, int eflags)
{
- TidScanState *tidstate;
- CommonScanState *scanstate;
- ItemPointer *tidList;
- int numTids;
- int tidPtr;
- List *rangeTable;
- RangeTblEntry *rtentry;
- Oid relid;
- Oid reloid;
-
+ TidScanState *tidstate;
Relation currentRelation;
- int baseid;
- List *execParam = NULL;
-
- /* ----------------
- * assign execution state to node
- * ----------------
+ /*
+ * create state structure
*/
- node->scan.plan.state = estate;
+ tidstate = makeNode(TidScanState);
+ tidstate->ss.ps.plan = (Plan *) node;
+ tidstate->ss.ps.state = estate;
+ tidstate->ss.ps.ExecProcNode = ExecTidScan;
- /* --------------------------------
- * Part 1) initialize scan state
+ /*
+ * Miscellaneous initialization
*
- * create new CommonScanState for node
- * --------------------------------
+ * create expression context for node
*/
- scanstate = makeNode(CommonScanState);
-/*
- scanstate->ss_ProcOuterFlag = false;
- scanstate->ss_OldRelId = 0;
-*/
-
- node->scan.scanstate = scanstate;
+ ExecAssignExprContext(estate, &tidstate->ss.ps);
- /* ----------------
- * assign node's base_id .. we don't use AssignNodeBaseid() because
- * the increment is done later on after we assign the tid scan's
- * scanstate. see below.
- * ----------------
- */
- baseid = estate->es_BaseId;
-/* scanstate->csstate.cstate.bnode.base_id = baseid; */
- scanstate->cstate.cs_base_id = baseid;
-
- /* ----------------
- * create expression context for node
- * ----------------
- */
- ExecAssignExprContext(estate, &scanstate->cstate);
-
-#define TIDSCAN_NSLOTS 3
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &scanstate->cstate);
- ExecInitScanTupleSlot(estate, scanstate);
-/* ExecInitRawTupleSlot(estate, scanstate); */
-
- /* ----------------
- * initialize projection info. result type comes from scan desc
- * below..
- * ----------------
- */
- ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
-
- /* --------------------------------
- * Part 2) initialize tid scan state
- *
- * create new TidScanState for node
- * --------------------------------
- */
- tidstate = makeNode(TidScanState);
- node->tidstate = tidstate;
-
- /* ----------------
- * assign base id to tid scan state also
- * ----------------
+ /*
+ * mark tid list as not computed yet
*/
- tidstate->cstate.cs_base_id = baseid;
- baseid++;
- estate->es_BaseId = baseid;
+ tidstate->tss_TidList = NULL;
+ tidstate->tss_NumTids = 0;
+ tidstate->tss_TidPtr = -1;
- /* ----------------
- * get the tid node information
- * ----------------
+ /*
+ * open the scan relation
*/
- tidList = (ItemPointer *)palloc(length(node->tideval) * sizeof(ItemPointer));
- numTids = 0;
- if (!node->needRescan)
- numTids = TidListCreate(node->tideval, scanstate->cstate.cs_ExprContext, tidList);
- tidPtr = -1;
+ currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
- CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext);
+ tidstate->ss.ss_currentRelation = currentRelation;
+ tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
- tidstate->tss_NumTids = numTids;
- tidstate->tss_TidPtr = tidPtr;
- tidstate->tss_TidList = tidList;
-
- /* ----------------
- * get the range table and direction information
- * from the execution state (these are needed to
- * open the relations).
- * ----------------
+ /*
+ * get the scan type from the relation descriptor.
*/
- rangeTable = estate->es_range_table;
+ ExecInitScanTupleSlot(estate, &tidstate->ss,
+ RelationGetDescr(currentRelation),
+ &TTSOpsBufferHeapTuple);
- /* ----------------
- * open the base relation
- * ----------------
- */
- relid = node->scan.scanrelid;
- rtentry = rt_fetch(relid, rangeTable);
- reloid = rtentry->relid;
-
- currentRelation = heap_open(reloid, AccessShareLock);
- if (currentRelation == NULL)
- elog(ERROR, "ExecInitTidScan heap_open failed.");
- scanstate->css_currentRelation = currentRelation;
- scanstate->css_currentScanDesc = 0;
-
- /* ----------------
- * get the scan type from the relation descriptor.
- * ----------------
+ /*
+ * Initialize result type and projection.
*/
- ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
- ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
+ ExecInitResultTypeTL(&tidstate->ss.ps);
+ ExecAssignScanProjectionInfo(&tidstate->ss);
- /* ----------------
- * tid scans don't have subtrees..
- * ----------------
+ /*
+ * initialize child expressions
*/
-/* scanstate->ss_ProcOuterFlag = false; */
+ tidstate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual, (PlanState *) tidstate);
- tidstate->cstate.cs_TupFromTlist = false;
+ TidExprListCreate(tidstate);
/*
- * if there are some PARAM_EXEC in skankeys then force tid rescan on
- * first scan.
- */
- ((Plan *) node)->chgParam = execParam;
-
- /* ----------------
- * all done.
- * ----------------
+ * all done.
*/
- return TRUE;
-}
-
-int
-ExecCountSlotsTidScan(TidScan *node)
-{
- return ExecCountSlotsNode(outerPlan((Plan *) node)) +
- ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS;
+ return tidstate;
}