mirror of
https://github.com/postgres/postgres.git
synced 2025-05-21 15:54:08 +03:00
plan nodes, so that the executor does not need to get these items from the range table at runtime. This will avoid needing to include these fields in the compact range table I'm expecting to make the executor use.
483 lines
12 KiB
C
483 lines
12 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* execAmi.c
|
|
* miscellaneous executor access method routines
|
|
*
|
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.92 2007/02/19 02:23:11 tgl Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "executor/execdebug.h"
|
|
#include "executor/instrument.h"
|
|
#include "executor/nodeAgg.h"
|
|
#include "executor/nodeAppend.h"
|
|
#include "executor/nodeBitmapAnd.h"
|
|
#include "executor/nodeBitmapHeapscan.h"
|
|
#include "executor/nodeBitmapIndexscan.h"
|
|
#include "executor/nodeBitmapOr.h"
|
|
#include "executor/nodeFunctionscan.h"
|
|
#include "executor/nodeGroup.h"
|
|
#include "executor/nodeGroup.h"
|
|
#include "executor/nodeHash.h"
|
|
#include "executor/nodeHashjoin.h"
|
|
#include "executor/nodeIndexscan.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/nodeTidscan.h"
|
|
#include "executor/nodeUnique.h"
|
|
#include "executor/nodeValuesscan.h"
|
|
|
|
|
|
/*
|
|
* ExecReScan
|
|
* Reset a plan node so that its output can be re-scanned.
|
|
*
|
|
* Note that if the plan node has parameters that have changed value,
|
|
* the output might be different from last time.
|
|
*
|
|
* The second parameter is currently only used to pass a NestLoop plan's
|
|
* econtext down to its inner child plan, in case that is an indexscan that
|
|
* needs access to variables of the current outer tuple. (The handling of
|
|
* this parameter is currently pretty inconsistent: some callers pass NULL
|
|
* and some pass down their parent's value; so don't rely on it in other
|
|
* situations. It'd probably be better to remove the whole thing and use
|
|
* the generalized parameter mechanism instead.)
|
|
*/
|
|
void
|
|
ExecReScan(PlanState *node, ExprContext *exprCtxt)
|
|
{
|
|
/* If collecting timing stats, update them */
|
|
if (node->instrument)
|
|
InstrEndLoop(node->instrument);
|
|
|
|
/* If we have changed parameters, propagate that info */
|
|
if (node->chgParam != NULL)
|
|
{
|
|
ListCell *l;
|
|
|
|
foreach(l, node->initPlan)
|
|
{
|
|
SubPlanState *sstate = (SubPlanState *) lfirst(l);
|
|
PlanState *splan = sstate->planstate;
|
|
|
|
if (splan->plan->extParam != NULL) /* don't care about child
|
|
* local Params */
|
|
UpdateChangedParamSet(splan, node->chgParam);
|
|
if (splan->chgParam != NULL)
|
|
ExecReScanSetParamPlan(sstate, node);
|
|
}
|
|
foreach(l, node->subPlan)
|
|
{
|
|
SubPlanState *sstate = (SubPlanState *) lfirst(l);
|
|
PlanState *splan = sstate->planstate;
|
|
|
|
if (splan->plan->extParam != NULL)
|
|
UpdateChangedParamSet(splan, node->chgParam);
|
|
}
|
|
/* Well. Now set chgParam for left/right trees. */
|
|
if (node->lefttree != NULL)
|
|
UpdateChangedParamSet(node->lefttree, node->chgParam);
|
|
if (node->righttree != NULL)
|
|
UpdateChangedParamSet(node->righttree, node->chgParam);
|
|
}
|
|
|
|
/* Shut down any SRFs in the plan node's targetlist */
|
|
if (node->ps_ExprContext)
|
|
ReScanExprContext(node->ps_ExprContext);
|
|
|
|
/* And do node-type-specific processing */
|
|
switch (nodeTag(node))
|
|
{
|
|
case T_ResultState:
|
|
ExecReScanResult((ResultState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_AppendState:
|
|
ExecReScanAppend((AppendState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_BitmapAndState:
|
|
ExecReScanBitmapAnd((BitmapAndState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_BitmapOrState:
|
|
ExecReScanBitmapOr((BitmapOrState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_SeqScanState:
|
|
ExecSeqReScan((SeqScanState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_IndexScanState:
|
|
ExecIndexReScan((IndexScanState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_BitmapIndexScanState:
|
|
ExecBitmapIndexReScan((BitmapIndexScanState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_BitmapHeapScanState:
|
|
ExecBitmapHeapReScan((BitmapHeapScanState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_TidScanState:
|
|
ExecTidReScan((TidScanState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_SubqueryScanState:
|
|
ExecSubqueryReScan((SubqueryScanState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_FunctionScanState:
|
|
ExecFunctionReScan((FunctionScanState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_ValuesScanState:
|
|
ExecValuesReScan((ValuesScanState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_NestLoopState:
|
|
ExecReScanNestLoop((NestLoopState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_MergeJoinState:
|
|
ExecReScanMergeJoin((MergeJoinState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_HashJoinState:
|
|
ExecReScanHashJoin((HashJoinState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_MaterialState:
|
|
ExecMaterialReScan((MaterialState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_SortState:
|
|
ExecReScanSort((SortState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_GroupState:
|
|
ExecReScanGroup((GroupState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_AggState:
|
|
ExecReScanAgg((AggState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_UniqueState:
|
|
ExecReScanUnique((UniqueState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_HashState:
|
|
ExecReScanHash((HashState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_SetOpState:
|
|
ExecReScanSetOp((SetOpState *) node, exprCtxt);
|
|
break;
|
|
|
|
case T_LimitState:
|
|
ExecReScanLimit((LimitState *) node, exprCtxt);
|
|
break;
|
|
|
|
default:
|
|
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
|
|
break;
|
|
}
|
|
|
|
if (node->chgParam != NULL)
|
|
{
|
|
bms_free(node->chgParam);
|
|
node->chgParam = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ExecMarkPos
|
|
*
|
|
* Marks the current scan position.
|
|
*/
|
|
void
|
|
ExecMarkPos(PlanState *node)
|
|
{
|
|
switch (nodeTag(node))
|
|
{
|
|
case T_SeqScanState:
|
|
ExecSeqMarkPos((SeqScanState *) node);
|
|
break;
|
|
|
|
case T_IndexScanState:
|
|
ExecIndexMarkPos((IndexScanState *) node);
|
|
break;
|
|
|
|
case T_TidScanState:
|
|
ExecTidMarkPos((TidScanState *) node);
|
|
break;
|
|
|
|
case T_FunctionScanState:
|
|
ExecFunctionMarkPos((FunctionScanState *) node);
|
|
break;
|
|
|
|
case T_ValuesScanState:
|
|
ExecValuesMarkPos((ValuesScanState *) node);
|
|
break;
|
|
|
|
case T_MaterialState:
|
|
ExecMaterialMarkPos((MaterialState *) node);
|
|
break;
|
|
|
|
case T_SortState:
|
|
ExecSortMarkPos((SortState *) node);
|
|
break;
|
|
|
|
case T_ResultState:
|
|
ExecResultMarkPos((ResultState *) node);
|
|
break;
|
|
|
|
default:
|
|
/* don't make hard error unless caller asks to restore... */
|
|
elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ExecRestrPos
|
|
*
|
|
* restores the scan position previously saved with ExecMarkPos()
|
|
*
|
|
* NOTE: the semantics of this are that the first ExecProcNode following
|
|
* the restore operation will yield the same tuple as the first one following
|
|
* the mark operation. It is unspecified what happens to the plan node's
|
|
* result TupleTableSlot. (In most cases the result slot is unchanged by
|
|
* a restore, but the node may choose to clear it or to load it with the
|
|
* restored-to tuple.) Hence the caller should discard any previously
|
|
* returned TupleTableSlot after doing a restore.
|
|
*/
|
|
void
|
|
ExecRestrPos(PlanState *node)
|
|
{
|
|
switch (nodeTag(node))
|
|
{
|
|
case T_SeqScanState:
|
|
ExecSeqRestrPos((SeqScanState *) node);
|
|
break;
|
|
|
|
case T_IndexScanState:
|
|
ExecIndexRestrPos((IndexScanState *) node);
|
|
break;
|
|
|
|
case T_TidScanState:
|
|
ExecTidRestrPos((TidScanState *) node);
|
|
break;
|
|
|
|
case T_FunctionScanState:
|
|
ExecFunctionRestrPos((FunctionScanState *) node);
|
|
break;
|
|
|
|
case T_ValuesScanState:
|
|
ExecValuesRestrPos((ValuesScanState *) node);
|
|
break;
|
|
|
|
case T_MaterialState:
|
|
ExecMaterialRestrPos((MaterialState *) node);
|
|
break;
|
|
|
|
case T_SortState:
|
|
ExecSortRestrPos((SortState *) node);
|
|
break;
|
|
|
|
case T_ResultState:
|
|
ExecResultRestrPos((ResultState *) node);
|
|
break;
|
|
|
|
default:
|
|
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ExecSupportsMarkRestore - does a plan type support mark/restore?
|
|
*
|
|
* XXX Ideally, all plan node types would support mark/restore, and this
|
|
* wouldn't be needed. For now, this had better match the routines above.
|
|
* But note the test is on Plan nodetype, not PlanState nodetype.
|
|
*
|
|
* (However, since the only present use of mark/restore is in mergejoin,
|
|
* there is no need to support mark/restore in any plan type that is not
|
|
* capable of generating ordered output. So the seqscan, tidscan,
|
|
* functionscan, and valuesscan support is actually useless code at present.)
|
|
*/
|
|
bool
|
|
ExecSupportsMarkRestore(NodeTag plantype)
|
|
{
|
|
switch (plantype)
|
|
{
|
|
case T_SeqScan:
|
|
case T_IndexScan:
|
|
case T_TidScan:
|
|
case T_FunctionScan:
|
|
case T_ValuesScan:
|
|
case T_Material:
|
|
case T_Sort:
|
|
return true;
|
|
|
|
case T_Result:
|
|
/*
|
|
* T_Result only supports mark/restore if it has a child plan
|
|
* that does, so we do not have enough information to give a
|
|
* really correct answer. However, for current uses it's
|
|
* enough to always say "false", because this routine is not
|
|
* asked about gating Result plans, only base-case Results.
|
|
*/
|
|
return false;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* ExecSupportsBackwardScan - does a plan type support backwards scanning?
|
|
*
|
|
* Ideally, all plan types would support backwards scan, but that seems
|
|
* unlikely to happen soon. In some cases, a plan node passes the backwards
|
|
* scan down to its children, and so supports backwards scan only if its
|
|
* children do. Therefore, this routine must be passed a complete plan tree.
|
|
*/
|
|
bool
|
|
ExecSupportsBackwardScan(Plan *node)
|
|
{
|
|
if (node == NULL)
|
|
return false;
|
|
|
|
switch (nodeTag(node))
|
|
{
|
|
case T_Result:
|
|
if (outerPlan(node) != NULL)
|
|
return ExecSupportsBackwardScan(outerPlan(node));
|
|
else
|
|
return false;
|
|
|
|
case T_Append:
|
|
{
|
|
ListCell *l;
|
|
|
|
foreach(l, ((Append *) node)->appendplans)
|
|
{
|
|
if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
case T_SeqScan:
|
|
case T_IndexScan:
|
|
case T_TidScan:
|
|
case T_FunctionScan:
|
|
case T_ValuesScan:
|
|
return true;
|
|
|
|
case T_SubqueryScan:
|
|
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
|
|
|
|
case T_Material:
|
|
case T_Sort:
|
|
return true;
|
|
|
|
case T_Unique:
|
|
return ExecSupportsBackwardScan(outerPlan(node));
|
|
|
|
case T_Limit:
|
|
return ExecSupportsBackwardScan(outerPlan(node));
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ExecMayReturnRawTuples
|
|
* Check whether a plan tree may return "raw" disk tuples (that is,
|
|
* pointers to original data in disk buffers, as opposed to temporary
|
|
* tuples constructed by projection steps). In the case of Append,
|
|
* some subplans may return raw tuples and others projected tuples;
|
|
* we return "true" if any of the returned tuples could be raw.
|
|
*
|
|
* This must be passed an already-initialized planstate tree, because we
|
|
* need to look at the results of ExecAssignScanProjectionInfo().
|
|
*/
|
|
bool
|
|
ExecMayReturnRawTuples(PlanState *node)
|
|
{
|
|
/*
|
|
* At a table scan node, we check whether ExecAssignScanProjectionInfo
|
|
* decided to do projection or not. Most non-scan nodes always project
|
|
* and so we can return "false" immediately. For nodes that don't project
|
|
* but just pass up input tuples, we have to recursively examine the input
|
|
* plan node.
|
|
*
|
|
* Note: Hash and Material are listed here because they sometimes return
|
|
* an original input tuple, not a copy. But Sort and SetOp never return
|
|
* an original tuple, so they can be treated like projecting nodes.
|
|
*/
|
|
switch (nodeTag(node))
|
|
{
|
|
/* Table scan nodes */
|
|
case T_SeqScanState:
|
|
case T_IndexScanState:
|
|
case T_BitmapHeapScanState:
|
|
case T_TidScanState:
|
|
if (node->ps_ProjInfo == NULL)
|
|
return true;
|
|
break;
|
|
|
|
case T_SubqueryScanState:
|
|
/* If not projecting, look at input plan */
|
|
if (node->ps_ProjInfo == NULL)
|
|
return ExecMayReturnRawTuples(((SubqueryScanState *) node)->subplan);
|
|
break;
|
|
|
|
/* Non-projecting nodes */
|
|
case T_HashState:
|
|
case T_MaterialState:
|
|
case T_UniqueState:
|
|
case T_LimitState:
|
|
return ExecMayReturnRawTuples(node->lefttree);
|
|
|
|
case T_AppendState:
|
|
{
|
|
AppendState *appendstate = (AppendState *) node;
|
|
int j;
|
|
|
|
for (j = 0; j < appendstate->as_nplans; j++)
|
|
{
|
|
if (ExecMayReturnRawTuples(appendstate->appendplans[j]))
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* All projecting node types come here */
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|