2424
2525/* Local functions */
2626static Relids find_placeholders_recurse (PlannerInfo * root , Node * jtnode );
27- static void find_placeholders_in_qual (PlannerInfo * root , Node * qual ,
27+ static void mark_placeholders_in_expr (PlannerInfo * root , Node * expr ,
2828 Relids relids );
2929
3030
@@ -50,18 +50,24 @@ make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
5050
5151/*
5252 * find_placeholder_info
53- * Fetch the PlaceHolderInfo for the given PHV; create it if not found
53+ * Fetch the PlaceHolderInfo for the given PHV
54+ *
55+ * If the PlaceHolderInfo doesn't exist yet, create it if create_new_ph is
56+ * true, else throw an error.
5457 *
5558 * This is separate from make_placeholder_expr because subquery pullup has
5659 * to make PlaceHolderVars for expressions that might not be used at all in
5760 * the upper query, or might not remain after const-expression simplification.
5861 * We build PlaceHolderInfos only for PHVs that are still present in the
5962 * simplified query passed to query_planner().
6063 *
61- * Note: this should only be called after query_planner() has started.
64+ * Note: this should only be called after query_planner() has started. Also,
65+ * create_new_ph must not be TRUE after deconstruct_jointree begins, because
66+ * make_outerjoininfo assumes that we already know about all placeholders.
6267 */
6368PlaceHolderInfo *
64- find_placeholder_info (PlannerInfo * root , PlaceHolderVar * phv )
69+ find_placeholder_info (PlannerInfo * root , PlaceHolderVar * phv ,
70+ bool create_new_ph )
6571{
6672 PlaceHolderInfo * phinfo ;
6773 ListCell * lc ;
@@ -77,6 +83,9 @@ find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
7783 }
7884
7985 /* Not found, so create it */
86+ if (!create_new_ph )
87+ elog (ERROR , "too late to create a new PlaceHolderInfo" );
88+
8089 phinfo = makeNode (PlaceHolderInfo );
8190
8291 phinfo -> phid = phv -> phid ;
@@ -157,7 +166,7 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
157166 /*
158167 * Now process the top-level quals.
159168 */
160- find_placeholders_in_qual (root , f -> quals , jtrelids );
169+ mark_placeholders_in_expr (root , f -> quals , jtrelids );
161170 }
162171 else if (IsA (jtnode , JoinExpr ))
163172 {
@@ -173,7 +182,7 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
173182 jtrelids = bms_join (leftids , rightids );
174183
175184 /* Process the qual clauses */
176- find_placeholders_in_qual (root , j -> quals , jtrelids );
185+ mark_placeholders_in_expr (root , j -> quals , jtrelids );
177186 }
178187 else
179188 {
@@ -185,14 +194,15 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
185194}
186195
187196/*
188- * find_placeholders_in_qual
189- * Process a qual clause for find_placeholders_in_jointree.
197+ * mark_placeholders_in_expr
198+ * Find all PlaceHolderVars in the given expression, and mark them
199+ * as possibly needed at the specified join level.
190200 *
191201 * relids is the syntactic join level to mark as the "maybe needed" level
192- * for each PlaceHolderVar found in the qual clause .
202+ * for each PlaceHolderVar found in the expression .
193203 */
194204static void
195- find_placeholders_in_qual (PlannerInfo * root , Node * qual , Relids relids )
205+ mark_placeholders_in_expr (PlannerInfo * root , Node * expr , Relids relids )
196206{
197207 List * vars ;
198208 ListCell * vl ;
@@ -201,7 +211,7 @@ find_placeholders_in_qual(PlannerInfo *root, Node *qual, Relids relids)
201211 * pull_var_clause does more than we need here, but it'll do and it's
202212 * convenient to use.
203213 */
204- vars = pull_var_clause (qual ,
214+ vars = pull_var_clause (expr ,
205215 PVC_RECURSE_AGGREGATES ,
206216 PVC_INCLUDE_PLACEHOLDERS );
207217 foreach (vl , vars )
@@ -214,25 +224,47 @@ find_placeholders_in_qual(PlannerInfo *root, Node *qual, Relids relids)
214224 continue ;
215225
216226 /* Create a PlaceHolderInfo entry if there's not one already */
217- phinfo = find_placeholder_info (root , phv );
218-
219- /* Mark the PHV as possibly needed at the qual's syntactic level */
220- phinfo -> ph_may_need = bms_add_members (phinfo -> ph_may_need , relids );
227+ phinfo = find_placeholder_info (root , phv , true);
221228
222- /*
223- * This is a bit tricky: the PHV's contained expression may contain
224- * other, lower-level PHVs. We need to get those into the
225- * PlaceHolderInfo list, but they aren't going to be needed where the
226- * outer PHV is referenced. Rather, they'll be needed where the outer
227- * PHV is evaluated. We can estimate that (conservatively) as the
228- * syntactic location of the PHV's expression. Recurse to take care
229- * of any such PHVs.
230- */
231- find_placeholders_in_qual (root , (Node * ) phv -> phexpr , phv -> phrels );
229+ /* Mark it, and recursively process any contained placeholders */
230+ mark_placeholder_maybe_needed (root , phinfo , relids );
232231 }
233232 list_free (vars );
234233}
235234
235+ /*
236+ * mark_placeholder_maybe_needed
237+ * Mark a placeholder as possibly needed at the specified join level.
238+ *
239+ * relids is the syntactic join level to mark as the "maybe needed" level
240+ * for the placeholder.
241+ *
242+ * This is called during an initial scan of the query's targetlist and quals
243+ * before we begin deconstruct_jointree. Once we begin deconstruct_jointree,
244+ * all active placeholders must be present in root->placeholder_list with
245+ * their correct ph_may_need values, because make_outerjoininfo and
246+ * update_placeholder_eval_levels require this info to be available while
247+ * we crawl up the join tree.
248+ */
249+ void
250+ mark_placeholder_maybe_needed (PlannerInfo * root , PlaceHolderInfo * phinfo ,
251+ Relids relids )
252+ {
253+ /* Mark the PHV as possibly needed at the given syntactic level */
254+ phinfo -> ph_may_need = bms_add_members (phinfo -> ph_may_need , relids );
255+
256+ /*
257+ * This is a bit tricky: the PHV's contained expression may contain other,
258+ * lower-level PHVs. We need to get those into the PlaceHolderInfo list,
259+ * but they aren't going to be needed where the outer PHV is referenced.
260+ * Rather, they'll be needed where the outer PHV is evaluated. We can
261+ * estimate that (conservatively) as the syntactic location of the PHV's
262+ * expression. Recurse to take care of any such PHVs.
263+ */
264+ mark_placeholders_in_expr (root , (Node * ) phinfo -> ph_var -> phexpr ,
265+ phinfo -> ph_var -> phrels );
266+ }
267+
236268/*
237269 * update_placeholder_eval_levels
238270 * Adjust the target evaluation levels for placeholders
@@ -353,7 +385,7 @@ fix_placeholder_input_needed_levels(PlannerInfo *root)
353385 PVC_RECURSE_AGGREGATES ,
354386 PVC_INCLUDE_PLACEHOLDERS );
355387
356- add_vars_to_targetlist (root , vars , eval_at );
388+ add_vars_to_targetlist (root , vars , eval_at , false );
357389 list_free (vars );
358390 }
359391 }
0 commit comments