@@ -282,44 +282,55 @@ add_paths_to_joinrel(PlannerInfo *root,
282
282
* across joins unless there's a join-order-constraint-based reason to do so.
283
283
* So we ignore the param_source_rels restriction when this case applies.
284
284
*
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
- *
302
285
* allow_star_schema_join() returns TRUE if the param_source_rels restriction
303
286
* should be overridden, ie, it's okay to perform this join.
304
287
*/
305
- static bool
288
+ static inline bool
306
289
allow_star_schema_join (PlannerInfo * root ,
307
290
Path * outer_path ,
308
291
Path * inner_path )
309
292
{
310
293
Relids innerparams = PATH_REQ_OUTER (inner_path );
311
294
Relids outerrelids = outer_path -> parent -> relids ;
312
- ListCell * lc ;
313
295
314
296
/*
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.
317
299
*/
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 ;
321
333
322
- /* Check for hazardous PHVs */
323
334
foreach (lc , root -> placeholder_list )
324
335
{
325
336
PlaceHolderInfo * phinfo = (PlaceHolderInfo * ) lfirst (lc );
@@ -358,13 +369,15 @@ try_nestloop_path(PlannerInfo *root,
358
369
/*
359
370
* Check to see if proposed path is still parameterized, and reject if the
360
371
* 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.
362
374
*/
363
375
required_outer = calc_nestloop_required_outer (outer_path ,
364
376
inner_path );
365
377
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 )))
368
381
{
369
382
/* Waste no memory when we reject a path here */
370
383
bms_free (required_outer );
0 commit comments