Skip to content

Commit 3b6db1f

Browse files
committed
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
1 parent 456ff08 commit 3b6db1f

File tree

18 files changed

+363
-16
lines changed

18 files changed

+363
-16
lines changed

doc/src/sgml/func.sgml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8295,6 +8295,12 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
82958295
<entry>circle to box</entry>
82968296
<entry><literal>box(circle '((0,0),2.0)')</literal></entry>
82978297
</row>
8298+
<row>
8299+
<entry><literal><function>box(<type>point</type>)</function></literal></entry>
8300+
<entry><type>box</type></entry>
8301+
<entry>point to empty box</entry>
8302+
<entry><literal>box(point '(0,0)')</literal></entry>
8303+
</row>
82988304
<row>
82998305
<entry><literal><function>box(<type>point</type>, <type>point</type>)</function></literal></entry>
83008306
<entry><type>box</type></entry>
@@ -8307,6 +8313,12 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
83078313
<entry>polygon to box</entry>
83088314
<entry><literal>box(polygon '((0,0),(1,1),(2,0))')</literal></entry>
83098315
</row>
8316+
<row>
8317+
<entry><literal><function>bound_box(<type>box</type>, <type>box</type>)</function></literal></entry>
8318+
<entry><type>box</type></entry>
8319+
<entry>boxes to bounding box</entry>
8320+
<entry><literal>bound_box(box '((0,0),(1,1))', box '((3,3),(4,4))')</literal></entry>
8321+
</row>
83108322
<row>
83118323
<entry>
83128324
<indexterm>
@@ -8734,6 +8746,30 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
87348746
<entry><literal>text(inet '192.168.1.5')</literal></entry>
87358747
<entry><literal>192.168.1.5/32</literal></entry>
87368748
</row>
8749+
<row>
8750+
<entry>
8751+
<indexterm>
8752+
<primary>inet_same_family</primary>
8753+
</indexterm>
8754+
<literal><function>inet_same_family(<type>inet</type>, <type>inet</type>)</function></literal>
8755+
</entry>
8756+
<entry><type>boolean</type></entry>
8757+
<entry>are the addresses from the same family?</entry>
8758+
<entry><literal>inet_same_family('192.168.1.5/24', '::1')</literal></entry>
8759+
<entry><literal>false</literal></entry>
8760+
</row>
8761+
<row>
8762+
<entry>
8763+
<indexterm>
8764+
<primary>inet_merge</primary>
8765+
</indexterm>
8766+
<literal><function>inet_merge(<type>inet</type>, <type>inet</type>)</function></literal>
8767+
</entry>
8768+
<entry><type>cidr</type></entry>
8769+
<entry>the smallest network which includes both of the given networks</entry>
8770+
<entry><literal>inet_merge('192.168.1.5/24', '192.168.2.5/24')</literal></entry>
8771+
<entry><literal>192.168.0.0/22</literal></entry>
8772+
</row>
87378773
</tbody>
87388774
</tgroup>
87398775
</table>
@@ -12090,6 +12126,17 @@ NULL baz</literallayout>(3 rows)</entry>
1209012126
<entry><literal>upper_inf('(,)'::daterange)</literal></entry>
1209112127
<entry><literal>true</literal></entry>
1209212128
</row>
12129+
<row>
12130+
<entry>
12131+
<literal>
12132+
<function>range_merge</function>(<type>anyrange</type>, <type>anyrange</type>)
12133+
</literal>
12134+
</entry>
12135+
<entry><type>anyrange</type></entry>
12136+
<entry>the smallest range which includes both of the given ranges</entry>
12137+
<entry><literal>range_merge('[1,2)'::int4range, '[3,4)'::int4range)</literal></entry>
12138+
<entry><literal>[1,4)</literal></entry>
12139+
</row>
1209312140
</tbody>
1209412141
</tgroup>
1209512142
</table>

