mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-24 18:55:04 +08:00
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:
parent
13637df458
commit
1a105cefbd
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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++)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
* ----------------
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
280
src/backend/executor/nodeSubplan.c
Normal file
280
src/backend/executor/nodeSubplan.c
Normal 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));
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user