@@ -421,12 +421,33 @@ have_unsafe_outer_join_ref(PlannerInfo *root,
421
421
422
422
/*
423
423
* paraminfo_get_equal_hashops
424
- * Determine if param_info and innerrel's lateral_vars can be hashed.
425
- * Returns true the hashing is possible, otherwise return false.
424
+ * Determine if the clauses in param_info and innerrel's lateral_vars
425
+ * can be hashed.
426
+ * Returns true if hashing is possible, otherwise false.
426
427
*
427
- * Additionally we also collect the outer exprs and the hash operators for
428
- * each parameter to innerrel. These set in 'param_exprs', 'operators' and
429
- * 'binary_mode' when we return true.
428
+ * Additionally, on success we collect the outer expressions and the
429
+ * appropriate equality operators for each hashable parameter to innerrel.
430
+ * These are returned in parallel lists in *param_exprs and *operators.
431
+ * We also set *binary_mode to indicate whether strict binary matching is
432
+ * required.
433
+ *
434
+ * A complication is that innerrel's lateral_vars may contain nullingrel
435
+ * markers that need adjustment. This occurs if we have applied outer join
436
+ * identity 3,
437
+ * (A leftjoin B on (Pab)) leftjoin C on (Pb*c)
438
+ * = A leftjoin (B leftjoin C on (Pbc)) on (Pab)
439
+ * and C contains lateral references to B. It's still safe to apply the
440
+ * identity, but the parser will have created those references in the form
441
+ * "b*" (i.e., with varnullingrels listing the A/B join), while what we will
442
+ * have available from the nestloop's outer side is just "b". We deal with
443
+ * that here by stripping the nullingrels down to what is available from the
444
+ * outer side according to outerrel->relids.
445
+ * That fixes matters for the case of forward application of identity 3.
446
+ * If the identity was applied in the reverse direction, we will have
447
+ * innerrel's lateral_vars containing too few nullingrel bits rather than
448
+ * too many. Currently, that causes no problems because setrefs.c applies
449
+ * only a subset check to nullingrels in NestLoopParams, but we'd have to
450
+ * work harder if we ever want to tighten that check.
430
451
*/
431
452
static bool
432
453
paraminfo_get_equal_hashops (PlannerInfo * root , ParamPathInfo * param_info ,
@@ -441,6 +462,7 @@ paraminfo_get_equal_hashops(PlannerInfo *root, ParamPathInfo *param_info,
441
462
* operators = NIL ;
442
463
* binary_mode = false;
443
464
465
+ /* Add join clauses from param_info to the hash key */
444
466
if (param_info != NULL )
445
467
{
446
468
List * clauses = param_info -> ppi_clauses ;
@@ -510,7 +532,7 @@ paraminfo_get_equal_hashops(PlannerInfo *root, ParamPathInfo *param_info,
510
532
Node * expr = (Node * ) lfirst (lc );
511
533
TypeCacheEntry * typentry ;
512
534
513
- /* Reject if there are any volatile functions */
535
+ /* Reject if there are any volatile functions in PHVs */
514
536
if (contain_volatile_functions (expr ))
515
537
{
516
538
list_free (* operators );
@@ -521,14 +543,33 @@ paraminfo_get_equal_hashops(PlannerInfo *root, ParamPathInfo *param_info,
521
543
typentry = lookup_type_cache (exprType (expr ),
522
544
TYPECACHE_HASH_PROC | TYPECACHE_EQ_OPR );
523
545
524
- /* can't use a memoize node without a valid hash equals operator */
546
+ /* can't use memoize without a valid hash proc and equals operator */
525
547
if (!OidIsValid (typentry -> hash_proc ) || !OidIsValid (typentry -> eq_opr ))
526
548
{
527
549
list_free (* operators );
528
550
list_free (* param_exprs );
529
551
return false;
530
552
}
531
553
554
+ /* OK, but adjust its nullingrels before adding it to result */
555
+ expr = copyObject (expr );
556
+ if (IsA (expr , Var ))
557
+ {
558
+ Var * var = (Var * ) expr ;
559
+
560
+ var -> varnullingrels = bms_intersect (var -> varnullingrels ,
561
+ outerrel -> relids );
562
+ }
563
+ else if (IsA (expr , PlaceHolderVar ))
564
+ {
565
+ PlaceHolderVar * phv = (PlaceHolderVar * ) expr ;
566
+
567
+ phv -> phnullingrels = bms_intersect (phv -> phnullingrels ,
568
+ outerrel -> relids );
569
+ }
570
+ else
571
+ Assert (false);
572
+
532
573
* operators = lappend_oid (* operators , typentry -> eq_opr );
533
574
* param_exprs = lappend (* param_exprs , expr );
534
575
0 commit comments