@ -395,6 +395,7 @@ create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
boundinfo - > ndatums = nparts ;
boundinfo - > ndatums = nparts ;
boundinfo - > datums = ( Datum * * ) palloc0 ( nparts * sizeof ( Datum * ) ) ;
boundinfo - > datums = ( Datum * * ) palloc0 ( nparts * sizeof ( Datum * ) ) ;
boundinfo - > kind = NULL ;
boundinfo - > kind = NULL ;
boundinfo - > interleaved_parts = NULL ;
boundinfo - > nindexes = greatest_modulus ;
boundinfo - > nindexes = greatest_modulus ;
boundinfo - > indexes = ( int * ) palloc ( greatest_modulus * sizeof ( int ) ) ;
boundinfo - > indexes = ( int * ) palloc ( greatest_modulus * sizeof ( int ) ) ;
for ( i = 0 ; i < greatest_modulus ; i + + )
for ( i = 0 ; i < greatest_modulus ; i + + )
@ -543,6 +544,7 @@ create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
boundinfo - > ndatums = ndatums ;
boundinfo - > ndatums = ndatums ;
boundinfo - > datums = ( Datum * * ) palloc0 ( ndatums * sizeof ( Datum * ) ) ;
boundinfo - > datums = ( Datum * * ) palloc0 ( ndatums * sizeof ( Datum * ) ) ;
boundinfo - > kind = NULL ;
boundinfo - > kind = NULL ;
boundinfo - > interleaved_parts = NULL ;
boundinfo - > nindexes = ndatums ;
boundinfo - > nindexes = ndatums ;
boundinfo - > indexes = ( int * ) palloc ( ndatums * sizeof ( int ) ) ;
boundinfo - > indexes = ( int * ) palloc ( ndatums * sizeof ( int ) ) ;
@ -607,6 +609,69 @@ create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
boundinfo - > default_index = ( * mapping ) [ default_index ] ;
boundinfo - > default_index = ( * mapping ) [ default_index ] ;
}
}
/*
* Calculate interleaved partitions . Here we look for partitions which
* might be interleaved with other partitions and set a bit in
* interleaved_parts for any partitions which may be interleaved with
* another partition .
*/
/*
* There must be multiple partitions to have any interleaved partitions ,
* otherwise there ' s nothing to interleave with .
*/
if ( nparts > 1 )
{
/*
* Short - circuit check to see if only 1 Datum is allowed per
* partition . When this is true there ' s no need to do the more
* expensive checks to look for interleaved values .
*/
if ( boundinfo - > ndatums +
partition_bound_accepts_nulls ( boundinfo ) +
partition_bound_has_default ( boundinfo ) ! = nparts )
{
int last_index = - 1 ;
/*
* Since the indexes array is sorted in Datum order , if any
* partitions are interleaved then it will show up by the
* partition indexes not being in ascending order . Here we check
* for that and record all partitions that are out of order .
*/
for ( i = 0 ; i < boundinfo - > nindexes ; i + + )
{
int index = boundinfo - > indexes [ i ] ;
if ( index < last_index )
boundinfo - > interleaved_parts = bms_add_member ( boundinfo - > interleaved_parts ,
index ) ;
/*
* Mark the NULL partition as interleaved if we find that it
* allows some other non - NULL Datum .
*/
if ( partition_bound_accepts_nulls ( boundinfo ) & &
index = = boundinfo - > null_index )
boundinfo - > interleaved_parts = bms_add_member ( boundinfo - > interleaved_parts ,
boundinfo - > null_index ) ;
last_index = index ;
}
}
/*
* The DEFAULT partition is the " catch-all " partition that can contain
* anything that does not belong to any other partition . If there are
* any other partitions then the DEFAULT partition must be marked as
* interleaved .
*/
if ( partition_bound_has_default ( boundinfo ) )
boundinfo - > interleaved_parts = bms_add_member ( boundinfo - > interleaved_parts ,
boundinfo - > default_index ) ;
}
/* All partitions must now have been assigned canonical indexes. */
/* All partitions must now have been assigned canonical indexes. */
Assert ( next_index = = nparts ) ;
Assert ( next_index = = nparts ) ;
return boundinfo ;
return boundinfo ;
@ -750,6 +815,7 @@ create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
boundinfo - > kind = ( PartitionRangeDatumKind * * )
boundinfo - > kind = ( PartitionRangeDatumKind * * )
palloc ( ndatums *
palloc ( ndatums *
sizeof ( PartitionRangeDatumKind * ) ) ;
sizeof ( PartitionRangeDatumKind * ) ) ;
boundinfo - > interleaved_parts = NULL ;
/*
/*
* For range partitioning , an additional value of - 1 is stored as the last
* For range partitioning , an additional value of - 1 is stored as the last
@ -993,6 +1059,9 @@ partition_bounds_copy(PartitionBoundInfo src,
else
else
dest - > kind = NULL ;
dest - > kind = NULL ;
/* copy interleaved partitions for LIST partitioned tables */
dest - > interleaved_parts = bms_copy ( src - > interleaved_parts ) ;
/*
/*
* For hash partitioning , datums array will have two elements - modulus
* For hash partitioning , datums array will have two elements - modulus
* and remainder .
* and remainder .
@ -2780,13 +2849,15 @@ add_merged_range_bounds(int partnatts, FmgrInfo *partsupfuncs,
* that is partitions appearing earlier in the PartitionDesc sequence
* that is partitions appearing earlier in the PartitionDesc sequence
* contain partition keys strictly less than those appearing later .
* contain partition keys strictly less than those appearing later .
* Also , if NULL values are possible , they must come in the last
* Also , if NULL values are possible , they must come in the last
* partition defined in the PartitionDesc .
* partition defined in the PartitionDesc . ' live_parts ' marks which
* partitions we should include when checking the ordering . Partitions
* that do not appear in ' live_parts ' are ignored .
*
*
* If out of order , or there is insufficient info to know the order ,
* If out of order , or there is insufficient info to know the order ,
* then we return false .
* then we return false .
*/
*/
bool
bool
partitions_are_ordered ( PartitionBoundInfo boundinfo , int n parts)
partitions_are_ordered ( PartitionBoundInfo boundinfo , Bitmapset * live_ parts)
{
{
Assert ( boundinfo ! = NULL ) ;
Assert ( boundinfo ! = NULL ) ;
@ -2798,38 +2869,24 @@ partitions_are_ordered(PartitionBoundInfo boundinfo, int nparts)
* RANGE - type partitioning guarantees that the partitions can be
* RANGE - type partitioning guarantees that the partitions can be
* scanned in the order that they ' re defined in the PartitionDesc
* scanned in the order that they ' re defined in the PartitionDesc
* to provide sequential , non - overlapping ranges of tuples .
* to provide sequential , non - overlapping ranges of tuples .
* However , if a DEFAULT partition exists then it doesn ' t work , as
* However , if a DEFAULT partition exists and it ' s contained
* that could contain tuples from either below or above the
* within live_parts , then the partitions are not ordered .
* defined range , or tuples belonging to gaps between partitions .
*/
*/
if ( ! partition_bound_has_default ( boundinfo ) )
if ( ! partition_bound_has_default ( boundinfo ) | |
! bms_is_member ( boundinfo - > default_index , live_parts ) )
return true ;
return true ;
break ;
break ;
case PARTITION_STRATEGY_LIST :
case PARTITION_STRATEGY_LIST :
/*
/*
* LIST partitioning can also guarantee ordering , but only if the
* LIST partitioned are ordered providing none of live_parts
* partitions don ' t accept interleaved values . We could likely
* overlap with the partitioned table ' s interleaved partitions .
* check for this by looping over the PartitionBound ' s indexes
* array to check that the indexes are in order . For now , let ' s
* just keep it simple and just accept LIST partitioning when
* there ' s no DEFAULT partition , exactly one value per partition ,
* and optionally a NULL partition that does not accept any other
* values . Such a NULL partition will come last in the
* PartitionDesc , and the other partitions will be properly
* ordered . This is a cheap test to make as it does not require
* any per - partition processing . Maybe we ' d like to handle more
* complex cases in the future .
*/
*/
if ( partition_bound_has_default ( boundinfo ) )
if ( ! bms_overlap ( live_parts , boundinfo - > interleaved_parts ) )
return false ;
if ( boundinfo - > ndatums + partition_bound_accepts_nulls ( boundinfo )
= = nparts )
return true ;
return true ;
break ;
break ;
default :
default :
/* HASH, or some other strategy */
/* HASH, or some other strategy */
break ;
break ;