450 lines
12 KiB
C
450 lines
12 KiB
C
|
/*-------------------------------------------------------------------------
|
||
|
*
|
||
|
* nodeSeqscan.c--
|
||
|
* Support routines for sequential scans of relations.
|
||
|
*
|
||
|
* Copyright (c) 1994, Regents of the University of California
|
||
|
*
|
||
|
*
|
||
|
* IDENTIFICATION
|
||
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.1.1.1 1996/07/09 06:21:27 scrappy 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
|
||
|
* ExecMarkPos marks scan position
|
||
|
* ExecRestrPos restores scan position
|
||
|
*
|
||
|
*/
|
||
|
#include "executor/executor.h"
|
||
|
#include "executor/nodeSeqscan.h"
|
||
|
#include "parser/parsetree.h"
|
||
|
|
||
|
/* ----------------------------------------------------------------
|
||
|
* Scan Support
|
||
|
* ----------------------------------------------------------------
|
||
|
*/
|
||
|
/* ----------------------------------------------------------------
|
||
|
* SeqNext
|
||
|
*
|
||
|
* This is a workhorse for ExecSeqScan
|
||
|
* ----------------------------------------------------------------
|
||
|
*/
|
||
|
TupleTableSlot *
|
||
|
SeqNext(SeqScan *node)
|
||
|
{
|
||
|
HeapTuple tuple;
|
||
|
HeapScanDesc scandesc;
|
||
|
CommonScanState *scanstate;
|
||
|
EState *estate;
|
||
|
ScanDirection direction;
|
||
|
TupleTableSlot *slot;
|
||
|
Buffer buffer;
|
||
|
|
||
|
/* ----------------
|
||
|
* get information from the estate and scan state
|
||
|
* ----------------
|
||
|
*/
|
||
|
estate = node->plan.state;
|
||
|
scanstate = node->scanstate;
|
||
|
scandesc = scanstate->css_currentScanDesc;
|
||
|
direction = estate->es_direction;
|
||
|
|
||
|
/* ----------------
|
||
|
* get the next tuple from the access methods
|
||
|
* ----------------
|
||
|
*/
|
||
|
tuple = heap_getnext(scandesc, /* scan desc */
|
||
|
ScanDirectionIsBackward(direction), /*backward flag*/
|
||
|
&buffer); /* return: buffer */
|
||
|
|
||
|
/* ----------------
|
||
|
* 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.
|
||
|
* ----------------
|
||
|
*/
|
||
|
slot = scanstate->css_ScanTupleSlot;
|
||
|
|
||
|
slot = ExecStoreTuple(tuple, /* tuple to store */
|
||
|
slot, /* slot to store in */
|
||
|
buffer, /* buffer associated with this tuple */
|
||
|
false); /* don't pfree this pointer */
|
||
|
|
||
|
/* ----------------
|
||
|
* XXX -- mao says: The sequential scan for heap relations will
|
||
|
* automatically unpin the buffer this tuple is on when we cross
|
||
|
* a page boundary. The clearslot code also does this. We bump
|
||
|
* the pin count on the page here, since we actually have two
|
||
|
* pointers to it -- one in the scan desc and one in the tuple
|
||
|
* table slot. --mar 20 91
|
||
|
* ----------------
|
||
|
*/
|
||
|
ExecIncrSlotBufferRefcnt(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(SeqScan *node)
|
||
|
{
|
||
|
TupleTableSlot *slot;
|
||
|
Plan *outerPlan;
|
||
|
|
||
|
S_printf("ExecSeqScan: scanning node: "); S_nodeDisplay(node);
|
||
|
|
||
|
/* ----------------
|
||
|
* if there is an outer subplan, get a tuple from it
|
||
|
* else, scan the relation
|
||
|
* ----------------
|
||
|
*/
|
||
|
outerPlan = outerPlan((Plan *) node);
|
||
|
if (outerPlan) {
|
||
|
slot = ExecProcNode(outerPlan, (Plan*) node);
|
||
|
} else {
|
||
|
slot = ExecScan(node, SeqNext);
|
||
|
}
|
||
|
|
||
|
S1_printf("ExecSeqScan: returned tuple slot: %d\n", slot);
|
||
|
|
||
|
return slot;
|
||
|
}
|
||
|
|
||
|
/* ----------------------------------------------------------------
|
||
|
* InitScanRelation
|
||
|
*
|
||
|
* This does the initialization for scan relations and
|
||
|
* subplans of scans.
|
||
|
* ----------------------------------------------------------------
|
||
|
*/
|
||
|
Oid
|
||
|
InitScanRelation(SeqScan *node, EState *estate,
|
||
|
CommonScanState *scanstate, Plan *outerPlan)
|
||
|
{
|
||
|
Index relid;
|
||
|
List *rangeTable;
|
||
|
RangeTblEntry *rtentry;
|
||
|
Oid reloid;
|
||
|
TimeQual timeQual;
|
||
|
ScanDirection direction;
|
||
|
Relation currentRelation;
|
||
|
HeapScanDesc currentScanDesc;
|
||
|
RelationInfo *resultRelationInfo;
|
||
|
|
||
|
if (outerPlan == NULL) {
|
||
|
/* ----------------
|
||
|
* if the outer node is nil then we are doing a simple
|
||
|
* sequential scan of a relation...
|
||
|
*
|
||
|
* get the relation object id from the relid'th entry
|
||
|
* in the range table, open that relation and initialize
|
||
|
* the scan state...
|
||
|
* ----------------
|
||
|
*/
|
||
|
relid = node->scanrelid;
|
||
|
rangeTable = estate->es_range_table;
|
||
|
rtentry = rt_fetch(relid, rangeTable);
|
||
|
reloid = rtentry->relid;
|
||
|
timeQual = rtentry->timeQual;
|
||
|
direction = estate->es_direction;
|
||
|
resultRelationInfo = estate->es_result_relation_info;
|
||
|
|
||
|
ExecOpenScanR(reloid, /* relation */
|
||
|
0, /* nkeys */
|
||
|
NULL, /* scan key */
|
||
|
0, /* is index */
|
||
|
direction, /* scan direction */
|
||
|
timeQual, /* time qual */
|
||
|
¤tRelation, /* return: rel desc */
|
||
|
(Pointer *) ¤tScanDesc); /* return: scan desc */
|
||
|
|
||
|
scanstate->css_currentRelation = currentRelation;
|
||
|
scanstate->css_currentScanDesc = currentScanDesc;
|
||
|
|
||
|
ExecAssignScanType(scanstate,
|
||
|
RelationGetTupleDescriptor(currentRelation));
|
||
|
} else {
|
||
|
/* ----------------
|
||
|
* otherwise we are scanning tuples from the
|
||
|
* outer subplan so we initialize the outer plan
|
||
|
* and nullify
|
||
|
* ----------------
|
||
|
*/
|
||
|
ExecInitNode(outerPlan, estate, (Plan*)node);
|
||
|
|
||
|
node->scanrelid = 0;
|
||
|
scanstate->css_currentRelation = NULL;
|
||
|
scanstate->css_currentScanDesc = NULL;
|
||
|
ExecAssignScanType(scanstate, NULL);
|
||
|
reloid = InvalidOid;
|
||
|
}
|
||
|
|
||
|
/* ----------------
|
||
|
* return the relation
|
||
|
* ----------------
|
||
|
*/
|
||
|
return reloid;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ----------------------------------------------------------------
|
||
|
* ExecInitSeqScan
|
||
|
*
|
||
|
* old comments
|
||
|
* Creates the run-time state information for the seqscan node
|
||
|
* and sets the relation id to contain relevant descriptors.
|
||
|
*
|
||
|
* If there is a outer subtree (sort), the outer subtree
|
||
|
* is initialized and the relation id is set to the descriptors
|
||
|
* returned by the subtree.
|
||
|
* ----------------------------------------------------------------
|
||
|
*/
|
||
|
bool
|
||
|
ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
|
||
|
{
|
||
|
CommonScanState *scanstate;
|
||
|
Plan *outerPlan;
|
||
|
Oid reloid;
|
||
|
HeapScanDesc scandesc;
|
||
|
|
||
|
/* ----------------
|
||
|
* assign the node's execution state
|
||
|
* ----------------
|
||
|
*/
|
||
|
node->plan.state = estate;
|
||
|
|
||
|
/* ----------------
|
||
|
* create new CommonScanState for node
|
||
|
* ----------------
|
||
|
*/
|
||
|
scanstate = makeNode(CommonScanState);
|
||
|
node->scanstate = scanstate;
|
||
|
|
||
|
/* ----------------
|
||
|
* Miscellanious initialization
|
||
|
*
|
||
|
* + assign node's base_id
|
||
|
* + create expression context for node
|
||
|
* ----------------
|
||
|
*/
|
||
|
ExecAssignNodeBaseInfo(estate, &scanstate->cstate, parent);
|
||
|
ExecAssignExprContext(estate, &scanstate->cstate);
|
||
|
|
||
|
#define SEQSCAN_NSLOTS 3
|
||
|
/* ----------------
|
||
|
* tuple table initialization
|
||
|
* ----------------
|
||
|
*/
|
||
|
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
||
|
ExecInitScanTupleSlot(estate, scanstate);
|
||
|
|
||
|
/* ----------------
|
||
|
* initialize scan relation or outer subplan
|
||
|
* ----------------
|
||
|
*/
|
||
|
outerPlan = outerPlan((Plan *)node);
|
||
|
|
||
|
reloid = InitScanRelation(node, estate, scanstate, outerPlan);
|
||
|
|
||
|
scandesc = scanstate->css_currentScanDesc;
|
||
|
scanstate->cstate.cs_TupFromTlist = false;
|
||
|
|
||
|
/* ----------------
|
||
|
* initialize tuple type
|
||
|
* ----------------
|
||
|
*/
|
||
|
ExecAssignResultTypeFromTL((Plan*)node, &scanstate->cstate);
|
||
|
ExecAssignProjectionInfo((Plan*)node, &scanstate->cstate);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ExecCountSlotsSeqScan(SeqScan *node)
|
||
|
{
|
||
|
return ExecCountSlotsNode(outerPlan(node)) +
|
||
|
ExecCountSlotsNode(innerPlan(node)) +
|
||
|
SEQSCAN_NSLOTS;
|
||
|
}
|
||
|
|
||
|
/* ----------------------------------------------------------------
|
||
|
* ExecEndSeqScan
|
||
|
*
|
||
|
* frees any storage allocated through C routines.
|
||
|
*| ...and also closes relations and/or shuts down outer subplan
|
||
|
*| -cim 8/14/89
|
||
|
* ----------------------------------------------------------------
|
||
|
*/
|
||
|
void
|
||
|
ExecEndSeqScan(SeqScan *node)
|
||
|
{
|
||
|
CommonScanState *scanstate;
|
||
|
Plan *outerPlan;
|
||
|
|
||
|
/* ----------------
|
||
|
* get information from node
|
||
|
* ----------------
|
||
|
*/
|
||
|
scanstate = node->scanstate;
|
||
|
|
||
|
/* ----------------
|
||
|
* 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 scan relation
|
||
|
* ----------------
|
||
|
*/
|
||
|
ExecCloseR((Plan*) node);
|
||
|
|
||
|
/* ----------------
|
||
|
* clean up outer subtree (does nothing if there is no outerPlan)
|
||
|
* ----------------
|
||
|
*/
|
||
|
outerPlan = outerPlan((Plan *)node);
|
||
|
ExecEndNode(outerPlan, (Plan*)node);
|
||
|
|
||
|
/* ----------------
|
||
|
* clean out the tuple table
|
||
|
* ----------------
|
||
|
*/
|
||
|
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
||
|
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
||
|
}
|
||
|
|
||
|
/* ----------------------------------------------------------------
|
||
|
* Join Support
|
||
|
* ----------------------------------------------------------------
|
||
|
*/
|
||
|
/* ----------------------------------------------------------------
|
||
|
* ExecSeqReScan
|
||
|
*
|
||
|
* Rescans the relation.
|
||
|
* ----------------------------------------------------------------
|
||
|
*/
|
||
|
void
|
||
|
ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan* parent)
|
||
|
{
|
||
|
CommonScanState *scanstate;
|
||
|
EState *estate;
|
||
|
Plan *outerPlan;
|
||
|
Relation rdesc;
|
||
|
HeapScanDesc sdesc;
|
||
|
ScanDirection direction;
|
||
|
|
||
|
scanstate = node->scanstate;
|
||
|
estate = node->plan.state;
|
||
|
|
||
|
outerPlan = outerPlan((Plan*)node);
|
||
|
if (outerPlan) {
|
||
|
/* we are scanning a subplan */
|
||
|
outerPlan = outerPlan((Plan *)node);
|
||
|
ExecReScan(outerPlan, exprCtxt, parent);
|
||
|
} else {
|
||
|
/* otherwise, we are scanning a relation */
|
||
|
rdesc = scanstate->css_currentRelation;
|
||
|
sdesc = scanstate->css_currentScanDesc;
|
||
|
direction = estate->es_direction;
|
||
|
sdesc = ExecReScanR(rdesc, sdesc, direction, 0, NULL);
|
||
|
scanstate->css_currentScanDesc = sdesc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ----------------------------------------------------------------
|
||
|
* ExecSeqMarkPos(node)
|
||
|
*
|
||
|
* Marks scan position.
|
||
|
* ----------------------------------------------------------------
|
||
|
*/
|
||
|
void
|
||
|
ExecSeqMarkPos(SeqScan *node)
|
||
|
{
|
||
|
CommonScanState *scanstate;
|
||
|
Plan *outerPlan;
|
||
|
HeapScanDesc sdesc;
|
||
|
|
||
|
scanstate = node->scanstate;
|
||
|
|
||
|
/* ----------------
|
||
|
* if we are scanning a subplan then propagate
|
||
|
* the ExecMarkPos() request to the subplan
|
||
|
* ----------------
|
||
|
*/
|
||
|
outerPlan = outerPlan((Plan*)node);
|
||
|
if (outerPlan) {
|
||
|
ExecMarkPos(outerPlan);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* ----------------
|
||
|
* otherwise we are scanning a relation so mark the
|
||
|
* position using the access methods..
|
||
|
*
|
||
|
* ----------------
|
||
|
*/
|
||
|
sdesc = scanstate->css_currentScanDesc;
|
||
|
heap_markpos(sdesc);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* ----------------------------------------------------------------
|
||
|
* ExecSeqRestrPos
|
||
|
*
|
||
|
* Restores scan position.
|
||
|
* ----------------------------------------------------------------
|
||
|
*/
|
||
|
void
|
||
|
ExecSeqRestrPos(SeqScan *node)
|
||
|
{
|
||
|
CommonScanState *scanstate;
|
||
|
Plan *outerPlan;
|
||
|
HeapScanDesc sdesc;
|
||
|
|
||
|
scanstate = node->scanstate;
|
||
|
|
||
|
/* ----------------
|
||
|
* if we are scanning a subplan then propagate
|
||
|
* the ExecRestrPos() request to the subplan
|
||
|
* ----------------
|
||
|
*/
|
||
|
outerPlan = outerPlan((Plan*)node);
|
||
|
if (outerPlan) {
|
||
|
ExecRestrPos(outerPlan);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* ----------------
|
||
|
* otherwise we are scanning a relation so restore the
|
||
|
* position using the access methods..
|
||
|
* ----------------
|
||
|
*/
|
||
|
sdesc = scanstate->css_currentScanDesc;
|
||
|
heap_restrpos(sdesc);
|
||
|
}
|