@@ -421,26 +421,8 @@ replace_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
421
421
* provide these values. This differs from replace_nestloop_param_var in
422
422
* that the PARAM_EXEC slots to use have already been determined.
423
423
*
424
- * An additional complication is that the subplan_params may contain
425
- * nullingrel markers that need adjustment. This occurs if we have applied
426
- * outer join identity 3,
427
- * (A leftjoin B on (Pab)) leftjoin C on (Pb*c)
428
- * = A leftjoin (B leftjoin C on (Pbc)) on (Pab)
429
- * and C is a subquery containing lateral references to B. It's still safe
430
- * to apply the identity, but the parser will have created those references
431
- * in the form "b*" (i.e., with varnullingrels listing the A/B join), while
432
- * what we will have available from the nestloop's outer side is just "b".
433
- * We deal with that here by stripping the nullingrels down to what is
434
- * available from the outer side according to root->curOuterRels.
435
- * That fixes matters for the case of forward application of identity 3.
436
- * If the identity was applied in the reverse direction, we will have
437
- * subplan_params containing too few nullingrel bits rather than too many.
438
- * Currently, that causes no problems because setrefs.c applies only a
439
- * subset check to nullingrels in NestLoopParams, but we'd have to work
440
- * harder if we ever want to tighten that check.
441
- *
442
424
* Note that we also use root->curOuterRels as an implicit parameter for
443
- * sanity checks and nullingrel adjustments .
425
+ * sanity checks.
444
426
*/
445
427
void
446
428
process_subquery_nestloop_params (PlannerInfo * root , List * subplan_params )
@@ -467,19 +449,17 @@ process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
467
449
nlp = (NestLoopParam * ) lfirst (lc2 );
468
450
if (nlp -> paramno == pitem -> paramId )
469
451
{
452
+ Assert (equal (var , nlp -> paramval ));
470
453
/* Present, so nothing to do */
471
454
break ;
472
455
}
473
456
}
474
457
if (lc2 == NULL )
475
458
{
476
- /* No, so add it after adjusting its nullingrels */
477
- var = copyObject (var );
478
- var -> varnullingrels = bms_intersect (var -> varnullingrels ,
479
- root -> curOuterRels );
459
+ /* No, so add it */
480
460
nlp = makeNode (NestLoopParam );
481
461
nlp -> paramno = pitem -> paramId ;
482
- nlp -> paramval = var ;
462
+ nlp -> paramval = copyObject ( var ) ;
483
463
root -> curOuterParams = lappend (root -> curOuterParams , nlp );
484
464
}
485
465
}
@@ -500,19 +480,17 @@ process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
500
480
nlp = (NestLoopParam * ) lfirst (lc2 );
501
481
if (nlp -> paramno == pitem -> paramId )
502
482
{
483
+ Assert (equal (phv , nlp -> paramval ));
503
484
/* Present, so nothing to do */
504
485
break ;
505
486
}
506
487
}
507
488
if (lc2 == NULL )
508
489
{
509
- /* No, so add it after adjusting its nullingrels */
510
- phv = copyObject (phv );
511
- phv -> phnullingrels = bms_intersect (phv -> phnullingrels ,
512
- root -> curOuterRels );
490
+ /* No, so add it */
513
491
nlp = makeNode (NestLoopParam );
514
492
nlp -> paramno = pitem -> paramId ;
515
- nlp -> paramval = (Var * ) phv ;
493
+ nlp -> paramval = (Var * ) copyObject ( phv ) ;
516
494
root -> curOuterParams = lappend (root -> curOuterParams , nlp );
517
495
}
518
496
}
@@ -525,6 +503,28 @@ process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
525
503
* Identify any NestLoopParams that should be supplied by a NestLoop plan
526
504
* node with the specified lefthand rels. Remove them from the active
527
505
* root->curOuterParams list and return them as the result list.
506
+ *
507
+ * XXX Here we also hack up the returned Vars and PHVs so that they do not
508
+ * contain nullingrel sets exceeding what is available from the outer side.
509
+ * This is needed if we have applied outer join identity 3,
510
+ * (A leftjoin B on (Pab)) leftjoin C on (Pb*c)
511
+ * = A leftjoin (B leftjoin C on (Pbc)) on (Pab)
512
+ * and C contains lateral references to B. It's still safe to apply the
513
+ * identity, but the parser will have created those references in the form
514
+ * "b*" (i.e., with varnullingrels listing the A/B join), while what we will
515
+ * have available from the nestloop's outer side is just "b". We deal with
516
+ * that here by stripping the nullingrels down to what is available from the
517
+ * outer side according to leftrelids.
518
+ *
519
+ * That fixes matters for the case of forward application of identity 3.
520
+ * If the identity was applied in the reverse direction, we will have
521
+ * parameter Vars containing too few nullingrel bits rather than too many.
522
+ * Currently, that causes no problems because setrefs.c applies only a
523
+ * subset check to nullingrels in NestLoopParams, but we'd have to work
524
+ * harder if we ever want to tighten that check. This is all pretty annoying
525
+ * because it greatly weakens setrefs.c's cross-check, but the alternative
526
+ * seems to be to generate multiple versions of each laterally-parameterized
527
+ * subquery, which'd be unduly expensive.
528
528
*/
529
529
List *
530
530
identify_current_nestloop_params (PlannerInfo * root , Relids leftrelids )
@@ -539,22 +539,32 @@ identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids)
539
539
540
540
/*
541
541
* We are looking for Vars and PHVs that can be supplied by the
542
- * lefthand rels.
542
+ * lefthand rels. When we find one, it's okay to modify it in-place
543
+ * because all the routines above make a fresh copy to put into
544
+ * curOuterParams.
543
545
*/
544
546
if (IsA (nlp -> paramval , Var ) &&
545
547
bms_is_member (nlp -> paramval -> varno , leftrelids ))
546
548
{
549
+ Var * var = (Var * ) nlp -> paramval ;
550
+
547
551
root -> curOuterParams = foreach_delete_current (root -> curOuterParams ,
548
552
cell );
553
+ var -> varnullingrels = bms_intersect (var -> varnullingrels ,
554
+ leftrelids );
549
555
result = lappend (result , nlp );
550
556
}
551
557
else if (IsA (nlp -> paramval , PlaceHolderVar ) &&
552
558
bms_is_subset (find_placeholder_info (root ,
553
559
(PlaceHolderVar * ) nlp -> paramval )-> ph_eval_at ,
554
560
leftrelids ))
555
561
{
562
+ PlaceHolderVar * phv = (PlaceHolderVar * ) nlp -> paramval ;
563
+
556
564
root -> curOuterParams = foreach_delete_current (root -> curOuterParams ,
557
565
cell );
566
+ phv -> phnullingrels = bms_intersect (phv -> phnullingrels ,
567
+ leftrelids );
558
568
result = lappend (result , nlp );
559
569
}
560
570
}
0 commit comments