Commit f23a5630 authored by Tom Lane's avatar Tom Lane

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
parent 02f65617
...@@ -8434,8 +8434,9 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple ...@@ -8434,8 +8434,9 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
<xref linkend="cidr-inet-operators-table"> shows the operators <xref linkend="cidr-inet-operators-table"> shows the operators
available for the <type>cidr</type> and <type>inet</type> types. available for the <type>cidr</type> and <type>inet</type> types.
The operators <literal>&lt;&lt;</literal>, The operators <literal>&lt;&lt;</literal>,
<literal>&lt;&lt;=</literal>, <literal>&gt;&gt;</literal>, and <literal>&lt;&lt;=</literal>, <literal>&gt;&gt;</literal>,
<literal>&gt;&gt;=</literal> test for subnet inclusion. They <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 consider only the network parts of the two addresses (ignoring any
host part) and determine whether one network is identical to host part) and determine whether one network is identical to
or a subnet of the other. or a subnet of the other.
...@@ -8484,12 +8485,12 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple ...@@ -8484,12 +8485,12 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
</row> </row>
<row> <row>
<entry> <literal>&lt;&lt;</literal> </entry> <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> <entry><literal>inet '192.168.1.5' &lt;&lt; inet '192.168.1/24'</literal></entry>
</row> </row>
<row> <row>
<entry> <literal>&lt;&lt;=</literal> </entry> <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> <entry><literal>inet '192.168.1/24' &lt;&lt;= inet '192.168.1/24'</literal></entry>
</row> </row>
<row> <row>
...@@ -8502,6 +8503,11 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple ...@@ -8502,6 +8503,11 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
<entry>contains or equals</entry> <entry>contains or equals</entry>
<entry><literal>inet '192.168.1/24' &gt;&gt;= inet '192.168.1/24'</literal></entry> <entry><literal>inet '192.168.1/24' &gt;&gt;= inet '192.168.1/24'</literal></entry>
</row> </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> <row>
<entry> <literal>~</literal> </entry> <entry> <literal>~</literal> </entry>
<entry>bitwise NOT</entry> <entry>bitwise NOT</entry>
......
...@@ -62,6 +62,365 @@ ...@@ -62,6 +62,365 @@
</para> </para>
</sect1> </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"> <sect1 id="gin-extensibility">
<title>Extensibility</title> <title>Extensibility</title>
......
...@@ -40,6 +40,184 @@ ...@@ -40,6 +40,184 @@
</sect1> </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"> <sect1 id="gist-extensibility">
<title>Extensibility</title> <title>Extensibility</title>
......
...@@ -239,6 +239,8 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable> ...@@ -239,6 +239,8 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
(See <xref linkend="functions-geometry"> for the meaning of (See <xref linkend="functions-geometry"> for the meaning of
these operators.) these operators.)
The GiST operator classes included in the standard distribution are
documented in <xref linkend="gist-builtin-opclasses-table">.
Many other GiST operator Many other GiST operator
classes are available in the <literal>contrib</> collection or as separate classes are available in the <literal>contrib</> collection or as separate
projects. For more information see <xref linkend="GiST">. projects. For more information see <xref linkend="GiST">.
...@@ -253,6 +255,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10; ...@@ -253,6 +255,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10;
</programlisting> </programlisting>
which finds the ten places closest to a given target point. The ability 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. 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>
<para> <para>
...@@ -283,6 +287,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10; ...@@ -283,6 +287,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10;
(See <xref linkend="functions-geometry"> for the meaning of (See <xref linkend="functions-geometry"> for the meaning of
these operators.) 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">. For more information see <xref linkend="SPGiST">.
</para> </para>
...@@ -314,6 +320,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10; ...@@ -314,6 +320,8 @@ SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10;
(See <xref linkend="functions-array"> for the meaning of (See <xref linkend="functions-array"> for the meaning of
these operators.) these operators.)
The GIN operator classes included in the standard distribution are
documented in <xref linkend="gin-builtin-opclasses-table">.
Many other GIN operator Many other GIN operator
classes are available in the <literal>contrib</> collection or as separate classes are available in the <literal>contrib</> collection or as separate
projects. For more information see <xref linkend="GIN">. projects. For more information see <xref linkend="GIN">.
...@@ -1003,7 +1011,9 @@ CREATE INDEX test_index ON test_table (col varchar_pattern_ops); ...@@ -1003,7 +1011,9 @@ CREATE INDEX test_index ON test_table (col varchar_pattern_ops);
<programlisting> <programlisting>
SELECT am.amname AS index_method, 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 FROM pg_am am, pg_opclass opc
WHERE opc.opcmethod = am.oid WHERE opc.opcmethod = am.oid
ORDER BY index_method, opclass_name; ORDER BY index_method, opclass_name;
...@@ -1020,6 +1030,22 @@ SELECT am.amname AS index_method, ...@@ -1020,6 +1030,22 @@ SELECT am.amname AS index_method,
associated with any single class within the family. associated with any single class within the family.
</para> </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> <para>
This query shows all defined operator families and all This query shows all defined operator families and all
the operators included in each family: the operators included in each family:
......
...@@ -53,6 +53,93 @@ ...@@ -53,6 +53,93 @@
</sect1> </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"> <sect1 id="spgist-extensibility">
<title>Extensibility</title> <title>Extensibility</title>
......
...@@ -23,7 +23,8 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \ ...@@ -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 \ 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 \ 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 \ 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 \ orderedsetaggs.o pg_lzcompress.o pg_locale.o pg_lsn.o \
pgstatfuncs.o pseudotypes.o quote.o rangetypes.o rangetypes_gist.o \ pgstatfuncs.o pseudotypes.o quote.o rangetypes.o rangetypes_gist.o \
rangetypes_selfuncs.o rangetypes_spgist.o rangetypes_typanalyze.o \ rangetypes_selfuncs.o rangetypes_spgist.o rangetypes_typanalyze.o \
......
...@@ -23,58 +23,9 @@ ...@@ -23,58 +23,9 @@
static int32 network_cmp_internal(inet *a1, inet *a2); 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 bool addressOK(unsigned char *a, int bits, int family);
static int ip_addrsize(inet *inetptr);
static inet *internal_inetpl(inet *ip, int64 addend); 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 * Common INET/CIDR input routine
...@@ -596,6 +547,21 @@ network_supeq(PG_FUNCTION_ARGS) ...@@ -596,6 +547,21 @@ network_supeq(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false); 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. * Extract data from a network datatype.
*/ */
...@@ -962,10 +928,10 @@ convert_network_to_scalar(Datum value, Oid typid) ...@@ -962,10 +928,10 @@ convert_network_to_scalar(Datum value, Oid typid)
* author: * author:
* Paul Vixie (ISC), June 1996 * Paul Vixie (ISC), June 1996
*/ */
static int int
bitncmp(void *l, void *r, int n) bitncmp(const unsigned char *l, const unsigned char *r, int n)
{ {
u_int lb, unsigned int lb,
rb; rb;
int x, int x,
b; b;
...@@ -975,8 +941,8 @@ bitncmp(void *l, void *r, int n) ...@@ -975,8 +941,8 @@ bitncmp(void *l, void *r, int n)
if (x || (n % 8) == 0) if (x || (n % 8) == 0)
return x; return x;
lb = ((const u_char *) l)[b]; lb = l[b];
rb = ((const u_char *) r)[b]; rb = r[b];
for (b = n % 8; b > 0; b--) for (b = n % 8; b > 0; b--)
{ {
if (IS_HIGHBIT_SET(lb) != IS_HIGHBIT_SET(rb)) if (IS_HIGHBIT_SET(lb) != IS_HIGHBIT_SET(rb))
...@@ -991,6 +957,49 @@ bitncmp(void *l, void *r, int n) ...@@ -991,6 +957,49 @@ bitncmp(void *l, void *r, int n)
return 0; 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 static bool
addressOK(unsigned char *a, int bits, int family) addressOK(unsigned char *a, int bits, int family)
{ {
......
This diff is collapsed.
/*-------------------------------------------------------------------------
*
* 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);
}
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201404081 #define CATALOG_VERSION_NO 201404082
#endif #endif
...@@ -818,4 +818,19 @@ DATA(insert ( 3474 3831 3831 8 s 3892 4000 0 )); ...@@ -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 2283 16 s 3889 4000 0 ));
DATA(insert ( 3474 3831 3831 18 s 3882 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 */ #endif /* PG_AMOP_H */
...@@ -399,6 +399,13 @@ DATA(insert ( 4037 3802 3802 2 3485 )); ...@@ -399,6 +399,13 @@ DATA(insert ( 4037 3802 3802 2 3485 ));
DATA(insert ( 4037 3802 3802 3 3486 )); DATA(insert ( 4037 3802 3802 3 3486 ));
DATA(insert ( 4037 3802 3802 4 3487 )); DATA(insert ( 4037 3802 3802 4 3487 ));
DATA(insert ( 4037 3802 3802 6 3489 )); 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 */ /* sp-gist */
DATA(insert ( 3474 3831 3831 1 3469 )); DATA(insert ( 3474 3831 3831 1 3469 ));
......
...@@ -112,6 +112,7 @@ DATA(insert OID = 3123 ( 403 float8_ops PGNSP PGUID 1970 701 t 0 )); ...@@ -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 ( 405 float8_ops PGNSP PGUID 1971 701 t 0 ));
DATA(insert ( 403 inet_ops PGNSP PGUID 1974 869 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 ( 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 )); DATA(insert OID = 1979 ( 403 int2_ops PGNSP PGUID 1976 21 t 0 ));
#define INT2_BTREE_OPS_OID 1979 #define INT2_BTREE_OPS_OID 1979
DATA(insert ( 405 int2_ops PGNSP PGUID 1977 21 t 0 )); DATA(insert ( 405 int2_ops PGNSP PGUID 1977 21 t 0 ));
......
...@@ -1140,18 +1140,20 @@ DATA(insert OID = 1205 ( ">" PGNSP PGUID b f f 869 869 16 1203 1204 network ...@@ -1140,18 +1140,20 @@ DATA(insert OID = 1205 ( ">" PGNSP PGUID b f f 869 869 16 1203 1204 network
DESCR("greater than"); DESCR("greater than");
DATA(insert OID = 1206 ( ">=" PGNSP PGUID b f f 869 869 16 1204 1203 network_ge scalargtsel scalargtjoinsel )); DATA(insert OID = 1206 ( ">=" PGNSP PGUID b f f 869 869 16 1204 1203 network_ge scalargtsel scalargtjoinsel ));
DESCR("greater than or equal"); 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"); DESCR("is subnet");
#define OID_INET_SUB_OP 931 #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"); DESCR("is subnet or equal");
#define OID_INET_SUBEQ_OP 932 #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"); DESCR("is supernet");
#define OID_INET_SUP_OP 933 #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"); DESCR("is supernet or equal");
#define OID_INET_SUPEQ_OP 934 #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 - - )); DATA(insert OID = 2634 ( "~" PGNSP PGUID l f f 0 869 869 0 0 inetnot - - ));
DESCR("bitwise not"); DESCR("bitwise not");
......
...@@ -78,6 +78,7 @@ DATA(insert OID = 1971 ( 405 float_ops PGNSP PGUID )); ...@@ -78,6 +78,7 @@ DATA(insert OID = 1971 ( 405 float_ops PGNSP PGUID ));
DATA(insert OID = 1974 ( 403 network_ops PGNSP PGUID )); DATA(insert OID = 1974 ( 403 network_ops PGNSP PGUID ));
#define NETWORK_BTREE_FAM_OID 1974 #define NETWORK_BTREE_FAM_OID 1974
DATA(insert OID = 1975 ( 405 network_ops PGNSP PGUID )); 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 )); DATA(insert OID = 1976 ( 403 integer_ops PGNSP PGUID ));
#define INTEGER_BTREE_FAM_OID 1976 #define INTEGER_BTREE_FAM_OID 1976
DATA(insert OID = 1977 ( 405 integer_ops PGNSP PGUID )); DATA(insert OID = 1977 ( 405 integer_ops PGNSP PGUID ));
......
...@@ -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 ...@@ -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 = 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 = 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 = 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 */ /* 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_ )); 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 ...@@ -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 = 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_ )); 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 = 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_ )); 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_ ));
......
...@@ -906,6 +906,7 @@ extern Datum network_sub(PG_FUNCTION_ARGS); ...@@ -906,6 +906,7 @@ extern Datum network_sub(PG_FUNCTION_ARGS);
extern Datum network_subeq(PG_FUNCTION_ARGS); extern Datum network_subeq(PG_FUNCTION_ARGS);
extern Datum network_sup(PG_FUNCTION_ARGS); extern Datum network_sup(PG_FUNCTION_ARGS);
extern Datum network_supeq(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_network(PG_FUNCTION_ARGS);
extern Datum network_netmask(PG_FUNCTION_ARGS); extern Datum network_netmask(PG_FUNCTION_ARGS);
extern Datum network_hostmask(PG_FUNCTION_ARGS); extern Datum network_hostmask(PG_FUNCTION_ARGS);
......
...@@ -53,6 +53,38 @@ typedef struct ...@@ -53,6 +53,38 @@ typedef struct
inet_struct inet_data; inet_struct inet_data;
} inet; } 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: * This is the internal storage format for MAC addresses:
...@@ -82,4 +114,27 @@ typedef struct macaddr ...@@ -82,4 +114,27 @@ typedef struct macaddr
#define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n)) #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
#define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x) #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 */ #endif /* INET_H */
...@@ -180,27 +180,28 @@ SELECT '' AS ten, i, c, ...@@ -180,27 +180,28 @@ SELECT '' AS ten, i, c,
i < c AS lt, i <= c AS le, i = c AS eq, 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 ge, i > c AS gt, i <> c AS ne,
i << c AS sb, i <<= c AS sbe, 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; FROM INET_TBL;
ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t | t
(17 rows) (17 rows)
-- check the conversion to/from text and set_netmask -- 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; ...@@ -226,7 +227,7 @@ SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL;
| ::4.3.2.1/24 | ::4.3.2.1/24
(17 rows) (17 rows)
-- check that index works correctly -- check that btree index works correctly
CREATE INDEX inet_idx1 ON inet_tbl(i); CREATE INDEX inet_idx1 ON inet_tbl(i);
SET enable_seqscan TO off; SET enable_seqscan TO off;
SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr; 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; ...@@ -250,6 +251,135 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr;
SET enable_seqscan TO on; SET enable_seqscan TO on;
DROP INDEX inet_idx1; 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 -- simple tests of inet boolean and arithmetic operators
SELECT i, ~i AS "~i" FROM inet_tbl; SELECT i, ~i AS "~i" FROM inet_tbl;
i | ~i i | ~i
......
...@@ -1118,6 +1118,15 @@ ORDER BY 1, 2, 3; ...@@ -1118,6 +1118,15 @@ ORDER BY 1, 2, 3;
783 | 15 | <-> 783 | 15 | <->
783 | 16 | @> 783 | 16 | @>
783 | 18 | = 783 | 18 | =
783 | 19 | <>
783 | 20 | <
783 | 21 | <=
783 | 22 | >
783 | 23 | >=
783 | 24 | <<
783 | 25 | <<=
783 | 26 | >>
783 | 27 | >>=
783 | 28 | <@ 783 | 28 | <@
783 | 48 | <@ 783 | 48 | <@
783 | 68 | <@ 783 | 68 | <@
...@@ -1153,7 +1162,7 @@ ORDER BY 1, 2, 3; ...@@ -1153,7 +1162,7 @@ ORDER BY 1, 2, 3;
4000 | 15 | > 4000 | 15 | >
4000 | 16 | @> 4000 | 16 | @>
4000 | 18 | = 4000 | 18 | =
(71 rows) (80 rows)
-- Check that all opclass search operators have selectivity estimators. -- Check that all opclass search operators have selectivity estimators.
-- This is not absolutely required, but it seems a reasonable thing -- This is not absolutely required, but it seems a reasonable thing
......
...@@ -52,12 +52,14 @@ SELECT '' AS ten, i, c, ...@@ -52,12 +52,14 @@ SELECT '' AS ten, i, c,
i < c AS lt, i <= c AS le, i = c AS eq, 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 ge, i > c AS gt, i <> c AS ne,
i << c AS sb, i <<= c AS sbe, 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; FROM INET_TBL;
-- check the conversion to/from text and set_netmask -- check the conversion to/from text and set_netmask
SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL; 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); CREATE INDEX inet_idx1 ON inet_tbl(i);
SET enable_seqscan TO off; SET enable_seqscan TO off;
SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr; 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; ...@@ -65,6 +67,23 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr;
SET enable_seqscan TO on; SET enable_seqscan TO on;
DROP INDEX inet_idx1; 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 -- simple tests of inet boolean and arithmetic operators
SELECT i, ~i AS "~i" FROM inet_tbl; SELECT i, ~i AS "~i" FROM inet_tbl;
SELECT i, c, i & c AS "and" FROM inet_tbl; SELECT i, c, i & c AS "and" FROM inet_tbl;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment