Logo Search packages:      
Sourcecode: postgresql-8.4 version File versions  Download package

nodeSeqscan.c

/*-------------------------------------------------------------------------
 *
 * nodeSeqscan.c
 *      Support routines for sequential scans of relations.
 *
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *      $PostgreSQL: pgsql/src/backend/executor/nodeSeqscan.c,v 1.66 2009/01/01 17:23:42 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */
/*
 * INTERFACE ROUTINES
 *          ExecSeqScan                   sequentially scans a relation.
 *          ExecSeqNext                   retrieve next tuple in sequential order.
 *          ExecInitSeqScan               creates and initializes a seqscan node.
 *          ExecEndSeqScan                releases any storage allocated.
 *          ExecSeqReScan                 rescans the relation
 *          ExecSeqMarkPos                marks scan position
 *          ExecSeqRestrPos               restores scan position
 */
#include "postgres.h"

#include "access/heapam.h"
#include "access/relscan.h"
#include "executor/execdebug.h"
#include "executor/nodeSeqscan.h"

static void InitScanRelation(SeqScanState *node, EState *estate);
static TupleTableSlot *SeqNext(SeqScanState *node);

/* ----------------------------------------------------------------
 *                                  Scan Support
 * ----------------------------------------------------------------
 */
/* ----------------------------------------------------------------
 *          SeqNext
 *
 *          This is a workhorse for ExecSeqScan
 * ----------------------------------------------------------------
 */
static TupleTableSlot *
SeqNext(SeqScanState *node)
{
      HeapTuple   tuple;
      HeapScanDesc scandesc;
      Index       scanrelid;
      EState         *estate;
      ScanDirection direction;
      TupleTableSlot *slot;

      /*
       * get information from the estate and scan state
       */
      estate = node->ps.state;
      scandesc = node->ss_currentScanDesc;
      scanrelid = ((SeqScan *) node->ps.plan)->scanrelid;
      direction = estate->es_direction;
      slot = node->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 SeqScan --> NewNode
       * switching in Init/ReScan plan...
       */
      if (estate->es_evTuple != NULL &&
            estate->es_evTuple[scanrelid - 1] != NULL)
      {
            if (estate->es_evTupleNull[scanrelid - 1])
                  return ExecClearTuple(slot);

            ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
                                 slot, InvalidBuffer, false);

            /*
             * Note that unlike IndexScan, SeqScan never use keys in
             * heap_beginscan (and this is very bad) - so, here we do not check
             * are keys ok or not.
             */

            /* Flag for the next call that no more tuples */
            estate->es_evTupleNull[scanrelid - 1] = true;
            return slot;
      }

      /*
       * get the next tuple from the access methods
       */
      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 ExecStoreTuple will increment the refcount of the buffer; the
       * refcount will not be dropped until the tuple table slot is cleared.
       */
      if (tuple)
            ExecStoreTuple(tuple,   /* tuple to store */
                                 slot,    /* slot to store in */
                                 scandesc->rs_cbuf,         /* buffer associated with this
                                                                         * tuple */
                                 false);  /* don't pfree this pointer */
      else
            ExecClearTuple(slot);

      return slot;
}

/* ----------------------------------------------------------------
 *          ExecSeqScan(node)
 *
 *          Scans the relation sequentially and returns the next qualifying
 *          tuple.
 *          It calls the ExecScan() routine and passes it the access method
 *          which retrieve tuples sequentially.
 *
 */

TupleTableSlot *
ExecSeqScan(SeqScanState *node)
{
      /*
       * use SeqNext as access method
       */
      return ExecScan((ScanState *) node, (ExecScanAccessMtd) SeqNext);
}

/* ----------------------------------------------------------------
 *          InitScanRelation
 *
 *          This does the initialization for scan relations and
 *          subplans of scans.
 * ----------------------------------------------------------------
 */
static void
InitScanRelation(SeqScanState *node, EState *estate)
{
      Relation    currentRelation;
      HeapScanDesc currentScanDesc;

      /*
       * get the relation object id from the relid'th entry in the range table,
       * open that relation and acquire appropriate lock on it.
       */
      currentRelation = ExecOpenScanRelation(estate,
                                                       ((SeqScan *) node->ps.plan)->scanrelid);

      currentScanDesc = heap_beginscan(currentRelation,
                                                       estate->es_snapshot,
                                                       0,
                                                       NULL);

      node->ss_currentRelation = currentRelation;
      node->ss_currentScanDesc = currentScanDesc;

      ExecAssignScanType(node, RelationGetDescr(currentRelation));
}


