I noticed a weird thing about rangetypes API while reviewing multiranges -- the combination of range_deserialize immediately followed by range_get_flags. It seems quite odd to have range_deserialize return only one flag (empty) and force callers to use a separate range_get_flags call in order to fetch anything else they need. I propose that it's simpler to have range_deserialize have an out param for flags (replacing "empty"), and callers can examine "IsEmpty" from that using a macro accessor. So there are two macros now: RangeFlagsIsEmpty() takes the 'flags' value and return whether the bit is set. Its companion RangeIsEmpty() does the range_get_flags() dance.
The attached patch does that, with a net savings of 8 lines of code in rangetypes.c. I know, it's not amazing. But it's slightly cleaner this way IMO. The reason things are this way is that initially (commit 4429f6a9e3e1) were all opaque; the external observer could only see "empty" when deserializing the value. Then commit 37ee4b75db8f added range_get_flags() to obtain the flags from a range, but at that point it was only used in places that did not deserialized the range anyway, so it was okay. I think it was commit c66e4f138b04 that ended up having both deserialize and get_flags in succession. So things are weird now, but they have not always been like that. I also chose to represent the flags out param as uint8 in range_deserialize. With this change, the compiler warns for callers using the old API (it used to take bool *), giving a chance to update. -- Álvaro Herrera
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c index 01ad8bc240..475165a912 100644 --- a/src/backend/utils/adt/rangetypes.c +++ b/src/backend/utils/adt/rangetypes.c @@ -124,20 +124,18 @@ range_out(PG_FUNCTION_ARGS) RangeType *range = PG_GETARG_RANGE_P(0); char *output_str; RangeIOData *cache; - char flags; + uint8 flags; char *lbound_str = NULL; char *ubound_str = NULL; RangeBound lower; RangeBound upper; - bool empty; check_stack_depth(); /* recurses when subtype is a range type */ cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_output); /* deserialize */ - range_deserialize(cache->typcache, range, &lower, &upper, &empty); - flags = range_get_flags(range); + range_deserialize(cache->typcache, range, &lower, &upper, &flags); /* call element type's output function */ if (RANGE_HAS_LBOUND(flags)) @@ -166,7 +164,7 @@ range_recv(PG_FUNCTION_ARGS) int32 typmod = PG_GETARG_INT32(2); RangeType *range; RangeIOData *cache; - char flags; + uint8 flags; RangeBound lower; RangeBound upper; @@ -175,7 +173,7 @@ range_recv(PG_FUNCTION_ARGS) cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_receive); /* receive the flags... */ - flags = (unsigned char) pq_getmsgbyte(buf); + flags = (uint8) pq_getmsgbyte(buf); /* * Mask out any unsupported flags, particularly RANGE_xB_NULL which would @@ -247,18 +245,16 @@ range_send(PG_FUNCTION_ARGS) RangeType *range = PG_GETARG_RANGE_P(0); StringInfo buf = makeStringInfo(); RangeIOData *cache; - char flags; + uint8 flags; RangeBound lower; RangeBound upper; - bool empty; check_stack_depth(); /* recurses when subtype is a range type */ cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_send); /* deserialize */ - range_deserialize(cache->typcache, range, &lower, &upper, &empty); - flags = range_get_flags(range); + range_deserialize(cache->typcache, range, &lower, &upper, &flags); /* construct output */ pq_begintypsend(buf); @@ -433,14 +429,14 @@ range_lower(PG_FUNCTION_ARGS) TypeCacheEntry *typcache; RangeBound lower; RangeBound upper; - bool empty; + uint8 flags; typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1)); - range_deserialize(typcache, r1, &lower, &upper, &empty); + range_deserialize(typcache, r1, &lower, &upper, &flags); /* Return NULL if there's no finite lower bound */ - if (empty || lower.infinite) + if (RangeFlagsIsEmpty(flags) || lower.infinite) PG_RETURN_NULL(); PG_RETURN_DATUM(lower.val); @@ -454,14 +450,14 @@ range_upper(PG_FUNCTION_ARGS) TypeCacheEntry *typcache; RangeBound lower; RangeBound upper; - bool empty; + uint8 flags; typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1)); - range_deserialize(typcache, r1, &lower, &upper, &empty); + range_deserialize(typcache, r1, &lower, &upper, &flags); /* Return NULL if there's no finite upper bound */ - if (empty || upper.infinite) + if (RangeFlagsIsEmpty(flags) || upper.infinite) PG_RETURN_NULL(); PG_RETURN_DATUM(upper.val); @@ -475,9 +471,8 @@ Datum range_empty(PG_FUNCTION_ARGS) { RangeType *r1 = PG_GETARG_RANGE_P(0); - char flags = range_get_flags(r1); - PG_RETURN_BOOL(flags & RANGE_EMPTY); + PG_RETURN_BOOL(RangeIsEmpty(r1)); } /* is lower bound inclusive? */ @@ -560,19 +555,19 @@ range_eq_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeType lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; /* Different types should be prevented by ANYRANGE matching rules */ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); - if (empty1 && empty2) + if (RangeFlagsIsEmpty(flags1) && RangeFlagsIsEmpty(flags2)) return true; - if (empty1 != empty2) + if (RangeFlagsIsEmpty(flags1) != RangeFlagsIsEmpty(flags2)) return false; if (range_cmp_bounds(typcache, &lower1, &lower2) != 0) @@ -651,18 +646,18 @@ range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, const Range lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; /* Different types should be prevented by ANYRANGE matching rules */ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* An empty range is neither before nor after any other range */ - if (empty1 || empty2) + if (RangeFlagsIsEmpty(flags1) || RangeFlagsIsEmpty(flags2)) return false; return (range_cmp_bounds(typcache, &upper1, &lower2) < 0); @@ -689,18 +684,18 @@ range_after_internal(TypeCacheEntry *typcache, const RangeType *r1, const RangeT lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; /* Different types should be prevented by ANYRANGE matching rules */ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* An empty range is neither before nor after any other range */ - if (empty1 || empty2) + if (RangeFlagsIsEmpty(flags1) || RangeFlagsIsEmpty(flags2)) return false; return (range_cmp_bounds(typcache, &lower1, &upper2) > 0); @@ -785,18 +780,18 @@ range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1, const Ran lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; /* Different types should be prevented by ANYRANGE matching rules */ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* An empty range is not adjacent to any other range */ - if (empty1 || empty2) + if (RangeFlagsIsEmpty(flags1) || RangeFlagsIsEmpty(flags2)) return false; /* @@ -828,18 +823,18 @@ range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, const Ran lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; /* Different types should be prevented by ANYRANGE matching rules */ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* An empty range does not overlap any other range */ - if (empty1 || empty2) + if (RangeFlagsIsEmpty(flags1) || RangeFlagsIsEmpty(flags2)) return false; if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0 && @@ -874,18 +869,18 @@ range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, const Ran lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; /* Different types should be prevented by ANYRANGE matching rules */ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* An empty range is neither before nor after any other range */ - if (empty1 || empty2) + if (RangeFlagsIsEmpty(flags1) || RangeFlagsIsEmpty(flags2)) return false; if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0) @@ -915,18 +910,18 @@ range_overright_internal(TypeCacheEntry *typcache, const RangeType *r1, const Ra lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; /* Different types should be prevented by ANYRANGE matching rules */ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* An empty range is neither before nor after any other range */ - if (empty1 || empty2) + if (RangeFlagsIsEmpty(flags1) || RangeFlagsIsEmpty(flags2)) return false; if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0) @@ -962,8 +957,8 @@ range_minus(PG_FUNCTION_ARGS) lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; int cmp_l1l2, cmp_l1u2, cmp_u1l2, @@ -975,11 +970,11 @@ range_minus(PG_FUNCTION_ARGS) typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1)); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* if either is empty, r1 is the correct answer */ - if (empty1 || empty2) + if (RangeFlagsIsEmpty(flags1) || RangeFlagsIsEmpty(flags2)) PG_RETURN_RANGE_P(r1); cmp_l1l2 = range_cmp_bounds(typcache, &lower1, &lower2); @@ -1028,8 +1023,8 @@ range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2, lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; RangeBound *result_lower; RangeBound *result_upper; @@ -1037,13 +1032,13 @@ range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2, if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* if either is empty, the other is the correct answer */ - if (empty1) + if (RangeFlagsIsEmpty(flags1)) return r2; - if (empty2) + if (RangeFlagsIsEmpty(flags2)) return r1; if (strict && @@ -1105,8 +1100,8 @@ range_intersect(PG_FUNCTION_ARGS) lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; RangeBound *result_lower; RangeBound *result_upper; @@ -1116,10 +1111,11 @@ range_intersect(PG_FUNCTION_ARGS) typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1)); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); - if (empty1 || empty2 || !DatumGetBool(range_overlaps(fcinfo))) + if (RangeFlagsIsEmpty(flags1) || RangeFlagsIsEmpty(flags2) || + !DatumGetBool(range_overlaps(fcinfo))) PG_RETURN_RANGE_P(make_empty_range(typcache)); if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0) @@ -1148,8 +1144,8 @@ range_cmp(PG_FUNCTION_ARGS) lower2; RangeBound upper1, upper2; - bool empty1, - empty2; + uint8 flags1, + flags2; int cmp; check_stack_depth(); /* recurses when subtype is a range type */ @@ -1160,15 +1156,15 @@ range_cmp(PG_FUNCTION_ARGS) typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1)); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* For b-tree use, empty ranges sort before all else */ - if (empty1 && empty2) + if (RangeFlagsIsEmpty(flags1) && RangeFlagsIsEmpty(flags2)) cmp = 0; - else if (empty1) + else if (RangeFlagsIsEmpty(flags1)) cmp = -1; - else if (empty2) + else if (RangeFlagsIsEmpty(flags2)) cmp = 1; else { @@ -1228,8 +1224,7 @@ hash_range(PG_FUNCTION_ARGS) TypeCacheEntry *scache; RangeBound lower; RangeBound upper; - bool empty; - char flags; + uint8 flags; uint32 lower_hash; uint32 upper_hash; @@ -1238,8 +1233,7 @@ hash_range(PG_FUNCTION_ARGS) typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r)); /* deserialize */ - range_deserialize(typcache, r, &lower, &upper, &empty); - flags = range_get_flags(r); + range_deserialize(typcache, r, &lower, &upper, &flags); /* * Look up the element type's hash function, if not done already. @@ -1295,8 +1289,7 @@ hash_range_extended(PG_FUNCTION_ARGS) TypeCacheEntry *scache; RangeBound lower; RangeBound upper; - bool empty; - char flags; + uint8 flags; uint64 lower_hash; uint64 upper_hash; @@ -1304,8 +1297,7 @@ hash_range_extended(PG_FUNCTION_ARGS) typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r)); - range_deserialize(typcache, r, &lower, &upper, &empty); - flags = range_get_flags(r); + range_deserialize(typcache, r, &lower, &upper, &flags); scache = typcache->rngelemtype; if (!OidIsValid(scache->hash_extended_proc_finfo.fn_oid)) @@ -1360,13 +1352,13 @@ int4range_canonical(PG_FUNCTION_ARGS) TypeCacheEntry *typcache; RangeBound lower; RangeBound upper; - bool empty; + uint8 flags; typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r)); - range_deserialize(typcache, r, &lower, &upper, &empty); + range_deserialize(typcache, r, &lower, &upper, &flags); - if (empty) + if (RangeFlagsIsEmpty(flags)) PG_RETURN_RANGE_P(r); if (!lower.infinite && !lower.inclusive) @@ -1391,13 +1383,13 @@ int8range_canonical(PG_FUNCTION_ARGS) TypeCacheEntry *typcache; RangeBound lower; RangeBound upper; - bool empty; + uint8 flags; typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r)); - range_deserialize(typcache, r, &lower, &upper, &empty); + range_deserialize(typcache, r, &lower, &upper, &flags); - if (empty) + if (RangeFlagsIsEmpty(flags)) PG_RETURN_RANGE_P(r); if (!lower.infinite && !lower.inclusive) @@ -1422,13 +1414,13 @@ daterange_canonical(PG_FUNCTION_ARGS) TypeCacheEntry *typcache; RangeBound lower; RangeBound upper; - bool empty; + uint8 flags; typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r)); - range_deserialize(typcache, r, &lower, &upper, &empty); + range_deserialize(typcache, r, &lower, &upper, &flags); - if (empty) + if (RangeFlagsIsEmpty(flags)) PG_RETURN_RANGE_P(r); if (!lower.infinite && !DATE_NOT_FINITE(DatumGetDateADT(lower.val)) && @@ -1697,9 +1689,8 @@ range_serialize(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, */ void range_deserialize(TypeCacheEntry *typcache, const RangeType *range, - RangeBound *lower, RangeBound *upper, bool *empty) + RangeBound *lower, RangeBound *upper, uint8 *flags) { - char flags; int16 typlen; bool typbyval; char typalign; @@ -1711,7 +1702,7 @@ range_deserialize(TypeCacheEntry *typcache, const RangeType *range, Assert(RangeTypeGetOid(range) == typcache->type_id); /* fetch the flag byte from datum's last byte */ - flags = *((const char *) range + VARSIZE(range) - 1); + *flags = *((const char *) range + VARSIZE(range) - 1); /* fetch information about range's element type */ typlen = typcache->rngelemtype->typlen; @@ -1722,7 +1713,7 @@ range_deserialize(TypeCacheEntry *typcache, const RangeType *range, ptr = (Pointer) (range + 1); /* fetch lower bound, if any */ - if (RANGE_HAS_LBOUND(flags)) + if (RANGE_HAS_LBOUND(*flags)) { /* att_align_pointer cannot be necessary here */ lbound = fetch_att(ptr, typbyval, typlen); @@ -1732,7 +1723,7 @@ range_deserialize(TypeCacheEntry *typcache, const RangeType *range, lbound = (Datum) 0; /* fetch upper bound, if any */ - if (RANGE_HAS_UBOUND(flags)) + if (RANGE_HAS_UBOUND(*flags)) { ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr); ubound = fetch_att(ptr, typbyval, typlen); @@ -1743,16 +1734,14 @@ range_deserialize(TypeCacheEntry *typcache, const RangeType *range, /* emit results */ - *empty = (flags & RANGE_EMPTY) != 0; - lower->val = lbound; - lower->infinite = (flags & RANGE_LB_INF) != 0; - lower->inclusive = (flags & RANGE_LB_INC) != 0; + lower->infinite = (*flags & RANGE_LB_INF) != 0; + lower->inclusive = (*flags & RANGE_LB_INC) != 0; lower->lower = true; upper->val = ubound; - upper->infinite = (flags & RANGE_UB_INF) != 0; - upper->inclusive = (flags & RANGE_UB_INC) != 0; + upper->infinite = (*flags & RANGE_UB_INF) != 0; + upper->inclusive = (*flags & RANGE_UB_INC) != 0; upper->lower = false; } @@ -1799,7 +1788,10 @@ make_range(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, range = range_serialize(typcache, lower, upper, empty); - /* no need to call canonical on empty ranges ... */ + /* + * no need to call canonical on empty ranges ... but don't rely + * solely on caller's idea of emptiness. + */ if (OidIsValid(typcache->rng_canonical_finfo.fn_oid) && !RangeIsEmpty(range)) range = DatumGetRangeTypeP(FunctionCall1(&typcache->rng_canonical_finfo, @@ -2304,22 +2296,22 @@ range_contains_internal(TypeCacheEntry *typcache, const RangeType *r1, const Ran { RangeBound lower1; RangeBound upper1; - bool empty1; + uint8 flags1; RangeBound lower2; RangeBound upper2; - bool empty2; + uint8 flags2; /* Different types should be prevented by ANYRANGE matching rules */ if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2)) elog(ERROR, "range types do not match"); - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); /* If either range is empty, the answer is easy */ - if (empty2) + if (RangeFlagsIsEmpty(flags2)) return true; - else if (empty1) + else if (RangeFlagsIsEmpty(flags1)) return false; /* Else we must have lower1 <= lower2 and upper1 >= upper2 */ @@ -2345,12 +2337,12 @@ range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum { RangeBound lower; RangeBound upper; - bool empty; + uint8 flags; int32 cmp; - range_deserialize(typcache, r, &lower, &upper, &empty); + range_deserialize(typcache, r, &lower, &upper, &flags); - if (empty) + if (RangeFlagsIsEmpty(flags)) return false; if (!lower.infinite) diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c index 75069c3ac2..0cc91efab8 100644 --- a/src/backend/utils/adt/rangetypes_gist.c +++ b/src/backend/utils/adt/rangetypes_gist.c @@ -246,8 +246,8 @@ range_gist_penalty(PG_FUNCTION_ARGS) new_lower, orig_upper, new_upper; - bool orig_empty, - new_empty; + uint8 orig_flags, + new_flags; if (RangeTypeGetOid(orig) != RangeTypeGetOid(new)) elog(ERROR, "range types do not match"); @@ -256,18 +256,18 @@ range_gist_penalty(PG_FUNCTION_ARGS) has_subtype_diff = OidIsValid(typcache->rng_subdiff_finfo.fn_oid); - range_deserialize(typcache, orig, &orig_lower, &orig_upper, &orig_empty); - range_deserialize(typcache, new, &new_lower, &new_upper, &new_empty); + range_deserialize(typcache, orig, &orig_lower, &orig_upper, &orig_flags); + range_deserialize(typcache, new, &new_lower, &new_upper, &new_flags); /* * Distinct branches for handling distinct classes of ranges. Note that * penalty values only need to be commensurate within the same class of * new range. */ - if (new_empty) + if (RangeFlagsIsEmpty(new_flags)) { /* Handle insertion of empty range */ - if (orig_empty) + if (RangeFlagsIsEmpty(orig_flags)) { /* * The best case is to insert it to empty original range. @@ -276,7 +276,7 @@ range_gist_penalty(PG_FUNCTION_ARGS) */ *penalty = 0.0; } - else if (RangeIsOrContainsEmpty(orig)) + else if (RangeFlagsIsOrContainsEmpty(orig_flags)) { /* * The second case is to insert empty range into range which @@ -337,7 +337,7 @@ range_gist_penalty(PG_FUNCTION_ARGS) *penalty = 2 * INFINITE_BOUND_PENALTY; } - if (RangeIsOrContainsEmpty(orig)) + if (RangeFlagsIsOrContainsEmpty(orig_flags)) { /* * Original range is narrower when it doesn't contain empty @@ -349,7 +349,7 @@ range_gist_penalty(PG_FUNCTION_ARGS) else if (new_lower.infinite) { /* Handle insertion of (-inf, x) range */ - if (!orig_empty && orig_lower.infinite) + if (!RangeFlagsIsEmpty(orig_flags) && orig_lower.infinite) { if (orig_upper.infinite) { @@ -396,7 +396,7 @@ range_gist_penalty(PG_FUNCTION_ARGS) else if (new_upper.infinite) { /* Handle insertion of (x, +inf) range */ - if (!orig_empty && orig_upper.infinite) + if (!RangeFlagsIsEmpty(orig_flags) && orig_upper.infinite) { if (orig_lower.infinite) { @@ -443,7 +443,7 @@ range_gist_penalty(PG_FUNCTION_ARGS) else { /* Handle insertion of normal (non-empty, non-infinite) range */ - if (orig_empty || orig_lower.infinite || orig_upper.infinite) + if (RangeFlagsIsEmpty(orig_flags) || orig_lower.infinite || orig_upper.infinite) { /* * Avoid mixing normal ranges with infinite and empty ranges. @@ -699,19 +699,15 @@ range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) lower2; RangeBound upper1, upper2; - bool empty1, - empty2; - char flags1, + uint8 flags1, flags2; RangeBound *result_lower; RangeBound *result_upper; - range_deserialize(typcache, r1, &lower1, &upper1, &empty1); - range_deserialize(typcache, r2, &lower2, &upper2, &empty2); - flags1 = range_get_flags(r1); - flags2 = range_get_flags(r2); + range_deserialize(typcache, r1, &lower1, &upper1, &flags1); + range_deserialize(typcache, r2, &lower2, &upper2, &flags2); - if (empty1) + if (RangeFlagsIsEmpty(flags1)) { /* We can return r2 as-is if it already is or contains empty */ if (flags2 & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY)) @@ -721,7 +717,7 @@ range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2) range_set_contain_empty(r2); return r2; } - if (empty2) + if (RangeFlagsIsEmpty(flags2)) { /* We can return r1 as-is if it already is or contains empty */ if (flags1 & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY)) @@ -983,17 +979,17 @@ range_gist_single_sorting_split(TypeCacheEntry *typcache, { RangeType *range = DatumGetRangeTypeP(entryvec->vector[i].key); RangeBound bound2; - bool empty; + uint8 flags; sortItems[i - 1].index = i; /* Put appropriate bound into array */ if (use_upper_bound) range_deserialize(typcache, range, &bound2, - &sortItems[i - 1].bound, &empty); + &sortItems[i - 1].bound, &flags); else range_deserialize(typcache, range, &sortItems[i - 1].bound, - &bound2, &empty); - Assert(!empty); + &bound2, &flags); + Assert(!RangeFlagsIsEmpty(flags)); } qsort_arg(sortItems, maxoff, sizeof(SingleBoundSortItem), @@ -1084,13 +1080,13 @@ range_gist_double_sorting_split(TypeCacheEntry *typcache, for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { RangeType *range = DatumGetRangeTypeP(entryvec->vector[i].key); - bool empty; + uint8 flags; range_deserialize(typcache, range, &by_lower[i - FirstOffsetNumber].lower, &by_lower[i - FirstOffsetNumber].upper, - &empty); - Assert(!empty); + &flags); + Assert(!RangeFlagsIsEmpty(flags)); } /* @@ -1253,14 +1249,14 @@ range_gist_double_sorting_split(TypeCacheEntry *typcache, { RangeBound lower, upper; - bool empty; + uint8 flags; /* * Get upper and lower bounds along selected axis. */ range = DatumGetRangeTypeP(entryvec->vector[i].key); - range_deserialize(typcache, range, &lower, &upper, &empty); + range_deserialize(typcache, range, &lower, &upper, &flags); if (range_cmp_bounds(typcache, &upper, context.left_upper) <= 0) { diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c index 25dd84f4df..c518b73fa9 100644 --- a/src/backend/utils/adt/rangetypes_selfuncs.c +++ b/src/backend/utils/adt/rangetypes_selfuncs.c @@ -381,7 +381,7 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata, int i; RangeBound const_lower; RangeBound const_upper; - bool empty; + uint8 flags; double hist_selec; /* Can't use the histogram with insecure range support functions */ @@ -417,9 +417,9 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata, for (i = 0; i < nhist; i++) { range_deserialize(typcache, DatumGetRangeTypeP(hslot.values[i]), - &hist_lower[i], &hist_upper[i], &empty); + &hist_lower[i], &hist_upper[i], &flags); /* The histogram should not contain any empty ranges */ - if (empty) + if (RangeFlagsIsEmpty(flags)) elog(ERROR, "bounds histogram contains an empty range"); } @@ -449,8 +449,8 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata, memset(&lslot, 0, sizeof(lslot)); /* Extract the bounds of the constant value. */ - range_deserialize(typcache, constval, &const_lower, &const_upper, &empty); - Assert(!empty); + range_deserialize(typcache, constval, &const_lower, &const_upper, &flags); + Assert(!RangeFlagsIsEmpty(flags)); /* * Calculate selectivity comparing the lower or upper bound of the diff --git a/src/backend/utils/adt/rangetypes_spgist.c b/src/backend/utils/adt/rangetypes_spgist.c index dd2bc742aa..edcd0eb1a9 100644 --- a/src/backend/utils/adt/rangetypes_spgist.c +++ b/src/backend/utils/adt/rangetypes_spgist.c @@ -96,16 +96,16 @@ getQuadrant(TypeCacheEntry *typcache, const RangeType *centroid, const RangeType { RangeBound centroidLower, centroidUpper; - bool centroidEmpty; + uint8 centroidFlags; RangeBound lower, upper; - bool empty; + uint8 flags; range_deserialize(typcache, centroid, ¢roidLower, ¢roidUpper, - ¢roidEmpty); - range_deserialize(typcache, tst, &lower, &upper, &empty); + ¢roidFlags); + range_deserialize(typcache, tst, &lower, &upper, &flags); - if (empty) + if (RangeFlagsIsEmpty(flags)) return 5; if (range_cmp_bounds(typcache, &lower, ¢roidLower) >= 0) @@ -205,7 +205,7 @@ spg_range_quad_picksplit(PG_FUNCTION_ARGS) int j; int nonEmptyCount; RangeType *centroid; - bool empty; + uint8 flags; TypeCacheEntry *typcache; /* Use the median values of lower and upper bounds as the centroid range */ @@ -224,8 +224,8 @@ spg_range_quad_picksplit(PG_FUNCTION_ARGS) for (i = 0; i < in->nTuples; i++) { range_deserialize(typcache, DatumGetRangeTypeP(in->datums[i]), - &lowerBounds[j], &upperBounds[j], &empty); - if (!empty) + &lowerBounds[j], &upperBounds[j], &flags); + if (!RangeFlagsIsEmpty(flags)) j++; } nonEmptyCount = j; @@ -409,7 +409,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) { RangeBound centroidLower, centroidUpper; - bool centroidEmpty; + uint8 centroidFlags; TypeCacheEntry *typcache; RangeType *centroid; @@ -418,7 +418,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) typcache = range_get_typcache(fcinfo, RangeTypeGetOid(DatumGetRangeTypeP(centroid))); range_deserialize(typcache, centroid, ¢roidLower, ¢roidUpper, - ¢roidEmpty); + ¢roidFlags); Assert(in->nNodes == 4 || in->nNodes == 5); @@ -434,13 +434,13 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) StrategyNumber strategy; RangeBound lower, upper; - bool empty; + uint8 flags; RangeType *range = NULL; RangeType *prevCentroid = NULL; RangeBound prevLower, prevUpper; - bool prevEmpty; + uint8 prevFlags; /* Restrictions on range bounds according to scan strategy */ RangeBound *minLower = NULL, @@ -475,14 +475,14 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) upper.lower = false; upper.val = in->scankeys[i].sk_argument; - empty = false; + flags = 0; strategy = RANGESTRAT_CONTAINS; } else { range = DatumGetRangeTypeP(in->scankeys[i].sk_argument); - range_deserialize(typcache, range, &lower, &upper, &empty); + range_deserialize(typcache, range, &lower, &upper, &flags); } /* @@ -547,7 +547,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) break; case RANGESTRAT_ADJACENT: - if (empty) + if (RangeFlagsIsEmpty(flags)) break; /* Skip to strictEmpty check. */ /* @@ -559,7 +559,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) { prevCentroid = DatumGetRangeTypeP(in->traversalValue); range_deserialize(typcache, prevCentroid, - &prevLower, &prevUpper, &prevEmpty); + &prevLower, &prevUpper, &prevFlags); } /* @@ -614,7 +614,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) * All non-empty ranges contain an empty range. */ strictEmpty = false; - if (!empty) + if (!RangeFlagsIsEmpty(flags)) { which &= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4); maxLower = &lower; @@ -625,7 +625,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) case RANGESTRAT_CONTAINED_BY: /* The opposite of contains. */ strictEmpty = false; - if (empty) + if (RangeFlagsIsEmpty(flags)) { /* An empty range is only contained by an empty range */ which &= (1 << 5); @@ -654,7 +654,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) if (strictEmpty) { - if (empty) + if (RangeFlagsIsEmpty(flags)) { /* Scan key is empty, no branches are satisfying */ which = 0; diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c index 57413b0720..f020537fb0 100644 --- a/src/backend/utils/adt/rangetypes_typanalyze.c +++ b/src/backend/utils/adt/rangetypes_typanalyze.c @@ -121,11 +121,11 @@ compute_range_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc, for (range_no = 0; range_no < samplerows; range_no++) { Datum value; - bool isnull, - empty; + bool isnull; RangeType *range; RangeBound lower, upper; + uint8 flags; float8 length; vacuum_delay_point(); @@ -146,9 +146,9 @@ compute_range_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc, /* Get range and deserialize it for further analysis. */ range = DatumGetRangeTypeP(value); - range_deserialize(typcache, range, &lower, &upper, &empty); + range_deserialize(typcache, range, &lower, &upper, &flags); - if (!empty) + if (!RangeFlagsIsEmpty(flags)) { /* Remember bounds and length for further usage in histograms */ lowers[non_empty_cnt] = lower; diff --git a/src/include/utils/rangetypes.h b/src/include/utils/rangetypes.h index 0cbbf09033..158fe78322 100644 --- a/src/include/utils/rangetypes.h +++ b/src/include/utils/rangetypes.h @@ -51,9 +51,13 @@ typedef struct RANGE_UB_NULL | \ RANGE_UB_INF))) -#define RangeIsEmpty(r) ((range_get_flags(r) & RANGE_EMPTY) != 0) -#define RangeIsOrContainsEmpty(r) \ - ((range_get_flags(r) & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY)) != 0) +#define RangeFlagsIsEmpty(flags) \ + (((flags) & RANGE_EMPTY) != 0) +#define RangeFlagsIsOrContainsEmpty(flags) \ + (((flags) & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY)) != 0) + +#define RangeIsEmpty(r) (RangeFlagsIsEmpty(range_get_flags(r))) +#define RangeIsOrContainsEmpty(r) (RangeFlagsIsOrContainsEmpty(range_get_flags(r))) /* Internal representation of either bound of a range (not what's on disk) */ @@ -123,7 +127,7 @@ extern RangeType *range_serialize(TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, bool empty); extern void range_deserialize(TypeCacheEntry *typcache, const RangeType *range, RangeBound *lower, RangeBound *upper, - bool *empty); + uint8 *flags); extern char range_get_flags(const RangeType *range); extern void range_set_contain_empty(RangeType *range); extern RangeType *make_range(TypeCacheEntry *typcache, RangeBound *lower,