1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-04 12:02:48 +03:00

Add geometry/range functions to support BRIN inclusion

This commit adds the following functions:
    box(point) -> box
    bound_box(box, box) -> box
    inet_same_family(inet, inet) -> bool
    inet_merge(inet, inet) -> cidr
    range_merge(anyrange, anyrange) -> anyrange

The first of these is also used to implement a new assignment cast from
point to box.

These functions are the first part of a base to implement an "inclusion"
operator class for BRIN, for multidimensional data types.

Author: Emre Hasegeli
Reviewed by: Andreas Karlsson
This commit is contained in:
Alvaro Herrera
2015-05-05 15:22:24 -03:00
parent 456ff08638
commit 3b6db1f445
18 changed files with 363 additions and 16 deletions

View File

@@ -4227,6 +4227,45 @@ box_div(PG_FUNCTION_ARGS)
PG_RETURN_BOX_P(result);
}
/*
* Convert point to empty box
*/
Datum
point_box(PG_FUNCTION_ARGS)
{
Point *pt = PG_GETARG_POINT_P(0);
BOX *box;
box = (BOX *) palloc(sizeof(BOX));
box->high.x = pt->x;
box->low.x = pt->x;
box->high.y = pt->y;
box->low.y = pt->y;
PG_RETURN_BOX_P(box);
}
/*
* Smallest bounding box that includes both of the given boxes
*/
Datum
boxes_bound_box(PG_FUNCTION_ARGS)
{
BOX *box1 = PG_GETARG_BOX_P(0),
*box2 = PG_GETARG_BOX_P(1),
*container;
container = (BOX *) palloc(sizeof(BOX));
container->high.x = Max(box1->high.x, box2->high.x);
container->low.x = Min(box1->low.x, box2->low.x);
container->high.y = Max(box1->high.y, box2->high.y);
container->low.y = Min(box1->low.y, box2->low.y);
PG_RETURN_BOX_P(container);
}
/***********************************************************************
**

View File

@@ -887,6 +887,58 @@ network_hostmask(PG_FUNCTION_ARGS)
PG_RETURN_INET_P(dst);
}
/*
* Returns true if the addresses are from the same family, or false. Used to
* check that we can create a network which contains both of the networks.
*/
Datum
inet_same_family(PG_FUNCTION_ARGS)
{
inet *a1 = PG_GETARG_INET_PP(0);
inet *a2 = PG_GETARG_INET_PP(1);
PG_RETURN_BOOL(ip_family(a1) == ip_family(a2));
}
/*
* Returns the smallest CIDR which contains both of the inputs.
*/
Datum
inet_merge(PG_FUNCTION_ARGS)
{
inet *a1 = PG_GETARG_INET_PP(0),
*a2 = PG_GETARG_INET_PP(1),
*result;
int commonbits;
if (ip_family(a1) != ip_family(a2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot merge addresses from different families")));
commonbits = bitncommon(ip_addr(a1), ip_addr(a2),
Min(ip_bits(a1), ip_bits(a2)));
/* Make sure any unused bits are zeroed. */
result = (inet *) palloc0(sizeof(inet));
ip_family(result) = ip_family(a1);
ip_bits(result) = commonbits;
/* Clone appropriate bytes of the address. */
if (commonbits > 0)
memcpy(ip_addr(result), ip_addr(a1), (commonbits + 7) / 8);
/* Clean any unwanted bits in the last partial byte. */
if (commonbits % 8 != 0)
ip_addr(result)[commonbits / 8] &= ~(0xFF >> (commonbits % 8));
/* Set varlena header correctly. */
SET_INET_VARSIZE(result);
PG_RETURN_INET_P(result);
}
/*
* Convert a value of a network datatype to an approximate scalar value.
* This is used for estimating selectivities of inequality operators

View File

@@ -1006,13 +1006,14 @@ range_minus(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
/* set union */
Datum
range_union(PG_FUNCTION_ARGS)
/*
* Set union. If strict is true, it is an error that the two input ranges
* are not adjacent or overlapping.
*/
static RangeType *
range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2,
bool strict)
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
@@ -1026,19 +1027,18 @@ range_union(PG_FUNCTION_ARGS)
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
elog(ERROR, "range types do not match");
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
/* if either is empty, the other is the correct answer */
if (empty1)
PG_RETURN_RANGE(r2);
return r2;
if (empty2)
PG_RETURN_RANGE(r1);
return r1;
if (!DatumGetBool(range_overlaps(fcinfo)) &&
!DatumGetBool(range_adjacent(fcinfo)))
if (strict &&
!DatumGetBool(range_overlaps_internal(typcache, r1, r2)) &&
!DatumGetBool(range_adjacent_internal(typcache, r1, r2)))
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("result of range union would not be contiguous")));
@@ -1053,7 +1053,35 @@ range_union(PG_FUNCTION_ARGS)
else
result_upper = &upper2;
PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
return make_range(typcache, result_lower, result_upper, false);
}
Datum
range_union(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_RANGE(range_union_internal(typcache, r1, r2, true));
}
/*
* range merge: like set union, except also allow and account for non-adjacent
* input ranges.
*/
Datum
range_merge(PG_FUNCTION_ARGS)
{
RangeType *r1 = PG_GETARG_RANGE(0);
RangeType *r2 = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache;
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
PG_RETURN_RANGE(range_union_internal(typcache, r1, r2, false));
}
/* set intersection */