@@ -74,6 +74,8 @@ static bool is_innerrel_unique_for(PlannerInfo *root,
74
74
List * restrictlist ,
75
75
List * * extra_clauses );
76
76
static int self_join_candidates_cmp (const void * a , const void * b );
77
+ static bool replace_relid_callback (Node * node ,
78
+ ChangeVarNodes_context * context );
77
79
78
80
79
81
/*
@@ -397,7 +399,8 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
397
399
{
398
400
Assert (subst > 0 );
399
401
400
- ChangeVarNodes ((Node * ) sjinf -> semi_rhs_exprs , relid , subst , 0 );
402
+ ChangeVarNodesExtended ((Node * ) sjinf -> semi_rhs_exprs , relid , subst ,
403
+ 0 , replace_relid_callback );
401
404
}
402
405
}
403
406
@@ -469,7 +472,8 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
469
472
sjinfo -> ojrelid , subst );
470
473
Assert (!bms_is_empty (phv -> phrels ));
471
474
472
- ChangeVarNodes ((Node * ) phv -> phexpr , relid , subst , 0 );
475
+ ChangeVarNodesExtended ((Node * ) phv -> phexpr , relid , subst , 0 ,
476
+ replace_relid_callback );
473
477
474
478
Assert (phv -> phnullingrels == NULL ); /* no need to adjust */
475
479
}
@@ -523,7 +527,8 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
523
527
}
524
528
525
529
if (subst > 0 )
526
- ChangeVarNodes ((Node * ) otherrel -> lateral_vars , relid , subst , 0 );
530
+ ChangeVarNodesExtended ((Node * ) otherrel -> lateral_vars , relid ,
531
+ subst , 0 , replace_relid_callback );
527
532
}
528
533
}
529
534
@@ -757,7 +762,8 @@ remove_rel_from_eclass(EquivalenceClass *ec, SpecialJoinInfo *sjinfo,
757
762
RestrictInfo * rinfo = (RestrictInfo * ) lfirst (lc );
758
763
759
764
if (sjinfo == NULL )
760
- ChangeVarNodes ((Node * ) rinfo , relid , subst , 0 );
765
+ ChangeVarNodesExtended ((Node * ) rinfo , relid , subst , 0 ,
766
+ replace_relid_callback );
761
767
else
762
768
remove_rel_from_restrictinfo (rinfo , relid , sjinfo -> ojrelid );
763
769
}
@@ -1548,7 +1554,8 @@ update_eclasses(EquivalenceClass *ec, int from, int to)
1548
1554
em -> em_jdomain -> jd_relids = adjust_relid_set (em -> em_jdomain -> jd_relids , from , to );
1549
1555
1550
1556
/* We only process inner joins */
1551
- ChangeVarNodes ((Node * ) em -> em_expr , from , to , 0 );
1557
+ ChangeVarNodesExtended ((Node * ) em -> em_expr , from , to , 0 ,
1558
+ replace_relid_callback );
1552
1559
1553
1560
foreach_node (EquivalenceMember , other , new_members )
1554
1561
{
@@ -1582,7 +1589,8 @@ update_eclasses(EquivalenceClass *ec, int from, int to)
1582
1589
continue ;
1583
1590
}
1584
1591
1585
- ChangeVarNodes ((Node * ) rinfo , from , to , 0 );
1592
+ ChangeVarNodesExtended ((Node * ) rinfo , from , to , 0 ,
1593
+ replace_relid_callback );
1586
1594
1587
1595
/*
1588
1596
* After switching the clause to the remaining relation, check it for
@@ -1677,6 +1685,118 @@ add_non_redundant_clauses(PlannerInfo *root,
1677
1685
}
1678
1686
}
1679
1687
1688
+ /*
1689
+ * A custom callback for ChangeVarNodesExtended() providing
1690
+ * Self-join elimination (SJE) related functionality
1691
+ *
1692
+ * SJE needs to skip the RangeTblRef node
1693
+ * type. During SJE's last step, remove_rel_from_joinlist() removes
1694
+ * remaining RangeTblRefs with target relid. If ChangeVarNodes() replaces
1695
+ * the target relid before, remove_rel_from_joinlist() fails to identify
1696
+ * the nodes to delete.
1697
+ *
1698
+ * SJE also needs to change the relids within RestrictInfo's.
1699
+ */
1700
+ static bool
1701
+ replace_relid_callback (Node * node , ChangeVarNodes_context * context )
1702
+ {
1703
+ if (IsA (node , RangeTblRef ))
1704
+ {
1705
+ return true;
1706
+ }
1707
+ else if (IsA (node , RestrictInfo ))
1708
+ {
1709
+ RestrictInfo * rinfo = (RestrictInfo * ) node ;
1710
+ int relid = -1 ;
1711
+ bool is_req_equal =
1712
+ (rinfo -> required_relids == rinfo -> clause_relids );
1713
+ bool clause_relids_is_multiple =
1714
+ (bms_membership (rinfo -> clause_relids ) == BMS_MULTIPLE );
1715
+
1716
+ /*
1717
+ * Recurse down into clauses if the target relation is present in
1718
+ * clause_relids or required_relids. We must check required_relids
1719
+ * because the relation not present in clause_relids might still be
1720
+ * present somewhere in orclause.
1721
+ */
1722
+ if (bms_is_member (context -> rt_index , rinfo -> clause_relids ) ||
1723
+ bms_is_member (context -> rt_index , rinfo -> required_relids ))
1724
+ {
1725
+ Relids new_clause_relids ;
1726
+
1727
+ ChangeVarNodesWalkExpression ((Node * ) rinfo -> clause , context );
1728
+ ChangeVarNodesWalkExpression ((Node * ) rinfo -> orclause , context );
1729
+
1730
+ new_clause_relids = adjust_relid_set (rinfo -> clause_relids ,
1731
+ context -> rt_index ,
1732
+ context -> new_index );
1733
+
1734
+ /*
1735
+ * Incrementally adjust num_base_rels based on the change of
1736
+ * clause_relids, which could contain both base relids and
1737
+ * outer-join relids. This operation is legal until we remove
1738
+ * only baserels.
1739
+ */
1740
+ rinfo -> num_base_rels -= bms_num_members (rinfo -> clause_relids ) -
1741
+ bms_num_members (new_clause_relids );
1742
+
1743
+ rinfo -> clause_relids = new_clause_relids ;
1744
+ rinfo -> left_relids =
1745
+ adjust_relid_set (rinfo -> left_relids , context -> rt_index , context -> new_index );
1746
+ rinfo -> right_relids =
1747
+ adjust_relid_set (rinfo -> right_relids , context -> rt_index , context -> new_index );
1748
+ }
1749
+
1750
+ if (is_req_equal )
1751
+ rinfo -> required_relids = rinfo -> clause_relids ;
1752
+ else
1753
+ rinfo -> required_relids =
1754
+ adjust_relid_set (rinfo -> required_relids , context -> rt_index , context -> new_index );
1755
+
1756
+ rinfo -> outer_relids =
1757
+ adjust_relid_set (rinfo -> outer_relids , context -> rt_index , context -> new_index );
1758
+ rinfo -> incompatible_relids =
1759
+ adjust_relid_set (rinfo -> incompatible_relids , context -> rt_index , context -> new_index );
1760
+
1761
+ if (rinfo -> mergeopfamilies &&
1762
+ bms_get_singleton_member (rinfo -> clause_relids , & relid ) &&
1763
+ clause_relids_is_multiple &&
1764
+ relid == context -> new_index && IsA (rinfo -> clause , OpExpr ))
1765
+ {
1766
+ Expr * leftOp ;
1767
+ Expr * rightOp ;
1768
+
1769
+ leftOp = (Expr * ) get_leftop (rinfo -> clause );
1770
+ rightOp = (Expr * ) get_rightop (rinfo -> clause );
1771
+
1772
+ /*
1773
+ * For self-join elimination, changing varnos could transform
1774
+ * "t1.a = t2.a" into "t1.a = t1.a". That is always true as long
1775
+ * as "t1.a" is not null. We use qual() to check for such a case,
1776
+ * and then we replace the qual for a check for not null
1777
+ * (NullTest).
1778
+ */
1779
+ if (leftOp != NULL && equal (leftOp , rightOp ))
1780
+ {
1781
+ NullTest * ntest = makeNode (NullTest );
1782
+
1783
+ ntest -> arg = leftOp ;
1784
+ ntest -> nulltesttype = IS_NOT_NULL ;
1785
+ ntest -> argisrow = false;
1786
+ ntest -> location = -1 ;
1787
+ rinfo -> clause = (Expr * ) ntest ;
1788
+ rinfo -> mergeopfamilies = NIL ;
1789
+ rinfo -> left_em = NULL ;
1790
+ rinfo -> right_em = NULL ;
1791
+ }
1792
+ Assert (rinfo -> orclause == NULL );
1793
+ }
1794
+ return true;
1795
+ }
1796
+
1797
+ return false;
1798
+ }
1799
+
1680
1800
/*
1681
1801
* Remove a relation after we have proven that it participates only in an
1682
1802
* unneeded unique self-join.
@@ -1725,7 +1845,8 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
1725
1845
foreach_node (RestrictInfo , rinfo , joininfos )
1726
1846
{
1727
1847
remove_join_clause_from_rels (root , rinfo , rinfo -> required_relids );
1728
- ChangeVarNodes ((Node * ) rinfo , toRemove -> relid , toKeep -> relid , 0 );
1848
+ ChangeVarNodesExtended ((Node * ) rinfo , toRemove -> relid , toKeep -> relid ,
1849
+ 0 , replace_relid_callback );
1729
1850
1730
1851
if (bms_membership (rinfo -> required_relids ) == BMS_MULTIPLE )
1731
1852
jinfo_candidates = lappend (jinfo_candidates , rinfo );
@@ -1743,7 +1864,8 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
1743
1864
restrictlist );
1744
1865
foreach_node (RestrictInfo , rinfo , toRemove -> baserestrictinfo )
1745
1866
{
1746
- ChangeVarNodes ((Node * ) rinfo , toRemove -> relid , toKeep -> relid , 0 );
1867
+ ChangeVarNodesExtended ((Node * ) rinfo , toRemove -> relid , toKeep -> relid ,
1868
+ 0 , replace_relid_callback );
1747
1869
1748
1870
if (bms_membership (rinfo -> required_relids ) == BMS_MULTIPLE )
1749
1871
jinfo_candidates = lappend (jinfo_candidates , rinfo );
@@ -1785,7 +1907,8 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
1785
1907
{
1786
1908
Node * node = lfirst (lc );
1787
1909
1788
- ChangeVarNodes (node , toRemove -> relid , toKeep -> relid , 0 );
1910
+ ChangeVarNodesExtended (node , toRemove -> relid , toKeep -> relid , 0 ,
1911
+ replace_relid_callback );
1789
1912
if (!list_member (toKeep -> reltarget -> exprs , node ))
1790
1913
toKeep -> reltarget -> exprs = lappend (toKeep -> reltarget -> exprs , node );
1791
1914
}
@@ -1829,14 +1952,18 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
1829
1952
* Replace varno in all the query structures, except nodes RangeTblRef
1830
1953
* otherwise later remove_rel_from_joinlist will yield errors.
1831
1954
*/
1832
- ChangeVarNodesExtended ((Node * ) root -> parse , toRemove -> relid , toKeep -> relid , 0 , false);
1955
+ ChangeVarNodesExtended ((Node * ) root -> parse , toRemove -> relid , toKeep -> relid ,
1956
+ 0 , replace_relid_callback );
1833
1957
1834
1958
/* Replace links in the planner info */
1835
1959
remove_rel_from_query (root , toRemove , toKeep -> relid , NULL , NULL );
1836
1960
1837
1961
/* At last, replace varno in root targetlist and HAVING clause */
1838
- ChangeVarNodes ((Node * ) root -> processed_tlist , toRemove -> relid , toKeep -> relid , 0 );
1839
- ChangeVarNodes ((Node * ) root -> processed_groupClause , toRemove -> relid , toKeep -> relid , 0 );
1962
+ ChangeVarNodesExtended ((Node * ) root -> processed_tlist , toRemove -> relid ,
1963
+ toKeep -> relid , 0 , replace_relid_callback );
1964
+ ChangeVarNodesExtended ((Node * ) root -> processed_groupClause ,
1965
+ toRemove -> relid , toKeep -> relid , 0 ,
1966
+ replace_relid_callback );
1840
1967
1841
1968
adjust_relid_set (root -> all_result_relids , toRemove -> relid , toKeep -> relid );
1842
1969
adjust_relid_set (root -> leaf_result_relids , toRemove -> relid , toKeep -> relid );
@@ -1919,8 +2046,10 @@ split_selfjoin_quals(PlannerInfo *root, List *joinquals, List **selfjoinquals,
1919
2046
* when we have cast of the same var to different (but compatible)
1920
2047
* types.
1921
2048
*/
1922
- ChangeVarNodes (rightexpr , bms_singleton_member (rinfo -> right_relids ),
1923
- bms_singleton_member (rinfo -> left_relids ), 0 );
2049
+ ChangeVarNodesExtended (rightexpr ,
2050
+ bms_singleton_member (rinfo -> right_relids ),
2051
+ bms_singleton_member (rinfo -> left_relids ), 0 ,
2052
+ replace_relid_callback );
1924
2053
1925
2054
if (equal (leftexpr , rightexpr ))
1926
2055
sjoinquals = lappend (sjoinquals , rinfo );
@@ -1956,7 +2085,8 @@ match_unique_clauses(PlannerInfo *root, RelOptInfo *outer, List *uclauses,
1956
2085
bms_is_empty (rinfo -> right_relids ));
1957
2086
1958
2087
clause = (Expr * ) copyObject (rinfo -> clause );
1959
- ChangeVarNodes ((Node * ) clause , relid , outer -> relid , 0 );
2088
+ ChangeVarNodesExtended ((Node * ) clause , relid , outer -> relid , 0 ,
2089
+ replace_relid_callback );
1960
2090
1961
2091
iclause = bms_is_empty (rinfo -> left_relids ) ? get_rightop (clause ) :
1962
2092
get_leftop (clause );
0 commit comments