* generate_orderedappend_paths * Generate ordered append paths for an append relation * * Usually we generate MergeAppend paths here, but there are some special * cases where we can generate simple Append paths, because the subpaths * can provide tuples in the required order already. * * We generate a path for each ordering (pathkey list) appearing in * all_child_pathkeys. * * We consid
| 2041 | * optimizer/README for why that might not ever happen, though.) |
| 2042 | */ |
| 2043 | static void |
| 2044 | generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, |
| 2045 | List *live_childrels, |
| 2046 | List *all_child_pathkeys) |
| 2047 | { |
| 2048 | ListCell *lcp; |
| 2049 | List *partition_pathkeys = NIL; |
| 2050 | List *partition_pathkeys_desc = NIL; |
| 2051 | bool partition_pathkeys_partial = true; |
| 2052 | bool partition_pathkeys_desc_partial = true; |
| 2053 | |
| 2054 | /* |
| 2055 | * Some partitioned table setups may allow us to use an Append node |
| 2056 | * instead of a MergeAppend. This is possible in cases such as RANGE |
| 2057 | * partitioned tables where it's guaranteed that an earlier partition must |
| 2058 | * contain rows which come earlier in the sort order. To detect whether |
| 2059 | * this is relevant, build pathkey descriptions of the partition ordering, |
| 2060 | * for both forward and reverse scans. |
| 2061 | */ |
| 2062 | if (rel->part_scheme != NULL && IS_SIMPLE_REL(rel) && |
| 2063 | partitions_are_ordered(rel->boundinfo, rel->nparts)) |
| 2064 | { |
| 2065 | partition_pathkeys = build_partition_pathkeys(root, rel, |
| 2066 | ForwardScanDirection, |
| 2067 | &partition_pathkeys_partial); |
| 2068 | |
| 2069 | partition_pathkeys_desc = build_partition_pathkeys(root, rel, |
| 2070 | BackwardScanDirection, |
| 2071 | &partition_pathkeys_desc_partial); |
| 2072 | |
| 2073 | /* |
| 2074 | * You might think we should truncate_useless_pathkeys here, but |
| 2075 | * allowing partition keys which are a subset of the query's pathkeys |
| 2076 | * can often be useful. For example, consider a table partitioned by |
| 2077 | * RANGE (a, b), and a query with ORDER BY a, b, c. If we have child |
| 2078 | * paths that can produce the a, b, c ordering (perhaps via indexes on |
| 2079 | * (a, b, c)) then it works to consider the appendrel output as |
| 2080 | * ordered by a, b, c. |
| 2081 | */ |
| 2082 | } |
| 2083 | |
| 2084 | /* Now consider each interesting sort ordering */ |
| 2085 | foreach(lcp, all_child_pathkeys) |
| 2086 | { |
| 2087 | List *pathkeys = (List *) lfirst(lcp); |
| 2088 | List *startup_subpaths = NIL; |
| 2089 | List *total_subpaths = NIL; |
| 2090 | bool startup_neq_total = false; |
| 2091 | ListCell *lcr; |
| 2092 | bool match_partition_order; |
| 2093 | bool match_partition_order_desc; |
| 2094 | |
| 2095 | /* |
| 2096 | * Determine if this sort ordering matches any partition pathkeys we |
| 2097 | * have, for both ascending and descending partition order. If the |
| 2098 | * partition pathkeys happen to be contained in pathkeys then it still |
| 2099 | * works, as described above, providing that the partition pathkeys |
| 2100 | * are complete and not just a prefix of the partition keys. (In such |
no test coverage detected