/* ----------------------------------------------------------------
 *          ExecInitSeqScan
 * ----------------------------------------------------------------
 */
SeqScanState *
ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
{
      SeqScanState *scanstate;

      /*
       * Once upon a time it was possible to have an outerPlan of a SeqScan, but
       * not any more.
       */
      Assert(outerPlan(node) == NULL);
      Assert(innerPlan(node) == NULL);

      /*
       * create state structure
       */
      scanstate = makeNode(SeqScanState);
      scanstate->ps.plan = (Plan *) node;
      scanstate->ps.state = estate;

      /*
       * Miscellaneous initialization
       *
       * create expression context for node
       */
      ExecAssignExprContext(estate, &scanstate->ps);

      /*
       * initialize child expressions
       */
      scanstate->ps.targetlist = (List *)
            ExecInitExpr((Expr *) node->plan.targetlist,
                               (PlanState *) scanstate);
      scanstate->ps.qual = (List *)
            ExecInitExpr((Expr *) node->plan.qual,
                               (PlanState *) scanstate);

#define SEQSCAN_NSLOTS 2

      /*
       * tuple table initialization
       */
      ExecInitResultTupleSlot(estate, &scanstate->ps);
      ExecInitScanTupleSlot(estate, scanstate);

      /*
       * initialize scan relation
       */
      InitScanRelation(scanstate, estate);

      scanstate->ps.ps_TupFromTlist = false;

      /*
       * Initialize result tuple type and projection info.
       */
      ExecAssignResultTypeFromTL(&scanstate->ps);
      ExecAssignScanProjectionInfo(scanstate);

      return scanstate;
}

int
ExecCountSlotsSeqScan(SeqScan *node)
{
      return ExecCountSlotsNode(outerPlan(node)) +
            ExecCountSlotsNode(innerPlan(node)) +
            SEQSCAN_NSLOTS;
}

/* ----------------------------------------------------------------
 *          ExecEndSeqScan
 *
 *          frees any storage allocated through C routines.
 * ----------------------------------------------------------------
 */
void
ExecEndSeqScan(SeqScanState *node)
{
      Relation    relation;
      HeapScanDesc scanDesc;

      /*
       * get information from node
       */
      relation = node->ss_currentRelation;
      scanDesc = node->ss_currentScanDesc;

      /*
       * Free the exprcontext
       */
      ExecFreeExprContext(&node->ps);

      /*
       * clean out the tuple table
       */
      ExecClearTuple(node->ps.ps_ResultTupleSlot);
      ExecClearTuple(node->ss_ScanTupleSlot);

      /*
       * close heap scan
       */
      heap_endscan(scanDesc);

      /*
       * close the heap relation.
       */
      ExecCloseScanRelation(relation);
}

/* ----------------------------------------------------------------
 *                                  Join Support
 * ----------------------------------------------------------------
 */

/* ----------------------------------------------------------------
 *          ExecSeqReScan
 *
 *          Rescans the relation.
 * ----------------------------------------------------------------
 */
void
ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt)
{
      EState         *estate;
      Index       scanrelid;
      HeapScanDesc scan;

      estate = node->ps.state;
      scanrelid = ((SeqScan *) node->ps.plan)->scanrelid;

      node->ps.ps_TupFromTlist = false;

      /* If this is re-scanning of PlanQual ... */
      if (estate->es_evTuple != NULL &&
            estate->es_evTuple[scanrelid - 1] != NULL)
      {
            estate->es_evTupleNull[scanrelid - 1] = false;
            return;
      }

      scan = node->ss_currentScanDesc;

      heap_rescan(scan,             /* scan desc */
                        NULL);                  /* new scan keys */
}

/* ----------------------------------------------------------------
 *          ExecSeqMarkPos(node)
 *
 *          Marks scan position.
 * ----------------------------------------------------------------
 */
void
ExecSeqMarkPos(SeqScanState *node)
{
      HeapScanDesc scan = node->ss_currentScanDesc;

      heap_markpos(scan);
}

/* ----------------------------------------------------------------
 *          ExecSeqRestrPos
 *
 *          Restores scan position.
 * ----------------------------------------------------------------
 */
void
ExecSeqRestrPos(SeqScanState *node)
{
      HeapScanDesc scan = node->ss_currentScanDesc;

      /*
       * Clear any reference to the previously returned tuple.  This is needed
       * because the slot is simply pointing at scan->rs_cbuf, which
       * heap_restrpos will change; we'd have an internally inconsistent slot if
       * we didn't do this.
       */
      ExecClearTuple(node->ss_ScanTupleSlot);

      heap_restrpos(scan);
}

Generated by  Doxygen 1.6.0   Back to index