8000 Add geometry/range functions to support BRIN inclusion · postgrespro/postgres@3b6db1f · GitHub
[go: up one dir, main page]

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
  • test/regress
  • 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>
    830 8000 98315
    </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);

    0 commit comments

    Comments
     (0)
    0