Skip to content

Commit e1fbe11

Browse files
committed
Fix BRIN minmax-multi distance for inet type
The distance calculation ignored the mask, unlike the inet comparator, which resulted in negative distance in some cases. Fixed by applying the mask in brin_minmax_multi_distance_inet. I've considered simply calling inetmi() to calculate the delta, but that does not consider mask either. Reviewed-by: Zhihong Yu Discussion: https://postgr.es/m/1a0a7b9d-9bda-e3a2-7fa4-88f15042a051%40enterprisedb.com
1 parent 7262f24 commit e1fbe11

File tree

1 file changed

+51
-8
lines changed

1 file changed

+51
-8
lines changed

src/backend/access/brin/brin_minmax_multi.c

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2297,31 +2297,74 @@ brin_minmax_multi_distance_inet(PG_FUNCTION_ARGS)
22972297
inet *ipa = PG_GETARG_INET_PP(0);
22982298
inet *ipb = PG_GETARG_INET_PP(1);
22992299

2300+
int lena,
2301+
lenb;
2302+
23002303
/*
23012304
* If the addresses are from different families, consider them to be in
23022305
* maximal possible distance (which is 1.0).
23032306
*/
23042307
if (ip_family(ipa) != ip_family(ipb))
23052308
PG_RETURN_FLOAT8(1.0);
23062309

2307-
/* ipv4 or ipv6 */
2308-
if (ip_family(ipa) == PGSQL_AF_INET)
2309-
len = 4;
2310-
else
2311-
len = 16; /* NS_IN6ADDRSZ */
2310+
addra = (unsigned char *) palloc(ip_addrsize(ipa));
2311+
memcpy(addra, ip_addr(ipa), ip_addrsize(ipa));
2312+
2313+
addrb = (unsigned char *) palloc(ip_addrsize(ipb));
2314+
memcpy(addrb, ip_addr(ipb), ip_addrsize(ipb));
2315+
2316+
/*
2317+
* The length is calculated from the mask length, because we sort the
2318+
* addresses by first address in the range, so A.B.C.D/24 < A.B.C.1
2319+
* (the first range starts at A.B.C.0, which is before A.B.C.1). We
2320+
* don't want to produce negative delta in this case, so we just cut
2321+
* the extra bytes.
2322+
*
2323+
* XXX Maybe this should be a bit more careful and cut the bits, not
2324+
* just whole bytes.
2325+
*/
2326+
lena = ip_bits(ipa);
2327+
lenb = ip_bits(ipb);
2328+
2329+
len = ip_addrsize(ipa);
2330+
2331+
/* apply the network mask to both addresses */
2332+
for (i = 0; i < len; i++)
2333+
{
2334+
unsigned char mask;
2335+
int nbits;
23122336

2313-
addra = ip_addr(ipa);
2314-
addrb = ip_addr(ipb);
2337+
nbits = lena - (i * 8);
2338+
if (nbits < 8)
2339+
{
2340+
mask = (0xFF << (8 - nbits));
2341+
addra[i] = (addra[i] & mask);
2342+
}
23152343

2344+
nbits = lenb - (i * 8);
2345+
if (nbits < 8)
2346+
{
2347+
mask = (0xFF << (8 - nbits));
2348+
addrb[i] = (addrb[i] & mask);
2349+
}
2350+
}
2351+
2352+
/* Calculate the difference between the addresses. */
23162353
delta = 0;
23172354
for (i = len - 1; i >= 0; i--)
23182355
{
2319-
delta += (float8) addrb[i] - (float8) addra[i];
2356+
unsigned char a = addra[i];
2357+
unsigned char b = addrb[i];
2358+
2359+
delta += (float8) b - (float8) a;
23202360
delta /= 256;
23212361
}
23222362

23232363
Assert((delta >= 0) && (delta <= 1));
23242364

2365+
pfree(addra);
2366+
pfree(addrb);
2367+
23252368
PG_RETURN_FLOAT8(delta);
23262369
}
23272370

0 commit comments

Comments
 (0)