Plan *outer_plan, Plan *inner_plan);
static Node *replace_nestloop_params(PlannerInfo *root, Node *expr);
static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root);
-static void identify_nestloop_extparams(PlannerInfo *root, Plan *subplan);
+static void process_subquery_nestloop_params(PlannerInfo *root,
+ List *subplan_params);
static List *fix_indexqual_references(PlannerInfo *root, IndexPath *index_path);
static List *fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path);
static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol);
{
Plan *plan;
+ /* plan_params should not be in use in current query level */
+ Assert(root->plan_params == NIL);
+
/* Initialize this module's private workspace in PlannerInfo */
root->curOuterRels = NULL;
root->curOuterParams = NIL;
if (root->curOuterParams != NIL)
elog(ERROR, "failed to assign all NestLoopParams to plan nodes");
+ /*
+ * Reset plan_params to ensure param IDs used for nestloop params are not
+ * re-used later
+ */
+ root->plan_params = NIL;
+
return plan;
}
}
}
else
+ {
tlist = build_relation_tlist(rel);
+ /*
+ * If it's a parameterized otherrel, there might be lateral references
+ * in the tlist, which need to be replaced with Params. This cannot
+ * happen for regular baserels, though. Note use_physical_tlist()
+ * always fails for otherrels, so we don't need to check this above.
+ */
+ if (rel->reloptkind != RELOPT_BASEREL && best_path->param_info)
+ tlist = (List *) replace_nestloop_params(root, (Node *) tlist);
+ }
+
/*
* Extract the relevant restriction clauses from the parent relation. The
* executor must apply all these restrictions during the scan, except for
{
TidScan *scan_plan;
Index scan_relid = best_path->path.parent->relid;
+ List *tidquals = best_path->tidquals;
List *ortidquals;
/* it should be a base rel... */
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
scan_clauses = extract_actual_clauses(scan_clauses, false);
+ /* Replace any outer-relation variables with nestloop params */
+ if (best_path->path.param_info)
+ {
+ tidquals = (List *)
+ replace_nestloop_params(root, (Node *) tidquals);
+ scan_clauses = (List *)
+ replace_nestloop_params(root, (Node *) scan_clauses);
+ }
+
/*
* Remove any clauses that are TID quals. This is a bit tricky since the
* tidquals list has implicit OR semantics.
*/
- ortidquals = best_path->tidquals;
+ ortidquals = tidquals;
if (list_length(ortidquals) > 1)
ortidquals = list_make1(make_orclause(ortidquals));
scan_clauses = list_difference(scan_clauses, ortidquals);
scan_plan = make_tidscan(tlist,
scan_clauses,
scan_relid,
- best_path->tidquals);
+ tidquals);
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
{
scan_clauses = (List *)
replace_nestloop_params(root, (Node *) scan_clauses);
- identify_nestloop_extparams(root, best_path->parent->subplan);
+ process_subquery_nestloop_params(root,
+ best_path->parent->subplan_params);
}
scan_plan = make_subqueryscan(tlist,
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
scan_clauses = extract_actual_clauses(scan_clauses, false);
+ /* Replace any outer-relation variables with nestloop params */
+ if (best_path->param_info)
+ {
+ scan_clauses = (List *)
+ replace_nestloop_params(root, (Node *) scan_clauses);
+ }
+
scan_plan = make_ctescan(tlist, scan_clauses, scan_relid,
plan_id, cte_param_id);
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
scan_clauses = extract_actual_clauses(scan_clauses, false);
+ /* Replace any outer-relation variables with nestloop params */
+ if (best_path->param_info)
+ {
+ scan_clauses = (List *)
+ replace_nestloop_params(root, (Node *) scan_clauses);
+ }
+
scan_plan = make_worktablescan(tlist, scan_clauses, scan_relid,
cteroot->wt_param_id);
}
/*
- * identify_nestloop_extparams
- * Identify extParams of a parameterized subquery that need to be fed
+ * process_subquery_nestloop_params
+ * Handle params of a parameterized subquery that need to be fed
* from an outer nestloop.
*
+ * Currently, that would be *all* params that a subquery in FROM has demanded
+ * from the current query level, since they must be LATERAL references.
+ *
* The subplan's references to the outer variables are already represented
* as PARAM_EXEC Params, so we need not modify the subplan here. What we
* do need to do is add entries to root->curOuterParams to signal the parent
* nestloop plan node that it must provide these values.
*/
static void
-identify_nestloop_extparams(PlannerInfo *root, Plan *subplan)
+process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
{
- Bitmapset *tmpset;
- int paramid;
+ ListCell *ppl;
- /* Examine each extParam of the subquery's plan */
- tmpset = bms_copy(subplan->extParam);
- while ((paramid = bms_first_member(tmpset)) >= 0)
+ foreach(ppl, subplan_params)
{
- PlannerParamItem *pitem = list_nth(root->glob->paramlist, paramid);
-
- /* Ignore anything coming from an upper query level */
- if (pitem->abslevel != root->query_level)
- continue;
+ PlannerParamItem *pitem = (PlannerParamItem *) lfirst(ppl);
if (IsA(pitem->item, Var))
{
NestLoopParam *nlp;
ListCell *lc;
- /* If not from a nestloop outer rel, nothing to do */
+ /* If not from a nestloop outer rel, complain */
if (!bms_is_member(var->varno, root->curOuterRels))
- continue;
+ elog(ERROR, "non-LATERAL parameter required by subquery");
/* Is this param already listed in root->curOuterParams? */
foreach(lc, root->curOuterParams)
{
nlp = (NestLoopParam *) lfirst(lc);
- if (nlp->paramno == paramid)
+ if (nlp->paramno == pitem->paramId)
{
Assert(equal(var, nlp->paramval));
/* Present, so nothing to do */
{
/* No, so add it */
nlp = makeNode(NestLoopParam);
- nlp->paramno = paramid;
+ nlp->paramno = pitem->paramId;
nlp->paramval = copyObject(var);
root->curOuterParams = lappend(root->curOuterParams, nlp);
}
NestLoopParam *nlp;
ListCell *lc;
- /*
- * If not from a nestloop outer rel, nothing to do. We use
- * bms_overlap as a cheap/quick test to see if the PHV might be
- * evaluated in the outer rels, and then grab its PlaceHolderInfo
- * to tell for sure.
- */
- if (!bms_overlap(phv->phrels, root->curOuterRels))
- continue;
+ /* If not from a nestloop outer rel, complain */
if (!bms_is_subset(find_placeholder_info(root, phv, false)->ph_eval_at,
root->curOuterRels))
- continue;
+ elog(ERROR, "non-LATERAL parameter required by subquery");
/* Is this param already listed in root->curOuterParams? */
foreach(lc, root->curOuterParams)
{
nlp = (NestLoopParam *) lfirst(lc);
- if (nlp->paramno == paramid)
+ if (nlp->paramno == pitem->paramId)
{
Assert(equal(phv, nlp->paramval));
/* Present, so nothing to do */
{
/* No, so add it */
nlp = makeNode(NestLoopParam);
- nlp->paramno = paramid;
+ nlp->paramno = pitem->paramId;
nlp->paramval = copyObject(phv);
root->curOuterParams = lappend(root->curOuterParams, nlp);
}
}
+ else
+ elog(ERROR, "unexpected type of subquery parameter");
}
- bms_free(tmpset);
}
/*