@@ -99,6 +99,7 @@ static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
9999List * all_child_pathkeys ,
100100PathKey * pathkeyAsc ,
101101PathKey * pathkeyDesc );
102+ static Path * get_cheapest_parameterized_child_path (PlannerInfo * root ,RelOptInfo * rel ,Relids required_outer );
102103
103104
104105/*
@@ -1616,6 +1617,49 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
16161617generate_mergeappend_paths (root ,rel ,live_childrels ,
16171618all_child_pathkeys ,pathkeyAsc ,
16181619pathkeyDesc );
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+ }
16191663}
16201664
16211665static List *
@@ -1624,7 +1668,78 @@ accumulate_append_subpath(List *subpaths, Path *path)
16241668return lappend (subpaths ,path );
16251669}
16261670
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 ;
16271697
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+ }
16281743
16291744
16301745//---------------------------------------------------------------