diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index dfc3636580..f37a7602ef 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.108 2010/02/14 18:42:14 rhaas Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.109 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -59,17 +59,9 @@ static bool IndexSupportsBackwardScan(Oid indexid); * * Note that if the plan node has parameters that have changed value, * the output might be different from last time. - * - * The second parameter is currently only used to pass a NestLoop plan's - * econtext down to its inner child plan, in case that is an indexscan that - * needs access to variables of the current outer tuple. (The handling of - * this parameter is currently pretty inconsistent: some callers pass NULL - * and some pass down their parent's value; so don't rely on it in other - * situations. It'd probably be better to remove the whole thing and use - * the generalized parameter mechanism instead.) */ void -ExecReScan(PlanState *node, ExprContext *exprCtxt) +ExecReScan(PlanState *node) { /* If collecting timing stats, update them */ if (node->instrument) @@ -126,119 +118,119 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt) switch (nodeTag(node)) { case T_ResultState: - ExecReScanResult((ResultState *) node, exprCtxt); + ExecReScanResult((ResultState *) node); break; case T_ModifyTableState: - ExecReScanModifyTable((ModifyTableState *) node, exprCtxt); + ExecReScanModifyTable((ModifyTableState *) node); break; case T_AppendState: - ExecReScanAppend((AppendState *) node, exprCtxt); + ExecReScanAppend((AppendState *) node); break; case T_RecursiveUnionState: - ExecRecursiveUnionReScan((RecursiveUnionState *) node, exprCtxt); + ExecReScanRecursiveUnion((RecursiveUnionState *) node); break; case T_BitmapAndState: - ExecReScanBitmapAnd((BitmapAndState *) node, exprCtxt); + ExecReScanBitmapAnd((BitmapAndState *) node); break; case T_BitmapOrState: - ExecReScanBitmapOr((BitmapOrState *) node, exprCtxt); + ExecReScanBitmapOr((BitmapOrState *) node); break; case T_SeqScanState: - ExecSeqReScan((SeqScanState *) node, exprCtxt); + ExecReScanSeqScan((SeqScanState *) node); break; case T_IndexScanState: - ExecIndexReScan((IndexScanState *) node, exprCtxt); + ExecReScanIndexScan((IndexScanState *) node); break; case T_BitmapIndexScanState: - ExecBitmapIndexReScan((BitmapIndexScanState *) node, exprCtxt); + ExecReScanBitmapIndexScan((BitmapIndexScanState *) node); break; case T_BitmapHeapScanState: - ExecBitmapHeapReScan((BitmapHeapScanState *) node, exprCtxt); + ExecReScanBitmapHeapScan((BitmapHeapScanState *) node); break; case T_TidScanState: - ExecTidReScan((TidScanState *) node, exprCtxt); + ExecReScanTidScan((TidScanState *) node); break; case T_SubqueryScanState: - ExecSubqueryReScan((SubqueryScanState *) node, exprCtxt); + ExecReScanSubqueryScan((SubqueryScanState *) node); break; case T_FunctionScanState: - ExecFunctionReScan((FunctionScanState *) node, exprCtxt); + ExecReScanFunctionScan((FunctionScanState *) node); break; case T_ValuesScanState: - ExecValuesReScan((ValuesScanState *) node, exprCtxt); + ExecReScanValuesScan((ValuesScanState *) node); break; case T_CteScanState: - ExecCteScanReScan((CteScanState *) node, exprCtxt); + ExecReScanCteScan((CteScanState *) node); break; case T_WorkTableScanState: - ExecWorkTableScanReScan((WorkTableScanState *) node, exprCtxt); + ExecReScanWorkTableScan((WorkTableScanState *) node); break; case T_NestLoopState: - ExecReScanNestLoop((NestLoopState *) node, exprCtxt); + ExecReScanNestLoop((NestLoopState *) node); break; case T_MergeJoinState: - ExecReScanMergeJoin((MergeJoinState *) node, exprCtxt); + ExecReScanMergeJoin((MergeJoinState *) node); break; case T_HashJoinState: - ExecReScanHashJoin((HashJoinState *) node, exprCtxt); + ExecReScanHashJoin((HashJoinState *) node); break; case T_MaterialState: - ExecMaterialReScan((MaterialState *) node, exprCtxt); + ExecReScanMaterial((MaterialState *) node); break; case T_SortState: - ExecReScanSort((SortState *) node, exprCtxt); + ExecReScanSort((SortState *) node); break; case T_GroupState: - ExecReScanGroup((GroupState *) node, exprCtxt); + ExecReScanGroup((GroupState *) node); break; case T_AggState: - ExecReScanAgg((AggState *) node, exprCtxt); + ExecReScanAgg((AggState *) node); break; case T_WindowAggState: - ExecReScanWindowAgg((WindowAggState *) node, exprCtxt); + ExecReScanWindowAgg((WindowAggState *) node); break; case T_UniqueState: - ExecReScanUnique((UniqueState *) node, exprCtxt); + ExecReScanUnique((UniqueState *) node); break; case T_HashState: - ExecReScanHash((HashState *) node, exprCtxt); + ExecReScanHash((HashState *) node); break; case T_SetOpState: - ExecReScanSetOp((SetOpState *) node, exprCtxt); + ExecReScanSetOp((SetOpState *) node); break; case T_LockRowsState: - ExecReScanLockRows((LockRowsState *) node, exprCtxt); + ExecReScanLockRows((LockRowsState *) node); break; case T_LimitState: - ExecReScanLimit((LimitState *) node, exprCtxt); + ExecReScanLimit((LimitState *) node); break; default: diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 473fbcdae1..9eb765378f 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.350 2010/07/09 14:06:01 rhaas Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.351 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -400,7 +400,7 @@ ExecutorRewind(QueryDesc *queryDesc) /* * rescan plan */ - ExecReScan(queryDesc->planstate, NULL); + ExecReScan(queryDesc->planstate); MemoryContextSwitchTo(oldcontext); } diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index b464e76993..2830bff871 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.70 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.71 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -341,7 +341,7 @@ ExecProcNode(PlanState *node) CHECK_FOR_INTERRUPTS(); if (node->chgParam != NULL) /* something changed */ - ExecReScan(node, NULL); /* let ReScan handle this */ + ExecReScan(node); /* let ReScan handle this */ if (node->instrument) InstrStartNode(node->instrument); @@ -504,7 +504,7 @@ MultiExecProcNode(PlanState *node) CHECK_FOR_INTERRUPTS(); if (node->chgParam != NULL) /* something changed */ - ExecReScan(node, NULL); /* let ReScan handle this */ + ExecReScan(node); /* let ReScan handle this */ switch (nodeTag(node)) { diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index e381e11282..e30689bba3 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.263 2010/02/26 02:00:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.264 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -78,7 +78,9 @@ static Datum ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); -static Datum ExecEvalParam(ExprState *exprstate, ExprContext *econtext, +static Datum ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone); +static Datum ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static void init_fcache(Oid foid, FuncExprState *fcache, MemoryContext fcacheCxt, bool needDescForSets); @@ -961,80 +963,87 @@ ExecEvalConst(ExprState *exprstate, ExprContext *econtext, } /* ---------------------------------------------------------------- - * ExecEvalParam + * ExecEvalParamExec * - * Returns the value of a parameter. A param node contains - * something like ($.name) and the expression context contains - * the current parameter bindings (name = "sam") (age = 34)... - * so our job is to find and return the appropriate datum ("sam"). + * Returns the value of a PARAM_EXEC parameter. * ---------------------------------------------------------------- */ static Datum -ExecEvalParam(ExprState *exprstate, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) +ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone) { Param *expression = (Param *) exprstate->expr; int thisParamId = expression->paramid; + ParamExecData *prm; if (isDone) *isDone = ExprSingleResult; - if (expression->paramkind == PARAM_EXEC) + /* + * PARAM_EXEC params (internal executor parameters) are stored in the + * ecxt_param_exec_vals array, and can be accessed by array index. + */ + prm = &(econtext->ecxt_param_exec_vals[thisParamId]); + if (prm->execPlan != NULL) { - /* - * PARAM_EXEC params (internal executor parameters) are stored in the - * ecxt_param_exec_vals array, and can be accessed by array index. - */ - ParamExecData *prm; - - prm = &(econtext->ecxt_param_exec_vals[thisParamId]); - if (prm->execPlan != NULL) - { - /* Parameter not evaluated yet, so go do it */ - ExecSetParamPlan(prm->execPlan, econtext); - /* ExecSetParamPlan should have processed this param... */ - Assert(prm->execPlan == NULL); - } - *isNull = prm->isnull; - return prm->value; + /* Parameter not evaluated yet, so go do it */ + ExecSetParamPlan(prm->execPlan, econtext); + /* ExecSetParamPlan should have processed this param... */ + Assert(prm->execPlan == NULL); } - else + *isNull = prm->isnull; + return prm->value; +} + +/* ---------------------------------------------------------------- + * ExecEvalParamExtern + * + * Returns the value of a PARAM_EXTERN parameter. + * ---------------------------------------------------------------- + */ +static Datum +ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone) +{ + Param *expression = (Param *) exprstate->expr; + int thisParamId = expression->paramid; + ParamListInfo paramInfo = econtext->ecxt_param_list_info; + + if (isDone) + *isDone = ExprSingleResult; + + /* + * PARAM_EXTERN parameters must be sought in ecxt_param_list_info. + */ + if (paramInfo && + thisParamId > 0 && thisParamId <= paramInfo->numParams) { - /* - * PARAM_EXTERN parameters must be sought in ecxt_param_list_info. - */ - ParamListInfo paramInfo = econtext->ecxt_param_list_info; + ParamExternData *prm = ¶mInfo->params[thisParamId - 1]; - Assert(expression->paramkind == PARAM_EXTERN); - if (paramInfo && - thisParamId > 0 && thisParamId <= paramInfo->numParams) + /* give hook a chance in case parameter is dynamic */ + if (!OidIsValid(prm->ptype) && paramInfo->paramFetch != NULL) + (*paramInfo->paramFetch) (paramInfo, thisParamId); + + if (OidIsValid(prm->ptype)) { - ParamExternData *prm = ¶mInfo->params[thisParamId - 1]; + /* safety check in case hook did something unexpected */ + if (prm->ptype != expression->paramtype) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)", + thisParamId, + format_type_be(prm->ptype), + format_type_be(expression->paramtype)))); - /* give hook a chance in case parameter is dynamic */ - if (!OidIsValid(prm->ptype) && paramInfo->paramFetch != NULL) - (*paramInfo->paramFetch) (paramInfo, thisParamId); - - if (OidIsValid(prm->ptype)) - { - /* safety check in case hook did something unexpected */ - if (prm->ptype != expression->paramtype) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)", - thisParamId, - format_type_be(prm->ptype), - format_type_be(expression->paramtype)))); - - *isNull = prm->isnull; - return prm->value; - } + *isNull = prm->isnull; + return prm->value; } - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("no value found for parameter %d", thisParamId))); - return (Datum) 0; /* keep compiler quiet */ } + + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("no value found for parameter %d", thisParamId))); + return (Datum) 0; /* keep compiler quiet */ } @@ -4228,7 +4237,19 @@ ExecInitExpr(Expr *node, PlanState *parent) break; case T_Param: state = (ExprState *) makeNode(ExprState); - state->evalfunc = ExecEvalParam; + switch (((Param *) node)->paramkind) + { + case PARAM_EXEC: + state->evalfunc = ExecEvalParamExec; + break; + case PARAM_EXTERN: + state->evalfunc = ExecEvalParamExtern; + break; + default: + elog(ERROR, "unrecognized paramkind: %d", + (int) ((Param *) node)->paramkind); + break; + } break; case T_CoerceToDomainValue: state = (ExprState *) makeNode(ExprState); diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 74fc87a66a..a28d73fd32 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -71,7 +71,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.175 2010/02/26 02:00:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.176 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1886,7 +1886,7 @@ ExecEndAgg(AggState *node) } void -ExecReScanAgg(AggState *node, ExprContext *exprCtxt) +ExecReScanAgg(AggState *node) { ExprContext *econtext = node->ss.ps.ps_ExprContext; int aggno; @@ -1911,7 +1911,7 @@ ExecReScanAgg(AggState *node, ExprContext *exprCtxt) * parameter changes, then we can just rescan the existing hash table; * no need to build it again. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) + if (node->ss.ps.lefttree->chgParam == NULL) { ResetTupleHashIterator(node->hashtable, &node->hashiter); return; @@ -1967,8 +1967,8 @@ ExecReScanAgg(AggState *node, ExprContext *exprCtxt) * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ss.ps.lefttree->chgParam == NULL) + ExecReScan(node->ss.ps.lefttree); } /* diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 60026613c0..4a40b831dd 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.77 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.78 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -263,7 +263,7 @@ ExecEndAppend(AppendState *node) } void -ExecReScanAppend(AppendState *node, ExprContext *exprCtxt) +ExecReScanAppend(AppendState *node) { int i; @@ -280,12 +280,10 @@ ExecReScanAppend(AppendState *node, ExprContext *exprCtxt) /* * If chgParam of subnode is not null then plan will be re-scanned by - * first ExecProcNode. However, if caller is passing us an exprCtxt - * then forcibly rescan all the subnodes now, so that we can pass the - * exprCtxt down to the subnodes (needed for appendrel indexscan). + * first ExecProcNode. */ - if (subnode->chgParam == NULL || exprCtxt != NULL) - ExecReScan(subnode, exprCtxt); + if (subnode->chgParam == NULL) + ExecReScan(subnode); } node->as_whichplan = 0; exec_append_initialize_next(node); diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c index dbfcfb1cab..9ae2df76af 100644 --- a/src/backend/executor/nodeBitmapAnd.c +++ b/src/backend/executor/nodeBitmapAnd.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapAnd.c,v 1.13 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapAnd.c,v 1.14 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -185,7 +185,7 @@ ExecEndBitmapAnd(BitmapAndState *node) } void -ExecReScanBitmapAnd(BitmapAndState *node, ExprContext *exprCtxt) +ExecReScanBitmapAnd(BitmapAndState *node) { int i; @@ -201,9 +201,10 @@ ExecReScanBitmapAnd(BitmapAndState *node, ExprContext *exprCtxt) UpdateChangedParamSet(subnode, node->ps.chgParam); /* - * Always rescan the inputs immediately, to ensure we can pass down - * any outer tuple that might be used in index quals. + * If chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. */ - ExecReScan(subnode, exprCtxt); + if (subnode->chgParam == NULL) + ExecReScan(subnode); } } diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index 2a7ce62432..0ea3a88e45 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -21,7 +21,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.38 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.39 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -30,7 +30,7 @@ * ExecBitmapHeapScan scans a relation using bitmap info * ExecBitmapHeapNext workhorse for above * ExecInitBitmapHeapScan creates and initializes state info. - * ExecBitmapHeapReScan prepares to rescan the plan. + * ExecReScanBitmapHeapScan prepares to rescan the plan. * ExecEndBitmapHeapScan releases all storage. */ #include "postgres.h" @@ -420,24 +420,12 @@ ExecBitmapHeapScan(BitmapHeapScanState *node) } /* ---------------------------------------------------------------- - * ExecBitmapHeapReScan(node) + * ExecReScanBitmapHeapScan(node) * ---------------------------------------------------------------- */ void -ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt) +ExecReScanBitmapHeapScan(BitmapHeapScanState *node) { - /* - * If we are being passed an outer tuple, link it into the "regular" - * per-tuple econtext for possible qual eval. - */ - if (exprCtxt != NULL) - { - ExprContext *stdecontext; - - stdecontext = node->ss.ps.ps_ExprContext; - stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple; - } - /* rescan to release any page pin */ heap_rescan(node->ss.ss_currentScanDesc, NULL); @@ -455,10 +443,11 @@ ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt) ExecScanReScan(&node->ss); /* - * Always rescan the input immediately, to ensure we can pass down any - * outer tuple that might be used in index quals. + * if chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. */ - ExecReScan(outerPlanState(node), exprCtxt); + if (node->ss.ps.lefttree->chgParam == NULL) + ExecReScan(node->ss.ps.lefttree); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c index 0781c21676..73b569458d 100644 --- a/src/backend/executor/nodeBitmapIndexscan.c +++ b/src/backend/executor/nodeBitmapIndexscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.33 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.34 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,7 +16,7 @@ * INTERFACE ROUTINES * MultiExecBitmapIndexScan scans a relation using index. * ExecInitBitmapIndexScan creates and initializes state info. - * ExecBitmapIndexReScan prepares to rescan the plan. + * ExecReScanBitmapIndexScan prepares to rescan the plan. * ExecEndBitmapIndexScan releases all storage. */ #include "postgres.h" @@ -60,7 +60,7 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node) if (!node->biss_RuntimeKeysReady && (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0)) { - ExecReScan((PlanState *) node, NULL); + ExecReScan((PlanState *) node); doscan = node->biss_RuntimeKeysReady; } else @@ -106,39 +106,28 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node) } /* ---------------------------------------------------------------- - * ExecBitmapIndexReScan(node) + * ExecReScanBitmapIndexScan(node) * - * Recalculates the value of the scan keys whose value depends on - * information known at runtime and rescans the indexed relation. + * Recalculates the values of any scan keys whose value depends on + * information known at runtime, then rescans the indexed relation. * ---------------------------------------------------------------- */ void -ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt) +ExecReScanBitmapIndexScan(BitmapIndexScanState *node) { - ExprContext *econtext; - - econtext = node->biss_RuntimeContext; /* context for runtime keys */ - - if (econtext) - { - /* - * If we are being passed an outer tuple, save it for runtime key - * calc. - */ - if (exprCtxt != NULL) - econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple; - - /* - * Reset the runtime-key context so we don't leak memory as each outer - * tuple is scanned. Note this assumes that we will recalculate *all* - * runtime keys on each call. - */ - ResetExprContext(econtext); - } + ExprContext *econtext = node->biss_RuntimeContext; /* - * If we are doing runtime key calculations (ie, the index keys depend on - * data from an outer scan), compute the new key values. + * Reset the runtime-key context so we don't leak memory as each outer + * tuple is scanned. Note this assumes that we will recalculate *all* + * runtime keys on each call. + */ + if (econtext) + ResetExprContext(econtext); + + /* + * If we are doing runtime key calculations (ie, any of the index key + * values weren't simple Consts), compute the new key values. * * Array keys are also treated as runtime keys; note that if we return * with biss_RuntimeKeysReady still false, then there is an empty array diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c index 97cadd6b85..8faba8b300 100644 --- a/src/backend/executor/nodeBitmapOr.c +++ b/src/backend/executor/nodeBitmapOr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapOr.c,v 1.12 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapOr.c,v 1.13 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -201,7 +201,7 @@ ExecEndBitmapOr(BitmapOrState *node) } void -ExecReScanBitmapOr(BitmapOrState *node, ExprContext *exprCtxt) +ExecReScanBitmapOr(BitmapOrState *node) { int i; @@ -217,9 +217,10 @@ ExecReScanBitmapOr(BitmapOrState *node, ExprContext *exprCtxt) UpdateChangedParamSet(subnode, node->ps.chgParam); /* - * Always rescan the inputs immediately, to ensure we can pass down - * any outer tuple that might be used in index quals. + * If chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. */ - ExecReScan(subnode, exprCtxt); + if (subnode->chgParam == NULL) + ExecReScan(subnode); } } diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c index 0c90a1e37e..408cd05120 100644 --- a/src/backend/executor/nodeCtescan.c +++ b/src/backend/executor/nodeCtescan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeCtescan.c,v 1.8 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeCtescan.c,v 1.9 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -298,13 +298,13 @@ ExecEndCteScan(CteScanState *node) } /* ---------------------------------------------------------------- - * ExecCteScanReScan + * ExecReScanCteScan * * Rescans the relation. * ---------------------------------------------------------------- */ void -ExecCteScanReScan(CteScanState *node, ExprContext *exprCtxt) +ExecReScanCteScan(CteScanState *node) { Tuplestorestate *tuplestorestate = node->leader->cte_table; diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index 6989961f8a..e64b57d09a 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.55 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.56 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,7 +18,7 @@ * ExecFunctionNext retrieve next tuple in sequential order. * ExecInitFunctionScan creates and initializes a functionscan node. * ExecEndFunctionScan releases any storage allocated. - * ExecFunctionReScan rescans the function + * ExecReScanFunctionScan rescans the function */ #include "postgres.h" @@ -255,13 +255,13 @@ ExecEndFunctionScan(FunctionScanState *node) } /* ---------------------------------------------------------------- - * ExecFunctionReScan + * ExecReScanFunctionScan * * Rescans the relation. * ---------------------------------------------------------------- */ void -ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt) +ExecReScanFunctionScan(FunctionScanState *node) { ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index 26b59df866..e56fddadd8 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -15,7 +15,7 @@ * locate group boundaries. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.77 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.78 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -277,14 +277,18 @@ ExecEndGroup(GroupState *node) } void -ExecReScanGroup(GroupState *node, ExprContext *exprCtxt) +ExecReScanGroup(GroupState *node) { node->grp_done = FALSE; node->ss.ps.ps_TupFromTlist = false; /* must clear first tuple */ ExecClearTuple(node->ss.ss_ScanTupleSlot); - if (((PlanState *) node)->lefttree && - ((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + /* + * if chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. + */ + if (node->ss.ps.lefttree && + node->ss.ps.lefttree->chgParam == NULL) + ExecReScan(node->ss.ps.lefttree); } diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index be45d732e0..0fa8b33606 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.129 2010/02/26 02:00:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.130 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -961,14 +961,14 @@ ExecHashTableReset(HashJoinTable hashtable) } void -ExecReScanHash(HashState *node, ExprContext *exprCtxt) +ExecReScanHash(HashState *node) { /* * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ps.lefttree->chgParam == NULL) + ExecReScan(node->ps.lefttree); } diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 4749d353b9..a6cd481f7e 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.103 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.104 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -842,7 +842,7 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate, void -ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) +ExecReScanHashJoin(HashJoinState *node) { /* * In a multi-batch join, we currently have to do rescans the hard way, @@ -854,7 +854,7 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) if (node->hj_HashTable != NULL) { if (node->hj_HashTable->nbatch == 1 && - ((PlanState *) node)->righttree->chgParam == NULL) + node->js.ps.righttree->chgParam == NULL) { /* * okay to reuse the hash table; needn't rescan inner, either. @@ -880,8 +880,8 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) * if chgParam of subnode is not null then plan will be re-scanned * by first ExecProcNode. */ - if (((PlanState *) node)->righttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->righttree, exprCtxt); + if (node->js.ps.righttree->chgParam == NULL) + ExecReScan(node->js.ps.righttree); } } @@ -900,6 +900,6 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->js.ps.lefttree->chgParam == NULL) + ExecReScan(node->js.ps.lefttree); } diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 0994dbf84e..ad64c14824 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.139 2010/02/26 02:00:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.140 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,7 +17,7 @@ * ExecIndexScan scans a relation using indices * ExecIndexNext using index to retrieve next tuple * ExecInitIndexScan creates and initializes state info. - * ExecIndexReScan rescans the indexed relation. + * ExecReScanIndexScan rescans the indexed relation. * ExecEndIndexScan releases all storage. * ExecIndexMarkPos marks scan position. * ExecIndexRestrPos restores scan position. @@ -141,7 +141,7 @@ ExecIndexScan(IndexScanState *node) * If we have runtime keys and they've not already been set up, do it now. */ if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady) - ExecReScan((PlanState *) node, NULL); + ExecReScan((PlanState *) node); return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext, @@ -149,54 +149,35 @@ ExecIndexScan(IndexScanState *node) } /* ---------------------------------------------------------------- - * ExecIndexReScan(node) + * ExecReScanIndexScan(node) + * + * Recalculates the values of any scan keys whose value depends on + * information known at runtime, then rescans the indexed relation. * - * Recalculates the value of the scan keys whose value depends on - * information known at runtime and rescans the indexed relation. * Updating the scan key was formerly done separately in * ExecUpdateIndexScanKeys. Integrating it into ReScan makes * rescans of indices and relations/general streams more uniform. * ---------------------------------------------------------------- */ void -ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt) +ExecReScanIndexScan(IndexScanState *node) { - ExprContext *econtext; - - econtext = node->iss_RuntimeContext; /* context for runtime keys */ - - if (econtext) - { - /* - * If we are being passed an outer tuple, save it for runtime key - * calc. We also need to link it into the "regular" per-tuple - * econtext, so it can be used during indexqualorig evaluations. - */ - if (exprCtxt != NULL) - { - ExprContext *stdecontext; - - econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple; - stdecontext = node->ss.ps.ps_ExprContext; - stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple; - } - - /* - * Reset the runtime-key context so we don't leak memory as each outer - * tuple is scanned. Note this assumes that we will recalculate *all* - * runtime keys on each call. - */ - ResetExprContext(econtext); - } - /* - * If we are doing runtime key calculations (ie, the index keys depend on - * data from an outer scan), compute the new key values + * If we are doing runtime key calculations (ie, any of the index key + * values weren't simple Consts), compute the new key values. But first, + * reset the context so we don't leak memory as each outer tuple is + * scanned. Note this assumes that we will recalculate *all* runtime keys + * on each call. */ if (node->iss_NumRuntimeKeys != 0) + { + ExprContext *econtext = node->iss_RuntimeContext; + + ResetExprContext(econtext); ExecIndexEvalRuntimeKeys(econtext, node->iss_RuntimeKeys, node->iss_NumRuntimeKeys); + } node->iss_RuntimeKeysReady = true; /* reset index scan */ @@ -229,11 +210,11 @@ ExecIndexEvalRuntimeKeys(ExprContext *econtext, /* * For each run-time key, extract the run-time expression and evaluate - * it with respect to the current outer tuple. We then stick the - * result into the proper scan key. + * it with respect to the current context. We then stick the result + * into the proper scan key. * * Note: the result of the eval could be a pass-by-ref value that's - * stored in the outer scan's tuple, not in + * stored in some outer scan's tuple, not in * econtext->ecxt_per_tuple_memory. We assume that the outer tuple * will stay put throughout our scan. If this is wrong, we could copy * the result into our context explicitly, but I think that's not diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c index 48fb32d384..a873ab88f6 100644 --- a/src/backend/executor/nodeLimit.c +++ b/src/backend/executor/nodeLimit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeLimit.c,v 1.41 2010/01/02 16:57:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeLimit.c,v 1.42 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -404,7 +404,7 @@ ExecEndLimit(LimitState *node) void -ExecReScanLimit(LimitState *node, ExprContext *exprCtxt) +ExecReScanLimit(LimitState *node) { /* * Recompute limit/offset in case parameters changed, and reset the state @@ -417,6 +417,6 @@ ExecReScanLimit(LimitState *node, ExprContext *exprCtxt) * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ps.lefttree->chgParam == NULL) + ExecReScan(node->ps.lefttree); } diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 0eafa0afa2..d573853eba 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeLockRows.c,v 1.4 2010/02/26 02:00:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeLockRows.c,v 1.5 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -339,12 +339,12 @@ ExecEndLockRows(LockRowsState *node) void -ExecReScanLockRows(LockRowsState *node, ExprContext *exprCtxt) +ExecReScanLockRows(LockRowsState *node) { /* * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ps.lefttree->chgParam == NULL) + ExecReScan(node->ps.lefttree); } diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c index 414ff53390..78f29d872e 100644 --- a/src/backend/executor/nodeMaterial.c +++ b/src/backend/executor/nodeMaterial.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.71 2010/01/02 16:57:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.72 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -309,22 +309,22 @@ ExecMaterialRestrPos(MaterialState *node) } /* ---------------------------------------------------------------- - * ExecMaterialReScan + * ExecReScanMaterial * * Rescans the materialized relation. * ---------------------------------------------------------------- */ void -ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt) +ExecReScanMaterial(MaterialState *node) { ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); if (node->eflags != 0) { /* - * If we haven't materialized yet, just return. If outerplan' chgParam - * is not NULL then it will be re-scanned by ExecProcNode, else - no - * reason to re-scan it at all. + * If we haven't materialized yet, just return. If outerplan's + * chgParam is not NULL then it will be re-scanned by ExecProcNode, + * else no reason to re-scan it at all. */ if (!node->tuplestorestate) return; @@ -339,13 +339,13 @@ ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt) * Otherwise we can just rewind and rescan the stored output. The * state of the subnode does not change. */ - if (((PlanState *) node)->lefttree->chgParam != NULL || + if (node->ss.ps.lefttree->chgParam != NULL || (node->eflags & EXEC_FLAG_REWIND) == 0) { tuplestore_end(node->tuplestorestate); node->tuplestorestate = NULL; - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ss.ps.lefttree->chgParam == NULL) + ExecReScan(node->ss.ps.lefttree); node->eof_underlying = false; } else @@ -359,8 +359,8 @@ ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt) * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ss.ps.lefttree->chgParam == NULL) + ExecReScan(node->ss.ps.lefttree); node->eof_underlying = false; } } diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index 948f580095..104482a633 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.103 2010/07/06 19:18:56 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.104 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1680,7 +1680,7 @@ ExecEndMergeJoin(MergeJoinState *node) } void -ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt) +ExecReScanMergeJoin(MergeJoinState *node) { ExecClearTuple(node->mj_MarkedTupleSlot); @@ -1695,9 +1695,9 @@ ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt) * if chgParam of subnodes is not null then plans will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); - if (((PlanState *) node)->righttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->righttree, exprCtxt); + if (node->js.ps.lefttree->chgParam == NULL) + ExecReScan(node->js.ps.lefttree); + if (node->js.ps.righttree->chgParam == NULL) + ExecReScan(node->js.ps.righttree); } diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index adfe97cefd..a5e24def37 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.7 2010/02/26 02:00:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.8 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1045,7 +1045,7 @@ ExecEndModifyTable(ModifyTableState *node) } void -ExecReScanModifyTable(ModifyTableState *node, ExprContext *exprCtxt) +ExecReScanModifyTable(ModifyTableState *node) { /* * Currently, we don't need to support rescan on ModifyTable nodes. The diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index 1bcaef96e6..d59ed92f01 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.55 2010/01/02 16:57:44 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.56 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -59,6 +59,7 @@ TupleTableSlot * ExecNestLoop(NestLoopState *node) { + NestLoop *nl; PlanState *innerPlan; PlanState *outerPlan; TupleTableSlot *outerTupleSlot; @@ -66,12 +67,14 @@ ExecNestLoop(NestLoopState *node) List *joinqual; List *otherqual; ExprContext *econtext; + ListCell *lc; /* * get information from the node */ ENL1_printf("getting info from node"); + nl = (NestLoop *) node->js.ps.plan; joinqual = node->js.joinqual; otherqual = node->js.ps.qual; outerPlan = outerPlanState(node); @@ -133,17 +136,34 @@ ExecNestLoop(NestLoopState *node) node->nl_NeedNewOuter = false; node->nl_MatchedOuter = false; + /* + * fetch the values of any outer Vars that must be passed to + * the inner scan, and store them in the appropriate PARAM_EXEC + * slots. + */ + foreach(lc, nl->nestParams) + { + NestLoopParam *nlp = (NestLoopParam *) lfirst(lc); + int paramno = nlp->paramno; + ParamExecData *prm; + + prm = &(econtext->ecxt_param_exec_vals[paramno]); + /* Param value should be an OUTER var */ + Assert(nlp->paramval->varno == OUTER); + Assert(nlp->paramval->varattno > 0); + prm->value = slot_getattr(outerTupleSlot, + nlp->paramval->varattno, + &(prm->isnull)); + /* Flag parameter value as changed */ + innerPlan->chgParam = bms_add_member(innerPlan->chgParam, + paramno); + } + /* * now rescan the inner plan */ ENL1_printf("rescanning inner plan"); - - /* - * The scan key of the inner plan might depend on the current - * outer tuple (e.g. in index scans), that's why we pass our expr - * context. - */ - ExecReScan(innerPlan, econtext); + ExecReScan(innerPlan); } /* @@ -308,15 +328,18 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) /* * initialize child nodes * - * Tell the inner child that cheap rescans would be good. (This is - * unnecessary if we are doing nestloop with inner indexscan, because the - * rescan will always be with a fresh parameter --- but since - * nodeIndexscan doesn't actually care about REWIND, there's no point in - * dealing with that refinement.) + * If we have no parameters to pass into the inner rel from the outer, + * tell the inner child that cheap rescans would be good. If we do have + * such parameters, then there is no point in REWIND support at all in + * the inner child, because it will always be rescanned with fresh + * parameter values. */ outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate, eflags); - innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, - eflags | EXEC_FLAG_REWIND); + if (node->nestParams == NIL) + eflags |= EXEC_FLAG_REWIND; + else + eflags &= ~EXEC_FLAG_REWIND; + innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags); /* * tuple table initialization @@ -395,18 +418,22 @@ ExecEndNestLoop(NestLoopState *node) * ---------------------------------------------------------------- */ void -ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt) +ExecReScanNestLoop(NestLoopState *node) { PlanState *outerPlan = outerPlanState(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... + * re-scanned by first ExecProcNode. */ if (outerPlan->chgParam == NULL) - ExecReScan(outerPlan, exprCtxt); + ExecReScan(outerPlan); + + /* + * 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... + */ node->js.ps.ps_TupFromTlist = false; node->nl_NeedNewOuter = true; diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c index 68484ef092..3cd9495f8a 100644 --- a/src/backend/executor/nodeRecursiveunion.c +++ b/src/backend/executor/nodeRecursiveunion.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeRecursiveunion.c,v 1.6 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeRecursiveunion.c,v 1.7 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -299,13 +299,13 @@ ExecEndRecursiveUnion(RecursiveUnionState *node) } /* ---------------------------------------------------------------- - * ExecRecursiveUnionReScan + * ExecReScanRecursiveUnion * * Rescans the relation. * ---------------------------------------------------------------- */ void -ExecRecursiveUnionReScan(RecursiveUnionState *node, ExprContext *exprCtxt) +ExecReScanRecursiveUnion(RecursiveUnionState *node) { PlanState *outerPlan = outerPlanState(node); PlanState *innerPlan = innerPlanState(node); @@ -323,7 +323,7 @@ ExecRecursiveUnionReScan(RecursiveUnionState *node, ExprContext *exprCtxt) * non-recursive term. */ if (outerPlan->chgParam == NULL) - ExecReScan(outerPlan, exprCtxt); + ExecReScan(outerPlan); /* Release any hashtable storage */ if (node->tableContext) diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c index 537df9d5d7..a9ad0dca87 100644 --- a/src/backend/executor/nodeResult.c +++ b/src/backend/executor/nodeResult.c @@ -38,7 +38,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.45 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.46 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -292,7 +292,7 @@ ExecEndResult(ResultState *node) } void -ExecReScanResult(ResultState *node, ExprContext *exprCtxt) +ExecReScanResult(ResultState *node) { node->rs_done = false; node->ps.ps_TupFromTlist = false; @@ -300,11 +300,9 @@ ExecReScanResult(ResultState *node, ExprContext *exprCtxt) /* * If chgParam of subnode is not null then plan will be re-scanned by - * first ExecProcNode. However, if caller is passing us an exprCtxt then - * forcibly rescan the subnode now, so that we can pass the exprCtxt down - * to the subnode (needed for gated indexscan). + * first ExecProcNode. */ if (node->ps.lefttree && - (node->ps.lefttree->chgParam == NULL || exprCtxt != NULL)) - ExecReScan(node->ps.lefttree, exprCtxt); + node->ps.lefttree->chgParam == NULL) + ExecReScan(node->ps.lefttree); } diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 75623be371..f65a79310f 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeSeqscan.c,v 1.70 2010/02/26 02:00:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeSeqscan.c,v 1.71 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,7 +18,7 @@ * ExecSeqNext retrieve next tuple in sequential order. * ExecInitSeqScan creates and initializes a seqscan node. * ExecEndSeqScan releases any storage allocated. - * ExecSeqReScan rescans the relation + * ExecReScanSeqScan rescans the relation * ExecSeqMarkPos marks scan position * ExecSeqRestrPos restores scan position */ @@ -255,13 +255,13 @@ ExecEndSeqScan(SeqScanState *node) */ /* ---------------------------------------------------------------- - * ExecSeqReScan + * ExecReScanSeqScan * * Rescans the relation. * ---------------------------------------------------------------- */ void -ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt) +ExecReScanSeqScan(SeqScanState *node) { HeapScanDesc scan; diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index 7b3ee6d92d..1063ff701b 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeSetOp.c,v 1.33 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeSetOp.c,v 1.34 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -597,7 +597,7 @@ ExecEndSetOp(SetOpState *node) void -ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt) +ExecReScanSetOp(SetOpState *node) { ExecClearTuple(node->ps.ps_ResultTupleSlot); node->setop_done = false; @@ -619,7 +619,7 @@ ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt) * parameter changes, then we can just rescan the existing hash table; * no need to build it again. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) + if (node->ps.lefttree->chgParam == NULL) { ResetTupleHashIterator(node->hashtable, &node->hashiter); return; @@ -648,6 +648,6 @@ ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt) * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ps.lefttree->chgParam == NULL) + ExecReScan(node->ps.lefttree); } diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index 5b925da75a..5b993c199b 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.67 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.68 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -287,11 +287,11 @@ ExecSortRestrPos(SortState *node) } void -ExecReScanSort(SortState *node, ExprContext *exprCtxt) +ExecReScanSort(SortState *node) { /* - * If we haven't sorted yet, just return. If outerplan' chgParam is not - * NULL then it will be re-scanned by ExecProcNode, else - no reason to + * If we haven't sorted yet, just return. If outerplan's chgParam is not + * NULL then it will be re-scanned by ExecProcNode, else no reason to * re-scan it at all. */ if (!node->sort_Done) @@ -307,7 +307,7 @@ ExecReScanSort(SortState *node, ExprContext *exprCtxt) * * Otherwise we can just rewind and rescan the sorted output. */ - if (((PlanState *) node)->lefttree->chgParam != NULL || + if (node->ss.ps.lefttree->chgParam != NULL || node->bounded != node->bounded_Done || node->bound != node->bound_Done || !node->randomAccess) @@ -320,8 +320,8 @@ ExecReScanSort(SortState *node, ExprContext *exprCtxt) * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ss.ps.lefttree->chgParam == NULL) + ExecReScan(node->ss.ps.lefttree); } else tuplesort_rescan((Tuplesortstate *) node->tuplesortstate); diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index f5ac47402e..419f3f36bd 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.101 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.102 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -256,7 +256,7 @@ ExecScanSubPlan(SubPlanState *node, /* * Now that we've set up its parameters, we can reset the subplan. */ - ExecReScan(planstate, NULL); + ExecReScan(planstate); /* * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result @@ -508,7 +508,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext) /* * Reset subplan to start. */ - ExecReScan(planstate, NULL); + ExecReScan(planstate); /* * Scan the subplan and load the hash table(s). Note that when there are @@ -884,7 +884,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) * * Executes an InitPlan subplan and sets its output parameters. * - * This is called from ExecEvalParam() when the value of a PARAM_EXEC + * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC * parameter is requested and the param's execPlan field is set (indicating * that the param has not yet been evaluated). This allows lazy evaluation * of initplans: we don't run the subplan until/unless we need its output. diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index dbd42d7972..9741a103b5 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.45 2010/02/26 02:00:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.46 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,7 +22,7 @@ * ExecSubqueryNext retrieve next tuple in sequential order. * ExecInitSubqueryScan creates and initializes a subqueryscan node. * ExecEndSubqueryScan releases any storage allocated. - * ExecSubqueryReScan rescans the relation + * ExecReScanSubqueryScan rescans the relation * */ #include "postgres.h" @@ -187,13 +187,13 @@ ExecEndSubqueryScan(SubqueryScanState *node) } /* ---------------------------------------------------------------- - * ExecSubqueryReScan + * ExecReScanSubqueryScan * * Rescans the relation. * ---------------------------------------------------------------- */ void -ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt) +ExecReScanSubqueryScan(SubqueryScanState *node) { ExecScanReScan(&node->ss); @@ -210,5 +210,5 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt) * first ExecProcNode. */ if (node->subplan->chgParam == NULL) - ExecReScan(node->subplan, NULL); + ExecReScan(node->subplan); } diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index e66f97833f..7a8c7479aa 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeTidscan.c,v 1.65 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeTidscan.c,v 1.66 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,7 +17,7 @@ * * ExecTidScan scans a relation using tids * ExecInitTidScan creates and initializes state info. - * ExecTidReScan rescans the tid relation. + * ExecReScanTidScan rescans the tid relation. * ExecEndTidScan releases all storage. * ExecTidMarkPos marks scan position. * ExecTidRestrPos restores scan position. @@ -398,17 +398,12 @@ ExecTidScan(TidScanState *node) } /* ---------------------------------------------------------------- - * ExecTidReScan(node) + * ExecReScanTidScan(node) * ---------------------------------------------------------------- */ void -ExecTidReScan(TidScanState *node, ExprContext *exprCtxt) +ExecReScanTidScan(TidScanState *node) { - /* If we are being passed an outer tuple, save it for runtime key calc */ - if (exprCtxt != NULL) - node->ss.ps.ps_ExprContext->ecxt_outertuple = - exprCtxt->ecxt_outertuple; - if (node->tss_TidList) pfree(node->tss_TidList); node->tss_TidList = NULL; diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c index 82abb18477..1fd1109051 100644 --- a/src/backend/executor/nodeUnique.c +++ b/src/backend/executor/nodeUnique.c @@ -16,7 +16,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeUnique.c,v 1.63 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeUnique.c,v 1.64 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -184,7 +184,7 @@ ExecEndUnique(UniqueState *node) void -ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt) +ExecReScanUnique(UniqueState *node) { /* must clear result tuple so first input tuple is returned */ ExecClearTuple(node->ps.ps_ResultTupleSlot); @@ -193,6 +193,6 @@ ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt) * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ps.lefttree->chgParam == NULL) + ExecReScan(node->ps.lefttree); } diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index 482577b2fe..79d41ecc27 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.12 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.13 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,7 +19,7 @@ * ExecValuesNext retrieve next tuple in sequential order. * ExecInitValuesScan creates and initializes a valuesscan node. * ExecEndValuesScan releases any storage allocated. - * ExecValuesReScan rescans the values list + * ExecReScanValuesScan rescans the values list */ #include "postgres.h" @@ -319,13 +319,13 @@ ExecValuesRestrPos(ValuesScanState *node) } /* ---------------------------------------------------------------- - * ExecValuesReScan + * ExecReScanValuesScan * * Rescans the relation. * ---------------------------------------------------------------- */ void -ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt) +ExecReScanValuesScan(ValuesScanState *node) { ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index de6d0385e9..ad20c3cca1 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -27,7 +27,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeWindowAgg.c,v 1.13 2010/03/21 00:17:58 petere Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeWindowAgg.c,v 1.14 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1664,7 +1664,7 @@ ExecEndWindowAgg(WindowAggState *node) * ----------------- */ void -ExecReScanWindowAgg(WindowAggState *node, ExprContext *exprCtxt) +ExecReScanWindowAgg(WindowAggState *node) { ExprContext *econtext = node->ss.ps.ps_ExprContext; @@ -1691,8 +1691,8 @@ ExecReScanWindowAgg(WindowAggState *node, ExprContext *exprCtxt) * if chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. */ - if (((PlanState *) node)->lefttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->lefttree, exprCtxt); + if (node->ss.ps.lefttree->chgParam == NULL) + ExecReScan(node->ss.ps.lefttree); } /* diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c index 3fba4e3d9b..d0d22e6481 100644 --- a/src/backend/executor/nodeWorktablescan.c +++ b/src/backend/executor/nodeWorktablescan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeWorktablescan.c,v 1.10 2010/01/02 16:57:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeWorktablescan.c,v 1.11 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -203,13 +203,13 @@ ExecEndWorkTableScan(WorkTableScanState *node) } /* ---------------------------------------------------------------- - * ExecWorkTableScanReScan + * ExecReScanWorkTableScan * * Rescans the relation. * ---------------------------------------------------------------- */ void -ExecWorkTableScanReScan(WorkTableScanState *node, ExprContext *exprCtxt) +ExecReScanWorkTableScan(WorkTableScanState *node) { ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 829dc7ba8d..8e47403a48 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.464 2010/02/26 02:00:43 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.465 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -564,6 +564,11 @@ _copyNestLoop(NestLoop *from) */ CopyJoinFields((Join *) from, (Join *) newnode); + /* + * copy remainder of node + */ + COPY_NODE_FIELD(nestParams); + return newnode; } @@ -844,6 +849,20 @@ _copyLimit(Limit *from) return newnode; } +/* + * _copyNestLoopParam + */ +static NestLoopParam * +_copyNestLoopParam(NestLoopParam *from) +{ + NestLoopParam *newnode = makeNode(NestLoopParam); + + COPY_SCALAR_FIELD(paramno); + COPY_NODE_FIELD(paramval); + + return newnode; +} + /* * _copyPlanRowMark */ @@ -3671,6 +3690,9 @@ copyObject(void *from) case T_Limit: retval = _copyLimit(from); break; + case T_NestLoopParam: + retval = _copyNestLoopParam(from); + break; case T_PlanRowMark: retval = _copyPlanRowMark(from); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index dba8d4b669..ff4a9aaeef 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.385 2010/03/30 21:58:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.386 2010/07/12 17:01:05 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -517,6 +517,8 @@ _outNestLoop(StringInfo str, NestLoop *node) WRITE_NODE_TYPE("NESTLOOP"); _outJoinPlanInfo(str, (Join *) node); + + WRITE_NODE_FIELD(nestParams); } static void @@ -748,6 +750,15 @@ _outLimit(StringInfo str, Limit *node) WRITE_NODE_FIELD(limitCount); } +static void +_outNestLoopParam(StringInfo str, NestLoopParam *node) +{ + WRITE_NODE_TYPE("NESTLOOPPARAM"); + + WRITE_INT_FIELD(paramno); + WRITE_NODE_FIELD(paramval); +} + static void _outPlanRowMark(StringInfo str, PlanRowMark *node) { @@ -1565,6 +1576,8 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node) WRITE_BOOL_FIELD(hasPseudoConstantQuals); WRITE_BOOL_FIELD(hasRecursion); WRITE_INT_FIELD(wt_param_id); + WRITE_BITMAPSET_FIELD(curOuterRels); + WRITE_NODE_FIELD(curOuterParams); } static void @@ -2562,6 +2575,9 @@ _outNode(StringInfo str, void *obj) case T_Limit: _outLimit(str, obj); break; + case T_NestLoopParam: + _outNestLoopParam(str, obj); + break; case T_PlanRowMark: _outPlanRowMark(str, obj); break; diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 3d6f9f94fa..434babc5d8 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.275 2010/05/25 17:44:41 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.276 2010/07/12 17:01:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,6 +28,7 @@ #include "optimizer/planmain.h" #include "optimizer/predtest.h" #include "optimizer/restrictinfo.h" +#include "optimizer/subselect.h" #include "optimizer/tlist.h" #include "optimizer/var.h" #include "parser/parse_clause.h" @@ -35,6 +36,7 @@ #include "utils/lsyscache.h" +static Plan *create_plan_recurse(PlannerInfo *root, Path *best_path); static Plan *create_scan_plan(PlannerInfo *root, Path *best_path); static List *build_relation_tlist(RelOptInfo *rel); static bool use_physical_tlist(PlannerInfo *root, RelOptInfo *rel); @@ -72,7 +74,10 @@ static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path, Plan *outer_plan, Plan *inner_plan); static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path, Plan *outer_plan, Plan *inner_plan); -static List *fix_indexqual_references(List *indexquals, IndexPath *index_path); +static Node *replace_nestloop_params(PlannerInfo *root, Node *expr); +static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root); +static List *fix_indexqual_references(PlannerInfo *root, IndexPath *index_path, + List *indexquals); static List *get_switched_clauses(List *clauses, Relids outerrelids); static List *order_qual_clauses(PlannerInfo *root, List *clauses); static void copy_path_costsize(Plan *dest, Path *src); @@ -103,7 +108,7 @@ static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual, static BitmapAnd *make_bitmap_and(List *bitmapplans); static BitmapOr *make_bitmap_or(List *bitmapplans); static NestLoop *make_nestloop(List *tlist, - List *joinclauses, List *otherclauses, + List *joinclauses, List *otherclauses, List *nestParams, Plan *lefttree, Plan *righttree, JoinType jointype); static HashJoin *make_hashjoin(List *tlist, @@ -133,8 +138,8 @@ static Material *make_material(Plan *lefttree); /* * create_plan - * Creates the access plan for a query by tracing backwards through the - * desired chain of pathnodes, starting at the node 'best_path'. For + * Creates the access plan for a query by recursively processing the + * desired tree of pathnodes, starting at the node 'best_path'. For * every pathnode found, we create a corresponding plan node containing * appropriate id, target list, and qualification information. * @@ -151,6 +156,29 @@ create_plan(PlannerInfo *root, Path *best_path) { Plan *plan; + /* Initialize this module's private workspace in PlannerInfo */ + root->curOuterRels = NULL; + root->curOuterParams = NIL; + + /* Recursively process the path tree */ + plan = create_plan_recurse(root, best_path); + + /* Check we successfully assigned all NestLoopParams to plan nodes */ + if (root->curOuterParams != NIL) + elog(ERROR, "failed to assign all NestLoopParams to plan nodes"); + + return plan; +} + +/* + * create_plan_recurse + * Recursive guts of create_plan(). + */ +static Plan * +create_plan_recurse(PlannerInfo *root, Path *best_path) +{ + Plan *plan; + switch (best_path->pathtype) { case T_SeqScan: @@ -477,9 +505,16 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path) Plan *outer_plan; Plan *inner_plan; Plan *plan; + Relids saveOuterRels = root->curOuterRels; - outer_plan = create_plan(root, best_path->outerjoinpath); - inner_plan = create_plan(root, best_path->innerjoinpath); + outer_plan = create_plan_recurse(root, best_path->outerjoinpath); + + /* For a nestloop, include outer relids in curOuterRels for inner side */ + if (best_path->path.pathtype == T_NestLoop) + root->curOuterRels = bms_union(root->curOuterRels, + best_path->outerjoinpath->parent->relids); + + inner_plan = create_plan_recurse(root, best_path->innerjoinpath); switch (best_path->path.pathtype) { @@ -496,6 +531,10 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path) inner_plan); break; case T_NestLoop: + /* Restore curOuterRels */ + bms_free(root->curOuterRels); + root->curOuterRels = saveOuterRels; + plan = (Plan *) create_nestloop_plan(root, (NestPath *) best_path, outer_plan, @@ -571,7 +610,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path) { Path *subpath = (Path *) lfirst(subpaths); - subplans = lappend(subplans, create_plan(root, subpath)); + subplans = lappend(subplans, create_plan_recurse(root, subpath)); } plan = make_append(subplans, tlist); @@ -616,7 +655,7 @@ create_material_plan(PlannerInfo *root, MaterialPath *best_path) Material *plan; Plan *subplan; - subplan = create_plan(root, best_path->subpath); + subplan = create_plan_recurse(root, best_path->subpath); /* We don't want any excess columns in the materialized tuples */ disuse_physical_tlist(subplan, best_path->subpath); @@ -650,7 +689,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path) int groupColPos; ListCell *l; - subplan = create_plan(root, best_path->subpath); + subplan = create_plan_recurse(root, best_path->subpath); /* Done if we don't need to do any actual unique-ifying */ if (best_path->umethod == UNIQUE_PATH_NOOP) @@ -904,7 +943,7 @@ create_indexscan_plan(PlannerInfo *root, * The executor needs a copy with the indexkey on the left of each clause * and with index attr numbers substituted for table ones. */ - fixed_indexquals = fix_indexqual_references(indexquals, best_path); + fixed_indexquals = fix_indexqual_references(root, best_path, indexquals); /* * If this is an innerjoin scan, the indexclauses will contain join @@ -975,6 +1014,22 @@ create_indexscan_plan(PlannerInfo *root, /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */ qpqual = extract_actual_clauses(qpqual, false); + /* + * We have to replace any outer-relation variables with nestloop params + * in the indexqualorig and qpqual expressions. A bit annoying to have to + * do this separately from the processing in fix_indexqual_references --- + * rethink this when generalizing the inner indexscan support. But note + * we can't really do this earlier because it'd break the comparisons to + * predicates above ... (or would it? Those wouldn't have outer refs) + */ + if (best_path->isjoininner) + { + stripped_indexquals = (List *) + replace_nestloop_params(root, (Node *) stripped_indexquals); + qpqual = (List *) + replace_nestloop_params(root, (Node *) qpqual); + } + /* Finally ready to build the plan node */ scan_plan = make_indexscan(tlist, qpqual, @@ -1267,6 +1322,17 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, *indexqual = lappend(*indexqual, pred); } } + /* + * Replace outer-relation variables with nestloop params, but only + * after doing the above comparisons to index predicates. + */ + if (ipath->isjoininner) + { + *qual = (List *) + replace_nestloop_params(root, (Node *) *qual); + *indexqual = (List *) + replace_nestloop_params(root, (Node *) *indexqual); + } } else { @@ -1572,11 +1638,16 @@ create_nestloop_plan(PlannerInfo *root, Plan *outer_plan, Plan *inner_plan) { + NestLoop *join_plan; List *tlist = build_relation_tlist(best_path->path.parent); List *joinrestrictclauses = best_path->joinrestrictinfo; List *joinclauses; List *otherclauses; - NestLoop *join_plan; + Relids outerrelids; + List *nestParams; + ListCell *cell; + ListCell *prev; + ListCell *next; /* * If the inner path is a nestloop inner indexscan, it might be using some @@ -1605,9 +1676,32 @@ create_nestloop_plan(PlannerInfo *root, otherclauses = NIL; } + /* + * Identify any nestloop parameters that should be supplied by this join + * node, and move them from root->curOuterParams to the nestParams list. + */ + outerrelids = best_path->outerjoinpath->parent->relids; + nestParams = NIL; + prev = NULL; + for (cell = list_head(root->curOuterParams); cell; cell = next) + { + NestLoopParam *nlp = (NestLoopParam *) lfirst(cell); + + next = lnext(cell); + if (bms_is_member(nlp->paramval->varno, outerrelids)) + { + root->curOuterParams = list_delete_cell(root->curOuterParams, + cell, prev); + nestParams = lappend(nestParams, nlp); + } + else + prev = cell; + } + join_plan = make_nestloop(tlist, joinclauses, otherclauses, + nestParams, outer_plan, inner_plan, best_path->jointype); @@ -2015,13 +2109,73 @@ create_hashjoin_plan(PlannerInfo *root, * *****************************************************************************/ +/* + * replace_nestloop_params + * Replace outer-relation Vars in the given expression with nestloop Params + * + * All Vars belonging to the relation(s) identified by root->curOuterRels + * are replaced by Params, and entries are added to root->curOuterParams if + * not already present. + */ +static Node * +replace_nestloop_params(PlannerInfo *root, Node *expr) +{ + /* No setup needed for tree walk, so away we go */ + return replace_nestloop_params_mutator(expr, root); +} + +static Node * +replace_nestloop_params_mutator(Node *node, PlannerInfo *root) +{ + if (node == NULL) + return NULL; + if (IsA(node, Var)) + { + Var *var = (Var *) node; + Param *param; + NestLoopParam *nlp; + ListCell *lc; + + /* Upper-level Vars should be long gone at this point */ + Assert(var->varlevelsup == 0); + /* If not to be replaced, we can just return the Var unmodified */ + if (!bms_is_member(var->varno, root->curOuterRels)) + return node; + /* Create a Param representing the Var */ + param = assign_nestloop_param(root, var); + /* Is this param already listed in root->curOuterParams? */ + foreach(lc, root->curOuterParams) + { + nlp = (NestLoopParam *) lfirst(lc); + if (nlp->paramno == param->paramid) + { + Assert(equal(var, nlp->paramval)); + /* Present, so we can just return the Param */ + return (Node *) param; + } + } + /* No, so add it */ + nlp = makeNode(NestLoopParam); + nlp->paramno = param->paramid; + nlp->paramval = var; + root->curOuterParams = lappend(root->curOuterParams, nlp); + /* And return the replacement Param */ + return (Node *) param; + } + return expression_tree_mutator(node, + replace_nestloop_params_mutator, + (void *) root); +} + /* * fix_indexqual_references * Adjust indexqual clauses to the form the executor's indexqual * machinery needs. * - * We have three tasks here: + * We have four tasks here: * * Remove RestrictInfo nodes from the input clauses. + * * Replace any outer-relation Var nodes with nestloop Params. + * (XXX eventually, that responsibility should go elsewhere?) * * Index keys must be represented by Var nodes with varattno set to the * index's attribute number, not the attribute number in the original rel. * * If the index key is on the right, commute the clause to put it on the @@ -2033,7 +2187,8 @@ create_hashjoin_plan(PlannerInfo *root, * two separate copies of the subplan tree, or things will go awry). */ static List * -fix_indexqual_references(List *indexquals, IndexPath *index_path) +fix_indexqual_references(PlannerInfo *root, IndexPath *index_path, + List *indexquals) { IndexOptInfo *index = index_path->indexinfo; List *fixed_indexquals; @@ -2041,26 +2196,20 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path) fixed_indexquals = NIL; - /* - * For each qual clause, commute if needed to put the indexkey operand on - * the left, and then fix its varattno. (We do not need to change the - * other side of the clause.) - */ foreach(l, indexquals) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - Expr *clause; + Node *clause; Assert(IsA(rinfo, RestrictInfo)); /* - * Make a copy that will become the fixed clause. + * Replace any outer-relation variables with nestloop params. * - * We used to try to do a shallow copy here, but that fails if there - * is a subplan in the arguments of the opclause. So just do a full - * copy. + * This also makes a copy of the clause, so it's safe to modify it + * in-place below. */ - clause = (Expr *) copyObject((Node *) rinfo->clause); + clause = replace_nestloop_params(root, (Node *) rinfo->clause); if (IsA(clause, OpExpr)) { @@ -2765,6 +2914,7 @@ static NestLoop * make_nestloop(List *tlist, List *joinclauses, List *otherclauses, + List *nestParams, Plan *lefttree, Plan *righttree, JoinType jointype) @@ -2779,6 +2929,7 @@ make_nestloop(List *tlist, plan->righttree = righttree; node->join.jointype = jointype; node->join.joinqual = joinclauses; + node->nestParams = nestParams; return node; } diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 70be2e66f2..450970e5c3 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.160 2010/02/26 02:00:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.161 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -89,8 +89,6 @@ static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset); static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context); static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context); static void set_join_references(PlannerGlobal *glob, Join *join, int rtoffset); -static void set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan, - indexed_tlist *outer_itlist); static void set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset); static void set_dummy_tlist_references(Plan *plan, int rtoffset); static indexed_tlist *build_tlist_index(List *tlist); @@ -878,12 +876,11 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context) Assert(var->varlevelsup == 0); /* - * We should not see any Vars marked INNER, but in a nestloop inner - * scan there could be OUTER Vars. Leave them alone. + * We should not see any Vars marked INNER or OUTER. */ Assert(var->varno != INNER); - if (var->varno > 0 && var->varno != OUTER) - var->varno += context->rtoffset; + Assert(var->varno != OUTER); + var->varno += context->rtoffset; if (var->varnoold > 0) var->varnoold += context->rtoffset; return (Node *) var; @@ -927,10 +924,6 @@ fix_scan_expr_walker(Node *node, fix_scan_expr_context *context) * values to the result domain number of either the corresponding outer * or inner join tuple item. Also perform opcode lookup for these * expressions. and add regclass OIDs to glob->relationOids. - * - * In the case of a nestloop with inner indexscan, we will also need to - * apply the same transformation to any outer vars appearing in the - * quals of the child indexscan. set_inner_join_references does that. */ static void set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) @@ -966,8 +959,18 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) /* Now do join-type-specific stuff */ if (IsA(join, NestLoop)) { - /* This processing is split out to handle possible recursion */ - set_inner_join_references(glob, inner_plan, outer_itlist); + NestLoop *nl = (NestLoop *) join; + ListCell *lc; + + foreach(lc, nl->nestParams) + { + NestLoopParam *nlp = (NestLoopParam *) lfirst(lc); + + nlp->paramval = (Var *) fix_upper_expr(glob, + (Node *) nlp->paramval, + outer_itlist, + rtoffset); + } } else if (IsA(join, MergeJoin)) { @@ -996,193 +999,6 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) pfree(inner_itlist); } -/* - * set_inner_join_references - * Handle join references appearing in an inner indexscan's quals - * - * To handle bitmap-scan plan trees, we have to be able to recurse down - * to the bottom BitmapIndexScan nodes; likewise, appendrel indexscans - * require recursing through Append nodes. This is split out as a separate - * function so that it can recurse. - * - * Note we do *not* apply any rtoffset for non-join Vars; this is because - * the quals will be processed again by fix_scan_expr when the set_plan_refs - * recursion reaches the inner indexscan, and so we'd have done it twice. - */ -static void -set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan, - indexed_tlist *outer_itlist) -{ - if (IsA(inner_plan, IndexScan)) - { - /* - * An index is being used to reduce the number of tuples scanned in - * the inner relation. If there are join clauses being used with the - * index, we must update their outer-rel var nodes to refer to the - * outer side of the join. - */ - IndexScan *innerscan = (IndexScan *) inner_plan; - List *indexqualorig = innerscan->indexqualorig; - - /* No work needed if indexqual refers only to its own rel... */ - if (NumRelids((Node *) indexqualorig) > 1) - { - Index innerrel = innerscan->scan.scanrelid; - - /* only refs to outer vars get changed in the inner qual */ - innerscan->indexqualorig = fix_join_expr(glob, - indexqualorig, - outer_itlist, - NULL, - innerrel, - 0); - innerscan->indexqual = fix_join_expr(glob, - innerscan->indexqual, - outer_itlist, - NULL, - innerrel, - 0); - - /* - * We must fix the inner qpqual too, if it has join clauses (this - * could happen if special operators are involved: some indexquals - * may get rechecked as qpquals). - */ - if (NumRelids((Node *) inner_plan->qual) > 1) - inner_plan->qual = fix_join_expr(glob, - inner_plan->qual, - outer_itlist, - NULL, - innerrel, - 0); - } - } - else if (IsA(inner_plan, BitmapIndexScan)) - { - /* - * Same, but index is being used within a bitmap plan. - */ - BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan; - List *indexqualorig = innerscan->indexqualorig; - - /* No work needed if indexqual refers only to its own rel... */ - if (NumRelids((Node *) indexqualorig) > 1) - { - Index innerrel = innerscan->scan.scanrelid; - - /* only refs to outer vars get changed in the inner qual */ - innerscan->indexqualorig = fix_join_expr(glob, - indexqualorig, - outer_itlist, - NULL, - innerrel, - 0); - innerscan->indexqual = fix_join_expr(glob, - innerscan->indexqual, - outer_itlist, - NULL, - innerrel, - 0); - /* no need to fix inner qpqual */ - Assert(inner_plan->qual == NIL); - } - } - else if (IsA(inner_plan, BitmapHeapScan)) - { - /* - * The inner side is a bitmap scan plan. Fix the top node, and - * recurse to get the lower nodes. - * - * Note: create_bitmap_scan_plan removes clauses from bitmapqualorig - * if they are duplicated in qpqual, so must test these independently. - */ - BitmapHeapScan *innerscan = (BitmapHeapScan *) inner_plan; - Index innerrel = innerscan->scan.scanrelid; - List *bitmapqualorig = innerscan->bitmapqualorig; - - /* only refs to outer vars get changed in the inner qual */ - if (NumRelids((Node *) bitmapqualorig) > 1) - innerscan->bitmapqualorig = fix_join_expr(glob, - bitmapqualorig, - outer_itlist, - NULL, - innerrel, - 0); - - /* - * We must fix the inner qpqual too, if it has join clauses (this - * could happen if special operators are involved: some indexquals may - * get rechecked as qpquals). - */ - if (NumRelids((Node *) inner_plan->qual) > 1) - inner_plan->qual = fix_join_expr(glob, - inner_plan->qual, - outer_itlist, - NULL, - innerrel, - 0); - - /* Now recurse */ - set_inner_join_references(glob, inner_plan->lefttree, outer_itlist); - } - else if (IsA(inner_plan, BitmapAnd)) - { - /* All we need do here is recurse */ - BitmapAnd *innerscan = (BitmapAnd *) inner_plan; - ListCell *l; - - foreach(l, innerscan->bitmapplans) - { - set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist); - } - } - else if (IsA(inner_plan, BitmapOr)) - { - /* All we need do here is recurse */ - BitmapOr *innerscan = (BitmapOr *) inner_plan; - ListCell *l; - - foreach(l, innerscan->bitmapplans) - { - set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist); - } - } - else if (IsA(inner_plan, TidScan)) - { - TidScan *innerscan = (TidScan *) inner_plan; - Index innerrel = innerscan->scan.scanrelid; - - innerscan->tidquals = fix_join_expr(glob, - innerscan->tidquals, - outer_itlist, - NULL, - innerrel, - 0); - } - else if (IsA(inner_plan, Append)) - { - /* - * The inner side is an append plan. Recurse to see if it contains - * indexscans that need to be fixed. - */ - Append *appendplan = (Append *) inner_plan; - ListCell *l; - - foreach(l, appendplan->appendplans) - { - set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist); - } - } - else if (IsA(inner_plan, Result)) - { - /* Recurse through a gating Result node (similar to Append case) */ - Result *result = (Result *) inner_plan; - - if (result->plan.lefttree) - set_inner_join_references(glob, result->plan.lefttree, outer_itlist); - } -} - /* * set_upper_references * Update the targetlist and quals of an upper-level plan node @@ -1532,23 +1348,21 @@ search_indexed_tlist_for_sortgroupref(Node *node, * * This is used in two different scenarios: a normal join clause, where * all the Vars in the clause *must* be replaced by OUTER or INNER references; - * and an indexscan being used on the inner side of a nestloop join. - * In the latter case we want to replace the outer-relation Vars by OUTER - * references, while Vars of the inner relation should be adjusted by rtoffset. - * (We also implement RETURNING clause fixup using this second scenario.) + * and a RETURNING clause, which may contain both Vars of the target relation + * and Vars of other relations. In the latter case we want to replace the + * other-relation Vars by OUTER references, while leaving target Vars alone. * * For a normal join, acceptable_rel should be zero so that any failure to - * match a Var will be reported as an error. For the indexscan case, - * pass inner_itlist = NULL and acceptable_rel = the (not-offseted-yet) ID - * of the inner relation. + * match a Var will be reported as an error. For the RETURNING case, pass + * inner_itlist = NULL and acceptable_rel = the ID of the target relation. * * 'clauses' is the targetlist or list of join clauses * 'outer_itlist' is the indexed target list of the outer join relation * 'inner_itlist' is the indexed target list of the inner join relation, * or NULL * 'acceptable_rel' is either zero or the rangetable index of a relation - * whose Vars may appear in the clause without provoking an error. - * 'rtoffset' is what to add to varno for Vars of acceptable_rel. + * whose Vars may appear in the clause without provoking an error + * 'rtoffset': how much to increment varnoold by * * Returns the new expression tree. The original clause structure is * not modified. @@ -1603,8 +1417,8 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) if (var->varno == context->acceptable_rel) { var = copyVar(var); - var->varno += context->rtoffset; - var->varnoold += context->rtoffset; + if (var->varnoold > 0) + var->varnoold += context->rtoffset; return (Node *) var; } @@ -1783,7 +1597,7 @@ set_returning_clause_references(PlannerGlobal *glob, /* * We can perform the desired Var fixup by abusing the fix_join_expr - * machinery that normally handles inner indexscan fixup. We search the + * machinery that formerly handled inner indexscan fixup. We search the * top plan's targetlist for Vars of non-result relations, and use * fix_join_expr to convert RETURNING Vars into references to those tlist * entries, while leaving result-rel Vars as-is. diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index cf503d5113..b94419a09d 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.162 2010/04/19 00:55:25 rhaas Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.163 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -83,30 +83,20 @@ static bool finalize_primnode(Node *node, finalize_primnode_context *context); /* - * Generate a Param node to replace the given Var, - * which is expected to have varlevelsup > 0 (ie, it is not local). + * Select a PARAM_EXEC number to identify the given Var. + * If the Var already has a param slot, return that one. */ -static Param * -replace_outer_var(PlannerInfo *root, Var *var) +static int +assign_param_for_var(PlannerInfo *root, Var *var) { - Param *retval; ListCell *ppl; PlannerParamItem *pitem; Index abslevel; int i; - Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level); abslevel = root->query_level - var->varlevelsup; - /* - * If there's already a paramlist entry for this same Var, just use it. - * NOTE: in sufficiently complex querytrees, it is possible for the same - * varno/abslevel to refer to different RTEs in different parts of the - * parsetree, so that different fields might end up sharing the same Param - * number. As long as we check the vartype/typmod as well, I believe that - * this sort of aliasing will cause no trouble. The correct field should - * get stored into the Param slot at execution in each part of the tree. - */ + /* If there's already a paramlist entry for this same Var, just use it */ i = 0; foreach(ppl, root->glob->paramlist) { @@ -119,24 +109,76 @@ replace_outer_var(PlannerInfo *root, Var *var) pvar->varattno == var->varattno && pvar->vartype == var->vartype && pvar->vartypmod == var->vartypmod) - break; + return i; } i++; } - if (!ppl) - { - /* Nope, so make a new one */ - var = (Var *) copyObject(var); - var->varlevelsup = 0; + /* Nope, so make a new one */ + var = (Var *) copyObject(var); + var->varlevelsup = 0; - pitem = makeNode(PlannerParamItem); - pitem->item = (Node *) var; - pitem->abslevel = abslevel; + pitem = makeNode(PlannerParamItem); + pitem->item = (Node *) var; + pitem->abslevel = abslevel; - root->glob->paramlist = lappend(root->glob->paramlist, pitem); - /* i is already the correct index for the new item */ - } + root->glob->paramlist = lappend(root->glob->paramlist, pitem); + + /* i is already the correct list index for the new item */ + return i; +} + +/* + * Generate a Param node to replace the given Var, + * which is expected to have varlevelsup > 0 (ie, it is not local). + */ +static Param * +replace_outer_var(PlannerInfo *root, Var *var) +{ + Param *retval; + int i; + + Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level); + + /* + * Find the Var in root->glob->paramlist, or add it if not present. + * + * NOTE: in sufficiently complex querytrees, it is possible for the same + * varno/abslevel to refer to different RTEs in different parts of the + * parsetree, so that different fields might end up sharing the same Param + * number. As long as we check the vartype/typmod as well, I believe that + * this sort of aliasing will cause no trouble. The correct field should + * get stored into the Param slot at execution in each part of the tree. + */ + i = assign_param_for_var(root, var); + + retval = makeNode(Param); + retval->paramkind = PARAM_EXEC; + retval->paramid = i; + retval->paramtype = var->vartype; + retval->paramtypmod = var->vartypmod; + retval->location = -1; + + return retval; +} + +/* + * Generate a Param node to replace the given Var, which will be supplied + * from an upper NestLoop join node. + * + * Because we allow nestloop and subquery Params to alias each other, + * this is effectively the same as replace_outer_var, except that we expect + * the Var to be local to the current query level. + */ +Param * +assign_nestloop_param(PlannerInfo *root, Var *var) +{ + Param *retval; + int i; + + Assert(var->varlevelsup == 0); + + i = assign_param_for_var(root, var); retval = makeNode(Param); retval->paramkind = PARAM_EXEC; @@ -1773,8 +1815,9 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan, bool attach_initplans) * * Note: this is a bit overly generous since some parameters of upper * query levels might belong to query subtrees that don't include this - * query. However, valid_params is only a debugging crosscheck, so it - * doesn't seem worth expending lots of cycles to try to be exact. + * query, or might be nestloop params that won't be passed down at all. + * However, valid_params is only a debugging crosscheck, so it doesn't + * seem worth expending lots of cycles to try to be exact. */ valid_params = bms_copy(initSetParam); paramid = 0; @@ -1849,6 +1892,8 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, { finalize_primnode_context context; int locally_added_param; + Bitmapset *nestloop_params; + Bitmapset *child_params; if (plan == NULL) return NULL; @@ -1856,6 +1901,7 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, context.root = root; context.paramids = NULL; /* initialize set to empty */ locally_added_param = -1; /* there isn't one */ + nestloop_params = NULL; /* there aren't any */ /* * When we call finalize_primnode, context.paramids sets are automatically @@ -2056,8 +2102,20 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, break; case T_NestLoop: - finalize_primnode((Node *) ((Join *) plan)->joinqual, - &context); + { + ListCell *l; + + finalize_primnode((Node *) ((Join *) plan)->joinqual, + &context); + /* collect set of params that will be passed to right child */ + foreach(l, ((NestLoop *) plan)->nestParams) + { + NestLoopParam *nlp = (NestLoopParam *) lfirst(l); + + nestloop_params = bms_add_member(nestloop_params, + nlp->paramno); + } + } break; case T_MergeJoin: @@ -2120,17 +2178,32 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, } /* Process left and right child plans, if any */ - context.paramids = bms_add_members(context.paramids, - finalize_plan(root, - plan->lefttree, - valid_params, - scan_params)); + child_params = finalize_plan(root, + plan->lefttree, + valid_params, + scan_params); + context.paramids = bms_add_members(context.paramids, child_params); - context.paramids = bms_add_members(context.paramids, - finalize_plan(root, - plan->righttree, - valid_params, - scan_params)); + if (nestloop_params) + { + /* right child can reference nestloop_params as well as valid_params */ + child_params = finalize_plan(root, + plan->righttree, + bms_union(nestloop_params, valid_params), + scan_params); + /* ... and they don't count as parameters used at my level */ + child_params = bms_difference(child_params, nestloop_params); + bms_free(nestloop_params); + } + else + { + /* easy case */ + child_params = finalize_plan(root, + plan->righttree, + valid_params, + scan_params); + } + context.paramids = bms_add_members(context.paramids, child_params); /* * Any locally generated parameter doesn't count towards its generating diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 119cc2505b..ecaaab5f75 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.169 2010/07/09 14:06:01 rhaas Exp $ + * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.170 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -82,7 +82,7 @@ extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook; /* * prototypes from functions in execAmi.c */ -extern void ExecReScan(PlanState *node, ExprContext *exprCtxt); +extern void ExecReScan(PlanState *node); extern void ExecMarkPos(PlanState *node); extern void ExecRestrPos(PlanState *node); extern bool ExecSupportsMarkRestore(NodeTag plantype); diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h index 67cc71c84b..5e7ab5913b 100644 --- a/src/include/executor/nodeAgg.h +++ b/src/include/executor/nodeAgg.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeAgg.h,v 1.32 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeAgg.h,v 1.33 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,7 +19,7 @@ extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags); extern TupleTableSlot *ExecAgg(AggState *node); extern void ExecEndAgg(AggState *node); -extern void ExecReScanAgg(AggState *node, ExprContext *exprCtxt); +extern void ExecReScanAgg(AggState *node); extern Size hash_agg_entry_size(int numAggs); diff --git a/src/include/executor/nodeAppend.h b/src/include/executor/nodeAppend.h index fbecd82049..9e3f293785 100644 --- a/src/include/executor/nodeAppend.h +++ b/src/include/executor/nodeAppend.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeAppend.h,v 1.30 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeAppend.h,v 1.31 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern AppendState *ExecInitAppend(Append *node, EState *estate, int eflags); extern TupleTableSlot *ExecAppend(AppendState *node); extern void ExecEndAppend(AppendState *node); -extern void ExecReScanAppend(AppendState *node, ExprContext *exprCtxt); +extern void ExecReScanAppend(AppendState *node); #endif /* NODEAPPEND_H */ diff --git a/src/include/executor/nodeBitmapAnd.h b/src/include/executor/nodeBitmapAnd.h index 6a8bdf4363..fa09a790fb 100644 --- a/src/include/executor/nodeBitmapAnd.h +++ b/src/include/executor/nodeBitmapAnd.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeBitmapAnd.h,v 1.8 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeBitmapAnd.h,v 1.9 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern BitmapAndState *ExecInitBitmapAnd(BitmapAnd *node, EState *estate, int eflags); extern Node *MultiExecBitmapAnd(BitmapAndState *node); extern void ExecEndBitmapAnd(BitmapAndState *node); -extern void ExecReScanBitmapAnd(BitmapAndState *node, ExprContext *exprCtxt); +extern void ExecReScanBitmapAnd(BitmapAndState *node); #endif /* NODEBITMAPAND_H */ diff --git a/src/include/executor/nodeBitmapHeapscan.h b/src/include/executor/nodeBitmapHeapscan.h index 174f60dd0a..472181881f 100644 --- a/src/include/executor/nodeBitmapHeapscan.h +++ b/src/include/executor/nodeBitmapHeapscan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeBitmapHeapscan.h,v 1.8 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeBitmapHeapscan.h,v 1.9 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags); extern TupleTableSlot *ExecBitmapHeapScan(BitmapHeapScanState *node); extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node); -extern void ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt); +extern void ExecReScanBitmapHeapScan(BitmapHeapScanState *node); #endif /* NODEBITMAPHEAPSCAN_H */ diff --git a/src/include/executor/nodeBitmapIndexscan.h b/src/include/executor/nodeBitmapIndexscan.h index 480494be0c..bb4b28cc1a 100644 --- a/src/include/executor/nodeBitmapIndexscan.h +++ b/src/include/executor/nodeBitmapIndexscan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeBitmapIndexscan.h,v 1.8 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeBitmapIndexscan.h,v 1.9 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern BitmapIndexScanState *ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags); extern Node *MultiExecBitmapIndexScan(BitmapIndexScanState *node); extern void ExecEndBitmapIndexScan(BitmapIndexScanState *node); -extern void ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt); +extern void ExecReScanBitmapIndexScan(BitmapIndexScanState *node); #endif /* NODEBITMAPINDEXSCAN_H */ diff --git a/src/include/executor/nodeBitmapOr.h b/src/include/executor/nodeBitmapOr.h index a9ada8f63f..8987c700c5 100644 --- a/src/include/executor/nodeBitmapOr.h +++ b/src/include/executor/nodeBitmapOr.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeBitmapOr.h,v 1.8 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeBitmapOr.h,v 1.9 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern BitmapOrState *ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags); extern Node *MultiExecBitmapOr(BitmapOrState *node); extern void ExecEndBitmapOr(BitmapOrState *node); -extern void ExecReScanBitmapOr(BitmapOrState *node, ExprContext *exprCtxt); +extern void ExecReScanBitmapOr(BitmapOrState *node); #endif /* NODEBITMAPOR_H */ diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h index 54008f8b74..22e6dd2152 100644 --- a/src/include/executor/nodeCtescan.h +++ b/src/include/executor/nodeCtescan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeCtescan.h,v 1.4 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeCtescan.h,v 1.5 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern CteScanState *ExecInitCteScan(CteScan *node, EState *estate, int eflags); extern TupleTableSlot *ExecCteScan(CteScanState *node); extern void ExecEndCteScan(CteScanState *node); -extern void ExecCteScanReScan(CteScanState *node, ExprContext *exprCtxt); +extern void ExecReScanCteScan(CteScanState *node); #endif /* NODECTESCAN_H */ diff --git a/src/include/executor/nodeFunctionscan.h b/src/include/executor/nodeFunctionscan.h index 21e868aff6..1584783ed0 100644 --- a/src/include/executor/nodeFunctionscan.h +++ b/src/include/executor/nodeFunctionscan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeFunctionscan.h,v 1.15 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeFunctionscan.h,v 1.16 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags); extern TupleTableSlot *ExecFunctionScan(FunctionScanState *node); extern void ExecEndFunctionScan(FunctionScanState *node); -extern void ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt); +extern void ExecReScanFunctionScan(FunctionScanState *node); #endif /* NODEFUNCTIONSCAN_H */ diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h index a7362b2a79..8af917a83f 100644 --- a/src/include/executor/nodeGroup.h +++ b/src/include/executor/nodeGroup.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeGroup.h,v 1.35 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeGroup.h,v 1.36 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern GroupState *ExecInitGroup(Group *node, EState *estate, int eflags); extern TupleTableSlot *ExecGroup(GroupState *node); extern void ExecEndGroup(GroupState *node); -extern void ExecReScanGroup(GroupState *node, ExprContext *exprCtxt); +extern void ExecReScanGroup(GroupState *node); #endif /* NODEGROUP_H */ diff --git a/src/include/executor/nodeHash.h b/src/include/executor/nodeHash.h index c5e18a93e7..53348c435f 100644 --- a/src/include/executor/nodeHash.h +++ b/src/include/executor/nodeHash.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeHash.h,v 1.49 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeHash.h,v 1.50 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,7 +20,7 @@ extern HashState *ExecInitHash(Hash *node, EState *estate, int eflags); extern TupleTableSlot *ExecHash(HashState *node); extern Node *MultiExecHash(HashState *node); extern void ExecEndHash(HashState *node); -extern void ExecReScanHash(HashState *node, ExprContext *exprCtxt); +extern void ExecReScanHash(HashState *node); extern HashJoinTable ExecHashTableCreate(Hash *node, List *hashOperators); extern void ExecHashTableDestroy(HashJoinTable hashtable); diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h index 462410d95c..0a68e65f51 100644 --- a/src/include/executor/nodeHashjoin.h +++ b/src/include/executor/nodeHashjoin.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeHashjoin.h,v 1.40 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeHashjoin.h,v 1.41 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,7 +20,7 @@ extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags); extern TupleTableSlot *ExecHashJoin(HashJoinState *node); extern void ExecEndHashJoin(HashJoinState *node); -extern void ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt); +extern void ExecReScanHashJoin(HashJoinState *node); extern void ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue, BufFile **fileptr); diff --git a/src/include/executor/nodeIndexscan.h b/src/include/executor/nodeIndexscan.h index 15608cdff8..2a740a4f3e 100644 --- a/src/include/executor/nodeIndexscan.h +++ b/src/include/executor/nodeIndexscan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.36 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.37 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,7 +21,7 @@ extern TupleTableSlot *ExecIndexScan(IndexScanState *node); extern void ExecEndIndexScan(IndexScanState *node); extern void ExecIndexMarkPos(IndexScanState *node); extern void ExecIndexRestrPos(IndexScanState *node); -extern void ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt); +extern void ExecReScanIndexScan(IndexScanState *node); /* routines exported to share code with nodeBitmapIndexscan.c */ extern void ExecIndexBuildScanKeys(PlanState *planstate, Relation index, diff --git a/src/include/executor/nodeLimit.h b/src/include/executor/nodeLimit.h index 33cd5e298d..1e57eca559 100644 --- a/src/include/executor/nodeLimit.h +++ b/src/include/executor/nodeLimit.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeLimit.h,v 1.18 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeLimit.h,v 1.19 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern LimitState *ExecInitLimit(Limit *node, EState *estate, int eflags); extern TupleTableSlot *ExecLimit(LimitState *node); extern void ExecEndLimit(LimitState *node); -extern void ExecReScanLimit(LimitState *node, ExprContext *exprCtxt); +extern void ExecReScanLimit(LimitState *node); #endif /* NODELIMIT_H */ diff --git a/src/include/executor/nodeLockRows.h b/src/include/executor/nodeLockRows.h index c2ea69611e..b3bb3a277c 100644 --- a/src/include/executor/nodeLockRows.h +++ b/src/include/executor/nodeLockRows.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeLockRows.h,v 1.2 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeLockRows.h,v 1.3 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern LockRowsState *ExecInitLockRows(LockRows *node, EState *estate, int eflags); extern TupleTableSlot *ExecLockRows(LockRowsState *node); extern void ExecEndLockRows(LockRowsState *node); -extern void ExecReScanLockRows(LockRowsState *node, ExprContext *exprCtxt); +extern void ExecReScanLockRows(LockRowsState *node); #endif /* NODELOCKROWS_H */ diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h index bc350d1bde..ff1087b0cc 100644 --- a/src/include/executor/nodeMaterial.h +++ b/src/include/executor/nodeMaterial.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeMaterial.h,v 1.30 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeMaterial.h,v 1.31 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,6 @@ extern TupleTableSlot *ExecMaterial(MaterialState *node); extern void ExecEndMaterial(MaterialState *node); extern void ExecMaterialMarkPos(MaterialState *node); extern void ExecMaterialRestrPos(MaterialState *node); -extern void ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt); +extern void ExecReScanMaterial(MaterialState *node); #endif /* NODEMATERIAL_H */ diff --git a/src/include/executor/nodeMergejoin.h b/src/include/executor/nodeMergejoin.h index 24b4835ec0..6a176d90f0 100644 --- a/src/include/executor/nodeMergejoin.h +++ b/src/include/executor/nodeMergejoin.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeMergejoin.h,v 1.29 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeMergejoin.h,v 1.30 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags); extern TupleTableSlot *ExecMergeJoin(MergeJoinState *node); extern void ExecEndMergeJoin(MergeJoinState *node); -extern void ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt); +extern void ExecReScanMergeJoin(MergeJoinState *node); #endif /* NODEMERGEJOIN_H */ diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h index a503581943..373ae1c13f 100644 --- a/src/include/executor/nodeModifyTable.h +++ b/src/include/executor/nodeModifyTable.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeModifyTable.h,v 1.2 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeModifyTable.h,v 1.3 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,6 +18,6 @@ extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags); extern TupleTableSlot *ExecModifyTable(ModifyTableState *node); extern void ExecEndModifyTable(ModifyTableState *node); -extern void ExecReScanModifyTable(ModifyTableState *node, ExprContext *exprCtxt); +extern void ExecReScanModifyTable(ModifyTableState *node); #endif /* NODEMODIFYTABLE_H */ diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h index ce960de8f2..01e22b6082 100644 --- a/src/include/executor/nodeNestloop.h +++ b/src/include/executor/nodeNestloop.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeNestloop.h,v 1.30 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeNestloop.h,v 1.31 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate, int eflags); extern TupleTableSlot *ExecNestLoop(NestLoopState *node); extern void ExecEndNestLoop(NestLoopState *node); -extern void ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt); +extern void ExecReScanNestLoop(NestLoopState *node); #endif /* NODENESTLOOP_H */ diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h index 8d8c99b0e6..87d9888f86 100644 --- a/src/include/executor/nodeRecursiveunion.h +++ b/src/include/executor/nodeRecursiveunion.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeRecursiveunion.h,v 1.4 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeRecursiveunion.h,v 1.5 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern RecursiveUnionState *ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags); extern TupleTableSlot *ExecRecursiveUnion(RecursiveUnionState *node); extern void ExecEndRecursiveUnion(RecursiveUnionState *node); -extern void ExecRecursiveUnionReScan(RecursiveUnionState *node, ExprContext *exprCtxt); +extern void ExecReScanRecursiveUnion(RecursiveUnionState *node); #endif /* NODERECURSIVEUNION_H */ diff --git a/src/include/executor/nodeResult.h b/src/include/executor/nodeResult.h index 89085e8945..4c6234d688 100644 --- a/src/include/executor/nodeResult.h +++ b/src/include/executor/nodeResult.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeResult.h,v 1.28 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeResult.h,v 1.29 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,6 @@ extern TupleTableSlot *ExecResult(ResultState *node); extern void ExecEndResult(ResultState *node); extern void ExecResultMarkPos(ResultState *node); extern void ExecResultRestrPos(ResultState *node); -extern void ExecReScanResult(ResultState *node, ExprContext *exprCtxt); +extern void ExecReScanResult(ResultState *node); #endif /* NODERESULT_H */ diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h index 6184c3edcd..334fd44920 100644 --- a/src/include/executor/nodeSeqscan.h +++ b/src/include/executor/nodeSeqscan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeSeqscan.h,v 1.29 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeSeqscan.h,v 1.30 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,6 @@ extern TupleTableSlot *ExecSeqScan(SeqScanState *node); extern void ExecEndSeqScan(SeqScanState *node); extern void ExecSeqMarkPos(SeqScanState *node); extern void ExecSeqRestrPos(SeqScanState *node); -extern void ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt); +extern void ExecReScanSeqScan(SeqScanState *node); #endif /* NODESEQSCAN_H */ diff --git a/src/include/executor/nodeSetOp.h b/src/include/executor/nodeSetOp.h index 791b6595aa..cdb0579afd 100644 --- a/src/include/executor/nodeSetOp.h +++ b/src/include/executor/nodeSetOp.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeSetOp.h,v 1.18 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeSetOp.h,v 1.19 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate, int eflags); extern TupleTableSlot *ExecSetOp(SetOpState *node); extern void ExecEndSetOp(SetOpState *node); -extern void ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt); +extern void ExecReScanSetOp(SetOpState *node); #endif /* NODESETOP_H */ diff --git a/src/include/executor/nodeSort.h b/src/include/executor/nodeSort.h index d5a87e8923..ee63274af2 100644 --- a/src/include/executor/nodeSort.h +++ b/src/include/executor/nodeSort.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeSort.h,v 1.27 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeSort.h,v 1.28 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,6 @@ extern TupleTableSlot *ExecSort(SortState *node); extern void ExecEndSort(SortState *node); extern void ExecSortMarkPos(SortState *node); extern void ExecSortRestrPos(SortState *node); -extern void ExecReScanSort(SortState *node, ExprContext *exprCtxt); +extern void ExecReScanSort(SortState *node); #endif /* NODESORT_H */ diff --git a/src/include/executor/nodeSubqueryscan.h b/src/include/executor/nodeSubqueryscan.h index 387a12b045..1139ce3f3e 100644 --- a/src/include/executor/nodeSubqueryscan.h +++ b/src/include/executor/nodeSubqueryscan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeSubqueryscan.h,v 1.18 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeSubqueryscan.h,v 1.19 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags); extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node); extern void ExecEndSubqueryScan(SubqueryScanState *node); -extern void ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt); +extern void ExecReScanSubqueryScan(SubqueryScanState *node); #endif /* NODESUBQUERYSCAN_H */ diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h index 1bbbb1e52f..45b9b814cb 100644 --- a/src/include/executor/nodeTidscan.h +++ b/src/include/executor/nodeTidscan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeTidscan.h,v 1.22 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeTidscan.h,v 1.23 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,6 @@ extern TupleTableSlot *ExecTidScan(TidScanState *node); extern void ExecEndTidScan(TidScanState *node); extern void ExecTidMarkPos(TidScanState *node); extern void ExecTidRestrPos(TidScanState *node); -extern void ExecTidReScan(TidScanState *node, ExprContext *exprCtxt); +extern void ExecReScanTidScan(TidScanState *node); #endif /* NODETIDSCAN_H */ diff --git a/src/include/executor/nodeUnique.h b/src/include/executor/nodeUnique.h index 4fd4d92d4d..1c57a23fb1 100644 --- a/src/include/executor/nodeUnique.h +++ b/src/include/executor/nodeUnique.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeUnique.h,v 1.27 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeUnique.h,v 1.28 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern UniqueState *ExecInitUnique(Unique *node, EState *estate, int eflags); extern TupleTableSlot *ExecUnique(UniqueState *node); extern void ExecEndUnique(UniqueState *node); -extern void ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt); +extern void ExecReScanUnique(UniqueState *node); #endif /* NODEUNIQUE_H */ diff --git a/src/include/executor/nodeValuesscan.h b/src/include/executor/nodeValuesscan.h index 81b2f4108d..049d66923a 100644 --- a/src/include/executor/nodeValuesscan.h +++ b/src/include/executor/nodeValuesscan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeValuesscan.h,v 1.7 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeValuesscan.h,v 1.8 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,6 @@ extern TupleTableSlot *ExecValuesScan(ValuesScanState *node); extern void ExecEndValuesScan(ValuesScanState *node); extern void ExecValuesMarkPos(ValuesScanState *node); extern void ExecValuesRestrPos(ValuesScanState *node); -extern void ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt); +extern void ExecReScanValuesScan(ValuesScanState *node); #endif /* NODEVALUESSCAN_H */ diff --git a/src/include/executor/nodeWindowAgg.h b/src/include/executor/nodeWindowAgg.h index 759120a7e7..5e944e45a8 100644 --- a/src/include/executor/nodeWindowAgg.h +++ b/src/include/executor/nodeWindowAgg.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeWindowAgg.h,v 1.4 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeWindowAgg.h,v 1.5 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern WindowAggState *ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags); extern TupleTableSlot *ExecWindowAgg(WindowAggState *node); extern void ExecEndWindowAgg(WindowAggState *node); -extern void ExecReScanWindowAgg(WindowAggState *node, ExprContext *exprCtxt); +extern void ExecReScanWindowAgg(WindowAggState *node); #endif /* NODEWINDOWAGG_H */ diff --git a/src/include/executor/nodeWorktablescan.h b/src/include/executor/nodeWorktablescan.h index cda6d0a91e..53e465ce33 100644 --- a/src/include/executor/nodeWorktablescan.h +++ b/src/include/executor/nodeWorktablescan.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/nodeWorktablescan.h,v 1.4 2010/01/02 16:58:03 momjian Exp $ + * $PostgreSQL: pgsql/src/include/executor/nodeWorktablescan.h,v 1.5 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern WorkTableScanState *ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags); extern TupleTableSlot *ExecWorkTableScan(WorkTableScanState *node); extern void ExecEndWorkTableScan(WorkTableScanState *node); -extern void ExecWorkTableScanReScan(WorkTableScanState *node, ExprContext *exprCtxt); +extern void ExecReScanWorkTableScan(WorkTableScanState *node); #endif /* NODEWORKTABLESCAN_H */ diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 401b69e088..24ddb3f0d3 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.234 2010/03/28 22:59:33 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.235 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -74,6 +74,7 @@ typedef enum NodeTag T_LockRows, T_Limit, /* these aren't subclasses of Plan: */ + T_NestLoopParam, T_PlanRowMark, T_PlanInvalItem, diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 79876100d5..5ca1b0f8fb 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.117 2010/02/26 02:01:25 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.118 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -432,13 +432,26 @@ typedef struct Join /* ---------------- * nest loop join node + * + * The nestParams list identifies any executor Params that must be passed + * into execution of the inner subplan carrying values from the current row + * of the outer subplan. Currently we restrict these values to be simple + * Vars, but perhaps someday that'd be worth relaxing. * ---------------- */ typedef struct NestLoop { Join join; + List *nestParams; /* list of NestLoopParam nodes */ } NestLoop; +typedef struct NestLoopParam +{ + NodeTag type; + int paramno; /* number of the PARAM_EXEC Param to set */ + Var *paramval; /* outer-relation Var to assign to Param */ +} NestLoopParam; + /* ---------------- * merge join node * diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 3fc3d3483b..484eb0d627 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.156 2010/02/26 02:01:25 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.157 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -175,7 +175,8 @@ typedef struct Const * Such parameters are numbered from 1 to n. * * PARAM_EXEC: The parameter is an internal executor parameter, used - * for passing values into and out of sub-queries. + * for passing values into and out of sub-queries or from + * nestloop joins to their inner scans. * For historical reasons, such parameters are numbered from 0. * These numbers are independent of PARAM_EXTERN numbers. * diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index a684f19222..3374e5fae7 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.187 2010/07/06 19:19:00 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.188 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -209,6 +209,10 @@ typedef struct PlannerInfo int wt_param_id; /* PARAM_EXEC ID for the work table */ struct Plan *non_recursive_plan; /* plan for non-recursive term */ + /* These fields are workspace for createplan.c */ + Relids curOuterRels; /* outer rels above current node */ + List *curOuterParams; /* not-yet-assigned NestLoopParams */ + /* optional private data for join_search_hook, e.g., GEQO */ void *join_search_private; } PlannerInfo; @@ -1330,16 +1334,20 @@ typedef struct PlaceHolderInfo /* * glob->paramlist keeps track of the PARAM_EXEC slots that we have decided * we need for the query. At runtime these slots are used to pass values - * either down into subqueries (for outer references in subqueries) or up out - * of subqueries (for the results of a subplan). The n'th entry in the list - * (n counts from 0) corresponds to Param->paramid = n. + * around from one plan node to another. They can be used to pass values + * down into subqueries (for outer references in subqueries), or up out of + * subqueries (for the results of a subplan), or from a NestLoop plan node + * into its inner relation (when the inner scan is parameterized with values + * from the outer relation). The n'th entry in the list (n counts from 0) + * corresponds to Param->paramid = n. * * Each paramlist item shows the absolute query level it is associated with, * where the outermost query is level 1 and nested subqueries have higher * numbers. The item the parameter slot represents can be one of three kinds: * * A Var: the slot represents a variable of that level that must be passed - * down because subqueries have outer references to it. The varlevelsup + * down because subqueries have outer references to it, or must be passed + * from a NestLoop node of that level to its inner scan. The varlevelsup * value in the Var will always be zero. * * An Aggref (with an expression tree representing its argument): the slot @@ -1352,7 +1360,13 @@ typedef struct PlaceHolderInfo * to the parent query of the subplan. * * Note: we detect duplicate Var parameters and coalesce them into one slot, - * but we do not do this for Aggref or Param slots. + * but we do not bother to do this for Aggrefs, and it would be incorrect + * to do so for Param slots. Duplicate detection is actually *necessary* + * in the case of NestLoop parameters since it serves to match up the usage + * of a Param (in the inner scan) with the assignment of the value (in the + * NestLoop node). This might result in the same PARAM_EXEC slot being used + * by multiple NestLoop nodes or SubPlan nodes, but no harm is done since + * the same value would be assigned anyway. */ typedef struct PlannerParamItem { diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h index 1bc52cc14c..abbbd58c24 100644 --- a/src/include/optimizer/subselect.h +++ b/src/include/optimizer/subselect.h @@ -5,7 +5,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.39 2010/01/02 16:58:07 momjian Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.40 2010/07/12 17:01:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,6 +29,7 @@ extern void SS_finalize_plan(PlannerInfo *root, Plan *plan, bool attach_initplans); extern Param *SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, Oid resulttype, int32 resulttypmod); +extern Param *assign_nestloop_param(PlannerInfo *root, Var *var); extern int SS_assign_special_param(PlannerInfo *root); #endif /* SUBSELECT_H */ diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out index 66736a3564..f1466e0d44 100644 --- a/src/test/regress/expected/rangefuncs.out +++ b/src/test/regress/expected/rangefuncs.out @@ -281,7 +281,7 @@ INSERT INTO foorescan values(5007,5,'abc.5007.5'); INSERT INTO foorescan values(5008,5,'abc.5008.5'); INSERT INTO foorescan values(5009,5,'abc.5009.5'); CREATE FUNCTION foorescan(int,int) RETURNS setof foorescan AS 'SELECT * FROM foorescan WHERE fooid >= $1 and fooid < $2 ;' LANGUAGE SQL; ---invokes ExecFunctionReScan +--invokes ExecReScanFunctionScan SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM foorescan(5002,5004)) ORDER BY 1,2; fooid | foosubid | fooname -------+----------+------------ @@ -298,7 +298,7 @@ SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM foorescan(5002,500 (10 rows) CREATE VIEW vw_foorescan AS SELECT * FROM foorescan(5002,5004); ---invokes ExecFunctionReScan +--invokes ExecReScanFunctionScan SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM vw_foorescan) ORDER BY 1,2; fooid | foosubid | fooname -------+----------+------------ @@ -323,7 +323,7 @@ INSERT INTO barrescan values(5006); INSERT INTO barrescan values(5007); INSERT INTO barrescan values(5008); CREATE FUNCTION foorescan(int) RETURNS setof foorescan AS 'SELECT * FROM foorescan WHERE fooid = $1;' LANGUAGE SQL; ---invokes ExecFunctionReScan with chgParam != NULL +--invokes ExecReScanFunctionScan with chgParam != NULL SELECT f.* FROM barrescan b, foorescan f WHERE f.fooid = b.fooid AND b.fooid IN (SELECT fooid FROM foorescan(b.fooid)) ORDER BY 1,2; fooid | foosubid | fooname -------+----------+------------ diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql index db74770228..d1b9db7e51 100644 --- a/src/test/regress/sql/rangefuncs.sql +++ b/src/test/regress/sql/rangefuncs.sql @@ -164,12 +164,12 @@ INSERT INTO foorescan values(5009,5,'abc.5009.5'); CREATE FUNCTION foorescan(int,int) RETURNS setof foorescan AS 'SELECT * FROM foorescan WHERE fooid >= $1 and fooid < $2 ;' LANGUAGE SQL; ---invokes ExecFunctionReScan +--invokes ExecReScanFunctionScan SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM foorescan(5002,5004)) ORDER BY 1,2; CREATE VIEW vw_foorescan AS SELECT * FROM foorescan(5002,5004); ---invokes ExecFunctionReScan +--invokes ExecReScanFunctionScan SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM vw_foorescan) ORDER BY 1,2; CREATE TABLE barrescan (fooid int primary key); @@ -182,7 +182,7 @@ INSERT INTO barrescan values(5008); CREATE FUNCTION foorescan(int) RETURNS setof foorescan AS 'SELECT * FROM foorescan WHERE fooid = $1;' LANGUAGE SQL; ---invokes ExecFunctionReScan with chgParam != NULL +--invokes ExecReScanFunctionScan with chgParam != NULL SELECT f.* FROM barrescan b, foorescan f WHERE f.fooid = b.fooid AND b.fooid IN (SELECT fooid FROM foorescan(b.fooid)) ORDER BY 1,2; SELECT b.fooid, max(f.foosubid) FROM barrescan b, foorescan f WHERE f.fooid = b.fooid AND b.fooid IN (SELECT fooid FROM foorescan(b.fooid)) GROUP BY b.fooid ORDER BY 1,2;