24
24
25
25
/* Local functions */
26
26
static 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 ,
28
28
Relids relids );
29
29
30
30
@@ -50,18 +50,24 @@ make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
50
50
51
51
/*
52
52
* 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.
54
57
*
55
58
* This is separate from make_placeholder_expr because subquery pullup has
56
59
* to make PlaceHolderVars for expressions that might not be used at all in
57
60
* the upper query, or might not remain after const-expression simplification.
58
61
* We build PlaceHolderInfos only for PHVs that are still present in the
59
62
* simplified query passed to query_planner().
60
63
*
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.
62
67
*/
63
68
PlaceHolderInfo *
64
- find_placeholder_info (PlannerInfo * root , PlaceHolderVar * phv )
69
+ find_placeholder_info (PlannerInfo * root , PlaceHolderVar * phv ,
70
+ bool create_new_ph )
65
71
{
66
72
PlaceHolderInfo * phinfo ;
67
73
ListCell * lc ;
@@ -77,6 +83,9 @@ find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
77
83
}
78
84
79
85
/* Not found, so create it */
86
+ if (!create_new_ph )
87
+ elog (ERROR , "too late to create a new PlaceHolderInfo" );
88
+
80
89
phinfo = makeNode (PlaceHolderInfo );
81
90
82
91
phinfo -> phid = phv -> phid ;
@@ -157,7 +166,7 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
157
166
/*
158
167
* Now process the top-level quals.
159
168
*/
160
- find_placeholders_in_qual (root , f -> quals , jtrelids );
169
+ mark_placeholders_in_expr (root , f -> quals , jtrelids );
161
170
}
162
171
else if (IsA (jtnode , JoinExpr ))
163
172
{
@@ -173,7 +182,7 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
173
182
jtrelids = bms_join (leftids , rightids );
174
183
175
184
/* Process the qual clauses */
176
- find_placeholders_in_qual (root , j -> quals , jtrelids );
185
+ mark_placeholders_in_expr (root , j -> quals , jtrelids );
177
186
}
178
187
else
179
188
{
@@ -185,14 +194,15 @@ find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
185
194
}
186
195
187
196
/*
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.
190
200
*
191
201
* 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 .
193
203
*/
194
204
static void
195
- find_placeholders_in_qual (PlannerInfo * root , Node * qual , Relids relids )
205
+ mark_placeholders_in_expr (PlannerInfo * root , Node * expr , Relids relids )
196
206
{
197
207
List * vars ;
198
208
ListCell * vl ;
@@ -201,7 +211,7 @@ find_placeholders_in_qual(PlannerInfo *root, Node *qual, Relids relids)
201
211
* pull_var_clause does more than we need here, but it'll do and it's
202
212
* convenient to use.
203
213
*/
204
- vars = pull_var_clause (qual ,
214
+ vars = pull_var_clause (expr ,
205
215
PVC_RECURSE_AGGREGATES ,
206
216
PVC_INCLUDE_PLACEHOLDERS );
207
217
foreach (vl , vars )
@@ -214,25 +224,47 @@ find_placeholders_in_qual(PlannerInfo *root, Node *qual, Relids relids)
214
224
continue ;
215
225
216
226
/* 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);
221
228
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 );
232
231
}
233
232
list_free (vars );
234
233
}
235
234
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
+
236
268
/*
237
269
* update_placeholder_eval_levels
238
270
* Adjust the target evaluation levels for placeholders
@@ -353,7 +385,7 @@ fix_placeholder_input_needed_levels(PlannerInfo *root)
353
385
PVC_RECURSE_AGGREGATES ,
354
386
PVC_INCLUDE_PLACEHOLDERS );
355
387
356
- add_vars_to_targetlist (root , vars , eval_at );
388
+ add_vars_to_targetlist (root , vars , eval_at , false );
357
389
list_free (vars );
358
390
}
359
391
}
0 commit comments