src/backend/utils/adt/geo_ops.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4227,6 +4227,45 @@ box_div(PG_FUNCTION_ARGS)
42274227
PG_RETURN_BOX_P(result);
42284228
}
42294229

4230+
/*
4231+
* Convert point to empty box
4232+
*/
4233+
Datum
4234+
point_box(PG_FUNCTION_ARGS)
4235+
{
4236+
Point *pt = PG_GETARG_POINT_P(0);
4237+
BOX *box;
4238+
4239+
box = (BOX *) palloc(sizeof(BOX));
4240+
4241+
box->high.x = pt->x;
4242+
box->low.x = pt->x;
4243+
box->high.y = pt->y;
4244+
box->low.y = pt->y;
4245+
4246+
PG_RETURN_BOX_P(box);
4247+
}
4248+
4249+
/*
4250+
* Smallest bounding box that includes both of the given boxes
4251+
*/
4252+
Datum
4253+
boxes_bound_box(PG_FUNCTION_ARGS)
4254+
{
4255+
BOX *box1 = PG_GETARG_BOX_P(0),
4256+
*box2 = PG_GETARG_BOX_P(1),
4257+
*container;
4258+
4259+
container = (BOX *) palloc(sizeof(BOX));
4260+
4261+
container->high.x = Max(box1->high.x, box2->high.x);
4262+
container->low.x = Min(box1->low.x, box2->low.x);
4263+
container->high.y = Max(box1->high.y, box2->high.y);
4264+
container->low.y = Min(box1->low.y, box2->low.y);
4265+
4266+
PG_RETURN_BOX_P(container);
4267+
}
4268+
42304269

