@@ -1942,58 +1942,67 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo)
1942
1942
/*
1943
1943
* Initialize the subplan_map and subpart_map.
1944
1944
*
1945
- * The set of partitions that exist now might not be the same that
1946
- * existed when the plan was made. The normal case is that it is;
1947
- * optimize for that case with a quick comparison, and just copy
1948
- * the subplan_map and make subpart_map point to the one in
1949
- * PruneInfo.
1945
+ * Because we request detached partitions to be included, and
1946
+ * detaching waits for old transactions, it is safe to assume that
1947
+ * no partitions have disappeared since this query was planned.
1950
1948
*
1951
- * For the case where they aren't identical, we could have more
1952
- * partitions on either side; or even exactly the same number of
1953
- * them on both but the set of OIDs doesn't match fully. Handle
1954
- * this by creating new subplan_map and subpart_map arrays that
1955
- * corresponds to the ones in the PruneInfo where the new
1956
- * partition descriptor's OIDs match. Any that don't match can be
1957
- * set to -1, as if they were pruned. Both arrays must be in
1958
- * numerical OID order.
1949
+ * However, new partitions may have been added.
1959
1950
*/
1951
+ Assert (partdesc -> nparts >= pinfo -> nparts );
1960
1952
pprune -> nparts = partdesc -> nparts ;
1961
1953
pprune -> subplan_map = palloc (sizeof (int ) * partdesc -> nparts );
1962
-
1963
- if (partdesc -> nparts == pinfo -> nparts &&
1964
- memcmp (partdesc -> oids , pinfo -> relid_map ,
1965
- sizeof (int ) * partdesc -> nparts ) == 0 )
1954
+ if (partdesc -> nparts == pinfo -> nparts )
1966
1955
{
1956
+ /*
1957
+ * There are no new partitions, so this is simple. We can
1958
+ * simply point to the subpart_map from the plan, but we must
1959
+ * copy the subplan_map since we may change it later.
1960
+ */
1967
1961
pprune -> subpart_map = pinfo -> subpart_map ;
1968
1962
memcpy (pprune -> subplan_map , pinfo -> subplan_map ,
1969
1963
sizeof (int ) * pinfo -> nparts );
1964
+
1965
+ /*
1966
+ * Double-check that the list of unpruned relations has not
1967
+ * changed. (Pruned partitions are not in relid_map[].)
1968
+ */
1969
+ #ifdef USE_ASSERT_CHECKING
1970
+ for (int k = 0 ; k < pinfo -> nparts ; k ++ )
1971
+ {
1972
+ Assert (partdesc -> oids [k ] == pinfo -> relid_map [k ] ||
1973
+ pinfo -> subplan_map [k ] == -1 );
1974
+ }
1975
+ #endif
1970
1976
}
1971
1977
else
1972
1978
{
1973
1979
int pd_idx = 0 ;
1974
1980
int pp_idx ;
1975
1981
1976
1982
/*
1977
- * When the partition arrays are not identical, there could be
1978
- * some new ones but it's also possible that one was removed;
1979
- * we cope with both situations by walking the arrays and
1980
- * discarding those that don't match.
1983
+ * Some new partitions have appeared since plan time, and
1984
+ * those are reflected in our PartitionDesc but were not
1985
+ * present in the one used to construct subplan_map and
1986
+ * subpart_map. So we must construct new and longer arrays
1987
+ * where the partitions that were originally present map to
1988
+ * the same sub-structures, and any added partitions map to
1989
+ * -1, as if the new partitions had been pruned.
1981
1990
*
1982
- * If the number of partitions on both sides match, it's still
1983
- * possible that one partition has been detached and another
1984
- * attached. Cope with that by creating a map that skips any
1985
- * mismatches.
1991
+ * Note: pinfo->relid_map[] may contain InvalidOid entries for
1992
+ * partitions pruned by the planner. We cannot tell exactly
1993
+ * which of the partdesc entries these correspond to, but we
1994
+ * don't have to; just skip over them. The non-pruned
1995
+ * relid_map entries, however, had better be a subset of the
1996
+ * partdesc entries and in the same order.
1986
1997
*/
1987
1998
pprune -> subpart_map = palloc (sizeof (int ) * partdesc -> nparts );
1988
-
1989
1999
for (pp_idx = 0 ; pp_idx < partdesc -> nparts ; pp_idx ++ )
1990
2000
{
1991
2001
/* Skip any InvalidOid relid_map entries */
1992
2002
while (pd_idx < pinfo -> nparts &&
1993
2003
!OidIsValid (pinfo -> relid_map [pd_idx ]))
1994
2004
pd_idx ++ ;
1995
2005
1996
- recheck :
1997
2006
if (pd_idx < pinfo -> nparts &&
1998
2007
pinfo -> relid_map [pd_idx ] == partdesc -> oids [pp_idx ])
1999
2008
{
@@ -2003,43 +2012,24 @@ CreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *pruneinfo)
2003
2012
pprune -> subpart_map [pp_idx ] =
2004
2013
pinfo -> subpart_map [pd_idx ];
2005
2014
pd_idx ++ ;
2006
- continue ;
2007
2015
}
2008
-
2009
- /*
2010
- * There isn't an exact match in the corresponding
2011
- * positions of both arrays. Peek ahead in
2012
- * pinfo->relid_map to see if we have a match for the
2013
- * current partition in partdesc. Normally if a match
2014
- * exists it's just one element ahead, and it means the
2015
- * planner saw one extra partition that we no longer see
2016
- * now (its concurrent detach finished just in between);
2017
- * so we skip that one by updating pd_idx to the new
2018
- * location and jumping above. We can then continue to
2019
- * match the rest of the elements after skipping the OID
2020
- * with no match; no future matches are tried for the
2021
- * element that was skipped, because we know the arrays to
2022
- * be in the same order.
2023
- *
2024
- * If we don't see a match anywhere in the rest of the
2025
- * pinfo->relid_map array, that means we see an element
2026
- * now that the planner didn't see, so mark that one as
2027
- * pruned and move on.
2028
- */
2029
- for (int pd_idx2 = pd_idx + 1 ; pd_idx2 < pinfo -> nparts ; pd_idx2 ++ )
2016
+ else
2030
2017
{
2031
- if (pd_idx2 >= pinfo -> nparts )
2032
- break ;
2033
- if (pinfo -> relid_map [pd_idx2 ] == partdesc -> oids [pp_idx ])
2034
- {
2035
- pd_idx = pd_idx2 ;
2036
- goto recheck ;
2037
- }
2018
+ /* this partdesc entry is not in the plan */
2019
+ pprune -> subplan_map [pp_idx ] = -1 ;
2020
+ pprune -> subpart_map [pp_idx ] = -1 ;
2038
2021
}
2039
-
2040
- pprune -> subpart_map [pp_idx ] = -1 ;
2041
- pprune -> subplan_map [pp_idx ] = -1 ;
2042
2022
}
2023
+
2024
+ /*
2025
+ * It might seem that we need to skip any trailing InvalidOid
2026
+ * entries in pinfo->relid_map before checking that we scanned
2027
+ * all of the relid_map. But we will have skipped them above,
2028
+ * because they must correspond to some partdesc->oids
2029
+ * entries; we just couldn't tell which.
2030
+ */
2031
+ if (pd_idx != pinfo -> nparts )
2032
+ elog (ERROR , "could not match partition child tables to plan elements" );
2043
2033
}
2044
2034
2045
2035
/* present_parts is also subject to later modification */
0 commit comments