@@ -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 ,
@@ -803,39 +806,29 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
803
806
foreach (l , all_child_outers )
804
807
{
805
808
Relids required_outer = (Relids ) lfirst (l );
806
- bool ok = true;
809
+ bool subpaths_valid = true;
807
810
ListCell * lcr ;
808
811
809
812
/* Select the child paths for an Append with this parameterization */
810
813
subpaths = NIL ;
811
814
foreach (lcr , live_childrels )
812
815
{
813
816
RelOptInfo * childrel = (RelOptInfo * ) lfirst (lcr );
814
- Path * cheapest_total ;
817
+ Path * subpath ;
815
818
816
- cheapest_total =
817
- get_cheapest_path_for_pathkeys (childrel -> pathlist ,
818
- NIL ,
819
- required_outer ,
820
- TOTAL_COST );
821
- Assert (cheapest_total != NULL );
822
-
823
- /* Children must have exactly the desired parameterization */
824
- if (!bms_equal (PATH_REQ_OUTER (cheapest_total ), required_outer ))
819
+ subpath = get_cheapest_parameterized_child_path (root ,
820
+ childrel ,
821
+ required_outer );
822
+ if (subpath == NULL )
825
823
{
826
- cheapest_total = reparameterize_path (root , cheapest_total ,
827
- required_outer , 1.0 );
828
- if (cheapest_total == NULL )
829
- {
830
- ok = false;
831
- break ;
832
- }
824
+ /* failed to make a suitable path for this child */
825
+ subpaths_valid = false;
826
+ break ;
833
827
}
834
-
835
- subpaths = accumulate_append_subpath (subpaths , cheapest_total );
828
+ subpaths = accumulate_append_subpath (subpaths , subpath );
836
829
}
837
830
838
- if (ok )
831
+ if (subpaths_valid )
839
832
add_path (rel , (Path * )
840
833
create_append_path (rel , subpaths , required_outer ));
841
834
}
@@ -941,6 +934,79 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
941
934
}
942
935
}
943
936
937
+ /*
938
+ * get_cheapest_parameterized_child_path
939
+ * Get cheapest path for this relation that has exactly the requested
940
+ * parameterization.
941
+ *
942
+ * Returns NULL if unable to create such a path.
943
+ */
944
+ static Path *
945
+ get_cheapest_parameterized_child_path (PlannerInfo * root , RelOptInfo * rel ,
946
+ Relids required_outer )
947
+ {
948
+ Path * cheapest ;
949
+ ListCell * lc ;
950
+
951
+ /*
952
+ * Look up the cheapest existing path with no more than the needed
953
+ * parameterization. If it has exactly the needed parameterization, we're
954
+ * done.
955
+ */
956
+ cheapest = get_cheapest_path_for_pathkeys (rel -> pathlist ,
957
+ NIL ,
958
+ required_outer ,
959
+ TOTAL_COST );
960
+ Assert (cheapest != NULL );
961
+ if (bms_equal (PATH_REQ_OUTER (cheapest ), required_outer ))
962
+ return cheapest ;
963
+
964
+ /*
965
+ * Otherwise, we can "reparameterize" an existing path to match the given
966
+ * parameterization, which effectively means pushing down additional
967
+ * joinquals to be checked within the path's scan. However, some existing
968
+ * paths might check the available joinquals already while others don't;
969
+ * therefore, it's not clear which existing path will be cheapest after
970
+ * reparameterization. We have to go through them all and find out.
971
+ */
972
+ cheapest = NULL ;
973
+ foreach (lc , rel -> pathlist )
974
+ {
975
+ Path * path = (Path * ) lfirst (lc );
976
+
977
+ /* Can't use it if it needs more than requested parameterization */
978
+ if (!bms_is_subset (PATH_REQ_OUTER (path ), required_outer ))
979
+ continue ;
980
+
981
+ /*
982
+ * Reparameterization can only increase the path's cost, so if it's
983
+ * already more expensive than the current cheapest, forget it.
984
+ */
985
+ if (cheapest != NULL &&
986
+ compare_path_costs (cheapest , path , TOTAL_COST ) <= 0 )
987
+ continue ;
988
+
989
+ /* Reparameterize if needed, then recheck cost */
990
+ if (!bms_equal (PATH_REQ_OUTER (path ), required_outer ))
991
+ {
992
+ path = reparameterize_path (root , path , required_outer , 1.0 );
993
+ if (path == NULL )
994
+ continue ; /* failed to reparameterize this one */
995
+ Assert (bms_equal (PATH_REQ_OUTER (path ), required_outer ));
996
+
997
+ if (cheapest != NULL &&
998
+ compare_path_costs (cheapest , path , TOTAL_COST ) <= 0 )
999
+ continue ;
1000
+ }
1001
+
1002
+ /* We have a new best path */
1003
+ cheapest = path ;
1004
+ }
1005
+
1006
+ /* Return the best path, or NULL if we found no suitable candidate */
1007
+ return cheapest ;
1008
+ }
1009
+
944
1010
/*
945
1011
* accumulate_append_subpath
946
1012
* Add a subpath to the list being built for an Append or MergeAppend
0 commit comments