Add an in-core GiST index opclass for inet/cidr types.

This operator class can accelerate subnet/supernet tests as well as
btree-equivalent ordered comparisons.  It also handles a new network
operator inet && inet (overlaps, a/k/a "is supernet or subnet of"),
which is expected to be useful in exclusion constraints.

Ideally this opclass would be the default for GiST with inet/cidr data,
but we can't mark it that way until we figure out how to do a more or
less graceful transition from the current situation, in which the
really-completely-bogus inet/cidr opclasses in contrib/btree_gist are
marked as default.  Having the opclass in core and not default is better
than not having it at all, though.

While at it, add new documentation sections to allow us to officially
document GiST/GIN/SP-GiST opclasses, something there was never a clear
place to do before.  I filled these in with some simple tables listing
the existing opclasses and the operators they support, but there's
certainly scope to put more information there.

Emre Hasegeli, reviewed by Andreas Karlsson, further hacking by me
This commit is contained in:
Tom Lane 2014-04-08 15:46:14 -04:00
parent 02f65617ea
commit f23a5630eb
21 changed files with 1839 additions and 89 deletions

View File

@ -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>&lt;&lt;</literal>,
<literal>&lt;&lt;=</literal>, <literal>&gt;&gt;</literal>, and
<literal>&gt;&gt;=</literal> test for subnet inclusion. They
<literal>&lt;&lt;=</literal>, <literal>&gt;&gt;</literal>,
<literal>&gt;&gt;=</literal>, and <literal>&amp;&amp;</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>&lt;&lt;</literal> </entry>
<entry>is contained within</entry>
<entry>is contained by</entry>
<entry><literal>inet '192.168.1.5' &lt;&lt; inet '192.168.1/24'</literal></entry>
</row>
<row>
<entry> <literal>&lt;&lt;=</literal> </entry>
<entry>is contained within or equals</entry>
<entry>is contained by or equals</entry>
<entry><literal>inet '192.168.1/24' &lt;&lt;= 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' &gt;&gt;= inet '192.168.1/24'</literal></entry>
</row>
<row>
<entry> <literal>&amp;&amp;</literal> </entry>
<entry>contains or is contained by</entry>
<entry><literal>inet '192.168.1/24' &amp;&amp; inet '192.168.1.80/28'</literal></entry>
</row>
<row>
<entry> <literal>~</literal> </entry>
<entry>bitwise NOT</entry>

View File