42314270
/***********************************************************************
42324271
**

src/backend/utils/adt/network.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,58 @@ network_hostmask(PG_FUNCTION_ARGS)
887887
PG_RETURN_INET_P(dst);
888888
}
889889

890+
/*
891+
* Returns true if the addresses are from the same family, or false. Used to
892+
* check that we can create a network which contains both of the networks.
893+
*/
894+
Datum
895+
inet_same_family(PG_FUNCTION_ARGS)
896+
{
897+
inet *a1 = PG_GETARG_INET_PP(0);
898+
inet *a2 = PG_GETARG_INET_PP(1);
899+
900+
PG_RETURN_BOOL(ip_family(a1) == ip_family(a2));
901+
}
902+
903+
/*
904+
* Returns the smallest CIDR which contains both of the inputs.
905+
*/
906+
Datum
907+
inet_merge(PG_FUNCTION_ARGS)
908+
{
909+
inet *a1 = PG_GETARG_INET_PP(0),
910+
*a2 = PG_GETARG_INET_PP(1),
911+
*result;
912+
int commonbits;
913+
914+
if (ip_family(a1) != ip_family(a2))
915+
ereport(ERROR,
916+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
917+
errmsg("cannot merge addresses from different families")));
918+
919+
commonbits = bitncommon(ip_addr(a1), ip_addr(a2),
920+
Min(ip_bits(a1), ip_bits(a2)));
921+
922+
/* Make sure any unused bits are zeroed. */
923+
result = (inet *) palloc0(sizeof(inet));
924+
925+
ip_family(result) = ip_family(a1);
926+
ip_bits(result) = commonbits;
927+
928+
/* Clone appropriate bytes of the address. */
929+
if (commonbits > 0)
930+
memcpy(ip_addr(result), ip_addr(a1), (commonbits + 7) / 8);
931+
932+
/* Clean any unwanted bits in the last partial byte. */
933+
if (commonbits % 8 != 0)
934+
ip_addr(result)[commonbits / 8] &= ~(0xFF >> (commonbits % 8));
935+
936+
/* Set varlena header correctly. */
937+
SET_INET_VARSIZE(result);
938+
939+
PG_RETURN_INET_P(result);
940+
}
941+
890942
/*
891943
* Convert a value of a network datatype to an approximate scalar value.
892944
* This is used for estimating selectivities of inequality operators

src/backend/utils/adt/rangetypes.c

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,13 +1006,14 @@ range_minus(PG_FUNCTION_ARGS)
10061006
PG_RETURN_NULL();
10071007
}
10081008

1009-
/* set union */
1010-
Datum
1011-
range_union(PG_FUNCTION_ARGS)
1009+
/*
1010+
* Set union. If strict is true, it is an error that the two input ranges
1011+
* are not adjacent or overlapping.
1012+
*/
1013+
static RangeType *
1014+
range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2,
1015+
bool strict)
10121016
{
1013-
RangeType *r1 = PG_GETARG_RANGE(0);
1014-
RangeType *r2 = PG_GETARG_RANGE(1);
1015-
TypeCacheEntry *typcache;
10161017
RangeBound lower1,
10171018
lower2;
10181019
RangeBound upper1,
@@ -1026,19 +1027,18 @@ range_union(PG_FUNCTION_ARGS)
10261027
if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
10271028
elog(ERROR, "range types do not match");
10281029

1029-
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
1030-
10311030
range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
10321031
range_deserialize(typcache, r2, &lower2, &upper2, &empty2);
10331032

10341033
/* if either is empty, the other is the correct answer */
10351034
if (empty1)
1036-
PG_RETURN_RANGE(r2);
1035+
return r2;
10371036
if (empty2)
1038-
PG_RETURN_RANGE(r1);
1037+
return r1;
10391038

1040-
if (!DatumGetBool(range_overlaps(fcinfo)) &&
1041-
!DatumGetBool(range_adjacent(fcinfo)))
1039+
if (strict &&
1040+
!DatumGetBool(range_overlaps_internal(typcache, r1, r2)) &&
1041+
!DatumGetBool(range_adjacent_internal(typcache, r1, r2)))
10421042
ereport(ERROR,
10431043
(errcode(ERRCODE_DATA_EXCEPTION),
10441044
errmsg("result of range union would not be contiguous")));
@@ -1053,7 +1053,35 @@ range_union(PG_FUNCTION_ARGS)
10531053
else
10541054
result_upper = &upper2;
10551055

1056-
PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
1056+
return make_range(typcache, result_lower, result_upper, false);
1057+
}
1058+
1059+
Datum
1060+
range_union(PG_FUNCTION_ARGS)
1061+
{
1062+
RangeType *r1 = PG_GETARG_RANGE(0);
1063+
RangeType *r2 = PG_GETARG_RANGE(1);
1064+
TypeCacheEntry *typcache;
1065+
1066+
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
1067+
1068+
PG_RETURN_RANGE(range_union_internal(typcache, r1, r2, true));
1069+
}
1070+
1071+
/*
1072+
* range merge: like set union, except also allow and account for non-adjacent
1073+
* input ranges.
1074+
*/
1075+
Datum
1076+
range_merge(PG_FUNCTION_ARGS)
1077+
{
1078+
RangeType *r1 = PG_GETARG_RANGE(0);
1079+
RangeType *r2 = PG_GETARG_RANGE(1);
1080+
TypeCacheEntry *typcache;
1081+
1082+
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
1083+
1084+
PG_RETURN_RANGE(range_union_internal(typcache, r1, r2, false));
10571085
}
10581086

10591087
/* set intersection */

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201504291
56+
#define CATALOG_VERSION_NO 201505051
5757

5858
#endif

src/include/catalog/pg_cast.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ DATA(insert ( 703 23 0 e b ));
273273
/*
274274
* Geometric category
275275
*/
276+
DATA(insert ( 600 603 4091 a f ));
276277
DATA(insert ( 601 600 1532 e f ));
277278
DATA(insert ( 602 600 1533 e f ));
278279
DATA(insert ( 602 604 1449 a f ));

