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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user