Commit a2100230 authored by Tom Lane's avatar Tom Lane

Adjust INET/CIDR display conventions and reimplement some INET/CIDR

functions, per recent discussions on pghackers.  For now, I have called
the verbose-display formatting function text(), but will reconsider if
enough people object.
initdb forced.
parent d7f8ffa7
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.38 2000/10/04 15:47:45 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.39 2000/11/10 20:13:25 tgl Exp $
--> -->
<chapter id="datatype"> <chapter id="datatype">
...@@ -65,7 +65,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.38 2000/10/04 15:47:45 pe ...@@ -65,7 +65,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.38 2000/10/04 15:47:45 pe
<row> <row>
<entry>cidr</entry> <entry>cidr</entry>
<entry></entry> <entry></entry>
<entry>IP version 4 network or host address</entry> <entry>IP network address</entry>
</row> </row>
<row> <row>
<entry>circle</entry> <entry>circle</entry>
...@@ -95,7 +95,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.38 2000/10/04 15:47:45 pe ...@@ -95,7 +95,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.38 2000/10/04 15:47:45 pe
<row> <row>
<entry>inet</entry> <entry>inet</entry>
<entry></entry> <entry></entry>
<entry>IP version 4 network or host address</entry> <entry>IP network or host address</entry>
</row> </row>
<row> <row>
<entry>int2</entry> <entry>int2</entry>
...@@ -1736,7 +1736,7 @@ January 8 04:05:06 1999 PST ...@@ -1736,7 +1736,7 @@ January 8 04:05:06 1999 PST
<para> <para>
<productname>Postgres</> offers data types to store IP and MAC <productname>Postgres</> offers data types to store IP and MAC
addresses. It is preferrable to use these types over plain text addresses. It is preferable to use these types over plain text
types, because these types offer input error checking and several types, because these types offer input error checking and several
specialized operators and functions. specialized operators and functions.
...@@ -1755,16 +1755,16 @@ January 8 04:05:06 1999 PST ...@@ -1755,16 +1755,16 @@ January 8 04:05:06 1999 PST
<row> <row>
<entry>cidr</entry> <entry>cidr</entry>
<entry>11 bytes</entry> <entry>12 bytes</entry>
<entry>IP networks</entry> <entry>IP networks</entry>
<entry>valid IPv4 networks</entry> <entry>valid IPv4 networks</entry>
</row> </row>
<row> <row>
<entry>inet</entry> <entry>inet</entry>
<entry>11 bytes</entry> <entry>12 bytes</entry>
<entry>IP hosts and networks</entry> <entry>IP hosts and networks</entry>
<entry>valid IPv4 hosts</entry> <entry>valid IPv4 hosts or networks</entry>
</row> </row>
<row> <row>
...@@ -1784,19 +1784,48 @@ January 8 04:05:06 1999 PST ...@@ -1784,19 +1784,48 @@ January 8 04:05:06 1999 PST
</para> </para>
<sect2 id="inet-type">
<title><type>inet</type></title>
<para>
The <type>inet</type> type holds an IP host address, and
optionally the identity of the subnet it is in, all in one field.
The subnet identity is represented by the number of bits in the
network part of the address (the "netmask"). If the netmask is 32,
then the value does not indicate a subnet, only a single host.
Note that if you want to accept networks only, you should use the
<type>cidr</type> type rather than <type>inet</type>.
</para>
<para>
The input format for this type is <replaceable
class="parameter">x.x.x.x/y</replaceable> where <replaceable
class="parameter">x.x.x.x</replaceable> is an IP address and
<replaceable class="parameter">y</replaceable> is the number of
bits in the netmask. If the <replaceable
class="parameter">y</replaceable> part is left off, then the
netmask is 32, and the value represents just a single host.
On display, the <replaceable class="parameter">/y</replaceable>
portion is suppressed if the netmask is 32.
</para>
</sect2>
<sect2 id="cidr-type"> <sect2 id="cidr-type">
<title><type>cidr</></title> <title><type>cidr</></title>
<para> <para>
The <type>cidr</type> type holds an IP network. The format for The <type>cidr</type> type holds an IP network specification.
Input and output formats follow Classless Internet Domain Routing
conventions.
The format for
specifying classless networks is <replaceable specifying classless networks is <replaceable
class="parameter">x.x.x.x/y</> where <replaceable class="parameter">x.x.x.x/y</> where <replaceable
class="parameter">x.x.x.x</> is the network and <replaceable class="parameter">x.x.x.x</> is the network and <replaceable
class="parameter">y</> is the number of bits in the netmask. If class="parameter">y</> is the number of bits in the netmask. If
<replaceable class="parameter">y</> omitted, it is calculated <replaceable class="parameter">y</> omitted, it is calculated
using assumptions from the older classfull naming system except using assumptions from the older classful numbering system, except
that it is extended to include at least all of the octets in the that it will be at least large enough to include all of the octets
input. written in the input.
</para> </para>
<para> <para>
...@@ -1816,6 +1845,10 @@ January 8 04:05:06 1999 PST ...@@ -1816,6 +1845,10 @@ January 8 04:05:06 1999 PST
<entry>192.168.100.128/25</entry> <entry>192.168.100.128/25</entry>
<entry>192.168.100.128/25</entry> <entry>192.168.100.128/25</entry>
</row> </row>
<row>
<entry>192.168/24</entry>
<entry>192.168.0/24</entry>
</row>
<row> <row>
<entry>192.168/25</entry> <entry>192.168/25</entry>
<entry>192.168.0.0/25</entry> <entry>192.168.0.0/25</entry>
...@@ -1856,30 +1889,19 @@ January 8 04:05:06 1999 PST ...@@ -1856,30 +1889,19 @@ January 8 04:05:06 1999 PST
</tgroup> </tgroup>
</table> </table>
</para> </para>
</sect2>
<sect2 id="inet-type">
<title><type>inet</type></title>
<para> <para>
The <type>inet</type> type holds an IP host address, and The essential difference between <type>inet</type> and <type>cidr</type>
optionally the identity of the subnet it is in, all in one field. data types is that <type>inet</type> accepts values with nonzero bits to
Note that if you want to store networks only, you should use the the right of the netmask, whereas <type>cidr</type> does not.
<type>cidr</type> type. The <type>inet</type> type is similar to
the <type>cidr</type> type except that the bits in the host part <tip>
can be non-zero. Functions exist to extract the various elements <para>
of the field. If you do not like the output format for <type>inet</type> or
</para> <type>cidr</type> values, try the <function>host</>() and
<function>text</>() functions.
<para> </para>
The input format for this type is <replaceable </tip>
class="parameter">x.x.x.x/y</replaceable> where <replaceable
class="parameter">x.x.x.x</replaceable> is an internet host and
<replaceable class="parameter">y</replaceable> is the number of
bits in the netmask. If the <replaceable
class="parameter">y</replaceable> part is left off, then the
netmask is 32 and you are effectively only storing the address of
a single host.
</para> </para>
</sect2> </sect2>
......
...@@ -1480,62 +1480,98 @@ Not defined by this name. Implements the intersection operator '#' ...@@ -1480,62 +1480,98 @@ Not defined by this name. Implements the intersection operator '#'
<para> <para>
<table tocentry="1" id="cidr-inet-functions"> <table tocentry="1" id="cidr-inet-functions">
<title><type>cidr</> and <type>inet</> Functions</title> <title><type>cidr</> and <type>inet</> Functions</title>
<tgroup cols="4"> <tgroup cols="5">
<thead> <thead>
<row> <row>
<entry>Function</entry> <entry>Function</entry>
<entry>Returns</entry> <entry>Returns</entry>
<entry>Description</entry> <entry>Description</entry>
<entry>Example</entry> <entry>Example</entry>
<entry>Result</entry>
</row> </row>
</thead> </thead>
<tbody> <tbody>
<row>
<entry>broadcast(cidr)</entry>
<entry>text</entry>
<entry>construct broadcast address as text</entry>
<entry>broadcast('192.168.1.5/24')</entry>
</row>
<row> <row>
<entry>broadcast(inet)</entry> <entry>broadcast(inet)</entry>
<entry>text</entry> <entry>inet</entry>
<entry>construct broadcast address as text</entry> <entry>broadcast address for network</entry>
<entry>broadcast('192.168.1.5/24')</entry> <entry>broadcast('192.168.1.5/24')</entry>
<entry>192.168.1.255/24</entry>
</row> </row>
<row> <row>
<entry>host(inet)</entry> <entry>host(inet)</entry>
<entry>text</entry> <entry>text</entry>
<entry>extract host address as text</entry> <entry>extract IP address as text</entry>
<entry>host('192.168.1.5/24')</entry> <entry>host('192.168.1.5/24')</entry>
</row> <entry>192.168.1.5</entry>
<row>
<entry>masklen(cidr)</entry>
<entry>integer</entry>
<entry>calculate netmask length</entry>
<entry>masklen('192.168.1.5/24')</entry>
</row> </row>
<row> <row>
<entry>masklen(inet)</entry> <entry>masklen(inet)</entry>
<entry>integer</entry> <entry>integer</entry>
<entry>calculate netmask length</entry> <entry>extract netmask length</entry>
<entry>masklen('192.168.1.5/24')</entry> <entry>masklen('192.168.1.5/24')</entry>
<entry>24</entry>
</row> </row>
<row> <row>
<entry>netmask(inet)</entry> <entry>netmask(inet)</entry>
<entry>text</entry> <entry>inet</entry>
<entry>construct netmask as text</entry> <entry>construct netmask for network</entry>
<entry>netmask('192.168.1.5/24')</entry> <entry>netmask('192.168.1.5/24')</entry>
<entry>255.255.255.0</entry>
</row>
<row>
<entry>network(inet)</entry>
<entry>cidr</entry>
<entry>extract network part of address</entry>
<entry>network('192.168.1.5/24')</entry>
<entry>192.168.1/24</entry>
</row>
<row>
<entry>text(inet)</entry>
<entry>text</entry>
<entry>extract IP address and masklen as text</entry>
<entry>text(inet '192.168.1.5')</entry>
<entry>192.168.1.5/32</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
All of the functions for <type>inet</type> can be applied to
<type>cidr</type> values as well. The <function>host</>() and
<function>text</>() functions are primarily intended to offer
alternative display formats.
</para>
<para>
<table tocentry="1" id="macaddr-functions">
<title><type>macaddr</> Functions</title>
<tgroup cols="5">
<thead>
<row>
<entry>Function</entry>
<entry>Returns</entry>
<entry>Description</entry>
<entry>Example</entry>
<entry>Result</entry>
</row> </row>
</thead>
<tbody>
<row> <row>
<entry>trunc(macaddr)</entry> <entry>trunc(macaddr)</entry>
<entry>macaddr</entry> <entry>macaddr</entry>
<entry>set last 3 bytes to zero</entry> <entry>set last 3 bytes to zero</entry>
<entry>trunc(macaddr '12:34:56:78:90:ab')</entry> <entry>trunc(macaddr '12:34:56:78:90:ab')</entry>
<entry>12:34:56:00:00:00</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
</para>
<para>
The function <function>trunc</>(<type>macaddr</>) returns a MAC The function <function>trunc</>(<type>macaddr</>) returns a MAC
address with the last 3 bytes set to 0. This can be used to address with the last 3 bytes set to 0. This can be used to
associate the remaining prefix with a manufacturer. The directory associate the remaining prefix with a manufacturer. The directory
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/Attic/oper.sgml,v 1.21 2000/10/24 20:13:31 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/Attic/oper.sgml,v 1.22 2000/11/10 20:13:25 tgl Exp $
--> -->
<Chapter Id="operators"> <Chapter Id="operators">
...@@ -756,80 +756,11 @@ logical union ...@@ -756,80 +756,11 @@ logical union
<sect1 id="net-operators"> <sect1 id="net-operators">
<title>Network Address Type Operators</title> <title>Network Address Type Operators</title>
<sect2 id="cidr-operators"> <sect2 id="cidr-inet-operators">
<title><type>cidr</> Operators</title> <title><type>cidr</> and <type>inet</> Operators</title>
<table tocentry="1" id="cidr-operators-table"> <table tocentry="1" id="cidr-inet-operators-table">
<title><type>cidr</> Operators</title> <title><type>cidr</> and <type>inet</> Operators</title>
<TGROUP COLS="3">
<THEAD>
<ROW>
<ENTRY>Operator</ENTRY>
<ENTRY>Description</ENTRY>
<ENTRY>Usage</ENTRY>
</ROW>
</THEAD>
<TBODY>
<ROW>
<ENTRY> &lt; </ENTRY>
<ENTRY>Less than</ENTRY>
<ENTRY>'192.168.1.5'::cidr &lt; '192.168.1.6'::cidr</ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;= </ENTRY>
<ENTRY>Less than or equal</ENTRY>
<ENTRY>'192.168.1.5'::cidr &lt;= '192.168.1.5'::cidr</ENTRY>
</ROW>
<ROW>
<ENTRY> = </ENTRY>
<ENTRY>Equals</ENTRY>
<ENTRY>'192.168.1.5'::cidr = '192.168.1.5'::cidr</ENTRY>
</ROW>
<ROW>
<ENTRY> &gt;= </ENTRY>
<ENTRY>Greater or equal</ENTRY>
<ENTRY>'192.168.1.5'::cidr &gt;= '192.168.1.5'::cidr</ENTRY>
</ROW>
<ROW>
<ENTRY> &gt; </ENTRY>
<ENTRY>Greater</ENTRY>
<ENTRY>'192.168.1.5'::cidr &gt; '192.168.1.4'::cidr</ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;&gt; </ENTRY>
<ENTRY>Not equal</ENTRY>
<ENTRY>'192.168.1.5'::cidr &lt;&gt; '192.168.1.4'::cidr</ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;&lt; </ENTRY>
<ENTRY>is contained within</ENTRY>
<ENTRY>'192.168.1.5'::cidr &lt;&lt; '192.168.1/24'::cidr</ENTRY>
</ROW>
<ROW>
<ENTRY> &lt;&lt;= </ENTRY>
<ENTRY>is contained within or equals</ENTRY>
<ENTRY>'192.168.1/24'::cidr &lt;&lt;= '192.168.1/24'::cidr</ENTRY>
</ROW>
<ROW>
<ENTRY> &gt;&gt; </ENTRY>
<ENTRY>contains</ENTRY>
<ENTRY>'192.168.1/24'::cidr &gt;&gt; '192.168.1.5'::cidr</ENTRY>
</ROW>
<ROW>
<ENTRY> &gt;&gt;= </ENTRY>
<ENTRY>contains or equals</ENTRY>
<ENTRY>'192.168.1/24'::cidr &gt;&gt;= '192.168.1/24'::cidr</ENTRY>
</ROW>
</TBODY>
</TGROUP>
</TABLE>
</sect2>
<sect2 id="inet-operators">
<title><type>inet</> Operators</title>
<table tocentry="1" id="inet-operators-table">
<title><type>inet</> Operators</title>
<TGROUP COLS="3"> <TGROUP COLS="3">
<THEAD> <THEAD>
<ROW> <ROW>
...@@ -892,6 +823,16 @@ logical union ...@@ -892,6 +823,16 @@ logical union
</TBODY> </TBODY>
</TGROUP> </TGROUP>
</TABLE> </TABLE>
<para>
All of the operators for <type>inet</type> can be applied to
<type>cidr</type> values as well. The operators
<literal>&lt;&lt;</> <literal>&lt;&lt;=</>
<literal>&gt;&gt;</> <literal>&gt;&gt;=</>
test for subnet inclusion: they consider only the network parts
of the two addresses, ignoring any host part, and determine whether
one network part is identical to or a subnet of the other.
</para>
</sect2> </sect2>
<sect2 id="macaddr-operators"> <sect2 id="macaddr-operators">
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
*/ */
#if defined(LIBC_SCCS) && !defined(lint) #if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.8 1999/07/17 20:17:56 momjian Exp $"; static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.9 2000/11/10 20:13:25 tgl Exp $";
#endif #endif
...@@ -56,7 +56,7 @@ inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) ...@@ -56,7 +56,7 @@ inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
{ {
switch (af) switch (af)
{ {
case AF_INET: case AF_INET:
return (inet_cidr_ntop_ipv4(src, bits, dst, size)); return (inet_cidr_ntop_ipv4(src, bits, dst, size));
default: default:
errno = EAFNOSUPPORT; errno = EAFNOSUPPORT;
...@@ -102,15 +102,12 @@ inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) ...@@ -102,15 +102,12 @@ inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
/* Format whole octets. */ /* Format whole octets. */
for (b = bits / 8; b > 0; b--) for (b = bits / 8; b > 0; b--)
{ {
if (size < sizeof "255.") if (size < sizeof ".255")
goto emsgsize; goto emsgsize;
t = dst; t = dst;
dst += SPRINTF((dst, "%u", *src++)); if (dst != odst)
if (b > 1)
{
*dst++ = '.'; *dst++ = '.';
*dst = '\0'; dst += SPRINTF((dst, "%u", *src++));
}
size -= (size_t) (dst - t); size -= (size_t) (dst - t);
} }
...@@ -132,6 +129,7 @@ inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) ...@@ -132,6 +129,7 @@ inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
if (size < sizeof "/32") if (size < sizeof "/32")
goto emsgsize; goto emsgsize;
dst += SPRINTF((dst, "/%u", bits)); dst += SPRINTF((dst, "/%u", bits));
return (odst); return (odst);
emsgsize: emsgsize:
...@@ -159,7 +157,7 @@ inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) ...@@ -159,7 +157,7 @@ inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
{ {
switch (af) switch (af)
{ {
case AF_INET: case AF_INET:
return (inet_net_ntop_ipv4(src, bits, dst, size)); return (inet_net_ntop_ipv4(src, bits, dst, size));
default: default:
errno = EAFNOSUPPORT; errno = EAFNOSUPPORT;
...@@ -185,48 +183,34 @@ inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) ...@@ -185,48 +183,34 @@ inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
{ {
char *odst = dst; char *odst = dst;
char *t; char *t;
size_t len = 4; int len = 4;
int b, int b;
tb;
if (bits < 0 || bits > 32) if (bits < 0 || bits > 32)
{ {
errno = EINVAL; errno = EINVAL;
return (NULL); return (NULL);
} }
if (bits == 0)
{
if (size < sizeof "0")
goto emsgsize;
*dst++ = '0';
size--;
*dst = '\0';
}
/* Format whole octets plus nonzero trailing octets. */ /* Always format all four octets, regardless of mask length. */
tb = (bits == 32) ? 31 : bits; for (b = len; b > 0; b--)
for (b = 0; bits != 0 && (b <= (tb / 8) || (b < len && *src != 0)); b++)
{ {
if (size < sizeof "255.") if (size < sizeof ".255")
goto emsgsize; goto emsgsize;
t = dst; t = dst;
dst += SPRINTF((dst, "%u", *src++)); if (dst != odst)
if (b + 1 <= (tb / 8) || (b + 1 < len && *src != 0))
{
*dst++ = '.'; *dst++ = '.';
*dst = '\0'; dst += SPRINTF((dst, "%u", *src++));
}
size -= (size_t) (dst - t); size -= (size_t) (dst - t);
} }
/* don't print masklen if 32 bits */ /* don't print masklen if 32 bits */
if (bits == 32) if (bits != 32)
return odst; {
if (size < sizeof "/32")
/* Format CIDR /width. */ goto emsgsize;
if (size < sizeof "/32") dst += SPRINTF((dst, "/%u", bits));
goto emsgsize; }
dst += SPRINTF((dst, "/%u", bits));
return (odst); return (odst);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* is for IP V4 CIDR notation, but prepared for V6: just * is for IP V4 CIDR notation, but prepared for V6: just
* add the necessary bits where the comments indicate. * add the necessary bits where the comments indicate.
* *
* $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.25 2000/10/27 01:52:15 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.26 2000/11/10 20:13:25 tgl Exp $
* *
* Jon Postel RIP 16 Oct 1998 * Jon Postel RIP 16 Oct 1998
*/ */
...@@ -67,12 +67,12 @@ network_in(char *src, int type) ...@@ -67,12 +67,12 @@ network_in(char *src, int type)
/* /*
* Error check: CIDR values must not have any bits set beyond the masklen. * Error check: CIDR values must not have any bits set beyond the masklen.
* XXX this code not IPV6 ready. * XXX this code is not IPV6 ready.
*/ */
if (type) if (type)
{ {
if (! v4addressOK(ip_v4addr(dst), bits)) if (! v4addressOK(ip_v4addr(dst), bits))
elog(ERROR, "invalid CIDR value '%s': width too small", src); elog(ERROR, "invalid CIDR value '%s': has bits set to right of mask", src);
} }
VARATT_SIZEP(dst) = VARHDRSZ VARATT_SIZEP(dst) = VARHDRSZ
...@@ -338,12 +338,10 @@ network_host(PG_FUNCTION_ARGS) ...@@ -338,12 +338,10 @@ network_host(PG_FUNCTION_ARGS)
char *ptr, char *ptr,
tmp[sizeof("255.255.255.255/32")]; tmp[sizeof("255.255.255.255/32")];
if (ip_type(ip))
elog(ERROR, "CIDR type has no host part");
if (ip_family(ip) == AF_INET) if (ip_family(ip) == AF_INET)
{ {
/* It's an IP V4 address: */ /* It's an IP V4 address: */
/* force display of 32 bits, regardless of masklen... */
if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL) if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL)
elog(ERROR, "unable to print host (%s)", strerror(errno)); elog(ERROR, "unable to print host (%s)", strerror(errno));
} }
...@@ -351,7 +349,7 @@ network_host(PG_FUNCTION_ARGS) ...@@ -351,7 +349,7 @@ network_host(PG_FUNCTION_ARGS)
/* Go for an IPV6 address here, before faulting out: */ /* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "unknown address family (%d)", ip_family(ip)); elog(ERROR, "unknown address family (%d)", ip_family(ip));
/* Suppress /n if present */ /* Suppress /n if present (shouldn't happen now) */
if ((ptr = strchr(tmp, '/')) != NULL) if ((ptr = strchr(tmp, '/')) != NULL)
*ptr = '\0'; *ptr = '\0';
...@@ -363,6 +361,40 @@ network_host(PG_FUNCTION_ARGS) ...@@ -363,6 +361,40 @@ network_host(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(ret); PG_RETURN_TEXT_P(ret);
} }
Datum
network_show(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
text *ret;
int len;
char tmp[sizeof("255.255.255.255/32")];
if (ip_family(ip) == AF_INET)
{
/* It's an IP V4 address: */
/* force display of 32 bits, regardless of masklen... */
if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL)
elog(ERROR, "unable to print host (%s)", strerror(errno));
}
else
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "unknown address family (%d)", ip_family(ip));
/* Add /n if not present */
if (strchr(tmp, '/') == NULL)
{
len = strlen(tmp);
snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(ip));
}
/* Return string as a text datum */
len = strlen(tmp);
ret = (text *) palloc(len + VARHDRSZ);
VARATT_SIZEP(ret) = len + VARHDRSZ;
memcpy(VARDATA(ret), tmp, len);
PG_RETURN_TEXT_P(ret);
}
Datum Datum
network_masklen(PG_FUNCTION_ARGS) network_masklen(PG_FUNCTION_ARGS)
{ {
...@@ -375,100 +407,100 @@ Datum ...@@ -375,100 +407,100 @@ Datum
network_broadcast(PG_FUNCTION_ARGS) network_broadcast(PG_FUNCTION_ARGS)
{ {
inet *ip = PG_GETARG_INET_P(0); inet *ip = PG_GETARG_INET_P(0);
text *ret; inet *dst;
int len;
char *ptr, dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct));
tmp[sizeof("255.255.255.255/32")]; /* make sure any unused bits are zeroed */
MemSet(dst, 0, VARHDRSZ + sizeof(inet_struct));
if (ip_family(ip) == AF_INET) if (ip_family(ip) == AF_INET)
{ {
/* It's an IP V4 address: */ /* It's an IP V4 address: */
int addr;
unsigned long mask = 0xffffffff; unsigned long mask = 0xffffffff;
if (ip_bits(ip) < 32) mask >>= ip_bits(ip);
mask >>= ip_bits(ip);
addr = htonl(ntohl(ip_v4addr(ip)) | mask);
if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL) ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) | mask);
elog(ERROR, "unable to print address (%s)", strerror(errno));
} }
else else
/* Go for an IPV6 address here, before faulting out: */ /* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "unknown address family (%d)", ip_family(ip)); elog(ERROR, "unknown address family (%d)", ip_family(ip));
/* Suppress /n if present */ ip_family(dst) = ip_family(ip);
if ((ptr = strchr(tmp, '/')) != NULL) ip_bits(dst) = ip_bits(ip);
*ptr = '\0'; ip_type(dst) = 0;
VARATT_SIZEP(dst) = VARHDRSZ
+ ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
+ ip_addrsize(dst);
/* Return string as a text datum */ PG_RETURN_INET_P(dst);
len = strlen(tmp);
ret = (text *) palloc(len + VARHDRSZ);
VARATT_SIZEP(ret) = len + VARHDRSZ;
memcpy(VARDATA(ret), tmp, len);
PG_RETURN_TEXT_P(ret);
} }
Datum Datum
network_network(PG_FUNCTION_ARGS) network_network(PG_FUNCTION_ARGS)
{ {
inet *ip = PG_GETARG_INET_P(0); inet *ip = PG_GETARG_INET_P(0);
text *ret; inet *dst;
int len;
char tmp[sizeof("255.255.255.255/32")]; dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct));
/* make sure any unused bits are zeroed */
MemSet(dst, 0, VARHDRSZ + sizeof(inet_struct));
if (ip_family(ip) == AF_INET) if (ip_family(ip) == AF_INET)
{ {
/* It's an IP V4 address: */ /* It's an IP V4 address: */
int addr = htonl(ntohl(ip_v4addr(ip)) & (0xffffffff << (32 - ip_bits(ip)))); unsigned long mask = 0xffffffff;
if (inet_cidr_ntop(AF_INET, &addr, ip_bits(ip), tmp, sizeof(tmp)) == NULL) mask <<= (32 - ip_bits(ip));
elog(ERROR, "unable to print network (%s)", strerror(errno));
ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) & mask);
} }
else else
/* Go for an IPV6 address here, before faulting out: */ /* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "unknown address family (%d)", ip_family(ip)); elog(ERROR, "unknown address family (%d)", ip_family(ip));
/* Return string as a text datum */ ip_family(dst) = ip_family(ip);
len = strlen(tmp); ip_bits(dst) = ip_bits(ip);
ret = (text *) palloc(len + VARHDRSZ); ip_type(dst) = 1;
VARATT_SIZEP(ret) = len + VARHDRSZ; VARATT_SIZEP(dst) = VARHDRSZ
memcpy(VARDATA(ret), tmp, len); + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
PG_RETURN_TEXT_P(ret); + ip_addrsize(dst);
PG_RETURN_INET_P(dst);
} }
Datum Datum
network_netmask(PG_FUNCTION_ARGS) network_netmask(PG_FUNCTION_ARGS)
{ {
inet *ip = PG_GETARG_INET_P(0); inet *ip = PG_GETARG_INET_P(0);
text *ret; inet *dst;
int len;
char *ptr, dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct));
tmp[sizeof("255.255.255.255/32")]; /* make sure any unused bits are zeroed */
MemSet(dst, 0, VARHDRSZ + sizeof(inet_struct));
if (ip_family(ip) == AF_INET) if (ip_family(ip) == AF_INET)
{ {
/* It's an IP V4 address: */ /* It's an IP V4 address: */
int addr = htonl(ip_bits(ip) ? unsigned long mask = 0xffffffff;
(-1 << (32 - ip_bits(ip))) & 0xffffffff : 0x00000000);
mask <<= (32 - ip_bits(ip));
ip_v4addr(dst) = htonl(mask);
if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL) ip_bits(dst) = 32;
elog(ERROR, "unable to print netmask (%s)", strerror(errno));
} }
else else
/* Go for an IPV6 address here, before faulting out: */ /* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "unknown address family (%d)", ip_family(ip)); elog(ERROR, "unknown address family (%d)", ip_family(ip));
/* Suppress /n if present */ ip_family(dst) = ip_family(ip);
if ((ptr = strchr(tmp, '/')) != NULL) ip_type(dst) = 0;
*ptr = '\0'; VARATT_SIZEP(dst) = VARHDRSZ
+ ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
+ ip_addrsize(dst);
/* Return string as a text datum */ PG_RETURN_INET_P(dst);
len = strlen(tmp);
ret = (text *) palloc(len + VARHDRSZ);
VARATT_SIZEP(ret) = len + VARHDRSZ;
memcpy(VARDATA(ret), tmp, len);
PG_RETURN_TEXT_P(ret);
} }
/* /*
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.56 2000/11/08 16:59:50 petere Exp $ * $Id: catversion.h,v 1.57 2000/11/10 20:13:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200011080 #define CATALOG_VERSION_NO 200011101
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.172 2000/11/06 15:58:46 thomas Exp $ * $Id: pg_proc.h,v 1.173 2000/11/10 20:13:26 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -2270,17 +2270,19 @@ DESCR("is-supernet"); ...@@ -2270,17 +2270,19 @@ DESCR("is-supernet");
DATA(insert OID = 930 ( network_supeq PGUID 12 f t t t 2 f 16 "869 869" 100 0 0 100 network_supeq - )); DATA(insert OID = 930 ( network_supeq PGUID 12 f t t t 2 f 16 "869 869" 100 0 0 100 network_supeq - ));
DESCR("is-supernet-or-equal"); DESCR("is-supernet-or-equal");
/* inet/cidr versions */ /* inet/cidr functions */
DATA(insert OID = 696 ( netmask PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_netmask - )); DATA(insert OID = 683 ( network PGUID 12 f t t t 1 f 650 "869" 100 0 0 100 network_network - ));
DESCR("network part of address");
DATA(insert OID = 696 ( netmask PGUID 12 f t t t 1 f 869 "869" 100 0 0 100 network_netmask - ));
DESCR("netmask of address"); DESCR("netmask of address");
DATA(insert OID = 697 ( masklen PGUID 12 f t t t 1 f 23 "869" 100 0 0 100 network_masklen - )); DATA(insert OID = 697 ( masklen PGUID 12 f t t t 1 f 23 "869" 100 0 0 100 network_masklen - ));
DESCR("netmask length"); DESCR("netmask length");
DATA(insert OID = 698 ( broadcast PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_broadcast - )); DATA(insert OID = 698 ( broadcast PGUID 12 f t t t 1 f 869 "869" 100 0 0 100 network_broadcast - ));
DESCR("broadcast address"); DESCR("broadcast address of network");
DATA(insert OID = 699 ( host PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_host - )); DATA(insert OID = 699 ( host PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_host - ));
DESCR("host address"); DESCR("show address octets only");
DATA(insert OID = 683 ( network PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_network - )); DATA(insert OID = 730 ( text PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_show - ));
DESCR("network address"); DESCR("show all parts of inet/cidr value");
DATA(insert OID = 1691 ( boolle PGUID 12 f t t t 2 f 16 "16 16" 100 0 0 100 boolle - )); DATA(insert OID = 1691 ( boolle PGUID 12 f t t t 2 f 16 "16 16" 100 0 0 100 boolle - ));
DESCR("less-than-or-equal"); DESCR("less-than-or-equal");
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: builtins.h,v 1.140 2000/10/24 20:16:47 petere Exp $ * $Id: builtins.h,v 1.141 2000/11/10 20:13:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -504,6 +504,7 @@ extern Datum network_netmask(PG_FUNCTION_ARGS); ...@@ -504,6 +504,7 @@ extern Datum network_netmask(PG_FUNCTION_ARGS);
extern Datum network_masklen(PG_FUNCTION_ARGS); extern Datum network_masklen(PG_FUNCTION_ARGS);
extern Datum network_broadcast(PG_FUNCTION_ARGS); extern Datum network_broadcast(PG_FUNCTION_ARGS);
extern Datum network_host(PG_FUNCTION_ARGS); extern Datum network_host(PG_FUNCTION_ARGS);
extern Datum network_show(PG_FUNCTION_ARGS);
/* mac.c */ /* mac.c */
extern Datum macaddr_in(PG_FUNCTION_ARGS); extern Datum macaddr_in(PG_FUNCTION_ARGS);
......
...@@ -17,7 +17,7 @@ INSERT INTO INET_TBL (c, i) VALUES ('10', '11.1.2.3/8'); ...@@ -17,7 +17,7 @@ INSERT INTO INET_TBL (c, i) VALUES ('10', '11.1.2.3/8');
INSERT INTO INET_TBL (c, i) VALUES ('10', '9.1.2.3/8'); INSERT INTO INET_TBL (c, i) VALUES ('10', '9.1.2.3/8');
-- check that CIDR rejects invalid input: -- check that CIDR rejects invalid input:
INSERT INTO INET_TBL (c, i) VALUES ('192.168.1.2/24', '192.168.1.226'); INSERT INTO INET_TBL (c, i) VALUES ('192.168.1.2/24', '192.168.1.226');
ERROR: invalid CIDR value '192.168.1.2/24': width too small ERROR: invalid CIDR value '192.168.1.2/24': has bits set to right of mask
SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL;
ten | cidr | inet ten | cidr | inet
-----+--------------+------------------ -----+--------------+------------------
...@@ -34,35 +34,35 @@ SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; ...@@ -34,35 +34,35 @@ SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL;
(10 rows) (10 rows)
-- now test some support functions -- now test some support functions
SELECT '' AS ten, i AS inet, host(i) FROM INET_TBL; SELECT '' AS ten, i AS inet, host(i), text(i) FROM INET_TBL;
ten | inet | host ten | inet | host | text
-----+------------------+--------------- -----+------------------+---------------+------------------
| 192.168.1.226/24 | 192.168.1.226 | 192.168.1.226/24 | 192.168.1.226 | 192.168.1.226/24
| 192.168.1.226 | 192.168.1.226 | 192.168.1.226 | 192.168.1.226 | 192.168.1.226/32
| 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8
| 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8
| 10.1.2.3 | 10.1.2.3 | 10.1.2.3 | 10.1.2.3 | 10.1.2.3/32
| 10.1.2.3/24 | 10.1.2.3 | 10.1.2.3/24 | 10.1.2.3 | 10.1.2.3/24
| 10.1.2.3/16 | 10.1.2.3 | 10.1.2.3/16 | 10.1.2.3 | 10.1.2.3/16
| 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8
| 11.1.2.3/8 | 11.1.2.3 | 11.1.2.3/8 | 11.1.2.3 | 11.1.2.3/8
| 9.1.2.3/8 | 9.1.2.3 | 9.1.2.3/8 | 9.1.2.3 | 9.1.2.3/8
(10 rows) (10 rows)
SELECT '' AS ten, c AS cidr, broadcast(c), SELECT '' AS ten, c AS cidr, broadcast(c),
i AS inet, broadcast(i) FROM INET_TBL; i AS inet, broadcast(i) FROM INET_TBL;
ten | cidr | broadcast | inet | broadcast ten | cidr | broadcast | inet | broadcast
-----+--------------+-----------------+------------------+----------------- -----+--------------+------------------+------------------+------------------
| 192.168.1/24 | 192.168.1.255 | 192.168.1.226/24 | 192.168.1.255 | 192.168.1/24 | 192.168.1.255/24 | 192.168.1.226/24 | 192.168.1.255/24
| 192.168.1/24 | 192.168.1.255 | 192.168.1.226 | 255.255.255.255 | 192.168.1/24 | 192.168.1.255/24 | 192.168.1.226 | 255.255.255.255
| 10/8 | 10.255.255.255 | 10.1.2.3/8 | 10.255.255.255 | 10/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8
| 10.0.0.0/32 | 255.255.255.255 | 10.1.2.3/8 | 10.255.255.255 | 10.0.0.0/32 | 255.255.255.255 | 10.1.2.3/8 | 10.255.255.255/8
| 10.1.2.3/32 | 255.255.255.255 | 10.1.2.3 | 255.255.255.255 | 10.1.2.3/32 | 255.255.255.255 | 10.1.2.3 | 255.255.255.255
| 10.1.2/24 | 10.1.2.255 | 10.1.2.3/24 | 10.1.2.255 | 10.1.2/24 | 10.1.2.255/24 | 10.1.2.3/24 | 10.1.2.255/24
| 10.1/16 | 10.1.255.255 | 10.1.2.3/16 | 10.1.255.255 | 10.1/16 | 10.1.255.255/16 | 10.1.2.3/16 | 10.1.255.255/16
| 10/8 | 10.255.255.255 | 10.1.2.3/8 | 10.255.255.255 | 10/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8
| 10/8 | 10.255.255.255 | 11.1.2.3/8 | 11.255.255.255 | 10/8 | 10.255.255.255/8 | 11.1.2.3/8 | 11.255.255.255/8
| 10/8 | 10.255.255.255 | 9.1.2.3/8 | 9.255.255.255 | 10/8 | 10.255.255.255/8 | 9.1.2.3/8 | 9.255.255.255/8
(10 rows) (10 rows)
SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)", SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)",
......
...@@ -23,7 +23,7 @@ SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; ...@@ -23,7 +23,7 @@ SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL;
-- now test some support functions -- now test some support functions
SELECT '' AS ten, i AS inet, host(i) FROM INET_TBL; SELECT '' AS ten, i AS inet, host(i), text(i) FROM INET_TBL;
SELECT '' AS ten, c AS cidr, broadcast(c), SELECT '' AS ten, c AS cidr, broadcast(c),
i AS inet, broadcast(i) FROM INET_TBL; i AS inet, broadcast(i) FROM INET_TBL;
SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)", SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)",
......
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