@@ -282,44 +282,55 @@ add_paths_to_joinrel(PlannerInfo *root,
282282 * across joins unless there's a join-order-constraint-based reason to do so.
283283 * So we ignore the param_source_rels restriction when this case applies.
284284 *
285- * However, there's a pitfall: suppose the inner rel (call it A) has a
286- * parameter that is a PlaceHolderVar, and that PHV's minimum eval_at set
287- * includes the outer rel (B) and some third rel (C). If we treat this as a
288- * star-schema case and create a B/A nestloop join that's parameterized by C,
289- * we would end up with a plan in which the PHV's expression has to be
290- * evaluated as a nestloop parameter at the B/A join; and the executor is only
291- * set up to handle simple Vars as NestLoopParams. Rather than add complexity
292- * and overhead to the executor for such corner cases, it seems better to
293- * forbid the join. (Note that existence of such a PHV probably means there
294- * is a join order constraint that will cause us to consider joining B and C
295- * directly; so we can still make use of A's parameterized path, and there is
296- * no need for the star-schema exception.) To implement this exception to the
297- * exception, we check whether any PHVs used in the query could pose such a
298- * hazard. We don't have any simple way of checking whether a risky PHV would
299- * actually be used in the inner plan, and the case is so unusual that it
300- * doesn't seem worth working very hard on it.
301- *
302285 * allow_star_schema_join() returns TRUE if the param_source_rels restriction
303286 * should be overridden, ie, it's okay to perform this join.
304287 */
305- static bool
288+ static inline bool
306289allow_star_schema_join (PlannerInfo * root ,
307290 Path * outer_path ,
308291 Path * inner_path )
309292{
310293 Relids innerparams = PATH_REQ_OUTER (inner_path );
311294 Relids outerrelids = outer_path -> parent -> relids ;
312- ListCell * lc ;
313295
314296 /*
315- * It's not a star-schema case unless the outer rel provides some but not
316- * all of the inner rel's parameterization.
297+ * It's a star-schema case if the outer rel provides some but not all of
298+ * the inner rel's parameterization.
317299 */
318- if (!(bms_overlap (innerparams , outerrelids ) &&
319- bms_nonempty_difference (innerparams , outerrelids )))
320- return false;
300+ return (bms_overlap (innerparams , outerrelids ) &&
301+ bms_nonempty_difference (innerparams , outerrelids ));
302+ }
303+
304+ /*
305+ * There's a pitfall for creating parameterized nestloops: suppose the inner
306+ * rel (call it A) has a parameter that is a PlaceHolderVar, and that PHV's
307+ * minimum eval_at set includes the outer rel (B) and some third rel (C).
308+ * We might think we could create a B/A nestloop join that's parameterized by
309+ * C. But we would end up with a plan in which the PHV's expression has to be
310+ * evaluated as a nestloop parameter at the B/A join; and the executor is only
311+ * set up to handle simple Vars as NestLoopParams. Rather than add complexity
312+ * and overhead to the executor for such corner cases, it seems better to
313+ * forbid the join. (Note that existence of such a PHV probably means there
314+ * is a join order constraint that will cause us to consider joining B and C
315+ * directly; so we can still make use of A's parameterized path with B+C.)
316+ * So we check whether any PHVs used in the query could pose such a hazard.
317+ * We don't have any simple way of checking whether a risky PHV would actually
318+ * be used in the inner plan, and the case is so unusual that it doesn't seem
319+ * worth working very hard on it.
320+ *
321+ * This case can occur whether or not the join's remaining parameterization
322+ * overlaps param_source_rels, so we have to check for it separately from
323+ * allow_star_schema_join, even though it looks much like a star-schema case.
324+ */
325+ static inline bool
326+ check_hazardous_phv (PlannerInfo * root ,
327+ Path * outer_path ,
328+ Path * inner_path )
329+ {
330+ Relids innerparams = PATH_REQ_OUTER (inner_path );
331+ Relids outerrelids = outer_path -> parent -> relids ;
332+ ListCell * lc ;
321333
322- /* Check for hazardous PHVs */
323334 foreach (lc , root -> placeholder_list )
324335 {
325336 PlaceHolderInfo * phinfo = (PlaceHolderInfo * ) lfirst (lc );
@@ -358,13 +369,15 @@ try_nestloop_path(PlannerInfo *root,
358369 /*
359370 * Check to see if proposed path is still parameterized, and reject if the
360371 * parameterization wouldn't be sensible --- unless allow_star_schema_join
361- * says to allow it anyway.
372+ * says to allow it anyway. Also, we must reject if check_hazardous_phv
373+ * doesn't like the look of it.
362374 */
363375 required_outer = calc_nestloop_required_outer (outer_path ,
364376 inner_path );
365377 if (required_outer &&
366- !bms_overlap (required_outer , extra -> param_source_rels ) &&
367- !allow_star_schema_join (root , outer_path , inner_path ))
378+ ((!bms_overlap (required_outer , extra -> param_source_rels ) &&
379+ !allow_star_schema_join (root , outer_path , inner_path )) ||
380+ !check_hazardous_phv (root , outer_path , inner_path )))
368381 {
369382 /* Waste no memory when we reject a path here */
370383 bms_free (required_outer );
0 commit comments