+ * find_placeholders_in_jointree
+ * Search the jointree for PlaceHolderVars, and build PlaceHolderInfos
+ *
+ * We don't need to look at the targetlist because build_base_rel_tlists()
+ * will already have made entries for any PHVs in the tlist.
+ *
+ * This is called before we begin deconstruct_jointree. Once we begin
+ * deconstruct_jointree, all active placeholders must be present in
+ * root->placeholder_list, because make_outerjoininfo and
+ * update_placeholder_eval_levels require this info to be available
+ * while we crawl up the join tree.
+ */
+void
+find_placeholders_in_jointree(PlannerInfo *root)
+{
+ /* We need do nothing if the query contains no PlaceHolderVars */
+ if (root->glob->lastPHId != 0)
+ {
+ /* Start recursion at top of jointree */
+ Assert(root->parse->jointree != NULL &&
+ IsA(root->parse->jointree, FromExpr));
+ find_placeholders_recurse(root, (Node *) root->parse->jointree);
+ }
+}
+
+/*
+ * find_placeholders_recurse
+ * One recursion level of find_placeholders_in_jointree.
+ *
+ * jtnode is the current jointree node to examine.
+ */
+static void
+find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
+{
+ if (jtnode == NULL)
+ return;
+ if (IsA(jtnode, RangeTblRef))
+ {
+ /* No quals to deal with here */
+ }
+ else if (IsA(jtnode, FromExpr))
+ {
+ FromExpr *f = (FromExpr *) jtnode;
+ ListCell *l;
+
+ /*
+ * First, recurse to handle child joins.
+ */
+ foreach(l, f->fromlist)
+ {
+ find_placeholders_recurse(root, lfirst(l));
+ }
+
+ /*
+ * Now process the top-level quals.
+ */
+ find_placeholders_in_expr(root, f->quals);
+ }
+ else if (IsA(jtnode, JoinExpr))
+ {
+ JoinExpr *j = (JoinExpr *) jtnode;
+
+ /*
+ * First, recurse to handle child joins.
+ */
+ find_placeholders_recurse(root, j->larg);
+ find_placeholders_recurse(root, j->rarg);
+
+ /* Process the qual clauses */
+ find_placeholders_in_expr(root, j->quals);
+ }
+ else
+ elog(ERROR, "unrecognized node type: %d",
+ (int) nodeTag(jtnode));
+}
+
+/*
+ * find_placeholders_in_expr
+ * Find all PlaceHolderVars in the given expression, and create
+ * PlaceHolderInfo entries for them.
+ */
+static void
+find_placeholders_in_expr(PlannerInfo *root, Node *expr)
+{
+ List *vars;
+ ListCell *vl;
+
+ /*
+ * pull_var_clause does more than we need here, but it'll do and it's
+ * convenient to use.
+ */
+ vars = pull_var_clause(expr,
+ PVC_RECURSE_AGGREGATES |
+ PVC_RECURSE_WINDOWFUNCS |
+ PVC_INCLUDE_PLACEHOLDERS);
+ foreach(vl, vars)
+ {
+ PlaceHolderVar *phv = (PlaceHolderVar *) lfirst(vl);
+
+ /* Ignore any plain Vars */
+ if (!IsA(phv, PlaceHolderVar))
+ continue;
+
+ /* Create a PlaceHolderInfo entry if there's not one already */
+ (void) find_placeholder_info(root, phv, true);
+ }
+ list_free(vars);
+}
+
+/*
+ * update_placeholder_eval_levels