@ -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>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_bit_ops</></entry>
<entry><type>bit[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_bool_ops</></entry>
<entry><type>boolean[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_bpchar_ops</></entry>
<entry><type>character[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_bytea_ops</></entry>
<entry><type>bytea[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_char_ops</></entry>
<entry><type>"char"[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_cidr_ops</></entry>
<entry><type>cidr[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_date_ops</></entry>
<entry><type>date[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_float4_ops</></entry>
<entry><type>float4[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_float8_ops</></entry>
<entry><type>float8[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_inet_ops</></entry>
<entry><type>inet[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_int2_ops</></entry>
<entry><type>smallint[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_int4_ops</></entry>
<entry><type>integer[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_int8_ops</></entry>
<entry><type>bigint[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_interval_ops</></entry>
<entry><type>interval[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_macaddr_ops</></entry>
<entry><type>macaddr[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_money_ops</></entry>
<entry><type>money[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_name_ops</></entry>
<entry><type>name[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_numeric_ops</></entry>
<entry><type>numeric[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_oid_ops</></entry>
<entry><type>oid[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_oidvector_ops</></entry>
<entry><type>oidvector[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_reltime_ops</></entry>
<entry><type>reltime[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_text_ops</></entry>
<entry><type>text[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_time_ops</></entry>
<entry><type>time[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_timestamp_ops</></entry>
<entry><type>timestamp[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_timestamptz_ops</></entry>
<entry><type>timestamp with time zone[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_timetz_ops</></entry>
<entry><type>time with time zone[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_tinterval_ops</></entry>
<entry><type>tinterval[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_varbit_ops</></entry>
<entry><type>bit varying[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>_varchar_ops</></entry>
<entry><type>character varying[]</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>jsonb_ops</></entry>
<entry><type>jsonb</></entry>
<entry>
<literal>?</>
<literal>?&amp;</>
<literal>?|</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>jsonb_hash_ops</></entry>
<entry><type>jsonb</></entry>
<entry>
<literal>@&gt;</>
</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>

View File

@ -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>&amp;&amp;</>
<literal>&amp;&gt;</>
<literal>&amp;&lt;</>
<literal>&amp;&lt;|</>
<literal>&gt;&gt;</>
<literal>&lt;&lt;</>
<literal>&lt;&lt;|</>
<literal>&lt;@</>
<literal>@&gt;</>
<literal>@</>
<literal>|&amp;&gt;</>
<literal>|&gt;&gt;</>
<literal>~</>
<literal>~=</>
</entry>
<entry>
</entry>
</row>
<row>
<entry><literal>circle_ops</></entry>
<entry><type>circle</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&amp;&gt;</>
<literal>&amp;&lt;</>
<literal>&amp;&lt;|</>
<literal>&gt;&gt;</>
<literal>&lt;&lt;</>
<literal>&lt;&lt;|</>
<literal>&lt;@</>
<literal>@&gt;</>
<literal>@</>
<literal>|&amp;&gt;</>
<literal>|&gt;&gt;</>
<literal>~</>
<literal>~=</>
</entry>
<entry>
</entry>
</row>
<row>
<entry><literal>inet_ops</></entry>
<entry><type>inet</>, <type>cidr</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&gt;&gt;</>
<literal>&gt;&gt;=</>
<literal>&gt;</>
<literal>&gt;=</>
<literal>&lt;&gt;</>
<literal>&lt;&lt;</>
<literal>&lt;&lt;=</>
<literal>&lt;</>
<literal>&lt;=</>
<literal>=</>
</entry>
<entry>
</entry>
</row>
<row>
<entry><literal>point_ops</></entry>
<entry><type>point</></entry>
<entry>
<literal>&gt;&gt;</>
<literal>&gt;^</>
<literal>&lt;&lt;</>
<literal>&lt;@</>
<literal>&lt;@</>
<literal>&lt;@</>
<literal>&lt;^</>
<literal>~=</>
</entry>
<entry>
<literal>&lt;-&gt;</>
</entry>
</row>
<row>
<entry><literal>poly_ops</></entry>
<entry><type>polygon</></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&amp;&gt;</>
<literal>&amp;&lt;</>
<literal>&amp;&lt;|</>
<literal>&gt;&gt;</>
<literal>&lt;&lt;</>
<literal>&lt;&lt;|</>
<literal>&lt;@</>
<literal>@&gt;</>
<literal>@</>
<literal>|&amp;&gt;</>
<literal>|&gt;&gt;</>
<literal>~</>
<literal>~=</>
</entry>
<entry>
</entry>
</row>
<row>
<entry><literal>range_ops</></entry>
<entry>any range type</entry>
<entry>
<literal>&amp;&amp;</>
<literal>&amp;&gt;</>
<literal>&amp;&lt;</>
<literal>&gt;&gt;</>
<literal>&lt;&lt;</>
<literal>&lt;@</>
<literal>-|-</>
<literal>=</>
<literal>@&gt;</>
<literal>@&gt;</>
</entry>
<entry>
</entry>
</row>
<row>
<entry><literal>tsquery_ops</></entry>
<entry><type>tsquery</></entry>
<entry>
<literal>&lt;@</>
<literal>@&gt;</>
</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>

View File

@ -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:

View File

@ -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>&lt;&lt;</>
<literal>&lt;@</>
<literal>&lt;^</>
<literal>&gt;&gt;</>
<literal>&gt;^</>
<literal>~=</>
</entry>
</row>
<row>
<entry><literal>quad_point_ops</></entry>
<entry><type>point</></entry>
<entry>
<literal>&lt;&lt;</>
<literal>&lt;@</>
<literal>&lt;^</>
<literal>&gt;&gt;</>
<literal>&gt;^</>
<literal>~=</>
</entry>
</row>
<row>
<entry><literal>range_ops</></entry>
<entry>any range type</entry>
<entry>
<literal>&amp;&amp;</>
<literal>&amp;&lt;</>
<literal>&amp;&gt;</>
<literal>-|-</>
<literal>&lt;&lt;</>
<literal>&lt;@</>
<literal>=</>
<literal>&gt;&gt;</>
<literal>@&gt;</>
</entry>
</row>
<row>
<entry><literal>text_ops</></entry>
<entry><type>text</></entry>
<entry>
<literal>&lt;</>
<literal>&lt;=</>
<literal>=</>
<literal>&gt;</>
<literal>&gt;=</>
<literal>~&lt;=~</>
<literal>~&lt;~</>
<literal>~&gt;=~</>
<literal>~&gt;~</>
</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>

View File

@ -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 \

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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);
}

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201404081
#define CATALOG_VERSION_NO 201404082
#endif

View File

@ -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 */

View File

@ -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 ));

View File

@ -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 ));

View File

@ -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");

View File

@ -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 ));

View File

@ -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_ ));

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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;