Support for subselects.

ExecReScan for nodeAgg, nodeHash, nodeHashjoin, nodeNestloop and nodeResult.
Fixed ExecReScan for nodeMaterial.
Get rid of #ifdef INDEXSCAN_PATCH.
Get rid of ExecMarkPos and ExecRestrPos in nodeNestloop.
This commit is contained in:
Vadim B. Mikheev 1998-02-13 03:26:53 +00:00
parent 13637df458
commit 1a105cefbd
15 changed files with 677 additions and 153 deletions

View File

@ -4,7 +4,7 @@
# Makefile for executor
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.5 1997/12/20 00:23:37 scrappy Exp $
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.6 1998/02/13 03:26:35 vadim Exp $
#
#-------------------------------------------------------------------------
@ -20,7 +20,7 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \
execUtils.o functions.o nodeAppend.o nodeAgg.o nodeHash.o \
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSort.o \
nodeUnique.o nodeTee.o nodeGroup.o spi.o
nodeUnique.o nodeTee.o nodeGroup.o spi.o nodeSubplan.o
all: SUBSYS.o

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.16 1998/01/16 23:19:47 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.17 1998/02/13 03:26:36 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -37,6 +37,13 @@
#include "executor/nodeIndexscan.h"
#include "executor/nodeSort.h"
#include "executor/nodeTee.h"
#include "executor/nodeMaterial.h"
#include "executor/nodeNestloop.h"
#include "executor/nodeHashjoin.h"
#include "executor/nodeHash.h"
#include "executor/nodeAgg.h"
#include "executor/nodeResult.h"
#include "executor/nodeSubplan.h"
#include "executor/execdebug.h"
#include "optimizer/internal.h" /* for _TEMP_RELATION_ID_ */
#include "access/genam.h"
@ -287,35 +294,82 @@ ExecCloseR(Plan *node)
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:
case T_SeqScan:
ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
return;
break;
case T_IndexScan:
ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
return;
break;
case T_Material:
ExecMaterialReScan((Material*) node, exprCtxt, parent);
break;
/*
* the first call to ExecReScan should have no effect because
* everything is initialized properly already. the following
* calls will be handled by ExecSeqReScan() because the nodes
* below the Material node have already been materialized into
* a temp relation.
*/
return;
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_Result:
ExecReScanResult((Result*) node, exprCtxt, parent);
break;
/*
* Tee is never used
case T_Tee:
ExecTeeReScan((Tee *) node, exprCtxt, parent);
break;
*/
default:
elog(ERROR, "ExecReScan: not a seqscan or indexscan node.");
elog(ERROR, "ExecReScan: node type %u not supported", nodeTag(node));
return;
}
if ( node->chgParam != NULL )
{
freeList (node->chgParam);
node->chgParam = NULL;
}
}
/* ----------------------------------------------------------------
@ -352,7 +406,7 @@ ExecMarkPos(Plan *node)
{
switch (nodeTag(node))
{
case T_SeqScan:
case T_SeqScan:
ExecSeqMarkPos((SeqScan *) node);
break;
@ -365,7 +419,7 @@ ExecMarkPos(Plan *node)
break;
default:
/* elog(DEBUG, "ExecMarkPos: unsupported node type"); */
elog(DEBUG, "ExecMarkPos: node type %u not supported", nodeTag(node));
break;
}
return;
@ -382,7 +436,7 @@ ExecRestrPos(Plan *node)
{
switch (nodeTag(node))
{
case T_SeqScan:
case T_SeqScan:
ExecSeqRestrPos((SeqScan *) node);
return;
@ -395,7 +449,7 @@ ExecRestrPos(Plan *node)
return;
default:
/* elog(DEBUG, "ExecRestrPos: node type not supported"); */
elog(DEBUG, "ExecRestrPos: node type %u not supported", nodeTag(node));
return;
}
}

View File

