diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index f3e7aa83abf..11ccc2a9a60 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -1,5 +1,5 @@ <!-- -$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"> @@ -65,7 +65,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.38 2000/10/04 15:47:45 pe <row> <entry>cidr</entry> <entry></entry> - <entry>IP version 4 network or host address</entry> + <entry>IP network address</entry> </row> <row> <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 <row> <entry>inet</entry> <entry></entry> - <entry>IP version 4 network or host address</entry> + <entry>IP network or host address</entry> </row> <row> <entry>int2</entry> @@ -1736,7 +1736,7 @@ January 8 04:05:06 1999 PST <para> <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 specialized operators and functions. @@ -1755,16 +1755,16 @@ January 8 04:05:06 1999 PST <row> <entry>cidr</entry> - <entry>11 bytes</entry> + <entry>12 bytes</entry> <entry>IP networks</entry> <entry>valid IPv4 networks</entry> </row> <row> <entry>inet</entry> - <entry>11 bytes</entry> + <entry>12 bytes</entry> <entry>IP hosts and networks</entry> - <entry>valid IPv4 hosts</entry> + <entry>valid IPv4 hosts or networks</entry> </row> <row> @@ -1784,19 +1784,48 @@ January 8 04:05:06 1999 PST </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"> <title><type>cidr</></title> <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 class="parameter">x.x.x.x/y</> where <replaceable class="parameter">x.x.x.x</> is the network and <replaceable class="parameter">y</> is the number of bits in the netmask. If <replaceable class="parameter">y</> omitted, it is calculated - using assumptions from the older classfull naming system except - that it is extended to include at least all of the octets in the - input. + using assumptions from the older classful numbering system, except + that it will be at least large enough to include all of the octets + written in the input. </para> <para> @@ -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> </row> + <row> + <entry>192.168/24</entry> + <entry>192.168.0/24</entry> + </row> <row> <entry>192.168/25</entry> <entry>192.168.0.0/25</entry> @@ -1856,30 +1889,19 @@ January 8 04:05:06 1999 PST </tgroup> </table> </para> - </sect2> - - <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. - Note that if you want to store networks only, you should use the - <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 - can be non-zero. Functions exist to extract the various elements - of the field. - </para> + The essential difference between <type>inet</type> and <type>cidr</type> + data types is that <type>inet</type> accepts values with nonzero bits to + the right of the netmask, whereas <type>cidr</type> does not. - <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 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. + <tip> + <para> + If you do not like the output format for <type>inet</type> or + <type>cidr</type> values, try the <function>host</>() and + <function>text</>() functions. + </para> + </tip> </para> </sect2> diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index c51e8905e10..655c63a7931 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1480,62 +1480,98 @@ Not defined by this name. Implements the intersection operator '#' <para> <table tocentry="1" id="cidr-inet-functions"> <title><type>cidr</> and <type>inet</> Functions</title> - <tgroup cols="4"> + <tgroup cols="5"> <thead> <row> <entry>Function</entry> <entry>Returns</entry> <entry>Description</entry> <entry>Example</entry> + <entry>Result</entry> </row> </thead> <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> <entry>broadcast(inet)</entry> - <entry>text</entry> - <entry>construct broadcast address as text</entry> + <entry>inet</entry> + <entry>broadcast address for network</entry> <entry>broadcast('192.168.1.5/24')</entry> + <entry>192.168.1.255/24</entry> </row> <row> <entry>host(inet)</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> - </row> - <row> - <entry>masklen(cidr)</entry> - <entry>integer</entry> - <entry>calculate netmask length</entry> - <entry>masklen('192.168.1.5/24')</entry> + <entry>192.168.1.5</entry> </row> <row> <entry>masklen(inet)</entry> <entry>integer</entry> - <entry>calculate netmask length</entry> + <entry>extract netmask length</entry> <entry>masklen('192.168.1.5/24')</entry> + <entry>24</entry> </row> <row> <entry>netmask(inet)</entry> - <entry>text</entry> - <entry>construct netmask as text</entry> + <entry>inet</entry> + <entry>construct netmask for network</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> + </thead> + <tbody> <row> <entry>trunc(macaddr)</entry> <entry>macaddr</entry> <entry>set last 3 bytes to zero</entry> <entry>trunc(macaddr '12:34:56:78:90:ab')</entry> + <entry>12:34:56:00:00:00</entry> </row> </tbody> </tgroup> </table> + </para> + <para> The function <function>trunc</>(<type>macaddr</>) returns a MAC address with the last 3 bytes set to 0. This can be used to associate the remaining prefix with a manufacturer. The directory diff --git a/doc/src/sgml/oper.sgml b/doc/src/sgml/oper.sgml index deb3d33cde8..8934323cd05 100644 --- a/doc/src/sgml/oper.sgml +++ b/doc/src/sgml/oper.sgml @@ -1,5 +1,5 @@ <!-- -$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"> @@ -756,80 +756,11 @@ logical union <sect1 id="net-operators"> <title>Network Address Type Operators</title> - <sect2 id="cidr-operators"> - <title><type>cidr</> Operators</title> + <sect2 id="cidr-inet-operators"> + <title><type>cidr</> and <type>inet</> Operators</title> - <table tocentry="1" id="cidr-operators-table"> - <title><type>cidr</> Operators</title> - <TGROUP COLS="3"> - <THEAD> - <ROW> - <ENTRY>Operator</ENTRY> - <ENTRY>Description</ENTRY> - <ENTRY>Usage</ENTRY> - </ROW> - </THEAD> - <TBODY> - <ROW> - <ENTRY> < </ENTRY> - <ENTRY>Less than</ENTRY> - <ENTRY>'192.168.1.5'::cidr < '192.168.1.6'::cidr</ENTRY> - </ROW> - <ROW> - <ENTRY> <= </ENTRY> - <ENTRY>Less than or equal</ENTRY> - <ENTRY>'192.168.1.5'::cidr <= '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> >= </ENTRY> - <ENTRY>Greater or equal</ENTRY> - <ENTRY>'192.168.1.5'::cidr >= '192.168.1.5'::cidr</ENTRY> - </ROW> - <ROW> - <ENTRY> > </ENTRY> - <ENTRY>Greater</ENTRY> - <ENTRY>'192.168.1.5'::cidr > '192.168.1.4'::cidr</ENTRY> - </ROW> - <ROW> - <ENTRY> <> </ENTRY> - <ENTRY>Not equal</ENTRY> - <ENTRY>'192.168.1.5'::cidr <> '192.168.1.4'::cidr</ENTRY> - </ROW> - <ROW> - <ENTRY> << </ENTRY> - <ENTRY>is contained within</ENTRY> - <ENTRY>'192.168.1.5'::cidr << '192.168.1/24'::cidr</ENTRY> - </ROW> - <ROW> - <ENTRY> <<= </ENTRY> - <ENTRY>is contained within or equals</ENTRY> - <ENTRY>'192.168.1/24'::cidr <<= '192.168.1/24'::cidr</ENTRY> - </ROW> - <ROW> - <ENTRY> >> </ENTRY> - <ENTRY>contains</ENTRY> - <ENTRY>'192.168.1/24'::cidr >> '192.168.1.5'::cidr</ENTRY> - </ROW> - <ROW> - <ENTRY> >>= </ENTRY> - <ENTRY>contains or equals</ENTRY> - <ENTRY>'192.168.1/24'::cidr >>= '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> + <table tocentry="1" id="cidr-inet-operators-table"> + <title><type>cidr</> and <type>inet</> Operators</title> <TGROUP COLS="3"> <THEAD> <ROW> @@ -892,6 +823,16 @@ logical union </TBODY> </TGROUP> </TABLE> + + <para> + All of the operators for <type>inet</type> can be applied to + <type>cidr</type> values as well. The operators + <literal><<</> <literal><<=</> + <literal>>></> <literal>>>=</> + test for subnet inclusion: they consider only the network parts + of the two addresses, ignoring any host part, and determine whether + one network part is identical to or a subnet of the other. + </para> </sect2> <sect2 id="macaddr-operators"> diff --git a/src/backend/utils/adt/inet_net_ntop.c b/src/backend/utils/adt/inet_net_ntop.c index c38ecc5a6f2..ecc83cab814 100644 --- a/src/backend/utils/adt/inet_net_ntop.c +++ b/src/backend/utils/adt/inet_net_ntop.c @@ -16,7 +16,7 @@ */ #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 @@ -56,7 +56,7 @@ inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) { switch (af) { - case AF_INET: + case AF_INET: return (inet_cidr_ntop_ipv4(src, bits, dst, size)); default: errno = EAFNOSUPPORT; @@ -102,15 +102,12 @@ inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) /* Format whole octets. */ for (b = bits / 8; b > 0; b--) { - if (size < sizeof "255.") + if (size < sizeof ".255") goto emsgsize; t = dst; - dst += SPRINTF((dst, "%u", *src++)); - if (b > 1) - { + if (dst != odst) *dst++ = '.'; - *dst = '\0'; - } + dst += SPRINTF((dst, "%u", *src++)); size -= (size_t) (dst - t); } @@ -132,6 +129,7 @@ inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) if (size < sizeof "/32") goto emsgsize; dst += SPRINTF((dst, "/%u", bits)); + return (odst); emsgsize: @@ -159,7 +157,7 @@ inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) { switch (af) { - case AF_INET: + case AF_INET: return (inet_net_ntop_ipv4(src, bits, dst, size)); default: errno = EAFNOSUPPORT; @@ -185,48 +183,34 @@ inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) { char *odst = dst; char *t; - size_t len = 4; - int b, - tb; + int len = 4; + int b; if (bits < 0 || bits > 32) { errno = EINVAL; return (NULL); } - if (bits == 0) - { - if (size < sizeof "0") - goto emsgsize; - *dst++ = '0'; - size--; - *dst = '\0'; - } - /* Format whole octets plus nonzero trailing octets. */ - tb = (bits == 32) ? 31 : bits; - for (b = 0; bits != 0 && (b <= (tb / 8) || (b < len && *src != 0)); b++) + /* Always format all four octets, regardless of mask length. */ + for (b = len; b > 0; b--) { - if (size < sizeof "255.") + if (size < sizeof ".255") goto emsgsize; t = dst; - dst += SPRINTF((dst, "%u", *src++)); - if (b + 1 <= (tb / 8) || (b + 1 < len && *src != 0)) - { + if (dst != odst) *dst++ = '.'; - *dst = '\0'; - } + dst += SPRINTF((dst, "%u", *src++)); size -= (size_t) (dst - t); } /* don't print masklen if 32 bits */ - if (bits == 32) - return odst; - - /* Format CIDR /width. */ - if (size < sizeof "/32") - goto emsgsize; - dst += SPRINTF((dst, "/%u", bits)); + if (bits != 32) + { + if (size < sizeof "/32") + goto emsgsize; + dst += SPRINTF((dst, "/%u", bits)); + } return (odst); diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index a3070f29e76..52f4e8ecd2f 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -3,7 +3,7 @@ * is for IP V4 CIDR notation, but prepared for V6: just * 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 */ @@ -67,12 +67,12 @@ network_in(char *src, int type) /* * 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 (! 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 @@ -338,12 +338,10 @@ network_host(PG_FUNCTION_ARGS) char *ptr, 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) { /* 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)); } @@ -351,7 +349,7 @@ network_host(PG_FUNCTION_ARGS) /* Go for an IPV6 address here, before faulting out: */ 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) *ptr = '\0'; @@ -363,6 +361,40 @@ network_host(PG_FUNCTION_ARGS) 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 network_masklen(PG_FUNCTION_ARGS) { @@ -375,100 +407,100 @@ Datum network_broadcast(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); - text *ret; - int len; - char *ptr, - tmp[sizeof("255.255.255.255/32")]; + inet *dst; + + 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) { /* It's an IP V4 address: */ - int addr; unsigned long mask = 0xffffffff; - if (ip_bits(ip) < 32) - mask >>= ip_bits(ip); - addr = htonl(ntohl(ip_v4addr(ip)) | mask); + mask >>= ip_bits(ip); - if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL) - elog(ERROR, "unable to print address (%s)", strerror(errno)); + ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) | mask); } else /* Go for an IPV6 address here, before faulting out: */ elog(ERROR, "unknown address family (%d)", ip_family(ip)); - /* Suppress /n if present */ - if ((ptr = strchr(tmp, '/')) != NULL) - *ptr = '\0'; + ip_family(dst) = ip_family(ip); + ip_bits(dst) = ip_bits(ip); + ip_type(dst) = 0; + VARATT_SIZEP(dst) = VARHDRSZ + + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst)) + + ip_addrsize(dst); - /* 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); + PG_RETURN_INET_P(dst); } Datum network_network(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); - text *ret; - int len; - char tmp[sizeof("255.255.255.255/32")]; + inet *dst; + + 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) { /* 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) - elog(ERROR, "unable to print network (%s)", strerror(errno)); + mask <<= (32 - ip_bits(ip)); + + ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) & mask); } else /* Go for an IPV6 address here, before faulting out: */ elog(ERROR, "unknown address family (%d)", ip_family(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); + ip_family(dst) = ip_family(ip); + ip_bits(dst) = ip_bits(ip); + ip_type(dst) = 1; + VARATT_SIZEP(dst) = VARHDRSZ + + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst)) + + ip_addrsize(dst); + + PG_RETURN_INET_P(dst); } Datum network_netmask(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); - text *ret; - int len; - char *ptr, - tmp[sizeof("255.255.255.255/32")]; + inet *dst; + + 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) { /* It's an IP V4 address: */ - int addr = htonl(ip_bits(ip) ? - (-1 << (32 - ip_bits(ip))) & 0xffffffff : 0x00000000); + unsigned long mask = 0xffffffff; - if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL) - elog(ERROR, "unable to print netmask (%s)", strerror(errno)); + mask <<= (32 - ip_bits(ip)); + + ip_v4addr(dst) = htonl(mask); + + ip_bits(dst) = 32; } else /* Go for an IPV6 address here, before faulting out: */ elog(ERROR, "unknown address family (%d)", ip_family(ip)); - /* Suppress /n if present */ - if ((ptr = strchr(tmp, '/')) != NULL) - *ptr = '\0'; + ip_family(dst) = ip_family(ip); + ip_type(dst) = 0; + VARATT_SIZEP(dst) = VARHDRSZ + + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst)) + + ip_addrsize(dst); - /* 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); + PG_RETURN_INET_P(dst); } /* diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 01efe5efb98..bf66917aa7f 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * 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 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200011080 +#define CATALOG_VERSION_NO 200011101 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 30a7b2d9982..11f20071c7e 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * 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 * The script catalog/genbki.sh reads this file and generates .bki @@ -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 - )); DESCR("is-supernet-or-equal"); -/* inet/cidr versions */ -DATA(insert OID = 696 ( netmask PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_netmask - )); +/* inet/cidr functions */ +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"); DATA(insert OID = 697 ( masklen PGUID 12 f t t t 1 f 23 "869" 100 0 0 100 network_masklen - )); DESCR("netmask length"); -DATA(insert OID = 698 ( broadcast PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_broadcast - )); -DESCR("broadcast address"); +DATA(insert OID = 698 ( broadcast PGUID 12 f t t t 1 f 869 "869" 100 0 0 100 network_broadcast - )); +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 - )); -DESCR("host address"); -DATA(insert OID = 683 ( network PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_network - )); -DESCR("network address"); +DESCR("show address octets only"); +DATA(insert OID = 730 ( text PGUID 12 f t t t 1 f 25 "869" 100 0 0 100 network_show - )); +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 - )); DESCR("less-than-or-equal"); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 446c33cc420..f6a4055bb1d 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * 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); extern Datum network_masklen(PG_FUNCTION_ARGS); extern Datum network_broadcast(PG_FUNCTION_ARGS); extern Datum network_host(PG_FUNCTION_ARGS); +extern Datum network_show(PG_FUNCTION_ARGS); /* mac.c */ extern Datum macaddr_in(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out index daa9cded133..6f86056c013 100644 --- a/src/test/regress/expected/inet.out +++ b/src/test/regress/expected/inet.out @@ -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'); -- check that CIDR rejects invalid input: 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; ten | cidr | inet -----+--------------+------------------ @@ -34,35 +34,35 @@ SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; (10 rows) -- now test some support functions -SELECT '' AS ten, i AS inet, host(i) FROM INET_TBL; - ten | inet | host ------+------------------+--------------- - | 192.168.1.226/24 | 192.168.1.226 - | 192.168.1.226 | 192.168.1.226 - | 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/24 | 10.1.2.3 - | 10.1.2.3/16 | 10.1.2.3 - | 10.1.2.3/8 | 10.1.2.3 - | 11.1.2.3/8 | 11.1.2.3 - | 9.1.2.3/8 | 9.1.2.3 +SELECT '' AS ten, i AS inet, host(i), text(i) FROM INET_TBL; + 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 | 192.168.1.226/32 + | 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 | 10.1.2.3/32 + | 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/8 | 10.1.2.3 | 10.1.2.3/8 + | 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 (10 rows) SELECT '' AS ten, c AS cidr, broadcast(c), i AS inet, broadcast(i) FROM INET_TBL; - 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 | 192.168.1.226 | 255.255.255.255 - | 10/8 | 10.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 - | 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/16 | 10.1.255.255 | 10.1.2.3/16 | 10.1.255.255 - | 10/8 | 10.255.255.255 | 10.1.2.3/8 | 10.255.255.255 - | 10/8 | 10.255.255.255 | 11.1.2.3/8 | 11.255.255.255 - | 10/8 | 10.255.255.255 | 9.1.2.3/8 | 9.255.255.255 + ten | cidr | broadcast | inet | broadcast +-----+--------------+------------------+------------------+------------------ + | 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/24 | 192.168.1.226 | 255.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/8 + | 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/24 | 10.1.2.3/24 | 10.1.2.255/24 + | 10.1/16 | 10.1.255.255/16 | 10.1.2.3/16 | 10.1.255.255/16 + | 10/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8 + | 10/8 | 10.255.255.255/8 | 11.1.2.3/8 | 11.255.255.255/8 + | 10/8 | 10.255.255.255/8 | 9.1.2.3/8 | 9.255.255.255/8 (10 rows) SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)", diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql index e225b2824f7..d91c3a0bbf0 100644 --- a/src/test/regress/sql/inet.sql +++ b/src/test/regress/sql/inet.sql @@ -23,7 +23,7 @@ SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; -- 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), i AS inet, broadcast(i) FROM INET_TBL; SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)",