mirror of
https://github.com/postgres/postgres.git
synced 2026-05-28 03:25:38 -04:00
3908473c80
(WAL logging for this is not done yet, however.) Clean up a number of really crufty things that are no longer needed now that DROP behaves nicely. Make temp table mapper do the right things when drop or rename affecting a temp table is rolled back. Also, remove "relation modified while in use" error check, in favor of locking tables at first reference and holding that lock throughout the statement.
480 lines
12 KiB
C
480 lines
12 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* execAmi.c
|
|
* miscellaneous executor access method routines
|
|
*
|
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* $Id: execAmi.c,v 1.55 2000/11/08 22:09:57 tgl Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
/*
|
|
* INTERFACE ROUTINES
|
|
*
|
|
* ExecOpenScanR \ / amopen
|
|
* ExecBeginScan \ / ambeginscan
|
|
* ExecCloseR \ / amclose
|
|
* ExecInsert \ executor interface / aminsert
|
|
* ExecReScanR / to access methods \ amrescan
|
|
* ExecMarkPos / \ ammarkpos
|
|
* ExecRestrPos / \ amrestpos
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
#include "access/genam.h"
|
|
#include "access/heapam.h"
|
|
#include "catalog/heap.h"
|
|
#include "executor/execdebug.h"
|
|
#include "executor/nodeAgg.h"
|
|
#include "executor/nodeAppend.h"
|
|
#include "executor/nodeGroup.h"
|
|
#include "executor/nodeGroup.h"
|
|
#include "executor/nodeHash.h"
|
|
#include "executor/nodeHashjoin.h"
|
|
#include "executor/nodeIndexscan.h"
|
|
#include "executor/nodeTidscan.h"
|
|
#include "executor/nodeLimit.h"
|
|
#include "executor/nodeMaterial.h"
|
|
#include "executor/nodeMergejoin.h"
|
|
#include "executor/nodeNestloop.h"
|
|
#include "executor/nodeResult.h"
|
|
#include "executor/nodeSeqscan.h"
|
|
#include "executor/nodeSetOp.h"
|
|
#include "executor/nodeSort.h"
|
|
#include "executor/nodeSubplan.h"
|
|
#include "executor/nodeSubqueryscan.h"
|
|
#include "executor/nodeUnique.h"
|
|
|
|
static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
|
|
bool isindex, ScanDirection dir, Snapshot snapshot);
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecOpenScanR
|
|
*
|
|
* old comments:
|
|
* Parameters:
|
|
* relation -- relation to be opened and scanned.
|
|
* nkeys -- number of keys
|
|
* skeys -- keys to restrict scanning
|
|
* isindex -- if this is true, the relation is the relid of
|
|
* an index relation, else it is a heap relation.
|
|
* Returns the relation as(relDesc scanDesc)
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void
|
|
ExecOpenScanR(Oid relOid,
|
|
int nkeys,
|
|
ScanKey skeys,
|
|
bool isindex,
|
|
ScanDirection dir,
|
|
Snapshot snapshot,
|
|
Relation *returnRelation, /* return */
|
|
Pointer *returnScanDesc) /* return */
|
|
{
|
|
Relation relation;
|
|
Pointer scanDesc;
|
|
|
|
/* ----------------
|
|
* note: scanDesc returned by ExecBeginScan can be either
|
|
* a HeapScanDesc or an IndexScanDesc so for now we
|
|
* make it a Pointer. There should be a better scan
|
|
* abstraction someday -cim 9/9/89
|
|
* ----------------
|
|
*/
|
|
|
|
/* ----------------
|
|
* Open the relation with the correct call depending
|
|
* on whether this is a heap relation or an index relation.
|
|
*
|
|
* For a table, acquire AccessShareLock for the duration of the query
|
|
* execution. For indexes, acquire no lock here; the index machinery
|
|
* does its own locks and unlocks. (We rely on having some kind of
|
|
* lock on the parent table to ensure the index won't go away!)
|
|
* ----------------
|
|
*/
|
|
if (isindex)
|
|
relation = index_open(relOid);
|
|
else
|
|
relation = heap_open(relOid, AccessShareLock);
|
|
|
|
scanDesc = ExecBeginScan(relation,
|
|
nkeys,
|
|
skeys,
|
|
isindex,
|
|
dir,
|
|
snapshot);
|
|
|
|
if (returnRelation != NULL)
|
|
*returnRelation = relation;
|
|
if (scanDesc != NULL)
|
|
*returnScanDesc = scanDesc;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecBeginScan
|
|
*
|
|
* beginscans a relation in current direction.
|
|
*
|
|
* XXX fix parameters to AMbeginscan (and btbeginscan)
|
|
* currently we need to pass a flag stating whether
|
|
* or not the scan should begin at an endpoint of
|
|
* the relation.. Right now we always pass false
|
|
* -cim 9/14/89
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
static Pointer
|
|
ExecBeginScan(Relation relation,
|
|
int nkeys,
|
|
ScanKey skeys,
|
|
bool isindex,
|
|
ScanDirection dir,
|
|
Snapshot snapshot)
|
|
{
|
|
Pointer scanDesc;
|
|
|
|
/* ----------------
|
|
* open the appropriate type of scan.
|
|
*
|
|
* Note: ambeginscan()'s second arg is a boolean indicating
|
|
* that the scan should be done in reverse.. That is,
|
|
* if you pass it true, then the scan is backward.
|
|
* ----------------
|
|
*/
|
|
if (isindex)
|
|
{
|
|
scanDesc = (Pointer) index_beginscan(relation,
|
|
false, /* see above comment */
|
|
nkeys,
|
|
skeys);
|
|
}
|
|
else
|
|
{
|
|
scanDesc = (Pointer) heap_beginscan(relation,
|
|
ScanDirectionIsBackward(dir),
|
|
snapshot,
|
|
nkeys,
|
|
skeys);
|
|
}
|
|
|
|
if (scanDesc == NULL)
|
|
elog(DEBUG, "ExecBeginScan: scanDesc = NULL, heap_beginscan failed.");
|
|
|
|
return scanDesc;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecCloseR
|
|
*
|
|
* closes the relation and scan descriptor for a scan node.
|
|
* Also closes index relations and scans for index scans.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void
|
|
ExecCloseR(Plan *node)
|
|
{
|
|
CommonScanState *state;
|
|
Relation relation;
|
|
HeapScanDesc scanDesc;
|
|
|
|
/* ----------------
|
|
* get state for node and shut down the heap scan, if any
|
|
* ----------------
|
|
*/
|
|
switch (nodeTag(node))
|
|
{
|
|
case T_SeqScan:
|
|
state = ((SeqScan *) node)->scanstate;
|
|
break;
|
|
|
|
case T_IndexScan:
|
|
state = ((IndexScan *) node)->scan.scanstate;
|
|
break;
|
|
|
|
case T_TidScan:
|
|
state = ((TidScan *) node)->scan.scanstate;
|
|
break;
|
|
|
|
default:
|
|
elog(DEBUG, "ExecCloseR: not a scan node!");
|
|
return;
|
|
}
|
|
|
|
relation = state->css_currentRelation;
|
|
scanDesc = state->css_currentScanDesc;
|
|
|
|
if (scanDesc != NULL)
|
|
heap_endscan(scanDesc);
|
|
|
|
/* ----------------
|
|
* if this is an index scan then we have to take care
|
|
* of the index relations as well.
|
|
* ----------------
|
|
*/
|
|
if (IsA(node, IndexScan))
|
|
{
|
|
IndexScan *iscan = (IndexScan *) node;
|
|
IndexScanState *indexstate = iscan->indxstate;
|
|
int numIndices;
|
|
RelationPtr indexRelationDescs;
|
|
IndexScanDescPtr indexScanDescs;
|
|
int i;
|
|
|
|
numIndices = indexstate->iss_NumIndices;
|
|
indexRelationDescs = indexstate->iss_RelationDescs;
|
|
indexScanDescs = indexstate->iss_ScanDescs;
|
|
|
|
for (i = 0; i < numIndices; i++)
|
|
{
|
|
/* ----------------
|
|
* shut down each of the index scans and
|
|
* close each of the index relations
|
|
* ----------------
|
|
*/
|
|
if (indexScanDescs[i] != NULL)
|
|
index_endscan(indexScanDescs[i]);
|
|
|
|
if (indexRelationDescs[i] != NULL)
|
|
index_close(indexRelationDescs[i]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Finally, close the heap relation.
|
|
*
|
|
* Currently, we do not release the AccessShareLock acquired by
|
|
* ExecOpenScanR. This lock should be held till end of transaction.
|
|
* (There is a faction that considers this too much locking, however.)
|
|
*/
|
|
if (relation != NULL)
|
|
heap_close(relation, NoLock);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecReScan
|
|
*
|
|
* XXX this should be extended to cope with all the node types..
|
|
*
|
|
* takes the new expression context as an argument, so that
|
|
* index scans needn't have their scan keys updated separately
|
|
* - marcel 09/20/94
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void
|
|
ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
|
{
|
|
|
|
if (node->chgParam != NULL) /* Wow! */
|
|
{
|
|
List *lst;
|
|
|
|
foreach(lst, node->initPlan)
|
|
{
|
|
Plan *splan = ((SubPlan *) lfirst(lst))->plan;
|
|
|
|
if (splan->extParam != NULL) /* don't care about child
|
|
* locParam */
|
|
SetChangedParamList(splan, node->chgParam);
|
|
if (splan->chgParam != NULL)
|
|
ExecReScanSetParamPlan((SubPlan *) lfirst(lst), node);
|
|
}
|
|
foreach(lst, node->subPlan)
|
|
{
|
|
Plan *splan = ((SubPlan *) lfirst(lst))->plan;
|
|
|
|
if (splan->extParam != NULL)
|
|
SetChangedParamList(splan, node->chgParam);
|
|
}
|
|
/* Well. Now set chgParam for left/right trees. */
|
|
if (node->lefttree != NULL)
|
|
SetChangedParamList(node->lefttree, node->chgParam);
|
|
if (node->righttree != NULL)
|
|
SetChangedParamList(node->righttree, node->chgParam);
|
|
}
|
|
|
|
switch (nodeTag(node))
|
|
{
|
|
case T_SeqScan:
|
|
ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_IndexScan:
|
|
ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_TidScan:
|
|
ExecTidReScan((TidScan *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_SubqueryScan:
|
|
ExecSubqueryReScan((SubqueryScan *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_Material:
|
|
ExecMaterialReScan((Material *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_NestLoop:
|
|
ExecReScanNestLoop((NestLoop *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_HashJoin:
|
|
ExecReScanHashJoin((HashJoin *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_Hash:
|
|
ExecReScanHash((Hash *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_Agg:
|
|
ExecReScanAgg((Agg *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_Group:
|
|
ExecReScanGroup((Group *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_Result:
|
|
ExecReScanResult((Result *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_Unique:
|
|
ExecReScanUnique((Unique *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_SetOp:
|
|
ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_Limit:
|
|
ExecReScanLimit((Limit *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_Sort:
|
|
ExecReScanSort((Sort *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_MergeJoin:
|
|
ExecReScanMergeJoin((MergeJoin *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
case T_Append:
|
|
ExecReScanAppend((Append *) node, exprCtxt, parent);
|
|
break;
|
|
|
|
default:
|
|
elog(ERROR, "ExecReScan: node type %d not supported",
|
|
nodeTag(node));
|
|
return;
|
|
}
|
|
|
|
if (node->chgParam != NULL)
|
|
{
|
|
freeList(node->chgParam);
|
|
node->chgParam = NULL;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecReScanR
|
|
*
|
|
* XXX this does not do the right thing with indices yet.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
HeapScanDesc
|
|
ExecReScanR(Relation relDesc, /* LLL relDesc unused */
|
|
HeapScanDesc scanDesc,
|
|
ScanDirection direction,
|
|
int nkeys, /* LLL nkeys unused */
|
|
ScanKey skeys)
|
|
{
|
|
if (scanDesc != NULL)
|
|
heap_rescan(scanDesc, /* scan desc */
|
|
ScanDirectionIsBackward(direction), /* backward flag */
|
|
skeys); /* scan keys */
|
|
|
|
return scanDesc;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecMarkPos
|
|
*
|
|
* Marks the current scan position.
|
|
*
|
|
* XXX Needs to be extended to include all the node types,
|
|
* or at least all the ones that can be directly below a mergejoin.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void
|
|
ExecMarkPos(Plan *node)
|
|
{
|
|
switch (nodeTag(node))
|
|
{
|
|
case T_SeqScan:
|
|
ExecSeqMarkPos((SeqScan *) node);
|
|
break;
|
|
|
|
case T_IndexScan:
|
|
ExecIndexMarkPos((IndexScan *) node);
|
|
break;
|
|
|
|
case T_Material:
|
|
ExecMaterialMarkPos((Material *) node);
|
|
break;
|
|
|
|
case T_Sort:
|
|
ExecSortMarkPos((Sort *) node);
|
|
break;
|
|
|
|
case T_TidScan:
|
|
ExecTidMarkPos((TidScan *) node);
|
|
break;
|
|
|
|
default:
|
|
/* don't make hard error unless caller asks to restore... */
|
|
elog(DEBUG, "ExecMarkPos: node type %d not supported",
|
|
nodeTag(node));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* ExecRestrPos
|
|
*
|
|
* restores the scan position previously saved with ExecMarkPos()
|
|
*
|
|
* XXX Needs to be extended to include all the node types,
|
|
* or at least all the ones that can be directly below a mergejoin.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
void
|
|
ExecRestrPos(Plan *node)
|
|
{
|
|
switch (nodeTag(node))
|
|
{
|
|
case T_SeqScan:
|
|
ExecSeqRestrPos((SeqScan *) node);
|
|
break;
|
|
|
|
case T_IndexScan:
|
|
ExecIndexRestrPos((IndexScan *) node);
|
|
break;
|
|
|
|
case T_Material:
|
|
ExecMaterialRestrPos((Material *) node);
|
|
break;
|
|
|
|
case T_Sort:
|
|
ExecSortRestrPos((Sort *) node);
|
|
break;
|
|
|
|
default:
|
|
elog(ERROR, "ExecRestrPos: node type %d not supported",
|
|
nodeTag(node));
|
|
break;
|
|
}
|
|
}
|