@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.41 1998/02/10 04:00:45 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.42 1998/02/13 03:26:38 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -110,7 +110,14 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
/* sanity checks */
Assert(queryDesc != NULL);
if (queryDesc->plantree->nParamExec > 0)
{
estate->es_param_exec_vals = (ParamExecData*)
palloc (queryDesc->plantree->nParamExec * sizeof (ParamExecData));
memset (estate->es_param_exec_vals, 0 , queryDesc->plantree->nParamExec * sizeof (ParamExecData));
}
result = InitPlan(queryDesc->operation,
queryDesc->parsetree,
queryDesc->plantree,
@ -177,31 +184,6 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
estate->es_processed = 0;
estate->es_lastoid = InvalidOid;
#if 0
/*
* It doesn't work in common case (i.g. if function has a aggregate).
* Now we store parameter values before ExecutorStart. - vadim
* 01/22/97
*/
#ifdef INDEXSCAN_PATCH
/*
* If the plan is an index scan and some of the scan key are function
* arguments rescan the indices after the parameter values have been
* stored in the execution state. DZ - 27-8-1996
*/
if ((nodeTag(plan) == T_IndexScan) &&
(((IndexScan *) plan)->indxstate->iss_RuntimeKeyInfo != NULL))
{
ExprContext *econtext;
econtext = ((IndexScan *) plan)->scan.scanstate->cstate.cs_ExprContext;
ExecIndexReScan((IndexScan *) plan, econtext, plan);
}
#endif
#endif
switch (feature)
{
@ -1246,7 +1228,8 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
econtext->ecxt_outertuple = NULL; /* outer tuple slot */
econtext->ecxt_relation = NULL; /* relation */
econtext->ecxt_relid = 0; /* relid */
econtext->ecxt_param_list_info = NULL; /* param list info */
econtext->ecxt_param_list_info = NULL; /* param list info */
econtext->ecxt_param_exec_vals = NULL; /* exec param values */
econtext->ecxt_range_table = NULL; /* range table */
for (i = 0; i < ndef; i++)
{
@ -1322,6 +1305,7 @@ ExecRelCheck(Relation rel, HeapTuple tuple)
econtext->ecxt_relation = rel; /* relation */
econtext->ecxt_relid = 0; /* relid */
econtext->ecxt_param_list_info = NULL; /* param list info */
econtext->ecxt_param_exec_vals = NULL; /* exec param values */
econtext->ecxt_range_table = rtlist; /* range table */
for (i = 0; i < ncheck; i++)

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.7 1998/01/07 21:02:44 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.8 1998/02/13 03:26:40 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -89,6 +89,7 @@
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "executor/nodeTee.h"
#include "executor/nodeSubplan.h"
/* ------------------------------------------------------------------------
* ExecInitNode
@ -106,6 +107,7 @@ bool
ExecInitNode(Plan *node, EState *estate, Plan *parent)
{
bool result;
List *subp;
/* ----------------
* do nothing when we get to the end
@ -114,7 +116,14 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
*/
if (node == NULL)
return FALSE;
foreach (subp, node->initPlan)
{
result = ExecInitSubPlan ((SubPlan*) lfirst (subp), estate, node);
if ( result == FALSE )
return (FALSE);
}
switch (nodeTag(node))
{
/* ----------------
@ -190,10 +199,19 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
break;
default:
elog(DEBUG, "ExecInitNode: node not yet supported: %d",
nodeTag(node));
elog(ERROR, "ExecInitNode: node %d unsupported", nodeTag(node));
result = FALSE;
}
if ( result != FALSE )
{
foreach (subp, node->subPlan)
{
result = ExecInitSubPlan ((SubPlan*) lfirst (subp), estate, node);
if ( result == FALSE )
return (FALSE);
}
}
return result;
}
@ -217,7 +235,10 @@ ExecProcNode(Plan *node, Plan *parent)
*/
if (node == NULL)
return NULL;
if ( node->chgParam != NULL ) /* something changed */
ExecReScan (node, NULL, parent); /* let ReScan handle this */
switch (nodeTag(node))
{
/* ----------------
@ -293,9 +314,8 @@ ExecProcNode(Plan *node, Plan *parent)
break;
default:
elog(DEBUG, "ExecProcNode: node not yet supported: %d",
nodeTag(node));
result = FALSE;
elog(ERROR, "ExecProcNode: node %d unsupported", nodeTag(node));
result = NULL;
}
return result;
@ -389,6 +409,8 @@ ExecCountSlotsNode(Plan *node)
void
ExecEndNode(Plan *node, Plan *parent)
{
List *subp;
/* ----------------
* do nothing when we get to the end
* of a leaf on tree.
@ -396,6 +418,20 @@ ExecEndNode(Plan *node, Plan *parent)
*/
if (node == NULL)
return;
foreach (subp, node->initPlan)
{
ExecEndSubPlan ((SubPlan*) lfirst (subp));
}
foreach (subp, node->subPlan)
{
ExecEndSubPlan ((SubPlan*) lfirst (subp));
}
if ( node->chgParam != NULL )
{
freeList (node->chgParam);
node->chgParam = NULL;
}
switch (nodeTag(node))
{
@ -476,8 +512,7 @@ ExecEndNode(Plan *node, Plan *parent)
break;
default:
elog(DEBUG, "ExecEndNode: node not yet supported",
nodeTag(node));
elog(ERROR, "ExecEndNode: node %d unsupported", nodeTag(node));
break;
}
}

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.24 1998/01/31 04:38:27 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.25 1998/02/13 03:26:42 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -46,6 +46,7 @@
#include "executor/execdebug.h"
#include "executor/execFlatten.h"
#include "executor/functions.h"
#include "executor/nodeSubplan.h"
#include "access/heapam.h"
#include "utils/memutils.h"
#include "utils/builtins.h"
@ -374,14 +375,23 @@ ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
{
char *thisParameterName;
int thisParameterKind;
AttrNumber thisParameterId;
int thisParameterKind = expression->paramkind;
AttrNumber thisParameterId = expression->paramid;
int matchFound;
ParamListInfo paramList;
if ( thisParameterKind == PARAM_EXEC )
{
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[thisParameterId]);
if ( prm->execPlan != NULL )
ExecSetParamPlan (prm->execPlan);
Assert (prm->execPlan == NULL);
*isNull = prm->isnull;
return (prm->value);
}
thisParameterName = expression->paramname;
thisParameterKind = expression->paramkind;
thisParameterId = expression->paramid;
paramList = econtext->ecxt_param_list_info;
*isNull = false;
@ -1227,14 +1237,17 @@ ExecEvalExpr(Node *expression,
case NOT_EXPR:
retDatum = (Datum) ExecEvalNot(expr, econtext, isNull);
break;
case SUBPLAN_EXPR:
retDatum = (Datum) ExecSubPlan((SubPlan*) expr->oper, expr->args, econtext);
break;
default:
elog(ERROR, "ExecEvalExpr: unknown expression type");
elog(ERROR, "ExecEvalExpr: unknown expression type %d", expr->opType);
break;
}
break;
}
default:
elog(ERROR, "ExecEvalExpr: unknown expression type");
elog(ERROR, "ExecEvalExpr: unknown expression type %d", nodeTag(expression));
break;
}

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.28 1998/02/10 04:00:52 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.29 1998/02/13 03:26:43 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -180,11 +180,6 @@ void
ExecAssignExprContext(EState *estate, CommonState *commonstate)
{
ExprContext *econtext;
ParamListInfo paraminfo;
List *rangeTable;
paraminfo = estate->es_param_list_info;
rangeTable = estate->es_range_table;
econtext = makeNode(ExprContext);
econtext->ecxt_scantuple = NULL; /* scan tuple slot */
@ -192,8 +187,9 @@ ExecAssignExprContext(EState *estate, CommonState *commonstate)
econtext->ecxt_outertuple = NULL; /* outer tuple slot */
econtext->ecxt_relation = NULL; /* relation */
econtext->ecxt_relid = 0; /* relid */
econtext->ecxt_param_list_info = paraminfo; /* param list info */
econtext->ecxt_range_table = rangeTable; /* range table */
econtext->ecxt_param_list_info = estate->es_param_list_info;
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
econtext->ecxt_range_table = estate->es_range_table; /* range table */
commonstate->cs_ExprContext = econtext;
}
@ -1179,3 +1175,25 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
if (econtext != NULL)
pfree(econtext);
}
void
SetChangedParamList (Plan *node, List *newchg)
{
List *nl;
foreach (nl, newchg)
{
int paramId = lfirsti(nl);
/* if this node doesn't depend on a param ... */
if ( !intMember (paramId, node->extParam) &&
!intMember (paramId, node->locParam) )
continue;
/* if this param is already in list of changed ones ... */
if ( intMember (paramId, node->chgParam) )
continue;
/* else - add this param to the list */
node->chgParam = lappendi (node->chgParam, paramId);
}
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.15 1998/01/31 04:38:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.16 1998/02/13 03:26:44 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -303,8 +303,6 @@ postquel_execute(execution_state *es,
TupleTableSlot *slot;
Datum value;
#ifdef INDEXSCAN_PATCH
/*
* It's more right place to do it (before
* postquel_start->ExecutorStart). Now
@ -313,17 +311,12 @@ postquel_execute(execution_state *es,
*/
if (fcache->nargs > 0)
postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
#endif
if (es->status == F_EXEC_START)
{
postquel_start(es);
es->status = F_EXEC_RUN;
}
#ifndef INDEXSCAN_PATCH
if (fcache->nargs > 0)
postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
#endif
slot = postquel_getnext(es);

View File

@ -676,3 +676,21 @@ aggGetAttr(TupleTableSlot *slot,
return result;
}
void
ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
{
AggState *aggstate = node->aggstate;
ExprContext *econtext = aggstate->csstate.cstate.cs_ExprContext;
aggstate->agg_done = FALSE;
MemSet(econtext->ecxt_values, 0, sizeof(Datum) * length(node->aggs));
MemSet(econtext->ecxt_nulls, 0, length(node->aggs));
/*
* if chgParam of subnode is not null then plan
* will be re-scanned by first ExecProcNode.
*/
if (((Plan*) node)->lefttree->chgParam == NULL)
ExecReScan (((Plan*) node)->lefttree, exprCtxt, (Plan *) node);
}

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.18 1998/02/11 19:10:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.19 1998/02/13 03:26:46 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -890,3 +890,23 @@ mk_hj_temp(char *tempname)
sprintf(tempname, "HJ%d.%d", (int) MyProcPid, hjtmpcnt);
hjtmpcnt = (hjtmpcnt + 1) % 1000;
}
void
ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent)
{
HashState *hashstate = node->hashstate;
if (hashstate->hashBatches != NULL)
{
pfree(hashstate->hashBatches);
hashstate->hashBatches = NULL;
}
/*
* if chgParam of subnode is not null then plan
* will be re-scanned by first ExecProcNode.
*/
if (((Plan*) node)->lefttree->chgParam == NULL)
ExecReScan (((Plan*) node)->lefttree, exprCtxt, (Plan *) node);
}

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.9 1998/01/13 04:03:58 scrappy Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.10 1998/02/13 03:26:47 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -154,6 +154,9 @@ ExecHashJoin(HashJoin *node)
curbatch = 0;
node->hashdone = true;
}
else if (hashtable == NULL)
return (NULL);
nbatch = hashtable->nbatch;
outerbatches = hjstate->hj_OuterBatches;
if (nbatch > 0 && outerbatches == NULL)
@ -209,14 +212,12 @@ ExecHashJoin(HashJoin *node)
while (curbatch <= nbatch && TupIsNull(outerTupleSlot))
{
/*
* if the current batch runs out, switch to new batch
*/
curbatch = ExecHashJoinNewBatch(hjstate);
if (curbatch > nbatch)
{
/*
* when the last batch runs out, clean up
*/
@ -349,7 +350,6 @@ ExecHashJoin(HashJoin *node)
curbatch = ExecHashJoinNewBatch(hjstate);
if (curbatch > nbatch)
{
/*
* when the last batch runs out, clean up
*/
@ -841,3 +841,45 @@ ExecHashJoinSaveTuple(HeapTuple heapTuple,
return position;
}
void
ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent)
{
HashJoinState *hjstate = node->hashjoinstate;
if (!node->hashdone)
return;
node->hashdone = false;
/*
* Unfortunately, currently we have to destroy hashtable
* in all cases...
*/
if (hjstate->hj_HashTable)
{
ExecHashTableDestroy(hjstate->hj_HashTable);
hjstate->hj_HashTable = NULL;
}
hjstate->hj_CurBucket = (HashBucket) NULL;
hjstate->hj_CurTuple = (HeapTuple) NULL;
hjstate->hj_CurOTuple = (OverflowTuple) NULL;
hjstate->hj_InnerHashKey = (Var *) NULL;
hjstate->hj_OuterBatches = (File *) NULL;
hjstate->hj_InnerBatches = (File *) NULL;
hjstate->hj_OuterReadPos = (char *) NULL;
hjstate->hj_OuterReadBlk = (int) 0;
hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
hjstate->jstate.cs_TupFromTlist = (bool) false;
/*
* if chgParam of subnodes is not null then plans
* will be re-scanned by first ExecProcNode.
*/
if (((Plan*) node)->lefttree->chgParam == NULL)
ExecReScan (((Plan*) node)->lefttree, exprCtxt, (Plan *) node);
if (((Plan*) node)->righttree->chgParam == NULL)
ExecReScan (((Plan*) node)->righttree, exprCtxt, (Plan *) node);
}

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.13 1998/01/07 21:02:54 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.14 1998/02/13 03:26:49 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -247,7 +247,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
indexstate = node->indxstate;
estate = node->scan.plan.state;
direction = estate->es_direction;
indexstate = node->indxstate;
numIndices = indexstate->iss_NumIndices;
scanDescs = indexstate->iss_ScanDescs;
scanKeys = indexstate->iss_ScanKeys;
@ -268,7 +267,11 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
n_keys = numScanKeys[indexPtr];
run_keys = (int *) runtimeKeyInfo[indexPtr];
scan_keys = (ScanKey) scanKeys[indexPtr];
/* it's possible in subselects */
if (exprCtxt == NULL)
exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;
for (j = 0; j < n_keys; j++)
{
@ -485,6 +488,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
HeapScanDesc currentScanDesc;
ScanDirection direction;
int baseid;
List *execParam = NULL;
/* ----------------
* assign execution state to node
@ -696,7 +701,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
*/
run_keys[j] = NO_OP;
scanvalue = ((Const *) leftop)->constvalue;
#ifdef INDEXSCAN_PATCH
}
else if (IsA(leftop, Param))
{
@ -707,13 +711,24 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
* it identifies the value to place in our scan key.
* ----------------
*/
run_keys[j] = NO_OP;
scanvalue = ExecEvalParam((Param *) leftop,
scanstate->cstate.cs_ExprContext,
&isnull);
if (isnull)
flags |= SK_ISNULL;
#endif
/* Life was so easy before ... subselects */
if ( ((Param *) leftop)->paramkind == PARAM_EXEC )
{
have_runtime_keys = true;
run_keys[j] = LEFT_OP;
execParam = lappendi (execParam, ((Param*) leftop)->paramid);
}
else
{
scanvalue = ExecEvalParam((Param *) leftop,
scanstate->cstate.cs_ExprContext,
&isnull);
if (isnull)
flags |= SK_ISNULL;
run_keys[j] = NO_OP;
}
}
else if (leftop != NULL &&
is_funcclause(leftop) &&
@ -779,7 +794,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
*/
run_keys[j] = NO_OP;
scanvalue = ((Const *) rightop)->constvalue;
#ifdef INDEXSCAN_PATCH
}
else if (IsA(rightop, Param))
{
@ -790,13 +804,24 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
* it identifies the value to place in our scan key.
* ----------------
*/
run_keys[j] = NO_OP;
scanvalue = ExecEvalParam((Param *) rightop,
scanstate->cstate.cs_ExprContext,
&isnull);
if (isnull)
flags |= SK_ISNULL;
#endif
/* Life was so easy before ... subselects */
if ( ((Param *) rightop)->paramkind == PARAM_EXEC )
{
have_runtime_keys = true;
run_keys[j] = RIGHT_OP;
execParam = lappendi (execParam, ((Param*) rightop)->paramid);
}
else
{
scanvalue = ExecEvalParam((Param *) rightop,
scanstate->cstate.cs_ExprContext,
&isnull);
if (isnull)
flags |= SK_ISNULL;
run_keys[j] = NO_OP;
}
}
else if (rightop != NULL &&
is_funcclause(rightop) &&
@ -964,7 +989,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
indexstate->iss_ScanDescs = scanDescs;
indexstate->cstate.cs_TupFromTlist = false;
/*
* if there are some PARAM_EXEC in skankeys then
* force index rescan on first scan.
*/
((Plan*) node)->chgParam = execParam;
/* ----------------
* all done.
* ----------------

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.11 1997/11/28 17:27:25 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.12 1998/02/13 03:26:50 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -341,6 +341,27 @@ ExecEndMaterial(Material *node)
ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
}
/* ----------------------------------------------------------------
* ExecMaterialReScan
*
* Rescans the temporary relation.
* ----------------------------------------------------------------
*/
void
ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
{
MaterialState *matstate = node->matstate;
if (matstate->mat_Flag == false)
return;
matstate->csstate.css_currentScanDesc =
ExecReScanR (matstate->csstate.css_currentRelation,
matstate->csstate.css_currentScanDesc,
node->plan.state->es_direction, 0, NULL);
}
#ifdef NOT_USED /* not used */
/* ----------------------------------------------------------------
* ExecMaterialMarkPos

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.7 1997/09/08 21:43:16 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.8 1998/02/13 03:26:51 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -86,7 +86,8 @@ ExecNestLoop(NestLoop *node, Plan *parent)
*/
econtext = nlstate->jstate.cs_ExprContext;
/* ---------------- * get the current outer tuple
/* ----------------
* get the current outer tuple
* ----------------
*/
outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
@ -118,16 +119,9 @@ ExecNestLoop(NestLoop *node, Plan *parent)
*/
needNewOuterTuple = false;
/* ----------------
* If outer tuple is not null then that means
* we are in the middle of a scan and we should
* restore our previously saved scan position.
* ----------------
*/
if (!TupIsNull(outerTupleSlot))
{
ENL1_printf("have outer tuple, restoring outer plan");
ExecRestrPos(outerPlan);
ENL1_printf("have outer tuple, deal with it");
}
else
{
@ -179,14 +173,7 @@ ExecNestLoop(NestLoop *node, Plan *parent)
return NULL;
}
/* ----------------
* we have a new outer tuple so we mark our position
* in the outer scan and save the outer tuple in the
* NestLoop state
* ----------------
*/
ENL1_printf("saving new outer tuple information");
ExecMarkPos(outerPlan);
nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
/* ----------------
@ -385,3 +372,30 @@ ExecEndNestLoop(NestLoop *node)
NL1_printf("ExecEndNestLoop: %s\n",
"node processing ended");
}
/* ----------------------------------------------------------------
* ExecReScanNestLoop
* ----------------------------------------------------------------
*/
void
ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
{
NestLoopState *nlstate = node->nlstate;
Plan *outerPlan = outerPlan((Plan*) node);
/*
* If outerPlan->chgParam is not null then plan will be
* automatically re-scanned by first ExecProcNode.
* innerPlan is re-scanned for each new outer tuple and MUST NOT
* be re-scanned from here or you'll get troubles from inner
* index scans when outer Vars are used as run-time keys...
*/
if (outerPlan->chgParam == NULL)
ExecReScan (outerPlan, exprCtxt, (Plan *) node);
/* let outerPlan to free its result typle ... */
nlstate->jstate.cs_OuterTupleSlot = NULL;
nlstate->jstate.cs_TupFromTlist = false;
return;
}

View File

@ -27,7 +27,7 @@
* SeqScan (emp.all)
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.5 1997/09/08 21:43:16 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.6 1998/02/13 03:26:52 vadim Exp $
*
*-------------------------------------------------------------------------
*/
@ -58,8 +58,6 @@ ExecResult(Result *node)
TupleTableSlot *resultSlot;
Plan *outerPlan;
ExprContext *econtext;
Node *qual;
bool qualResult;
bool isDone;
ProjectionInfo *projInfo;
@ -79,26 +77,16 @@ ExecResult(Result *node)
* check tautological qualifications like (2 > 1)
* ----------------
*/
qual = node->resconstantqual;
if (qual != NULL)
if (resstate->rs_checkqual)
{
qualResult = ExecQual((List *) qual, econtext);
/* ----------------
* if we failed the constant qual, then there
* is no need to continue processing because regardless of
* what happens, the constant qual will be false..
* ----------------
*/
bool qualResult = ExecQual((List *) node->resconstantqual, econtext);
resstate->rs_checkqual = false;
if (qualResult == false)
{
resstate->rs_done = true;
return NULL;
/* ----------------
* our constant qualification succeeded so now we
* throw away the qual because we know it will always
* succeed.
* ----------------
*/
node->resconstantqual = NULL;
}
}
if (resstate->cstate.cs_TupFromTlist)
@ -204,9 +192,10 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
* ----------------
*/
resstate = makeNode(ResultState);
resstate->rs_done = 0;
resstate->rs_done = false;
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
node->resstate = resstate;
/* ----------------
* Miscellanious initialization
*
@ -243,12 +232,6 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
/* ----------------
* set "are we done yet" to false
* ----------------
*/
resstate->rs_done = 0;
return TRUE;
}
@ -294,3 +277,21 @@ ExecEndResult(Result *node)
*/
ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
}
void
ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
{
ResultState *resstate = node->resstate;
resstate->rs_done = false;
resstate->cstate.cs_TupFromTlist = false;
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
/*
* if chgParam of subnode is not null then plan
* will be re-scanned by first ExecProcNode.
*/
if (((Plan*) node)->lefttree->chgParam == NULL)
ExecReScan (((Plan*) node)->lefttree, exprCtxt, (Plan *) node);
}

View File

@ -0,0 +1,280 @@
/*-------------------------------------------------------------------------
*
* nodeSubplan.c--
* routines to support subselects
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecSubPlan - process a subselect
* ExecInitSubPlan - initialize a subselect
* ExecEndSubPlan - shut down a subselect
*/
#include "postgres.h"
#include "access/heapam.h"
#include "tcop/pquery.h"
#include "executor/executor.h"
#include "executor/execdebug.h"
#include "executor/nodeSubplan.h"
/* ----------------------------------------------------------------
* ExecSubPlan(node)
*
* ----------------------------------------------------------------
*/
Datum
ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
{
Plan *plan = node->plan;
SubLink *sublink = node->sublink;
TupleTableSlot *slot;
List *lst;
bool result = false;
bool found = false;
if ( node->setParam != NULL )
elog (ERROR, "ExecSubPlan: can't set parent params from subquery");
/*
* Set Params of this plan from parent plan correlation Vars
*/
if ( node->parParam != NULL )
{
foreach (lst, node->parParam)
{
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
prm->value = ExecEvalExpr ((Node*) lfirst(pvar),
econtext,
&(prm->isnull), NULL);
pvar = lnext (pvar);
}
plan->chgParam = nconc (plan->chgParam, listCopy(node->parParam));
}
ExecReScan (plan, (ExprContext*) NULL, plan);
for (slot = ExecProcNode (plan, plan);
!TupIsNull(slot);
slot = ExecProcNode (plan, plan))
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
int i = 1;
if ( sublink->subLinkType == EXPR_SUBLINK && found )
{
elog (ERROR, "ExecSubPlan: more than one tuple returned by expression subselect");
return ((Datum) false);
}
if ( sublink->subLinkType == EXISTS_SUBLINK )
return ((Datum) true);
found = true;
foreach (lst, sublink->oper)
{
Expr *expr = (Expr*) lfirst(lst);
Const *con = lsecond(expr->args);
bool isnull;
con->constvalue = heap_getattr (tup, i, tdesc, &(con->constisnull));
result = (bool) ExecEvalExpr ((Node*) expr, econtext, &isnull, (bool*) NULL);
if ( isnull )
result = false;
if ( (!result && !(sublink->useor)) || (result && sublink->useor) )
break;
i++;
}
if ( (!result && sublink->subLinkType == ALL_SUBLINK) ||
(result && sublink->subLinkType == ANY_SUBLINK) )
break;
}
return ((Datum) result);
}
/* ----------------------------------------------------------------
* ExecInitSubPlan
*
* ----------------------------------------------------------------
*/
bool
ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
{
EState *sp_estate = CreateExecutorState ();
sp_estate->es_range_table = node->rtable;
sp_estate->es_param_list_info = estate->es_param_list_info;
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
sp_estate->es_tupleTable =
ExecCreateTupleTable (ExecCountSlotsNode(node->plan) + 10);
pfree (sp_estate->es_refcount);
sp_estate->es_refcount = estate->es_refcount;
if ( !ExecInitNode (node->plan, sp_estate, NULL) )
return (false);
node->shutdown = true;
/*
* If this plan is un-correlated or undirect correlated one and
* want to set params for parent plan then prepare parameters.
*/
if ( node->setParam != NULL )
{
List *lst;
foreach (lst, node->setParam)
{
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = node;
}
/*
* Note that in the case of un-correlated subqueries we don't care
* about setting parent->chgParam here: indices take care about it,
* for others - it doesn't matter...
*/
}
return (true);
}
/* ----------------------------------------------------------------
* ExecSetParamPlan
*
* Executes plan of node and sets parameters.
* ----------------------------------------------------------------
*/
void
ExecSetParamPlan (SubPlan *node)
{
Plan *plan = node->plan;
SubLink *sublink = node->sublink;
TupleTableSlot *slot;
List *lst;
bool found = false;
if ( sublink->subLinkType == ANY_SUBLINK ||
sublink->subLinkType == ALL_SUBLINK )
elog (ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
if ( plan->chgParam != NULL )
ExecReScan (plan, (ExprContext*) NULL, plan);
for (slot = ExecProcNode (plan, plan);
!TupIsNull(slot);
slot = ExecProcNode (plan, plan))
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
int i = 1;
if ( sublink->subLinkType == EXPR_SUBLINK && found )
{
elog (ERROR, "ExecSetParamPlan: more than one tuple returned by expression subselect");
return;
}
found = true;
if ( sublink->subLinkType == EXISTS_SUBLINK )
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
prm->execPlan = NULL;
prm->value = (Datum) true;
prm->isnull = false;
break;
}
foreach (lst, node->setParam)
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = NULL;
prm->value = heap_getattr (tup, i, tdesc, &(prm->isnull));
i++;
}
}
if ( !found )
{
if ( sublink->subLinkType == EXISTS_SUBLINK )
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
prm->execPlan = NULL;
prm->value = (Datum) false;
prm->isnull = false;
}
else
{
foreach (lst, node->setParam)
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = NULL;
prm->value = (Datum) NULL;
prm->isnull = true;
}
}
}
if ( plan->extParam == NULL ) /* un-correlated ... */
{
ExecEndNode (plan, plan);
node->shutdown = false;
}
}
/* ----------------------------------------------------------------
* ExecEndSubPlan
* ----------------------------------------------------------------
*/
void
ExecEndSubPlan(SubPlan *node)
{
if ( node->shutdown )
{
ExecEndNode (node->plan, node->plan);
node->shutdown = false;
}
}
void
ExecReScanSetParamPlan (SubPlan *node, Plan *parent)
{
Plan *plan = node->plan;
List *lst;
if ( node->parParam != NULL )
elog (ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
if ( node->setParam == NULL )
elog (ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
if ( plan->extParam == NULL )
elog (ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
/*
* Don't actual re-scan: ExecSetParamPlan does re-scan if
* node->plan->chgParam is not NULL...
ExecReScan (plan, NULL, plan);
*/
foreach (lst, node->setParam)
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = node;
}
parent->chgParam = nconc (parent->chgParam, listCopy(node->setParam));
}