diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 73764f2bedc29d44f9749e0fb1163d5bec48f745..0809a6d2e921a8fccb9418175062a6e5f93c61c7 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -8434,8 +8434,9 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple <xref linkend="cidr-inet-operators-table"> shows the operators available for the <type>cidr</type> and <type>inet</type> types. The operators <literal><<</literal>, - <literal><<=</literal>, <literal>>></literal>, and - <literal>>>=</literal> test for subnet inclusion. They + <literal><<=</literal>, <literal>>></literal>, + <literal>>>=</literal>, and <literal>&&</literal> + test for subnet inclusion. They consider only the network parts of the two addresses (ignoring any host part) and determine whether one network is identical to or a subnet of the other. @@ -8484,12 +8485,12 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple </row> <row> <entry> <literal><<</literal> </entry> - <entry>is contained within</entry> + <entry>is contained by</entry> <entry><literal>inet '192.168.1.5' << inet '192.168.1/24'</literal></entry> </row> <row> <entry> <literal><<=</literal> </entry> - <entry>is contained within or equals</entry> + <entry>is contained by or equals</entry> <entry><literal>inet '192.168.1/24' <<= inet '192.168.1/24'</literal></entry> </row> <row> @@ -8502,6 +8503,11 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple <entry>contains or equals</entry> <entry><literal>inet '192.168.1/24' >>= inet '192.168.1/24'</literal></entry> </row> + <row> + <entry> <literal>&&</literal> </entry> + <entry>contains or is contained by</entry> + <entry><literal>inet '192.168.1/24' && inet '192.168.1.80/28'</literal></entry> + </row> <row> <entry> <literal>~</literal> </entry> <entry>bitwise NOT</entry> diff --git a/doc/src/sgml/gin.sgml b/doc/src/sgml/gin.sgml index 561608f8fa8079657000bfa1c675a684e57b2544..576ad3005aa18754bd8aa5a9e60ff5a1352fb5fe 100644 --- a/doc/src/sgml/gin.sgml +++ b/doc/src/sgml/gin.sgml @@ -62,6 +62,365 @@ </para> </sect1> +<sect1 id="gin-builtin-opclasses"> + <title>Built-in Operator Classes</title> + + <para> + The core <productname>PostgreSQL</> distribution + includes the <acronym>GIN</acronym> operator classes shown in + <xref linkend="gin-builtin-opclasses-table">. + (Some of the optional modules described in <xref linkend="contrib"> + provide additional <acronym>GIN</acronym> operator classes.) + </para> + + <table id="gin-builtin-opclasses-table"> + <title>Built-in <acronym>GIN</acronym> Operator Classes</title> + <tgroup cols="3"> + <thead> + <row> + <entry>Name</entry> + <entry>Indexed Data Type</entry> + <entry>Indexable Operators</entry> + </row> + </thead> + <tbody> + <row> + <entry><literal>_abstime_ops</></entry> + <entry><type>abstime[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_bit_ops</></entry> + <entry><type>bit[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_bool_ops</></entry> + <entry><type>boolean[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_bpchar_ops</></entry> + <entry><type>character[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_bytea_ops</></entry> + <entry><type>bytea[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_char_ops</></entry> + <entry><type>"char"[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_cidr_ops</></entry> + <entry><type>cidr[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_date_ops</></entry> + <entry><type>date[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_float4_ops</></entry> + <entry><type>float4[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_float8_ops</></entry> + <entry><type>float8[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_inet_ops</></entry> + <entry><type>inet[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_int2_ops</></entry> + <entry><type>smallint[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_int4_ops</></entry> + <entry><type>integer[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_int8_ops</></entry> + <entry><type>bigint[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_interval_ops</></entry> + <entry><type>interval[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_macaddr_ops</></entry> + <entry><type>macaddr[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_money_ops</></entry> + <entry><type>money[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_name_ops</></entry> + <entry><type>name[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_numeric_ops</></entry> + <entry><type>numeric[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_oid_ops</></entry> + <entry><type>oid[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_oidvector_ops</></entry> + <entry><type>oidvector[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_reltime_ops</></entry> + <entry><type>reltime[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_text_ops</></entry> + <entry><type>text[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_time_ops</></entry> + <entry><type>time[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_timestamp_ops</></entry> + <entry><type>timestamp[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_timestamptz_ops</></entry> + <entry><type>timestamp with time zone[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_timetz_ops</></entry> + <entry><type>time with time zone[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_tinterval_ops</></entry> + <entry><type>tinterval[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_varbit_ops</></entry> + <entry><type>bit varying[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>_varchar_ops</></entry> + <entry><type>character varying[]</></entry> + <entry> + <literal>&&</> + <literal><@</> + <literal>=</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>jsonb_ops</></entry> + <entry><type>jsonb</></entry> + <entry> + <literal>?</> + <literal>?&</> + <literal>?|</> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>jsonb_hash_ops</></entry> + <entry><type>jsonb</></entry> + <entry> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>tsvector_ops</></entry> + <entry><type>tsvector</></entry> + <entry> + <literal>@@</> + <literal>@@@</> + </entry> + </row> + </tbody> + </tgroup> + </table> + + <para> + Of the two operator classes for type <type>jsonb</>, <literal>jsonb_ops</> + is the default. <literal>jsonb_hash_ops</> supports fewer operators but + will work with larger indexed values than <literal>jsonb_ops</> can support. + </para> + +</sect1> + <sect1 id="gin-extensibility"> <title>Extensibility</title> diff --git a/doc/src/sgml/gist.sgml b/doc/src/sgml/gist.sgml index ed0bc54f52d672c4e69be6e72684bcba2428b45d..0158b1759e84b07354c212c818601c425a1103b5 100644 --- a/doc/src/sgml/gist.sgml +++ b/doc/src/sgml/gist.sgml @@ -40,6 +40,184 @@ </sect1> +<sect1 id="gist-builtin-opclasses"> + <title>Built-in Operator Classes</title> + + <para> + The core <productname>PostgreSQL</> distribution + includes the <acronym>GiST</acronym> operator classes shown in + <xref linkend="gist-builtin-opclasses-table">. + (Some of the optional modules described in <xref linkend="contrib"> + provide additional <acronym>GiST</acronym> operator classes.) + </para> + + <table id="gist-builtin-opclasses-table"> + <title>Built-in <acronym>GiST</acronym> Operator Classes</title> + <tgroup cols="4"> + <thead> + <row> + <entry>Name</entry> + <entry>Indexed Data Type</entry> + <entry>Indexable Operators</entry> + <entry>Ordering Operators</entry> + </row> + </thead> + <tbody> + <row> + <entry><literal>box_ops</></entry> + <entry><type>box</></entry> + <entry> + <literal>&&</> + <literal>&></> + <literal>&<</> + <literal>&<|</> + <literal>>></> + <literal><<</> + <literal><<|</> + <literal><@</> + <literal>@></> + <literal>@</> + <literal>|&></> + <literal>|>></> + <literal>~</> + <literal>~=</> + </entry> + <entry> + </entry> + </row> + <row> + <entry><literal>circle_ops</></entry> + <entry><type>circle</></entry> + <entry> + <literal>&&</> + <literal>&></> + <literal>&<</> + <literal>&<|</> + <literal>>></> + <literal><<</> + <literal><<|</> + <literal><@</> + <literal>@></> + <literal>@</> + <literal>|&></> + <literal>|>></> + <literal>~</> + <literal>~=</> + </entry> + <entry> + </entry> + </row> + <row> + <entry><literal>inet_ops</></entry> + <entry><type>inet</>, <type>cidr</></entry> + <entry> + <literal>&&</> + <literal>>></> + <literal>>>=</> + <literal>></> + <literal>>=</> + <literal><></> + <literal><<</> + <literal><<=</> + <literal><</> + <literal><=</> + <literal>=</> + </entry> + <entry> + </entry> + </row> + <row> + <entry><literal>point_ops</></entry> + <entry><type>point</></entry> + <entry> + <literal>>></> + <literal>>^</> + <literal><<</> + <literal><@</> + <literal><@</> + <literal><@</> + <literal><^</> + <literal>~=</> + </entry> + <entry> + <literal><-></> + </entry> + </row> + <row> + <entry><literal>poly_ops</></entry> + <entry><type>polygon</></entry> + <entry> + <literal>&&</> + <literal>&></> + <literal>&<</> + <literal>&<|</> + <literal>>></> + <literal><<</> + <literal><<|</> + <literal><@</> + <literal>@></> + <literal>@</> + <literal>|&></> + <literal>|>></> + <literal>~</> + <literal>~=</> + </entry> + <entry> + </entry> + </row> + <row> + <entry><literal>range_ops</></entry> + <entry>any range type</entry> + <entry> + <literal>&&</> + <literal>&></> + <literal>&<</> + <literal>>></> + <literal><<</> + <literal><@</> + <literal>-|-</> + <literal>=</> + <literal>@></> + <literal>@></> + </entry> + <entry> + </entry> + </row> + <row> + <entry><literal>tsquery_ops</></entry> + <entry><type>tsquery</></entry> + <entry> + <literal><@</> + <literal>@></> + </entry> + <entry> + </entry> + </row> + <row> + <entry><literal>tsvector_ops</></entry> + <entry><type>tsvector</></entry> + <entry> + <literal>@@</> + </entry> + <entry> + </entry> + </row> + </tbody> + </tgroup> + </table> + + <para> + For historical reasons, the <literal>inet_ops</> operator class is + not the default class for types <type>inet</> and <type>cidr</>. + To use it, mention the class name in <command>CREATE INDEX</>, + for example +<programlisting> +CREATE INDEX ON my_table USING gist (my_inet_column inet_ops); +</programlisting> + </para> + +</sect1> + <sect1 id="gist-extensibility"> <title>Extensibility</title> diff --git a/doc/src/sgml/indices.sgml b/doc/src/sgml/indices.sgml index b1c8f22718576182a51c28e381c8a1665ca6d994..64530a11c86f7cf12f94ed162e9124d0065b04ca 100644 --- a/doc/src/sgml/indices.sgml +++ b/doc/src/sgml/indices.sgml @@ -239,6 +239,8 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable> (See <xref linkend="functions-geometry"> for the meaning of these operators.) + The GiST operator classes included in the standard distribution are + documented in <xref linkend="gist-builtin-opclasses-table">. Many other GiST operator classes are available in the <literal>contrib</> collection or as separate projects. For more information see <xref linkend="GiST">. @@ -253,6 +255,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10; </programlisting> which finds the ten places closest to a given target point. The ability to do this is again dependent on the particular operator class being used. + In <xref linkend="gist-builtin-opclasses-table">, operators that can be + used in this way are listed in the column <quote>Ordering Operators</>. </para> <para> @@ -283,6 +287,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10; (See <xref linkend="functions-geometry"> for the meaning of these operators.) + The SP-GiST operator classes included in the standard distribution are + documented in <xref linkend="spgist-builtin-opclasses-table">. For more information see <xref linkend="SPGiST">. </para> @@ -314,6 +320,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10; (See <xref linkend="functions-array"> for the meaning of these operators.) + The GIN operator classes included in the standard distribution are + documented in <xref linkend="gin-builtin-opclasses-table">. Many other GIN operator classes are available in the <literal>contrib</> collection or as separate projects. For more information see <xref linkend="GIN">. @@ -1003,7 +1011,9 @@ CREATE INDEX test_index ON test_table (col varchar_pattern_ops); <programlisting> SELECT am.amname AS index_method, - opc.opcname AS opclass_name + opc.opcname AS opclass_name, + opc.opcintype::regtype AS indexed_type, + opc.opcdefault AS is_default FROM pg_am am, pg_opclass opc WHERE opc.opcmethod = am.oid ORDER BY index_method, opclass_name; @@ -1020,6 +1030,22 @@ SELECT am.amname AS index_method, associated with any single class within the family. </para> + <para> + This expanded version of the previous query shows the operator family + each operator class belongs to: +<programlisting> +SELECT am.amname AS index_method, + opc.opcname AS opclass_name, + opf.opfname AS opfamily_name, + opc.opcintype::regtype AS indexed_type, + opc.opcdefault AS is_default + FROM pg_am am, pg_opclass opc, pg_opfamily opf + WHERE opc.opcmethod = am.oid AND + opc.opcfamily = opf.oid + ORDER BY index_method, opclass_name; +</programlisting> + </para> + <para> This query shows all defined operator families and all the operators included in each family: diff --git a/doc/src/sgml/spgist.sgml b/doc/src/sgml/spgist.sgml index a043ffb06c464f103f166373ac4efe80cdc92814..56827e520dd62a7a07ac2959e8530143a3fb7dc9 100644 --- a/doc/src/sgml/spgist.sgml +++ b/doc/src/sgml/spgist.sgml @@ -53,6 +53,93 @@ </sect1> +<sect1 id="spgist-builtin-opclasses"> + <title>Built-in Operator Classes</title> + + <para> + The core <productname>PostgreSQL</> distribution + includes the <acronym>SP-GiST</acronym> operator classes shown in + <xref linkend="spgist-builtin-opclasses-table">. + </para> + + <table id="spgist-builtin-opclasses-table"> + <title>Built-in <acronym>SP-GiST</acronym> Operator Classes</title> + <tgroup cols="3"> + <thead> + <row> + <entry>Name</entry> + <entry>Indexed Data Type</entry> + <entry>Indexable Operators</entry> + </row> + </thead> + <tbody> + <row> + <entry><literal>kd_point_ops</></entry> + <entry><type>point</></entry> + <entry> + <literal><<</> + <literal><@</> + <literal><^</> + <literal>>></> + <literal>>^</> + <literal>~=</> + </entry> + </row> + <row> + <entry><literal>quad_point_ops</></entry> + <entry><type>point</></entry> + <entry> + <literal><<</> + <literal><@</> + <literal><^</> + <literal>>></> + <literal>>^</> + <literal>~=</> + </entry> + </row> + <row> + <entry><literal>range_ops</></entry> + <entry>any range type</entry> + <entry> + <literal>&&</> + <literal>&<</> + <literal>&></> + <literal>-|-</> + <literal><<</> + <literal><@</> + <literal>=</> + <literal>>></> + <literal>@></> + </entry> + </row> + <row> + <entry><literal>text_ops</></entry> + <entry><type>text</></entry> + <entry> + <literal><</> + <literal><=</> + <literal>=</> + <literal>></> + <literal>>=</> + <literal>~<=~</> + <literal>~<~</> + <literal>~>=~</> + <literal>~>~</> + </entry> + </row> + </tbody> + </tgroup> + </table> + + <para> + Of the two operator classes for type <type>point</>, + <literal>quad_point_ops</> is the default. <literal>kd_point_ops</> + supports the same operators but uses a different index data structure which + may offer better performance in some applications. + </para> + +</sect1> + <sect1 id="spgist-extensibility"> <title>Extensibility</title> diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 6b23069e26c36ce1303adcc828df9caeb88eb09a..7b4391bba179082c21e9ff526b1f8276687dfce4 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -23,7 +23,8 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \ geo_ops.o geo_selfuncs.o inet_cidr_ntop.o inet_net_pton.o int.o \ int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \ jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \ - network.o numeric.o numutils.o oid.o oracle_compat.o \ + network.o network_gist.o network_selfuncs.o \ + numeric.o numutils.o oid.o oracle_compat.o \ orderedsetaggs.o pg_lzcompress.o pg_locale.o pg_lsn.o \ pgstatfuncs.o pseudotypes.o quote.o rangetypes.o rangetypes_gist.o \ rangetypes_selfuncs.o rangetypes_spgist.o rangetypes_typanalyze.o \ diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 5e837fab2def2ca4272d04f32a805c782fc76635..8bdf5778d89e4fa9f7e1a47084c8c8518a95b881 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -23,58 +23,9 @@ static int32 network_cmp_internal(inet *a1, inet *a2); -static int bitncmp(void *l, void *r, int n); static bool addressOK(unsigned char *a, int bits, int family); -static int ip_addrsize(inet *inetptr); static inet *internal_inetpl(inet *ip, int64 addend); -/* - * Access macros. We use VARDATA_ANY so that we can process short-header - * varlena values without detoasting them. This requires a trick: - * VARDATA_ANY assumes the varlena header is already filled in, which is - * not the case when constructing a new value (until SET_INET_VARSIZE is - * called, which we typically can't do till the end). Therefore, we - * always initialize the newly-allocated value to zeroes (using palloc0). - * A zero length word will look like the not-1-byte case to VARDATA_ANY, - * and so we correctly construct an uncompressed value. - * - * Note that ip_maxbits() and SET_INET_VARSIZE() require - * the family field to be set correctly. - */ - -#define ip_family(inetptr) \ - (((inet_struct *) VARDATA_ANY(inetptr))->family) - -#define ip_bits(inetptr) \ - (((inet_struct *) VARDATA_ANY(inetptr))->bits) - -#define ip_addr(inetptr) \ - (((inet_struct *) VARDATA_ANY(inetptr))->ipaddr) - -#define ip_maxbits(inetptr) \ - (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128) - -#define SET_INET_VARSIZE(dst) \ - SET_VARSIZE(dst, VARHDRSZ + offsetof(inet_struct, ipaddr) + \ - ip_addrsize(dst)) - - -/* - * Return the number of bytes of address storage needed for this data type. - */ -static int -ip_addrsize(inet *inetptr) -{ - switch (ip_family(inetptr)) - { - case PGSQL_AF_INET: - return 4; - case PGSQL_AF_INET6: - return 16; - default: - return 0; - } -} /* * Common INET/CIDR input routine @@ -596,6 +547,21 @@ network_supeq(PG_FUNCTION_ARGS) PG_RETURN_BOOL(false); } +Datum +network_overlap(PG_FUNCTION_ARGS) +{ + inet *a1 = PG_GETARG_INET_PP(0); + inet *a2 = PG_GETARG_INET_PP(1); + + if (ip_family(a1) == ip_family(a2)) + { + PG_RETURN_BOOL(bitncmp(ip_addr(a1), ip_addr(a2), + Min(ip_bits(a1), ip_bits(a2))) == 0); + } + + PG_RETURN_BOOL(false); +} + /* * Extract data from a network datatype. */ @@ -962,10 +928,10 @@ convert_network_to_scalar(Datum value, Oid typid) * author: * Paul Vixie (ISC), June 1996 */ -static int -bitncmp(void *l, void *r, int n) +int +bitncmp(const unsigned char *l, const unsigned char *r, int n) { - u_int lb, + unsigned int lb, rb; int x, b; @@ -975,8 +941,8 @@ bitncmp(void *l, void *r, int n) if (x || (n % 8) == 0) return x; - lb = ((const u_char *) l)[b]; - rb = ((const u_char *) r)[b]; + lb = l[b]; + rb = r[b]; for (b = n % 8; b > 0; b--) { if (IS_HIGHBIT_SET(lb) != IS_HIGHBIT_SET(rb)) @@ -991,6 +957,49 @@ bitncmp(void *l, void *r, int n) return 0; } +/* + * bitncommon: compare bit masks l and r, for up to n bits. + * + * Returns the number of leading bits that match (0 to n). + */ +int +bitncommon(const unsigned char *l, const unsigned char *r, int n) +{ + int byte, + nbits; + + /* number of bits to examine in last byte */ + nbits = n % 8; + + /* check whole bytes */ + for (byte = 0; byte < n / 8; byte++) + { + if (l[byte] != r[byte]) + { + /* at least one bit in the last byte is not common */ + nbits = 7; + break; + } + } + + /* check bits in last partial byte */ + if (nbits != 0) + { + /* calculate diff of first non-matching bytes */ + unsigned int diff = l[byte] ^ r[byte]; + + /* compare the bits from the most to the least */ + while ((diff >> (8 - nbits)) != 0) + nbits--; + } + + return (8 * byte) + nbits; +} + + +/* + * Verify a CIDR address is OK (doesn't have bits set past the masklen) + */ static bool addressOK(unsigned char *a, int bits, int family) { diff --git a/src/backend/utils/adt/network_gist.c b/src/backend/utils/adt/network_gist.c new file mode 100644 index 0000000000000000000000000000000000000000..0a826ae90a2e5304a811d3ad0507d7f62f96617b --- /dev/null +++ b/src/backend/utils/adt/network_gist.c @@ -0,0 +1,789 @@ +/*------------------------------------------------------------------------- + * + * network_gist.c + * GiST support for network types. + * + * The key thing to understand about this code is the definition of the + * "union" of a set of INET/CIDR values. It works like this: + * 1. If the values are not all of the same IP address family, the "union" + * is a dummy value with family number zero, minbits zero, commonbits zero, + * address all zeroes. Otherwise: + * 2. The union has the common IP address family number. + * 3. The union's minbits value is the smallest netmask length ("ip_bits") + * of all the input values. + * 4. Let C be the number of leading address bits that are in common among + * all the input values (C ranges from 0 to ip_maxbits for the family). + * 5. The union's commonbits value is C. + * 6. The union's address value is the same as the common prefix for its + * first C bits, and is zeroes to the right of that. The physical width + * of the address value is ip_maxbits for the address family. + * + * In a leaf index entry (representing a single key), commonbits is equal to + * ip_maxbits for the address family, minbits is the same as the represented + * value's ip_bits, and the address is equal to the represented address. + * Although it may appear that we're wasting a byte by storing the union + * format and not just the represented INET/CIDR value in leaf keys, the + * extra byte is actually "free" because of alignment considerations. + * + * Note that this design tracks minbits and commonbits independently; in any + * given union value, either might be smaller than the other. This does not + * help us much when descending the tree, because of the way inet comparison + * is defined: at non-leaf nodes we can't compare more than minbits bits + * even if we know them. However, it greatly improves the quality of split + * decisions. Preliminary testing suggests that searches are as much as + * twice as fast as for a simpler design in which a single field doubles as + * the common prefix length and the minimum ip_bits value. + * + * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/network_gist.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <sys/socket.h> + +#include "access/gist.h" +#include "access/skey.h" +#include "utils/inet.h" + +/* + * Operator strategy numbers used in the GiST inet_ops opclass + */ +#define INETSTRAT_OVERLAPS 3 +#define INETSTRAT_EQ 18 +#define INETSTRAT_NE 19 +#define INETSTRAT_LT 20 +#define INETSTRAT_LE 21 +#define INETSTRAT_GT 22 +#define INETSTRAT_GE 23 +#define INETSTRAT_SUB 24 +#define INETSTRAT_SUBEQ 25 +#define INETSTRAT_SUP 26 +#define INETSTRAT_SUPEQ 27 + + +/* + * Representation of a GiST INET/CIDR index key. This is not identical to + * INET/CIDR because we need to keep track of the length of the common address + * prefix as well as the minimum netmask length. However, as long as it + * follows varlena header rules, the core GiST code won't know the difference. + * For simplicity we always use 1-byte-header varlena format. + */ +typedef struct GistInetKey +{ + uint8 va_header; /* varlena header --- don't touch directly */ + unsigned char family; /* PGSQL_AF_INET, PGSQL_AF_INET6, or zero */ + unsigned char minbits; /* minimum number of bits in netmask */ + unsigned char commonbits; /* number of common prefix bits in addresses */ + unsigned char ipaddr[16]; /* up to 128 bits of common address */ +} GistInetKey; + +#define DatumGetInetKeyP(X) ((GistInetKey *) DatumGetPointer(X)) +#define InetKeyPGetDatum(X) PointerGetDatum(X) + +/* + * Access macros; not really exciting, but we use these for notational + * consistency with access to INET/CIDR values. Note that family-zero values + * are stored with 4 bytes of address, not 16. + */ +#define gk_ip_family(gkptr) ((gkptr)->family) +#define gk_ip_minbits(gkptr) ((gkptr)->minbits) +#define gk_ip_commonbits(gkptr) ((gkptr)->commonbits) +#define gk_ip_addr(gkptr) ((gkptr)->ipaddr) +#define ip_family_maxbits(fam) ((fam) == PGSQL_AF_INET6 ? 128 : 32) + +/* These require that the family field has been set: */ +#define gk_ip_addrsize(gkptr) \ + (gk_ip_family(gkptr) == PGSQL_AF_INET6 ? 16 : 4) +#define gk_ip_maxbits(gkptr) \ + ip_family_maxbits(gk_ip_family(gkptr)) +#define SET_GK_VARSIZE(dst) \ + SET_VARSIZE_SHORT(dst, offsetof(GistInetKey, ipaddr) + gk_ip_addrsize(dst)) + + +/* + * The GiST query consistency check + */ +Datum +inet_gist_consistent(PG_FUNCTION_ARGS) +{ + GISTENTRY *ent = (GISTENTRY *) PG_GETARG_POINTER(0); + inet *query = PG_GETARG_INET_PP(1); + StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); + + /* Oid subtype = PG_GETARG_OID(3); */ + bool *recheck = (bool *) PG_GETARG_POINTER(4); + GistInetKey *key = DatumGetInetKeyP(ent->key); + int minbits, + order; + + /* All operators served by this function are exact. */ + *recheck = false; + + /* + * Check 0: different families + * + * If key represents multiple address families, its children could match + * anything. This can only happen on an inner index page. + */ + if (gk_ip_family(key) == 0) + { + Assert(!GIST_LEAF(ent)); + PG_RETURN_BOOL(true); + } + + /* + * Check 1: different families + * + * Matching families do not help any of the strategies. + */ + if (gk_ip_family(key) != ip_family(query)) + { + switch (strategy) + { + case INETSTRAT_LT: + case INETSTRAT_LE: + if (gk_ip_family(key) < ip_family(query)) + PG_RETURN_BOOL(true); + break; + + case INETSTRAT_GE: + case INETSTRAT_GT: + if (gk_ip_family(key) > ip_family(query)) + PG_RETURN_BOOL(true); + break; + + case INETSTRAT_NE: + PG_RETURN_BOOL(true); + } + /* For all other cases, we can be sure there is no match */ + PG_RETURN_BOOL(false); + } + + /* + * Check 2: network bit count + * + * Network bit count (ip_bits) helps to check leaves for sub network and + * sup network operators. At non-leaf nodes, we know every child value + * has ip_bits >= gk_ip_minbits(key), so we can avoid descending in some + * cases too. + */ + switch (strategy) + { + case INETSTRAT_SUB: + if (GIST_LEAF(ent) && gk_ip_minbits(key) <= ip_bits(query)) + PG_RETURN_BOOL(false); + break; + + case INETSTRAT_SUBEQ: + if (GIST_LEAF(ent) && gk_ip_minbits(key) < ip_bits(query)) + PG_RETURN_BOOL(false); + break; + + case INETSTRAT_SUPEQ: + case INETSTRAT_EQ: + if (gk_ip_minbits(key) > ip_bits(query)) + PG_RETURN_BOOL(false); + break; + + case INETSTRAT_SUP: + if (gk_ip_minbits(key) >= ip_bits(query)) + PG_RETURN_BOOL(false); + break; + } + + /* + * Check 3: common network bits + * + * Compare available common prefix bits to the query, but not beyond + * either the query's netmask or the minimum netmask among the represented + * values. If these bits don't match the query, we have our answer (and + * may or may not need to descend, depending on the operator). If they do + * match, and we are not at a leaf, we descend in all cases. + * + * Note this is the final check for operators that only consider the + * network part of the address. + */ + minbits = Min(gk_ip_commonbits(key), gk_ip_minbits(key)); + minbits = Min(minbits, ip_bits(query)); + + order = bitncmp(gk_ip_addr(key), ip_addr(query), minbits); + + switch (strategy) + { + case INETSTRAT_SUB: + case INETSTRAT_SUBEQ: + case INETSTRAT_OVERLAPS: + case INETSTRAT_SUPEQ: + case INETSTRAT_SUP: + PG_RETURN_BOOL(order == 0); + + case INETSTRAT_LT: + case INETSTRAT_LE: + if (order > 0) + PG_RETURN_BOOL(false); + if (order < 0 || !GIST_LEAF(ent)) + PG_RETURN_BOOL(true); + break; + + case INETSTRAT_EQ: + if (order != 0) + PG_RETURN_BOOL(false); + if (!GIST_LEAF(ent)) + PG_RETURN_BOOL(true); + break; + + case INETSTRAT_GE: + case INETSTRAT_GT: + if (order < 0) + PG_RETURN_BOOL(false); + if (order > 0 || !GIST_LEAF(ent)) + PG_RETURN_BOOL(true); + break; + + case INETSTRAT_NE: + if (order != 0 || !GIST_LEAF(ent)) + PG_RETURN_BOOL(true); + break; + } + + /* + * Remaining checks are only for leaves and basic comparison strategies. + * See network_cmp_internal() in network.c for the implementation we need + * to match. Note that in a leaf key, commonbits should equal the address + * length, so we compared the whole network parts above. + */ + Assert(GIST_LEAF(ent)); + + /* + * Check 4: network bit count + * + * Next step is to compare netmask widths. + */ + switch (strategy) + { + case INETSTRAT_LT: + case INETSTRAT_LE: + if (gk_ip_minbits(key) < ip_bits(query)) + PG_RETURN_BOOL(true); + if (gk_ip_minbits(key) > ip_bits(query)) + PG_RETURN_BOOL(false); + break; + + case INETSTRAT_EQ: + if (gk_ip_minbits(key) != ip_bits(query)) + PG_RETURN_BOOL(false); + break; + + case INETSTRAT_GE: + case INETSTRAT_GT: + if (gk_ip_minbits(key) > ip_bits(query)) + PG_RETURN_BOOL(true); + if (gk_ip_minbits(key) < ip_bits(query)) + PG_RETURN_BOOL(false); + break; + + case INETSTRAT_NE: + if (gk_ip_minbits(key) != ip_bits(query)) + PG_RETURN_BOOL(true); + break; + } + + /* + * Check 5: whole address + * + * Netmask bit counts are the same, so check all the address bits. + */ + order = bitncmp(gk_ip_addr(key), ip_addr(query), gk_ip_maxbits(key)); + + switch (strategy) + { + case INETSTRAT_LT: + PG_RETURN_BOOL(order < 0); + + case INETSTRAT_LE: + PG_RETURN_BOOL(order <= 0); + + case INETSTRAT_EQ: + PG_RETURN_BOOL(order == 0); + + case INETSTRAT_GE: + PG_RETURN_BOOL(order >= 0); + + case INETSTRAT_GT: + PG_RETURN_BOOL(order > 0); + + case INETSTRAT_NE: + PG_RETURN_BOOL(order != 0); + } + + elog(ERROR, "unknown strategy for inet GiST"); + PG_RETURN_BOOL(false); /* keep compiler quiet */ +} + +/* + * Calculate parameters of the union of some GistInetKeys. + * + * Examine the keys in elements m..n inclusive of the GISTENTRY array, + * and compute these output parameters: + * *minfamily_p = minimum IP address family number + * *maxfamily_p = maximum IP address family number + * *minbits_p = minimum netmask width + * *commonbits_p = number of leading bits in common among the addresses + * + * minbits and commonbits are forced to zero if there's more than one + * address family. + */ +static void +calc_inet_union_params(GISTENTRY *ent, + int m, int n, + int *minfamily_p, + int *maxfamily_p, + int *minbits_p, + int *commonbits_p) +{ + int minfamily, + maxfamily, + minbits, + commonbits; + unsigned char *addr; + GistInetKey *tmp; + int i; + + /* Must be at least one key. */ + Assert(m <= n); + + /* Initialize variables using the first key. */ + tmp = DatumGetInetKeyP(ent[m].key); + minfamily = maxfamily = gk_ip_family(tmp); + minbits = gk_ip_minbits(tmp); + commonbits = gk_ip_commonbits(tmp); + addr = gk_ip_addr(tmp); + + /* Scan remaining keys. */ + for (i = m + 1; i <= n; i++) + { + tmp = DatumGetInetKeyP(ent[i].key); + + /* Determine range of family numbers */ + if (minfamily > gk_ip_family(tmp)) + minfamily = gk_ip_family(tmp); + if (maxfamily < gk_ip_family(tmp)) + maxfamily = gk_ip_family(tmp); + + /* Find minimum minbits */ + if (minbits > gk_ip_minbits(tmp)) + minbits = gk_ip_minbits(tmp); + + /* Find minimum number of bits in common */ + if (commonbits > gk_ip_commonbits(tmp)) + commonbits = gk_ip_commonbits(tmp); + if (commonbits > 0) + commonbits = bitncommon(addr, gk_ip_addr(tmp), commonbits); + } + + /* Force minbits/commonbits to zero if more than one family. */ + if (minfamily != maxfamily) + minbits = commonbits = 0; + + *minfamily_p = minfamily; + *maxfamily_p = maxfamily; + *minbits_p = minbits; + *commonbits_p = commonbits; +} + +/* + * Same as above, but the GISTENTRY elements to examine are those with + * indices listed in the offsets[] array. + */ +static void +calc_inet_union_params_indexed(GISTENTRY *ent, + OffsetNumber *offsets, int noffsets, + int *minfamily_p, + int *maxfamily_p, + int *minbits_p, + int *commonbits_p) +{ + int minfamily, + maxfamily, + minbits, + commonbits; + unsigned char *addr; + GistInetKey *tmp; + int i; + + /* Must be at least one key. */ + Assert(noffsets > 0); + + /* Initialize variables using the first key. */ + tmp = DatumGetInetKeyP(ent[offsets[0]].key); + minfamily = maxfamily = gk_ip_family(tmp); + minbits = gk_ip_minbits(tmp); + commonbits = gk_ip_commonbits(tmp); + addr = gk_ip_addr(tmp); + + /* Scan remaining keys. */ + for (i = 1; i < noffsets; i++) + { + tmp = DatumGetInetKeyP(ent[offsets[i]].key); + + /* Determine range of family numbers */ + if (minfamily > gk_ip_family(tmp)) + minfamily = gk_ip_family(tmp); + if (maxfamily < gk_ip_family(tmp)) + maxfamily = gk_ip_family(tmp); + + /* Find minimum minbits */ + if (minbits > gk_ip_minbits(tmp)) + minbits = gk_ip_minbits(tmp); + + /* Find minimum number of bits in common */ + if (commonbits > gk_ip_commonbits(tmp)) + commonbits = gk_ip_commonbits(tmp); + if (commonbits > 0) + commonbits = bitncommon(addr, gk_ip_addr(tmp), commonbits); + } + + /* Force minbits/commonbits to zero if more than one family. */ + if (minfamily != maxfamily) + minbits = commonbits = 0; + + *minfamily_p = minfamily; + *maxfamily_p = maxfamily; + *minbits_p = minbits; + *commonbits_p = commonbits; +} + +/* + * Construct a GistInetKey representing a union value. + * + * Inputs are the family/minbits/commonbits values to use, plus a pointer to + * the address field of one of the union inputs. (Since we're going to copy + * just the bits-in-common, it doesn't matter which one.) + */ +static GistInetKey * +build_inet_union_key(int family, int minbits, int commonbits, + unsigned char *addr) +{ + GistInetKey *result; + + /* Make sure any unused bits are zeroed. */ + result = (GistInetKey *) palloc0(sizeof(GistInetKey)); + + gk_ip_family(result) = family; + gk_ip_minbits(result) = minbits; + gk_ip_commonbits(result) = commonbits; + + /* Clone appropriate bytes of the address. */ + if (commonbits > 0) + memcpy(gk_ip_addr(result), addr, (commonbits + 7) / 8); + + /* Clean any unwanted bits in the last partial byte. */ + if (commonbits % 8 != 0) + gk_ip_addr(result)[commonbits / 8] &= ~(0xFF >> (commonbits % 8)); + + /* Set varlena header correctly. */ + SET_GK_VARSIZE(result); + + return result; +} + + +/* + * The GiST union function + * + * See comments at head of file for the definition of the union. + */ +Datum +inet_gist_union(PG_FUNCTION_ARGS) +{ + GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); + GISTENTRY *ent = entryvec->vector; + int minfamily, + maxfamily, + minbits, + commonbits; + unsigned char *addr; + GistInetKey *tmp, + *result; + + /* Determine parameters of the union. */ + calc_inet_union_params(ent, 0, entryvec->n - 1, + &minfamily, &maxfamily, + &minbits, &commonbits); + + /* If more than one family, emit family number zero. */ + if (minfamily != maxfamily) + minfamily = 0; + + /* Initialize address using the first key. */ + tmp = DatumGetInetKeyP(ent[0].key); + addr = gk_ip_addr(tmp); + + /* Construct the union value. */ + result = build_inet_union_key(minfamily, minbits, commonbits, addr); + + PG_RETURN_POINTER(result); +} + +/* + * The GiST compress function + * + * Convert an inet value to GistInetKey. + */ +Datum +inet_gist_compress(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + GISTENTRY *retval; + + if (entry->leafkey) + { + retval = palloc(sizeof(GISTENTRY)); + if (DatumGetPointer(entry->key) != NULL) + { + inet *in = DatumGetInetPP(entry->key); + GistInetKey *r; + + r = (GistInetKey *) palloc0(sizeof(GistInetKey)); + + gk_ip_family(r) = ip_family(in); + gk_ip_minbits(r) = ip_bits(in); + gk_ip_commonbits(r) = gk_ip_maxbits(r); + memcpy(gk_ip_addr(r), ip_addr(in), gk_ip_addrsize(r)); + SET_GK_VARSIZE(r); + + gistentryinit(*retval, PointerGetDatum(r), + entry->rel, entry->page, + entry->offset, FALSE); + } + else + { + gistentryinit(*retval, (Datum) 0, + entry->rel, entry->page, + entry->offset, FALSE); + } + } + else + retval = entry; + PG_RETURN_POINTER(retval); +} + +/* + * The GiST decompress function + * + * do not do anything --- we just use the stored GistInetKey as-is. + */ +Datum +inet_gist_decompress(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + + PG_RETURN_POINTER(entry); +} + +/* + * The GiST page split penalty function + * + * Charge a large penalty if address family doesn't match, or a somewhat + * smaller one if the new value would degrade the union's minbits + * (minimum netmask width). Otherwise, penalty is inverse of the + * new number of common address bits. + */ +Datum +inet_gist_penalty(PG_FUNCTION_ARGS) +{ + GISTENTRY *origent = (GISTENTRY *) PG_GETARG_POINTER(0); + GISTENTRY *newent = (GISTENTRY *) PG_GETARG_POINTER(1); + float *penalty = (float *) PG_GETARG_POINTER(2); + GistInetKey *orig = DatumGetInetKeyP(origent->key), + *new = DatumGetInetKeyP(newent->key); + int commonbits; + + if (gk_ip_family(orig) == gk_ip_family(new)) + { + if (gk_ip_minbits(orig) <= gk_ip_minbits(new)) + { + commonbits = bitncommon(gk_ip_addr(orig), gk_ip_addr(new), + Min(gk_ip_commonbits(orig), + gk_ip_commonbits(new))); + if (commonbits > 0) + *penalty = 1.0f / commonbits; + else + *penalty = 2; + } + else + *penalty = 3; + } + else + *penalty = 4; + + PG_RETURN_POINTER(penalty); +} + +/* + * The GiST PickSplit method + * + * There are two ways to split. First one is to split by address families, + * if there are multiple families appearing in the input. + * + * The second and more common way is to split by addresses. To achieve this, + * determine the number of leading bits shared by all the keys, then split on + * the next bit. (We don't currently consider the netmask widths while doing + * this; should we?) If we fail to get a nontrivial split that way, split + * 50-50. + */ +Datum +inet_gist_picksplit(PG_FUNCTION_ARGS) +{ + GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); + GIST_SPLITVEC *splitvec = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); + GISTENTRY *ent = entryvec->vector; + int minfamily, + maxfamily, + minbits, + commonbits; + unsigned char *addr; + GistInetKey *tmp, + *left_union, + *right_union; + int maxoff, + nbytes; + OffsetNumber i, + *left, + *right; + + maxoff = entryvec->n - 1; + nbytes = (maxoff + 1) * sizeof(OffsetNumber); + + left = (OffsetNumber *) palloc(nbytes); + right = (OffsetNumber *) palloc(nbytes); + + splitvec->spl_left = left; + splitvec->spl_right = right; + + splitvec->spl_nleft = 0; + splitvec->spl_nright = 0; + + /* Determine parameters of the union of all the inputs. */ + calc_inet_union_params(ent, FirstOffsetNumber, maxoff, + &minfamily, &maxfamily, + &minbits, &commonbits); + + if (minfamily != maxfamily) + { + /* Multiple families, so split by family. */ + for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) + { + /* + * If there's more than 2 families, all but maxfamily go into the + * left union. This could only happen if the inputs include some + * IPv4, some IPv6, and some already-multiple-family unions. + */ + tmp = DatumGetInetKeyP(ent[i].key); + if (gk_ip_family(tmp) != maxfamily) + left[splitvec->spl_nleft++] = i; + else + right[splitvec->spl_nright++] = i; + } + } + else + { + /* + * Split on the next bit after the common bits. If that yields a + * trivial split, try the next bit position to the right. Repeat till + * success; or if we run out of bits, do an arbitrary 50-50 split. + */ + int maxbits = ip_family_maxbits(minfamily); + + while (commonbits < maxbits) + { + /* Split using the commonbits'th bit position. */ + int bitbyte = commonbits / 8; + int bitmask = 0x80 >> (commonbits % 8); + + splitvec->spl_nleft = splitvec->spl_nright = 0; + + for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) + { + tmp = DatumGetInetKeyP(ent[i].key); + addr = gk_ip_addr(tmp); + if ((addr[bitbyte] & bitmask) == 0) + left[splitvec->spl_nleft++] = i; + else + right[splitvec->spl_nright++] = i; + } + + if (splitvec->spl_nleft > 0 && splitvec->spl_nright > 0) + break; /* success */ + commonbits++; + } + + if (commonbits >= maxbits) + { + /* Failed ... do a 50-50 split. */ + splitvec->spl_nleft = splitvec->spl_nright = 0; + + for (i = FirstOffsetNumber; i <= maxoff / 2; i = OffsetNumberNext(i)) + { + left[splitvec->spl_nleft++] = i; + } + for (; i <= maxoff; i = OffsetNumberNext(i)) + { + right[splitvec->spl_nright++] = i; + } + } + } + + /* + * Compute the union value for each side from scratch. In most cases we + * could approximate the union values with what we already know, but this + * ensures that each side has minbits and commonbits set as high as + * possible. + */ + calc_inet_union_params_indexed(ent, left, splitvec->spl_nleft, + &minfamily, &maxfamily, + &minbits, &commonbits); + if (minfamily != maxfamily) + minfamily = 0; + tmp = DatumGetInetKeyP(ent[left[0]].key); + addr = gk_ip_addr(tmp); + left_union = build_inet_union_key(minfamily, minbits, commonbits, addr); + splitvec->spl_ldatum = PointerGetDatum(left_union); + + calc_inet_union_params_indexed(ent, right, splitvec->spl_nright, + &minfamily, &maxfamily, + &minbits, &commonbits); + if (minfamily != maxfamily) + minfamily = 0; + tmp = DatumGetInetKeyP(ent[right[0]].key); + addr = gk_ip_addr(tmp); + right_union = build_inet_union_key(minfamily, minbits, commonbits, addr); + splitvec->spl_rdatum = PointerGetDatum(right_union); + + PG_RETURN_POINTER(splitvec); +} + +/* + * The GiST equality function + */ +Datum +inet_gist_same(PG_FUNCTION_ARGS) +{ + GistInetKey *left = DatumGetInetKeyP(PG_GETARG_DATUM(0)); + GistInetKey *right = DatumGetInetKeyP(PG_GETARG_DATUM(1)); + bool *result = (bool *) PG_GETARG_POINTER(2); + + *result = (gk_ip_family(left) == gk_ip_family(right) && + gk_ip_minbits(left) == gk_ip_minbits(right) && + gk_ip_commonbits(left) == gk_ip_commonbits(right) && + memcmp(gk_ip_addr(left), gk_ip_addr(right), + gk_ip_addrsize(left)) == 0); + + PG_RETURN_POINTER(result); +} diff --git a/src/backend/utils/adt/network_selfuncs.c b/src/backend/utils/adt/network_selfuncs.c new file mode 100644 index 0000000000000000000000000000000000000000..d0d806f889dbc8dbf516c3305f43f7bff77d7fc8 --- /dev/null +++ b/src/backend/utils/adt/network_selfuncs.c @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * network_selfuncs.c + * Functions for selectivity estimation of inet/cidr operators + * + * Currently these are just stubs, but we hope to do better soon. + * + * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/network_selfuncs.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "utils/inet.h" + + +Datum +networksel(PG_FUNCTION_ARGS) +{ + PG_RETURN_FLOAT8(0.001); +} + +Datum +networkjoinsel(PG_FUNCTION_ARGS) +{ + PG_RETURN_FLOAT8(0.001); +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 4b3357ccd9710ba7f42a9e9afddcaac895fd6ca6..fe6144e2d344daaaa630e94a24b83ee1214d4e14 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201404081 +#define CATALOG_VERSION_NO 201404082 #endif diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index 262311355702a35b26fda0696acf5bec093ea085..8efd3be3c668a196c60b6a1a18dc69e568267eb4 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -818,4 +818,19 @@ DATA(insert ( 3474 3831 3831 8 s 3892 4000 0 )); DATA(insert ( 3474 3831 2283 16 s 3889 4000 0 )); DATA(insert ( 3474 3831 3831 18 s 3882 4000 0 )); +/* + * GiST inet_ops + */ +DATA(insert ( 3550 869 869 3 s 3552 783 0 )); +DATA(insert ( 3550 869 869 18 s 1201 783 0 )); +DATA(insert ( 3550 869 869 19 s 1202 783 0 )); +DATA(insert ( 3550 869 869 20 s 1203 783 0 )); +DATA(insert ( 3550 869 869 21 s 1204 783 0 )); +DATA(insert ( 3550 869 869 22 s 1205 783 0 )); +DATA(insert ( 3550 869 869 23 s 1206 783 0 )); +DATA(insert ( 3550 869 869 24 s 931 783 0 )); +DATA(insert ( 3550 869 869 25 s 932 783 0 )); +DATA(insert ( 3550 869 869 26 s 933 783 0 )); +DATA(insert ( 3550 869 869 27 s 934 783 0 )); + #endif /* PG_AMOP_H */ diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h index b28dd563a8c9f0de05a309621f41adb583551c42..198b126964f8f0d33912e3bd2bfa34d31d4da6e1 100644 --- a/src/include/catalog/pg_amproc.h +++ b/src/include/catalog/pg_amproc.h @@ -399,6 +399,13 @@ DATA(insert ( 4037 3802 3802 2 3485 )); DATA(insert ( 4037 3802 3802 3 3486 )); DATA(insert ( 4037 3802 3802 4 3487 )); DATA(insert ( 4037 3802 3802 6 3489 )); +DATA(insert ( 3550 869 869 1 3553 )); +DATA(insert ( 3550 869 869 2 3554 )); +DATA(insert ( 3550 869 869 3 3555 )); +DATA(insert ( 3550 869 869 4 3556 )); +DATA(insert ( 3550 869 869 5 3557 )); +DATA(insert ( 3550 869 869 6 3558 )); +DATA(insert ( 3550 869 869 7 3559 )); /* sp-gist */ DATA(insert ( 3474 3831 3831 1 3469 )); diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index 63a40a8412cce81c4d609eaec62169010ae7b201..49b24108de972073e2de3088aa2e4631c28a4c48 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -112,6 +112,7 @@ DATA(insert OID = 3123 ( 403 float8_ops PGNSP PGUID 1970 701 t 0 )); DATA(insert ( 405 float8_ops PGNSP PGUID 1971 701 t 0 )); DATA(insert ( 403 inet_ops PGNSP PGUID 1974 869 t 0 )); DATA(insert ( 405 inet_ops PGNSP PGUID 1975 869 t 0 )); +DATA(insert ( 783 inet_ops PGNSP PGUID 3550 869 f 0 )); DATA(insert OID = 1979 ( 403 int2_ops PGNSP PGUID 1976 21 t 0 )); #define INT2_BTREE_OPS_OID 1979 DATA(insert ( 405 int2_ops PGNSP PGUID 1977 21 t 0 )); diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index ac09034f3d0e5eb1d522f2e84654d479dbfb9003..f280af441c27723dd177b446d0469eb51e4955e8 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -1140,18 +1140,20 @@ DATA(insert OID = 1205 ( ">" PGNSP PGUID b f f 869 869 16 1203 1204 network DESCR("greater than"); DATA(insert OID = 1206 ( ">=" PGNSP PGUID b f f 869 869 16 1204 1203 network_ge scalargtsel scalargtjoinsel )); DESCR("greater than or equal"); -DATA(insert OID = 931 ( "<<" PGNSP PGUID b f f 869 869 16 933 0 network_sub - - )); +DATA(insert OID = 931 ( "<<" PGNSP PGUID b f f 869 869 16 933 0 network_sub networksel networkjoinsel )); DESCR("is subnet"); #define OID_INET_SUB_OP 931 -DATA(insert OID = 932 ( "<<=" PGNSP PGUID b f f 869 869 16 934 0 network_subeq - - )); +DATA(insert OID = 932 ( "<<=" PGNSP PGUID b f f 869 869 16 934 0 network_subeq networksel networkjoinsel )); DESCR("is subnet or equal"); #define OID_INET_SUBEQ_OP 932 -DATA(insert OID = 933 ( ">>" PGNSP PGUID b f f 869 869 16 931 0 network_sup - - )); +DATA(insert OID = 933 ( ">>" PGNSP PGUID b f f 869 869 16 931 0 network_sup networksel networkjoinsel )); DESCR("is supernet"); #define OID_INET_SUP_OP 933 -DATA(insert OID = 934 ( ">>=" PGNSP PGUID b f f 869 869 16 932 0 network_supeq - - )); +DATA(insert OID = 934 ( ">>=" PGNSP PGUID b f f 869 869 16 932 0 network_supeq networksel networkjoinsel )); DESCR("is supernet or equal"); #define OID_INET_SUPEQ_OP 934 +DATA(insert OID = 3552 ( "&&" PGNSP PGUID b f f 869 869 16 3552 0 network_overlap networksel networkjoinsel )); +DESCR("overlaps (is subnet or supernet)"); DATA(insert OID = 2634 ( "~" PGNSP PGUID l f f 0 869 869 0 0 inetnot - - )); DESCR("bitwise not"); diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h index 775be86c1af34db287f81d9cf0a94df41fa56c8a..9e8f4ac5b6310edf3ad3e2652bfa0b3556842481 100644 --- a/src/include/catalog/pg_opfamily.h +++ b/src/include/catalog/pg_opfamily.h @@ -78,6 +78,7 @@ DATA(insert OID = 1971 ( 405 float_ops PGNSP PGUID )); DATA(insert OID = 1974 ( 403 network_ops PGNSP PGUID )); #define NETWORK_BTREE_FAM_OID 1974 DATA(insert OID = 1975 ( 405 network_ops PGNSP PGUID )); +DATA(insert OID = 3550 ( 783 network_ops PGNSP PGUID )); DATA(insert OID = 1976 ( 403 integer_ops PGNSP PGUID )); #define INTEGER_BTREE_FAM_OID 1976 DATA(insert OID = 1977 ( 405 integer_ops PGNSP PGUID )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 21c17a08ed4c324634fff79e3a53782f3e08c114..7b9c5870fac6c86b2cc42bbe46d938412fed709a 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -2120,6 +2120,7 @@ DATA(insert OID = 927 ( network_sub PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1 DATA(insert OID = 928 ( network_subeq PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ network_subeq _null_ _null_ _null_ )); DATA(insert OID = 929 ( network_sup PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ network_sup _null_ _null_ _null_ )); DATA(insert OID = 930 ( network_supeq PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ network_supeq _null_ _null_ _null_ )); +DATA(insert OID = 3551 ( network_overlap PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ network_overlap _null_ _null_ _null_ )); /* inet/cidr functions */ DATA(insert OID = 598 ( abbrev PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "869" _null_ _null_ _null_ _null_ inet_abbrev _null_ _null_ _null_ )); @@ -2166,6 +2167,28 @@ DATA(insert OID = 2631 ( int8pl_inet PGNSP PGUID 14 1 0 0 0 f f f f t f i 2 0 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_ inetmi_int8 _null_ _null_ _null_ )); 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_ inetmi _null_ _null_ _null_ )); +/* GiST support for inet and cidr */ +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_ inet_gist_consistent _null_ _null_ _null_ )); +DESCR("GiST support"); +DATA(insert OID = 3554 ( inet_gist_union PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ inet_gist_union _null_ _null_ _null_ )); +DESCR("GiST support"); +DATA(insert OID = 3555 ( inet_gist_compress PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ inet_gist_compress _null_ _null_ _null_ )); +DESCR("GiST support"); +DATA(insert OID = 3556 ( inet_gist_decompress PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ inet_gist_decompress _null_ _null_ _null_ )); +DESCR("GiST support"); +DATA(insert OID = 3557 ( inet_gist_penalty PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ inet_gist_penalty _null_ _null_ _null_ )); +DESCR("GiST support"); +DATA(insert OID = 3558 ( inet_gist_picksplit PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ inet_gist_picksplit _null_ _null_ _null_ )); +DESCR("GiST support"); +DATA(insert OID = 3559 ( inet_gist_same PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 2281 "869 869 2281" _null_ _null_ _null_ _null_ inet_gist_same _null_ _null_ _null_ )); +DESCR("GiST support"); + +/* Selectivity estimation for inet and cidr */ +DATA(insert OID = 3560 ( networksel PGNSP PGUID 12 1 0 0 0 f f f f t f s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ networksel _null_ _null_ _null_ )); +DESCR("restriction selectivity for network operators"); +DATA(insert OID = 3561 ( networkjoinsel PGNSP PGUID 12 1 0 0 0 f f f f t f s 5 0 701 "2281 26 2281 21 2281" _null_ _null_ _null_ _null_ networkjoinsel _null_ _null_ _null_ )); +DESCR("join selectivity for network operators"); + DATA(insert OID = 1690 ( time_mi_time PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1186 "1083 1083" _null_ _null_ _null_ _null_ time_mi_time _null_ _null_ _null_ )); DATA(insert OID = 1691 ( boolle PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "16 16" _null_ _null_ _null_ _null_ boolle _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 720c83180113e8642b0b2b66b408b6dd8827979b..5907cb13fd31d0b5cd0ca5a61311c32c5864f7eb 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -906,6 +906,7 @@ extern Datum network_sub(PG_FUNCTION_ARGS); extern Datum network_subeq(PG_FUNCTION_ARGS); extern Datum network_sup(PG_FUNCTION_ARGS); extern Datum network_supeq(PG_FUNCTION_ARGS); +extern Datum network_overlap(PG_FUNCTION_ARGS); extern Datum network_network(PG_FUNCTION_ARGS); extern Datum network_netmask(PG_FUNCTION_ARGS); extern Datum network_hostmask(PG_FUNCTION_ARGS); diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h index 330f32de8f1c03c12060edbd8c905b20aa26f3e5..bd31c7169a19d28212f547a0442e02f512bdb005 100644 --- a/src/include/utils/inet.h +++ b/src/include/utils/inet.h @@ -53,6 +53,38 @@ typedef struct inet_struct inet_data; } inet; +/* + * Access macros. We use VARDATA_ANY so that we can process short-header + * varlena values without detoasting them. This requires a trick: + * VARDATA_ANY assumes the varlena header is already filled in, which is + * not the case when constructing a new value (until SET_INET_VARSIZE is + * called, which we typically can't do till the end). Therefore, we + * always initialize the newly-allocated value to zeroes (using palloc0). + * A zero length word will look like the not-1-byte case to VARDATA_ANY, + * and so we correctly construct an uncompressed value. + * + * Note that ip_addrsize(), ip_maxbits(), and SET_INET_VARSIZE() require + * the family field to be set correctly. + */ +#define ip_family(inetptr) \ + (((inet_struct *) VARDATA_ANY(inetptr))->family) + +#define ip_bits(inetptr) \ + (((inet_struct *) VARDATA_ANY(inetptr))->bits) + +#define ip_addr(inetptr) \ + (((inet_struct *) VARDATA_ANY(inetptr))->ipaddr) + +#define ip_addrsize(inetptr) \ + (ip_family(inetptr) == PGSQL_AF_INET ? 4 : 16) + +#define ip_maxbits(inetptr) \ + (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128) + +#define SET_INET_VARSIZE(dst) \ + SET_VARSIZE(dst, VARHDRSZ + offsetof(inet_struct, ipaddr) + \ + ip_addrsize(dst)) + /* * This is the internal storage format for MAC addresses: @@ -82,4 +114,27 @@ typedef struct macaddr #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n)) #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x) +/* + * Support functions in network.c + */ +extern int bitncmp(const unsigned char *l, const unsigned char *r, int n); +extern int bitncommon(const unsigned char *l, const unsigned char *r, int n); + +/* + * GiST support functions in network_gist.c + */ +extern Datum inet_gist_consistent(PG_FUNCTION_ARGS); +extern Datum inet_gist_union(PG_FUNCTION_ARGS); +extern Datum inet_gist_compress(PG_FUNCTION_ARGS); +extern Datum inet_gist_decompress(PG_FUNCTION_ARGS); +extern Datum inet_gist_penalty(PG_FUNCTION_ARGS); +extern Datum inet_gist_picksplit(PG_FUNCTION_ARGS); +extern Datum inet_gist_same(PG_FUNCTION_ARGS); + +/* + * Estimation functions in network_selfuncs.c + */ +extern Datum networksel(PG_FUNCTION_ARGS); +extern Datum networkjoinsel(PG_FUNCTION_ARGS); + #endif /* INET_H */ diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out index 356a397822dbbac2cde1c8bd017c075d8dc0cef5..008cc0b5ddf05ec8361f88c53c564587cd0566ea 100644 --- a/src/test/regress/expected/inet.out +++ b/src/test/regress/expected/inet.out @@ -180,27 +180,28 @@ SELECT '' AS ten, i, c, i < c AS lt, i <= c AS le, i = c AS eq, i >= c AS ge, i > c AS gt, i <> c AS ne, i << c AS sb, i <<= c AS sbe, - i >> c AS sup, i >>= c AS spe + i >> c AS sup, i >>= c AS spe, + i && c AS ovr FROM INET_TBL; - ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe ------+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+----- - | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t - | 192.168.1.226 | 192.168.1.0/26 | f | f | f | t | t | t | f | f | f | f - | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t - | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f - | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t - | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f - | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t - | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t - | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t - | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t - | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t - | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t - | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f - | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f - | 10:23::f1/64 | 10:23::f1/128 | t | t | f | f | f | t | f | f | t | t - | 10:23::ffff | 10:23::8000/113 | f | f | f | t | t | t | t | t | f | f - | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t + ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe | ovr +-----+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+-----+----- + | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t | t + | 192.168.1.226 | 192.168.1.0/26 | f | f | f | t | t | t | f | f | f | f | f + | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t | t + | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f | t + | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t | t + | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f | t + | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t | t + | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t | t + | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t | t + | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t | t + | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t | t + | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t | t + | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f | f + | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f | f + | 10:23::f1/64 | 10:23::f1/128 | t | t | f | f | f | t | f | f | t | t | t + | 10:23::ffff | 10:23::8000/113 | f | f | f | t | t | t | t | t | f | f | t + | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t | t (17 rows) -- check the conversion to/from text and set_netmask @@ -226,7 +227,7 @@ SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL; | ::4.3.2.1/24 (17 rows) --- check that index works correctly +-- check that btree index works correctly CREATE INDEX inet_idx1 ON inet_tbl(i); SET enable_seqscan TO off; SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr; @@ -250,6 +251,135 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr; SET enable_seqscan TO on; DROP INDEX inet_idx1; +-- check that gist index works correctly +CREATE INDEX inet_idx2 ON inet_tbl using gist (i inet_ops); +SET enable_seqscan TO off; +SELECT * FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+------------------ + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 +(3 rows) + +SELECT * FROM inet_tbl WHERE i <<= '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+------------------ + 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 +(6 rows) + +SELECT * FROM inet_tbl WHERE i && '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+------------------ + 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 +(6 rows) + +SELECT * FROM inet_tbl WHERE i >>= '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+------------------ + 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 +(3 rows) + +SELECT * FROM inet_tbl WHERE i >> '192.168.1.0/24'::cidr ORDER BY i; + c | i +---+--- +(0 rows) + +SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i; + c | i +-------------+------------- + 10.0.0.0/8 | 9.1.2.3/8 + 10.0.0.0/32 | 10.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.1.0.0/16 | 10.1.2.3/16 + 10.1.2.0/24 | 10.1.2.3/24 + 10.1.2.3/32 | 10.1.2.3 + 10.0.0.0/8 | 11.1.2.3/8 +(8 rows) + +SELECT * FROM inet_tbl WHERE i <= '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+---------------- + 10.0.0.0/8 | 9.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.0.0.0/32 | 10.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.1.0.0/16 | 10.1.2.3/16 + 10.1.2.0/24 | 10.1.2.3/24 + 10.1.2.3/32 | 10.1.2.3 + 10.0.0.0/8 | 11.1.2.3/8 + 192.168.1.0/24 | 192.168.1.0/24 +(9 rows) + +SELECT * FROM inet_tbl WHERE i = '192.168.1.0/24'::cidr ORDER BY i; + c | i +----------------+---------------- + 192.168.1.0/24 | 192.168.1.0/24 +(1 row) + +SELECT * FROM inet_tbl WHERE i >= '192.168.1.0/24'::cidr ORDER BY i; + c | i +--------------------+------------------ + 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 + ::ffff:1.2.3.4/128 | ::4.3.2.1/24 + 10:23::f1/128 | 10:23::f1/64 + 10:23::8000/113 | 10:23::ffff +(9 rows) + +SELECT * FROM inet_tbl WHERE i > '192.168.1.0/24'::cidr ORDER BY i; + c | i +--------------------+------------------ + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 + ::ffff:1.2.3.4/128 | ::4.3.2.1/24 + 10:23::f1/128 | 10:23::f1/64 + 10:23::8000/113 | 10:23::ffff +(8 rows) + +SELECT * FROM inet_tbl WHERE i <> '192.168.1.0/24'::cidr ORDER BY i; + c | i +--------------------+------------------ + 10.0.0.0/8 | 9.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.0.0.0/32 | 10.1.2.3/8 + 10.0.0.0/8 | 10.1.2.3/8 + 10.1.0.0/16 | 10.1.2.3/16 + 10.1.2.0/24 | 10.1.2.3/24 + 10.1.2.3/32 | 10.1.2.3 + 10.0.0.0/8 | 11.1.2.3/8 + 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.255/25 + 192.168.1.0/26 | 192.168.1.226 + ::ffff:1.2.3.4/128 | ::4.3.2.1/24 + 10:23::f1/128 | 10:23::f1/64 + 10:23::8000/113 | 10:23::ffff +(16 rows) + +SET enable_seqscan TO on; +DROP INDEX inet_idx2; -- simple tests of inet boolean and arithmetic operators SELECT i, ~i AS "~i" FROM inet_tbl; i | ~i diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index bf765014357a352ba1ec53812d35edc75ba559c5..118f7e43dc09ca18db44c7d64e11ad9d1d818443 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -1118,6 +1118,15 @@ ORDER BY 1, 2, 3; 783 | 15 | <-> 783 | 16 | @> 783 | 18 | = + 783 | 19 | <> + 783 | 20 | < + 783 | 21 | <= + 783 | 22 | > + 783 | 23 | >= + 783 | 24 | << + 783 | 25 | <<= + 783 | 26 | >> + 783 | 27 | >>= 783 | 28 | <@ 783 | 48 | <@ 783 | 68 | <@ @@ -1153,7 +1162,7 @@ ORDER BY 1, 2, 3; 4000 | 15 | > 4000 | 16 | @> 4000 | 18 | = -(71 rows) +(80 rows) -- Check that all opclass search operators have selectivity estimators. -- This is not absolutely required, but it seems a reasonable thing diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql index 328f14907ba21cae2181d46566af962658c5f826..be078fbb8471f958ae800966bdeb8a960d85e377 100644 --- a/src/test/regress/sql/inet.sql +++ b/src/test/regress/sql/inet.sql @@ -52,12 +52,14 @@ SELECT '' AS ten, i, c, i < c AS lt, i <= c AS le, i = c AS eq, i >= c AS ge, i > c AS gt, i <> c AS ne, i << c AS sb, i <<= c AS sbe, - i >> c AS sup, i >>= c AS spe + i >> c AS sup, i >>= c AS spe, + i && c AS ovr FROM INET_TBL; -- check the conversion to/from text and set_netmask SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL; --- check that index works correctly + +-- check that btree index works correctly CREATE INDEX inet_idx1 ON inet_tbl(i); SET enable_seqscan TO off; SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr; @@ -65,6 +67,23 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr; SET enable_seqscan TO on; DROP INDEX inet_idx1; +-- check that gist index works correctly +CREATE INDEX inet_idx2 ON inet_tbl using gist (i inet_ops); +SET enable_seqscan TO off; +SELECT * FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i <<= '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i && '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i >>= '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i >> '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i <= '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i = '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i >= '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i > '192.168.1.0/24'::cidr ORDER BY i; +SELECT * FROM inet_tbl WHERE i <> '192.168.1.0/24'::cidr ORDER BY i; +SET enable_seqscan TO on; +DROP INDEX inet_idx2; + -- simple tests of inet boolean and arithmetic operators SELECT i, ~i AS "~i" FROM inet_tbl; SELECT i, c, i & c AS "and" FROM inet_tbl;