diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile index b1ebb0b215..9ae3cfc351 100644 --- a/src/backend/executor/Makefile +++ b/src/backend/executor/Makefile @@ -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 diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 2349f32411..759d17be4f 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -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; } } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index c4bea118db..8702ede248 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -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++) diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index a2bd3e6ca6..017fdfba4d 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -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; } } diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 98a8042cc3..78c91539c7 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -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; } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index e02205828a..69ef667107 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -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); + } + +} diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 2cd62e39c0..f6e034d988 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -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); diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 444a5bc9db..9778e365a5 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -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); + +} diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 031d718250..5ebf508c0c 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -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); + +} diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index c5fa8a092d..21132410d4 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -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); + +} diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 6e220800f2..d15c9bfb35 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -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. * ---------------- diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index f821459f2a..800bab2b31 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -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 diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index ff9327ee99..4d1fb12cd2 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -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; +} diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 78f8c76261..7dcb9376ca 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -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); + +} diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c new file mode 100644 index 0000000000..610f0a0964 --- /dev/null +++ b/src/backend/executor/nodeSubplan.c @@ -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)); + +}