src/include/catalog/pg_proc.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,8 @@ DATA(insert OID = 978 ( box_distance PGNSP PGUID 12 1 0 0 0 f f f f t f i 2
11401140
DATA(insert OID = 979 ( area PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "602" _null_ _null_ _null_ _null_ _null_ path_area _null_ _null_ _null_ ));
11411141
DESCR("area of a closed path");
11421142
DATA(insert OID = 980 ( box_intersect PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 603 "603 603" _null_ _null_ _null_ _null_ _null_ box_intersect _null_ _null_ _null_ ));
1143+
DATA(insert OID = 4067 ( bound_box PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 603 "603 603" _null_ _null_ _null_ _null_ _null_ boxes_bound_box _null_ _null_ _null_ ));
1144+
DESCR("bounding box of two boxes");
11431145
DATA(insert OID = 981 ( diagonal PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 601 "603" _null_ _null_ _null_ _null_ _null_ box_diagonal _null_ _null_ _null_ ));
11441146
DESCR("box diagonal");
11451147
DATA(insert OID = 982 ( path_n_lt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "602 602" _null_ _null_ _null_ _null_ _null_ path_n_lt _null_ _null_ _null_ ));
@@ -1744,6 +1746,8 @@ DESCR("convert vertex count and circle to polygon");
17441746
DATA(insert OID = 1476 ( dist_pc PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 701 "600 718" _null_ _null_ _null_ _null_ _null_ dist_pc _null_ _null_ _null_ ));
17451747
DATA(insert OID = 1477 ( circle_contain_pt PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "718 600" _null_ _null_ _null_ _null_ _null_ circle_contain_pt _null_ _null_ _null_ ));
17461748
DATA(insert OID = 1478 ( pt_contained_circle PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "600 718" _null_ _null_ _null_ _null_ _null_ pt_contained_circle _null_ _null_ _null_ ));
1749+
DATA(insert OID = 4091 ( box PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 603 "600" _null_ _null_ _null_ _null_ _null_ point_box _null_ _null_ _null_ ));
1750+
DESCR("convert point to empty box");
17471751
DATA(insert OID = 1479 ( circle PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 718 "603" _null_ _null_ _null_ _null_ _null_ box_circle _null_ _null_ _null_ ));
17481752
DESCR("convert box to circle");
17491753
DATA(insert OID = 1480 ( box PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 603 "718" _null_ _null_ _null_ _null_ _null_ circle_box _null_ _null_ _null_ ));
@@ -2232,6 +2236,10 @@ DATA(insert OID = 2630 ( inetpl PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869
22322236
DATA(insert OID = 2631 ( int8pl_inet PGNSP PGUID 14 1 0 0 0 f f f f t f i 2 0 869 "20 869" _null_ _null_ _null_ _null_ _null_ "select $2 + $1" _null_ _null_ _null_ ));
22332237
DATA(insert OID = 2632 ( inetmi_int8 PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869 "869 20" _null_ _null_ _null_ _null_ _null_ inetmi_int8 _null_ _null_ _null_ ));
22342238
DATA(insert OID = 2633 ( inetmi PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 20 "869 869" _null_ _null_ _null_ _null_ _null_ inetmi _null_ _null_ _null_ ));
2239+
DATA(insert OID = 4071 ( inet_same_family PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ _null_ inet_same_family _null_ _null_ _null_ ));
2240+
DESCR("are the addresses from the same family?");
2241+
DATA(insert OID = 4063 ( inet_merge PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 650 "869 869" _null_ _null_ _null_ _null_ _null_ inet_merge _null_ _null_ _null_ ));
2242+
DESCR("the smallest network which includes both of the given networks");
22352243

22362244
/* GiST support for inet and cidr */
22372245
DATA(insert OID = 3553 ( inet_gist_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 5 0 16 "2281 869 23 26 2281" _null_ _null_ _null_ _null_ _null_ inet_gist_consistent _null_ _null_ _null_ ));
@@ -4937,6 +4945,8 @@ DATA(insert OID = 3866 ( range_overright PGNSP PGUID 12 1 0 0 0 f f f f t f i 2
49374945
DESCR("implementation of &> operator");
49384946
DATA(insert OID = 3867 ( range_union PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_union _null_ _null_ _null_ ));
49394947
DESCR("implementation of + operator");
4948+
DATA(insert OID = 4057 ( range_merge PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_merge _null_ _null_ _null_ ));
4949+
DESCR("the smallest range which includes both of the given ranges");
49404950
DATA(insert OID = 3868 ( range_intersect PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_intersect _null_ _null_ _null_ ));
49414951
DESCR("implementation of * operator");
49424952
DATA(insert OID = 3869 ( range_minus PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ _null_ range_minus _null_ _null_ _null_ ));

src/include/utils/builtins.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,8 @@ extern Datum inetpl(PG_FUNCTION_ARGS);
942942
extern Datum inetmi_int8(PG_FUNCTION_ARGS);
943943
extern Datum inetmi(PG_FUNCTION_ARGS);
944944
extern void clean_ipv6_addr(int addr_family, char *addr);
945+
extern Datum inet_same_family(PG_FUNCTION_ARGS);
946+
extern Datum inet_merge(PG_FUNCTION_ARGS);
945947

946948
/* mac.c */
947949
extern Datum macaddr_in(PG_FUNCTION_ARGS);

src/include/utils/geo_decls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ extern Datum box_add(PG_FUNCTION_ARGS);
302302
extern Datum box_sub(PG_FUNCTION_ARGS);
303303
extern Datum box_mul(PG_FUNCTION_ARGS);
304304
extern Datum box_div(PG_FUNCTION_ARGS);
305+
extern Datum point_box(PG_FUNCTION_ARGS);
306+
extern Datum boxes_bound_box(PG_FUNCTION_ARGS);
305307

306308
/* public path routines */
307309
extern Datum path_area(PG_FUNCTION_ARGS);

src/include/utils/rangetypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ extern Datum range_gist_compress(PG_FUNCTION_ARGS);
211211
extern Datum range_gist_decompress(PG_FUNCTION_ARGS);
212212
extern Datum range_gist_fetch(PG_FUNCTION_ARGS);
213213
extern Datum range_gist_union(PG_FUNCTION_ARGS);
214+
extern Datum range_merge(PG_FUNCTION_ARGS);
214215
extern Datum range_gist_penalty(PG_FUNCTION_ARGS);
215216
extern Datum range_gist_picksplit(PG_FUNCTION_ARGS);
216217
extern Datum range_gist_same(PG_FUNCTION_ARGS);

src/test/regress/expected/geometry.out

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,40 @@ SELECT '' AS twenty, b.f1 / p.f1 AS rotation
278278
| (0.3,0),(0.3,0)
279279
(20 rows)
280280

281+
SELECT f1::box
282+
FROM POINT_TBL;
283+
f1
284+
-----------------------
285+
(0,0),(0,0)
286+
(-10,0),(-10,0)
287+
(-3,4),(-3,4)
288+
(5.1,34.5),(5.1,34.5)
289+
(-5,-12),(-5,-12)
290+
(10,10),(10,10)
291+
(6 rows)
292+
293+
SELECT bound_box(a.f1, b.f1)
294+
FROM BOX_TBL a, BOX_TBL b;
295+
bound_box
296+
---------------------
297+
(2,2),(0,0)
298+
(3,3),(0,0)
299+
(2.5,3.5),(0,0)
300+
(3,3),(0,0)
301+
(3,3),(0,0)
302+
(3,3),(1,1)
303+
(3,3.5),(1,1)
304+
(3,3),(1,1)
305+
(2.5,3.5),(0,0)
306+
(3,3.5),(1,1)
307+
(2.5,3.5),(2.5,2.5)
308+
(3,3.5),(2.5,2.5)
309+
(3,3),(0,0)
310+
(3,3),(1,1)
311+
(3,3.5),(2.5,2.5)
312+
(3,3),(3,3)
313+
(16 rows)
314+
281315
--
282316
-- Paths
283317
--

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy