@@ -68,6 +68,9 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
68
68
static void generate_mergeappend_paths (PlannerInfo * root , RelOptInfo * rel ,
69
69
List * live_childrels ,
70
70
List * all_child_pathkeys );
71
+ static Path * get_cheapest_parameterized_child_path (PlannerInfo * root ,
72
+ RelOptInfo * rel ,
73
+ Relids required_outer );
71
74
static List * accumulate_append_subpath (List * subpaths , Path * path );
72
75
static void set_dummy_rel_pathlist (RelOptInfo * rel );
73
76
static void set_subquery_pathlist (PlannerInfo * root , RelOptInfo * rel ,
@@ -831,28 +834,18 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
831
834
foreach (lcr , live_childrels )
832
835
{
833
836
RelOptInfo * childrel = (RelOptInfo * ) lfirst (lcr );
834
- Path * cheapest_total ;
837
+ Path * subpath ;
835
838
836
- cheapest_total =
837
- get_cheapest_path_for_pathkeys (childrel -> pathlist ,
838
- NIL ,
839
- required_outer ,
840
- TOTAL_COST );
841
- Assert (cheapest_total != NULL );
842
-
843
- /* Children must have exactly the desired parameterization */
844
- if (!bms_equal (PATH_REQ_OUTER (cheapest_total ), required_outer ))
839
+ subpath = get_cheapest_parameterized_child_path (root ,
840
+ childrel ,
841
+ required_outer );
842
+ if (subpath == NULL )
845
843
{
846
- cheapest_total = reparameterize_path (root , cheapest_total ,
847
- required_outer , 1.0 );
848
- if (cheapest_total == NULL )
849
- {
850
- subpaths_valid = false;
851
- break ;
852
- }
844
+ /* failed to make a suitable path for this child */
845
+ subpaths_valid = false;
846
+ break ;
853
847
}
854
-
855
- subpaths = accumulate_append_subpath (subpaths , cheapest_total );
848
+ subpaths = accumulate_append_subpath (subpaths , subpath );
856
849
}
857
850
858
851
if (subpaths_valid )
@@ -962,6 +955,79 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
962
955
}
963
956
}
964
957
958
+ /*
959
+ * get_cheapest_parameterized_child_path
960
+ * Get cheapest path for this relation that has exactly the requested
961
+ * parameterization.
962
+ *
963
+ * Returns NULL if unable to create such a path.
964
+ */
965
+ static Path *
966
+ get_cheapest_parameterized_child_path (PlannerInfo * root , RelOptInfo * rel ,
967
+ Relids required_outer )
968
+ {
969
+ Path * cheapest ;
970
+ ListCell * lc ;
971
+
972
+ /*
973
+ * Look up the cheapest existing path with no more than the needed
974
+ * parameterization. If it has exactly the needed parameterization, we're
975
+ * done.
976
+ */
977
+ cheapest = get_cheapest_path_for_pathkeys (rel -> pathlist ,
978
+ NIL ,
979
+ required_outer ,
980
+ TOTAL_COST );
981
+ Assert (cheapest != NULL );
982
+ if (bms_equal (PATH_REQ_OUTER (cheapest ), required_outer ))
983
+ return cheapest ;
984
+
985
+ /*
986
+ * Otherwise, we can "reparameterize" an existing path to match the given
987
+ * parameterization, which effectively means pushing down additional
988
+ * joinquals to be checked within the path's scan. However, some existing
989
+ * paths might check the available joinquals already while others don't;
990
+ * therefore, it's not clear which existing path will be cheapest after
991
+ * reparameterization. We have to go through them all and find out.
992
+ */
993
+ cheapest = NULL ;
994
+ foreach (lc , rel -> pathlist )
995
+ {
996
+ Path * path = (Path * ) lfirst (lc );
997
+
998
+ /* Can't use it if it needs more than requested parameterization */
999
+ if (!bms_is_subset (PATH_REQ_OUTER (path ), required_outer ))
1000
+ continue ;
1001
+
1002
+ /*
1003
+ * Reparameterization can only increase the path's cost, so if it's
1004
+ * already more expensive than the current cheapest, forget it.
1005
+ */
1006
+ if (cheapest != NULL &&
1007
+ compare_path_costs (cheapest , path , TOTAL_COST ) <= 0 )
1008
+ continue ;
1009
+
1010
+ /* Reparameterize if needed, then recheck cost */
1011
+ if (!bms_equal (PATH_REQ_OUTER (path ), required_outer ))
1012
+ {
1013
+ path = reparameterize_path (root , path , required_outer , 1.0 );
1014
+ if (path == NULL )
1015
+ continue ; /* failed to reparameterize this one */
1016
+ Assert (bms_equal (PATH_REQ_OUTER (path ), required_outer ));
1017
+
1018
+ if (cheapest != NULL &&
1019
+ compare_path_costs (cheapest , path , TOTAL_COST ) <= 0 )
1020
+ continue ;
1021
+ }
1022
+
1023
+ /* We have a new best path */
1024
+ cheapest = path ;
1025
+ }
1026
+
1027
+ /* Return the best path, or NULL if we found no suitable candidate */
1028
+ return cheapest ;
1029
+ }
1030
+
965
1031
/*
966
1032
* accumulate_append_subpath
967
1033
* Add a subpath to the list being built for an Append or MergeAppend
0 commit comments