postgresql/src/backend/executor/nodeSeqscan.c

357 lines
8.9 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* nodeSeqscan.c
* Support routines for sequential scans of relations.
*
2003-08-04 04:40:20 +02:00
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
2003-08-04 04:40:20 +02:00
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.45 2003/08/04 02:39:59 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"
1999-07-16 07:00:38 +02:00
#include "access/heapam.h"
1996-11-08 07:02:30 +01:00
#include "executor/execdebug.h"
#include "executor/nodeSeqscan.h"
#include "parser/parsetree.h"
2003-08-04 02:43:34 +02:00
static void InitScanRelation(SeqScanState * node, EState *estate);
static TupleTableSlot *SeqNext(SeqScanState * node);
/* ----------------------------------------------------------------
* Scan Support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* SeqNext
*
* This is a workhorse for ExecSeqScan
* ----------------------------------------------------------------
*/
static TupleTableSlot *
2003-08-04 02:43:34 +02:00
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.
1999-05-25 18:15:34 +02:00
* 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...
*/
1999-05-25 18:15:34 +02:00
if (estate->es_evTuple != NULL &&
estate->es_evTuple[scanrelid - 1] != NULL)
{
ExecClearTuple(slot);
if (estate->es_evTupleNull[scanrelid - 1])
return slot; /* return empty slot */
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
slot, InvalidBuffer, false);
1999-05-25 18:15:34 +02:00
/*
1999-05-25 18:15:34 +02:00
* Note that unlike IndexScan, SeqScan never use keys in
* heap_beginscan (and this is very bad) - so, here we do not
1999-05-25 18:15:34 +02:00
* 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.
*/
slot = ExecStoreTuple(tuple, /* tuple to store */
slot, /* slot to store in */
scandesc->rs_cbuf, /* buffer associated with
* this tuple */
false); /* don't pfree this pointer */
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 *
2003-08-04 02:43:34 +02:00
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
2003-08-04 02:43:34 +02:00
InitScanRelation(SeqScanState * node, EState *estate)
{
Index relid;
List *rangeTable;
RangeTblEntry *rtentry;
Oid reloid;
Relation currentRelation;
HeapScanDesc currentScanDesc;
/*
* get the relation object id from the relid'th entry in the range
* table, open that relation and initialize the scan state.
*
* We acquire AccessShareLock for the duration of the scan.
*/
relid = ((SeqScan *) node->ps.plan)->scanrelid;
rangeTable = estate->es_range_table;
rtentry = rt_fetch(relid, rangeTable);
reloid = rtentry->relid;
currentRelation = heap_open(reloid, AccessShareLock);
currentScanDesc = heap_beginscan(currentRelation,
estate->es_snapshot,
0,
NULL);
node->ss_currentRelation = currentRelation;
node->ss_currentScanDesc = currentScanDesc;
ExecAssignScanType(node, RelationGetDescr(currentRelation), false);
}
/* ----------------------------------------------------------------
* ExecInitSeqScan
* ----------------------------------------------------------------
*/
SeqScanState *
ExecInitSeqScan(SeqScan *node, EState *estate)
{
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
2003-08-04 02:43:34 +02:00
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.
*
* Currently, we do not release the AccessShareLock acquired by
2002-09-04 22:31:48 +02:00
* InitScanRelation. This lock should be held till end of
* transaction. (There is a faction that considers this too much
* locking, however.)
*/
heap_close(relation, NoLock);
}
/* ----------------------------------------------------------------
* Join Support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* ExecSeqReScan
*
* Rescans the relation.
* ----------------------------------------------------------------
*/
void
2003-08-04 02:43:34 +02:00
ExecSeqReScan(SeqScanState * node, ExprContext *exprCtxt)
{
EState *estate;
Index scanrelid;
HeapScanDesc scan;
estate = node->ps.state;
scanrelid = ((SeqScan *) node->ps.plan)->scanrelid;
/* 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
2003-08-04 02:43:34 +02:00
ExecSeqMarkPos(SeqScanState * node)
{
HeapScanDesc scan;
scan = node->ss_currentScanDesc;
heap_markpos(scan);
}
/* ----------------------------------------------------------------
* ExecSeqRestrPos
*
* Restores scan position.
* ----------------------------------------------------------------
*/
void
2003-08-04 02:43:34 +02:00
ExecSeqRestrPos(SeqScanState * node)
{
HeapScanDesc scan;
scan = node->ss_currentScanDesc;
heap_restrpos(scan);
}