On 2018/07/27 1:28, Tom Lane wrote: > Rajkumar Raghuwanshi <rajkumar.raghuwan...@enterprisedb.com> writes: >> I am getting "ERROR: negative bitmapset member not allowed" when >> enable_partition_pruning set to true with below test case.
Thanks Rajkumar. > Confirmed here. It's failing in perform_pruning_combine_step, > which reaches this: > > result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - > 1); > > with boundinfo->ndatums == 0. It's not clear to me whether that situation > should be impossible or not. If it is valid, perhaps all we need is > something like > > if (boundinfo->ndatums > 0) > result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums > - 1); > else > result->bound_offsets = NULL; > > although that then opens the question of whether downstream code is > OK with bound_offsets being empty. Yeah, this seems to be the only possible fix and I checked that downstream code is fine with bound_offsets being NULL/empty. Actually, the code that's concerned with bound offsets is limited to partprune.c, because we don't propagate bound offsets themselves outside this file. I found one more place in get_matching_hash_bounds where I thought maybe it'd be a good idea to add this check (if ndatums > 0), but then realized that that would become dead code as the upstream code takes care of the 0 hash partitions case. So, maybe an Assert (ndatums > 0) would be better. Attached find a patch that does both. > (BTW, I'm not sure that it was wise to design bms_add_range to fail for > empty ranges. Maybe it'd be better to redefine it as a no-op for > upper < lower?) FWIW, I was thankful that David those left those checks there, because it helped expose quite a few bugs when writing this code or perhaps that was his intention to begin with, but maybe he thinks differently now (?). Thanks, Amit
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 354eb0d4e6..8c024773af 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -2048,8 +2048,12 @@ get_matching_hash_bounds(PartitionPruneContext *context, bms_make_singleton(rowHash % greatest_modulus); } else + { + /* Getting here means at least one hash partition exists. */ + Assert(boundinfo->ndatums > 0); result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - 1); + } /* * There is neither a special hash null partition or the default hash @@ -2995,7 +2999,11 @@ perform_pruning_combine_step(PartitionPruneContext *context, { PartitionBoundInfo boundinfo = context->boundinfo; - result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - 1); + if (boundinfo->ndatums > 0) + result->bound_offsets = bms_add_range(NULL, 0, + boundinfo->ndatums - 1); + else + result->bound_offsets = NULL; result->scan_default = partition_bound_has_default(boundinfo); result->scan_null = partition_bound_accepts_nulls(boundinfo); return result;