@@ -99,6 +99,7 @@ static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
99
99
List * all_child_pathkeys ,
100
100
PathKey * pathkeyAsc ,
101
101
PathKey * pathkeyDesc );
102
+ static Path * get_cheapest_parameterized_child_path (PlannerInfo * root ,RelOptInfo * rel ,Relids required_outer );
102
103
103
104
104
105
/*
@@ -1616,6 +1617,49 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
1616
1617
generate_mergeappend_paths (root ,rel ,live_childrels ,
1617
1618
all_child_pathkeys ,pathkeyAsc ,
1618
1619
pathkeyDesc );
1620
+
1621
+ /*
1622
+ * Build Append paths for each parameterization seen among the child rels.
1623
+ * (This may look pretty expensive, but in most cases of practical
1624
+ * interest, the child rels will expose mostly the same parameterizations,
1625
+ * so that not that many cases actually get considered here.)
1626
+ *
1627
+ * The Append node itself cannot enforce quals, so all qual checking must
1628
+ * be done in the child paths. This means that to have a parameterized
1629
+ * Append path, we must have the exact same parameterization for each
1630
+ * child path; otherwise some children might be failing to check the
1631
+ * moved-down quals. To make them match up, we can try to increase the
1632
+ * parameterization of lesser-parameterized paths.
1633
+ */
1634
+ foreach (l ,all_child_outers )
1635
+ {
1636
+ Relids required_outer = (Relids )lfirst (l );
1637
+ ListCell * lcr ;
1638
+
1639
+ /* Select the child paths for an Append with this parameterization */
1640
+ subpaths = NIL ;
1641
+ subpaths_valid = true;
1642
+ foreach (lcr ,live_childrels )
1643
+ {
1644
+ RelOptInfo * childrel = (RelOptInfo * )lfirst (lcr );
1645
+ Path * subpath ;
1646
+
1647
+ subpath = get_cheapest_parameterized_child_path (root ,
1648
+ childrel ,
1649
+ required_outer );
1650
+ if (subpath == NULL )
1651
+ {
1652
+ /* failed to make a suitable path for this child */
1653
+ subpaths_valid = false;
1654
+ break ;
1655
+ }
1656
+ subpaths = accumulate_append_subpath (subpaths ,subpath );
1657
+ }
1658
+
1659
+ if (subpaths_valid )
1660
+ add_path (rel , (Path * )
1661
+ create_append_path (rel ,subpaths ,required_outer ));
1662
+ }
1619
1663
}
1620
1664
1621
1665
static List *
@@ -1624,7 +1668,78 @@ accumulate_append_subpath(List *subpaths, Path *path)
1624
1668
return lappend (subpaths ,path );
1625
1669
}
1626
1670
1671
+ /*
1672
+ * get_cheapest_parameterized_child_path
1673
+ *Get cheapest path for this relation that has exactly the requested
1674
+ *parameterization.
1675
+ *
1676
+ * Returns NULL if unable to create such a path.
1677
+ */
1678
+ static Path *
1679
+ get_cheapest_parameterized_child_path (PlannerInfo * root ,RelOptInfo * rel ,
1680
+ Relids required_outer )
1681
+ {
1682
+ Path * cheapest ;
1683
+ ListCell * lc ;
1684
+
1685
+ /*
1686
+ * Look up the cheapest existing path with no more than the needed
1687
+ * parameterization. If it has exactly the needed parameterization, we're
1688
+ * done.
1689
+ */
1690
+ cheapest = get_cheapest_path_for_pathkeys (rel -> pathlist ,
1691
+ NIL ,
1692
+ required_outer ,
1693
+ TOTAL_COST );
1694
+ Assert (cheapest != NULL );
1695
+ if (bms_equal (PATH_REQ_OUTER (cheapest ),required_outer ))
1696
+ return cheapest ;
1627
1697
1698
+ /*
1699
+ * Otherwise, we can "reparameterize" an existing path to match the given
1700
+ * parameterization, which effectively means pushing down additional
1701
+ * joinquals to be checked within the path's scan. However, some existing
1702
+ * paths might check the available joinquals already while others don't;
1703
+ * therefore, it's not clear which existing path will be cheapest after
1704
+ * reparameterization. We have to go through them all and find out.
1705
+ */
1706
+ cheapest = NULL ;
1707
+ foreach (lc ,rel -> pathlist )
1708
+ {
1709
+ Path * path = (Path * )lfirst (lc );
1710
+
1711
+ /* Can't use it if it needs more than requested parameterization */
1712
+ if (!bms_is_subset (PATH_REQ_OUTER (path ),required_outer ))
1713
+ continue ;
1714
+
1715
+ /*
1716
+ * Reparameterization can only increase the path's cost, so if it's
1717
+ * already more expensive than the current cheapest, forget it.
1718
+ */
1719
+ if (cheapest != NULL &&
1720
+ compare_path_costs (cheapest ,path ,TOTAL_COST ) <=0 )
1721
+ continue ;
1722
+
1723
+ /* Reparameterize if needed, then recheck cost */
1724
+ if (!bms_equal (PATH_REQ_OUTER (path ),required_outer ))
1725
+ {
1726
+ path = reparameterize_path (root ,path ,required_outer ,1.0 );
1727
+ if (path == NULL )
1728
+ continue ;/* failed to reparameterize this one */
1729
+ Assert (bms_equal (PATH_REQ_OUTER (path ),required_outer ));
1730
+
1731
+ if (cheapest != NULL &&
1732
+ compare_path_costs (cheapest ,path ,TOTAL_COST ) <=0 )
1733
+ continue ;
1734
+ }
1735
+
1736
+ /* We have a new best path */
1737
+ cheapest = path ;
1738
+ }
1739
+
1740
+ /* Return the best path, or NULL if we found no suitable candidate */
1741
+ return cheapest ;
1742
+ }
1628
1743
1629
1744
1630
1745
//---------------------------------------------------------------