Re: ipv6 patch #3

From: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
To: Michael Graff <explorer(at)flame(dot)org>
Cc: pgsql-patches(at)postgresql(dot)org
Subject: Re: ipv6 patch #3
Date: 2003-05-31 02:15:22
Message-ID: 200305310215.h4V2FMx10958@candle.pha.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-patches


Your patch has been added to the PostgreSQL unapplied patches list at:

http://momjian.postgresql.org/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------

Michael Graff wrote:
> This includes several revisions from others.
>
> Major changes:
>
> Add ipv6 address parsing support to 'inet' and 'cidr' data types.
>
> Regression tests for IPv6 operations added.
>
> Documentation updated to document IPv6 bits.
>
> Stop treating IPv4 as an "unsigned int" and IPv6 as an array of
> characters. Instead, always use the array of characters so we
> can have one function fits all. This makes bitncmp(), addressOK(),
> and several other functions "just work" on both address families.
>
> add family() function which returns integer 4 or 6 for IPv4 or
> IPv6. (See examples below) Note that to add this new function
> you will need to dump/initdb/reload or find the correct magic
> to add the function to the postgresql function catalogs.
>
> IPv4 addresses always sort before IPv6.
>
> On disk we use AF_INET for IPv4, and AF_INET+1 for IPv6 addresses.
> This prevents the need for a dump and reload, but lets IPv6 parsing
> work on machines without AF_INET6.
>
> To select all IPv4 addresses from a table:
>
> select * from foo where family(addr) = 4 ...
>
> Order by and other bits should all work.
>
> Regression tests pass, at least on my NetBSD machine.
>
> --Michael
>
> diff -ur orig-postgresql-7.3.2/doc/src/sgml/datatype.sgml postgresql-7.3.2/doc/src/sgml/datatype.sgml
> --- orig-postgresql-7.3.2/doc/src/sgml/datatype.sgml 2003-01-28 17:09:03.000000000 -0800
> +++ postgresql-7.3.2/doc/src/sgml/datatype.sgml 2003-04-22 17:18:52.000000000 -0700
> @@ -101,7 +101,7 @@
> <row>
> <entry><type>cidr</type></entry>
> <entry></entry>
> - <entry>IP network address</entry>
> + <entry>IPv4 or IPc6 network address</entry>
> </row>
>
> <row>
> @@ -125,7 +125,7 @@
> <row>
> <entry><type>inet</type></entry>
> <entry></entry>
> - <entry>IP host address</entry>
> + <entry>IPv4 or IPv6 host address</entry>
> </row>
>
> <row>
> @@ -2538,7 +2538,7 @@
> </indexterm>
>
> <para>
> - <productname>PostgreSQL</> offers data types to store IP and MAC
> + <productname>PostgreSQL</> offers data types to store IPv4, IPv6, and MAC
> addresses, shown in <xref linkend="datatype-net-types-table">. It
> is preferable to use these types over plain text types, because
> these types offer input error checking and several specialized
> @@ -2560,16 +2560,16 @@
>
> <row>
> <entry><type>cidr</type></entry>
> - <entry>12 bytes</entry>
> + <entry>12 or 24 bytes</entry>
> <entry>IP networks</entry>
> - <entry>valid IPv4 networks</entry>
> + <entry>valid IPv4 or IPv6 networks</entry>
> </row>
>
> <row>
> <entry><type>inet</type></entry>
> - <entry>12 bytes</entry>
> + <entry>12 or 24 bytes</entry>
> <entry>IP hosts and networks</entry>
> - <entry>valid IPv4 hosts or networks</entry>
> + <entry>valid IPv4 or IPv6 hosts or networks</entry>
> </row>
>
> <row>
> @@ -2584,7 +2584,10 @@
> </table>
>
> <para>
> - IPv6 is not yet supported.
> + When sorting <type>inet</type> or <type>cidr</type> data types,
> + IPv4 addresses will always sort before IPv6 addresses, including
> + IPv4 addresses encapsulated or mapped into IPv6 addresses, such as
> + ::10.2.3.4 or ::ffff::10.4.3.2.
> </para>
>
>
> @@ -2596,26 +2599,31 @@
> </indexterm>
>
> <para>
> - The <type>inet</type> type holds an IP host address, and
> + The <type>inet</type> type holds an IPv4 or IPv6 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 <quote>netmask</quote>). If the
> - netmask is 32,
> - then the value does not indicate a subnet, only a single host.
> + netmask is 32 and the address is IPv4, then the value does not
> + indicate a subnet, only a single host. In IPv6, the address
> + length is 128 bits.
> 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.
> + The input format for this type is
> + <replaceable class="parameter">address/y</replaceable>
> + where
> + <replaceable class="parameter">address</replaceable>
> + is an IPv4 or IPv6 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 for IPv4 and 128 for IPv6, and the value represents
> + just a single host. On display, the
> + <replaceable class="parameter">/y</replaceable>
> + portion is suppressed if the netmask specifies a single host.
> </para>
> </sect2>
>
> @@ -2627,13 +2635,14 @@
> </indexterm>
>
> <para>
> - The <type>cidr</type> type holds an IP network specification.
> + The <type>cidr</type> type holds an IPv4 or IPv6 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">address/y</> where <replaceable
> + class="parameter">address</> is the network represented as an
> + IPv4 or IPv6 address, and <replaceable
> class="parameter">y</> is the number of bits in the netmask. If
> <replaceable class="parameter">y</> is omitted, it is calculated
> using assumptions from the older classful numbering system, except
> @@ -2711,6 +2720,28 @@
> <entry>10.0.0.0/8</entry>
> <entry>10/8</entry>
> </row>
> + <row>
> + <entry>10.1.2.3/32</entry>
> + <entry>10.1.2.3/32</entry>
> + <entry>10.1.2.3/32</entry>
> + <row>
> + <entry>2001:4f8:3:ba::/64</entry>
> + <entry>2001:4f8:3:ba::/64</entry>
> + <entry>2001:4f8:3:ba::/64</entry>
> + </row>
> + <row>
> + <entry>2001:4f8:3:ba:2e0:81ff:fe22:d1f1/128</entry>
> + <entry>2001:4f8:3:ba:2e0:81ff:fe22:d1f1/128</entry>
> + <entry>2001:4f8:3:ba:2e0:81ff:fe22:d1f1</entry>
> + </row>
> + <row>
> + <entry>::ffff:1.2.3.0/120</entry>
> + <entry>::ffff:1.2.3.0/120</entry>
> + <entry>::ffff:1.2.3/120</entry>
> + <row>
> + <entry>::ffff:1.2.3.0/128</entry>
> + <entry>::ffff:1.2.3.0/128</entry>
> + <entry>::ffff:1.2.3.0/128</entry>
> </tbody>
> </tgroup>
> </table>
> diff -ur orig-postgresql-7.3.2/doc/src/sgml/func.sgml postgresql-7.3.2/doc/src/sgml/func.sgml
> --- orig-postgresql-7.3.2/doc/src/sgml/func.sgml 2003-01-22 17:23:14.000000000 -0800
> +++ postgresql-7.3.2/doc/src/sgml/func.sgml 2003-04-22 17:20:23.000000000 -0700
> @@ -4886,6 +4886,11 @@
> <entry><literal>inet '192.168.1.5' &lt; inet '192.168.1.6'</literal></entry>
> </row>
> <row>
> + <entry> &lt; </entry>
> + <entry>Less than</entry>
> + <entry><literal>inet '1111::2222' &lt; inet '2222::1111'</literal></entry>
> + </row>
> + <row>
> <entry> &lt;= </entry>
> <entry>Less than or equal</entry>
> <entry><literal>inet '192.168.1.5' &lt;= inet '192.168.1.5'</literal></entry>
> diff -ur orig-postgresql-7.3.2/src/backend/utils/adt/inet_net_ntop.c postgresql-7.3.2/src/backend/utils/adt/inet_net_ntop.c
> --- orig-postgresql-7.3.2/src/backend/utils/adt/inet_net_ntop.c 2002-09-01 19:47:04.000000000 -0700
> +++ postgresql-7.3.2/src/backend/utils/adt/inet_net_ntop.c 2003-04-22 17:12:05.000000000 -0700
> @@ -27,8 +27,12 @@
>
> #include <errno.h>
>
> +#include "utils/inet.h"
> #include "utils/builtins.h"
>
> +#define NS_IN6ADDRSZ 16
> +#define NS_INT16SZ 2
> +
> #ifdef SPRINTF_CHAR
> #define SPRINTF(x) strlen(sprintf/**/x)
> #else
> @@ -36,9 +40,13 @@
> #endif
>
> static char *inet_net_ntop_ipv4(const u_char *src, int bits,
> - char *dst, size_t size);
> + char *dst, size_t size);
> static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
> - char *dst, size_t size);
> + char *dst, size_t size);
> +static char *inet_net_ntop_ipv6(const u_char *src, int bits,
> + char *dst, size_t size);
> +static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
> + char *dst, size_t size);
>
> /*
> * char *
> @@ -55,8 +63,10 @@
> {
> switch (af)
> {
> - case AF_INET:
> + case PGSQL_AF_INET:
> return (inet_cidr_ntop_ipv4(src, bits, dst, size));
> + case PGSQL_AF_INET6:
> + return (inet_cidr_ntop_ipv6(src, bits, dst, size));
> default:
> errno = EAFNOSUPPORT;
> return (NULL);
> @@ -136,6 +146,148 @@
> return (NULL);
> }
>
> +/*
> + * static char *
> + * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
> + * convert IPv6 network number from network to presentation format.
> + * generates CIDR style result always. Picks the shortest representation
> + * unless the IP is really IPv4.
> + * always prints specified number of bits (bits).
> + * return:
> + * pointer to dst, or NULL if an error occurred (check errno).
> + * note:
> + * network byte order assumed. this means 192.5.5.240/28 has
> + * 0x11110000 in its fourth octet.
> + * author:
> + * Vadim Kogan (UCB), June 2001
> + * Original version (IPv4) by Paul Vixie (ISC), July 1996
> + */
> +
> +static char *
> +inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
> +{
> + u_int m;
> + int b;
> + int p;
> + int zero_s, zero_l, tmp_zero_s, tmp_zero_l;
> + int i;
> + int is_ipv4 = 0;
> + int double_colon = 0;
> + unsigned char inbuf[16];
> + char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
> + char *cp;
> + int words;
> + u_char *s;
> +
> + if (bits < 0 || bits > 128) {
> + errno = EINVAL;
> + return (NULL);
> + }
> +
> + cp = outbuf;
> + double_colon = 0;
> +
> + if (bits == 0) {
> + *cp++ = ':';
> + *cp++ = ':';
> + *cp = '\0';
> + double_colon = 1;
> + } else {
> + /* Copy src to private buffer. Zero host part. */
> + p = (bits + 7) / 8;
> + memcpy(inbuf, src, p);
> + memset(inbuf + p, 0, 16 - p);
> + b = bits % 8;
> + if (b != 0) {
> + m = ~0 << (8 - b);
> + inbuf[p-1] &= m;
> + }
> +
> + s = inbuf;
> +
> + /* how many words need to be displayed in output */
> + words = (bits + 15) / 16;
> + if (words == 1)
> + words = 2;
> +
> + /* Find the longest substring of zero's */
> + zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
> + for (i = 0; i < (words * 2); i += 2) {
> + if ((s[i] | s[i+1]) == 0) {
> + if (tmp_zero_l == 0)
> + tmp_zero_s = i / 2;
> + tmp_zero_l++;
> + } else {
> + if (tmp_zero_l && zero_l < tmp_zero_l) {
> + zero_s = tmp_zero_s;
> + zero_l = tmp_zero_l;
> + tmp_zero_l = 0;
> + }
> + }
> + }
> +
> + if (tmp_zero_l && zero_l < tmp_zero_l) {
> + zero_s = tmp_zero_s;
> + zero_l = tmp_zero_l;
> + }
> +
> + if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
> + ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
> + ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
> + is_ipv4 = 1;
> +
> + /* Format whole words. */
> + for (p = 0; p < words; p++) {
> + if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
> + /* Time to skip some zeros */
> + if (p == zero_s)
> + *cp++ = ':';
> + if (p == words - 1) {
> + *cp++ = ':';
> + double_colon = 1;
> + }
> + s++;
> + s++;
> + continue;
> + }
> +
> + if (is_ipv4 && p > 5 ) {
> + *cp++ = (p == 6) ? ':' : '.';
> + cp += SPRINTF((cp, "%u", *s++));
> + /* we can potentially drop the last octet */
> + if (p != 7 || bits > 120) {
> + *cp++ = '.';
> + cp += SPRINTF((cp, "%u", *s++));
> + }
> + } else {
> + if (cp != outbuf)
> + *cp++ = ':';
> + cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
> + s += 2;
> + }
> + }
> + }
> +
> + if (!double_colon) {
> + if (bits < 128 - 32)
> + cp += SPRINTF((cp, "::", bits));
> + else if (bits < 128 - 16)
> + cp += SPRINTF((cp, ":0", bits));
> + }
> +
> + /* Format CIDR /width. */
> + SPRINTF((cp, "/%u", bits));
> +
> + if (strlen(outbuf) + 1 > size)
> + goto emsgsize;
> + strcpy(dst, outbuf);
> +
> + return (dst);
> +
> +emsgsize:
> + errno = EMSGSIZE;
> + return (NULL);
> +}
>
> /*
> * char *
> @@ -156,8 +308,10 @@
> {
> switch (af)
> {
> - case AF_INET:
> + case PGSQL_AF_INET:
> return (inet_net_ntop_ipv4(src, bits, dst, size));
> + case PGSQL_AF_INET6:
> + return (inet_net_ntop_ipv6(src, bits, dst, size));
> default:
> errno = EAFNOSUPPORT;
> return (NULL);
> @@ -217,3 +371,127 @@
> errno = EMSGSIZE;
> return (NULL);
> }
> +
> +static int
> +decoct(const u_char *src, int bytes, char *dst, size_t size) {
> + char *odst = dst;
> + char *t;
> + int b;
> +
> + for (b = 1; b <= bytes; b++) {
> + if (size < sizeof "255.")
> + return (0);
> + t = dst;
> + dst += SPRINTF((dst, "%u", *src++));
> + if (b != bytes) {
> + *dst++ = '.';
> + *dst = '\0';
> + }
> + size -= (size_t)(dst - t);
> + }
> + return (dst - odst);
> +}
> +
> +static char *
> +inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
> +{
> + /*
> + * Note that int32_t and int16_t need only be "at least" large enough
> + * to contain a value of the specified size. On some systems, like
> + * Crays, there is no such thing as an integer variable with 16 bits.
> + * Keep this in mind if you think this function should have been coded
> + * to use pointer overlays. All the world's not a VAX.
> + */
> + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
> + char *tp;
> + struct { int base, len; } best, cur;
> + u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
> + int i;
> +
> + if ((bits < -1) || (bits > 128)) {
> + errno = EINVAL;
> + return (NULL);
> + }
> +
> + /*
> + * Preprocess:
> + * Copy the input (bytewise) array into a wordwise array.
> + * Find the longest run of 0x00's in src[] for :: shorthanding.
> + */
> + memset(words, '\0', sizeof words);
> + for (i = 0; i < NS_IN6ADDRSZ; i++)
> + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
> + best.base = -1;
> + cur.base = -1;
> + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
> + if (words[i] == 0) {
> + if (cur.base == -1)
> + cur.base = i, cur.len = 1;
> + else
> + cur.len++;
> + } else {
> + if (cur.base != -1) {
> + if (best.base == -1 || cur.len > best.len)
> + best = cur;
> + cur.base = -1;
> + }
> + }
> + }
> + if (cur.base != -1) {
> + if (best.base == -1 || cur.len > best.len)
> + best = cur;
> + }
> + if (best.base != -1 && best.len < 2)
> + best.base = -1;
> +
> + /*
> + * Format the result.
> + */
> + tp = tmp;
> + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
> + /* Are we inside the best run of 0x00's? */
> + if (best.base != -1 && i >= best.base &&
> + i < (best.base + best.len)) {
> + if (i == best.base)
> + *tp++ = ':';
> + continue;
> + }
> + /* Are we following an initial run of 0x00s or any real hex? */
> + if (i != 0)
> + *tp++ = ':';
> + /* Is this address an encapsulated IPv4? */
> + if (i == 6 && best.base == 0 && (best.len == 6 ||
> + (best.len == 7 && words[7] != 0x0001) ||
> + (best.len == 5 && words[5] == 0xffff))) {
> + int n;
> +
> + n = decoct(src+12, 4, tp, sizeof tmp - (tp - tmp));
> + if (n == 0) {
> + errno = EMSGSIZE;
> + return (NULL);
> + }
> + tp += strlen(tp);
> + break;
> + }
> + tp += SPRINTF((tp, "%x", words[i]));
> + }
> +
> + /* Was it a trailing run of 0x00's? */
> + if (best.base != -1 && (best.base + best.len) ==
> + (NS_IN6ADDRSZ / NS_INT16SZ))
> + *tp++ = ':';
> + *tp = '\0';
> +
> + if (bits != -1 && bits != 128)
> + tp += SPRINTF((tp, "/%u", bits));
> +
> + /*
> + * Check for overflow, copy, and we're done.
> + */
> + if ((size_t)(tp - tmp) > size) {
> + errno = EMSGSIZE;
> + return (NULL);
> + }
> + strcpy(dst, tmp);
> + return (dst);
> +}
> diff -ur orig-postgresql-7.3.2/src/backend/utils/adt/inet_net_pton.c postgresql-7.3.2/src/backend/utils/adt/inet_net_pton.c
> --- orig-postgresql-7.3.2/src/backend/utils/adt/inet_net_pton.c 2002-09-01 19:47:04.000000000 -0700
> +++ postgresql-7.3.2/src/backend/utils/adt/inet_net_pton.c 2003-04-22 13:02:07.000000000 -0700
> @@ -29,16 +29,14 @@
> #include <ctype.h>
> #include <errno.h>
>
> -#include "utils/builtins.h"
> +#include "utils/inet.h"
>
> -#ifdef SPRINTF_CHAR
> -#define SPRINTF(x) strlen(sprintf/**/x)
> -#else
> -#define SPRINTF(x) ((size_t)sprintf x)
> -#endif
> +#include "utils/builtins.h"
>
> static int inet_net_pton_ipv4(const char *src, u_char *dst);
> static int inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size);
> +static int inet_net_pton_ipv6(const char *src, u_char *dst);
> +static int inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size);
>
> /*
> * static int
> @@ -63,10 +61,14 @@
> {
> switch (af)
> {
> - case AF_INET:
> + case PGSQL_AF_INET:
> return size == -1 ?
> inet_net_pton_ipv4(src, dst) :
> inet_cidr_pton_ipv4(src, dst, size);
> + case PGSQL_AF_INET6:
> + return size == -1 ?
> + inet_net_pton_ipv6(src, dst) :
> + inet_cidr_pton_ipv6(src, dst, size);
> default:
> errno = EAFNOSUPPORT;
> return (-1);
> @@ -335,3 +337,199 @@
> errno = EMSGSIZE;
> return (-1);
> }
> +
> +static int
> +getbits(const char *src, int *bitsp) {
> + static const char digits[] = "0123456789";
> + int n;
> + int val;
> + char ch;
> +
> + val = 0;
> + n = 0;
> + while ((ch = *src++) != '\0') {
> + const char *pch;
> +
> + pch = strchr(digits, ch);
> + if (pch != NULL) {
> + if (n++ != 0 && val == 0) /* no leading zeros */
> + return (0);
> + val *= 10;
> + val += (pch - digits);
> + if (val > 128) /* range */
> + return (0);
> + continue;
> + }
> + return (0);
> + }
> + if (n == 0)
> + return (0);
> + *bitsp = val;
> + return (1);
> +}
> +
> +static int
> +getv4(const char *src, u_char *dst, int *bitsp) {
> + static const char digits[] = "0123456789";
> + u_char *odst = dst;
> + int n;
> + u_int val;
> + char ch;
> +
> + val = 0;
> + n = 0;
> + while ((ch = *src++) != '\0') {
> + const char *pch;
> +
> + pch = strchr(digits, ch);
> + if (pch != NULL) {
> + if (n++ != 0 && val == 0) /* no leading zeros */
> + return (0);
> + val *= 10;
> + val += (pch - digits);
> + if (val > 255) /* range */
> + return (0);
> + continue;
> + }
> + if (ch == '.' || ch == '/') {
> + if (dst - odst > 3) /* too many octets? */
> + return (0);
> + *dst++ = val;
> + if (ch == '/')
> + return (getbits(src, bitsp));
> + val = 0;
> + n = 0;
> + continue;
> + }
> + return (0);
> + }
> + if (n == 0)
> + return (0);
> + if (dst - odst > 3) /* too many octets? */
> + return (0);
> + *dst++ = val;
> + return (1);
> +}
> +
> +static int
> +inet_net_pton_ipv6(const char *src, u_char *dst)
> +{
> + return inet_cidr_pton_ipv6(src, dst, 16);
> +}
> +
> +#define NS_IN6ADDRSZ 16
> +#define NS_INT16SZ 2
> +#define NS_INADDRSZ 4
> +
> +static int
> +inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size) {
> + static const char xdigits_l[] = "0123456789abcdef",
> + xdigits_u[] = "0123456789ABCDEF";
> + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
> + const char *xdigits, *curtok;
> + int ch, saw_xdigit;
> + u_int val;
> + int digits;
> + int bits;
> +
> + if (size < NS_IN6ADDRSZ)
> + goto emsgsize;
> +
> + memset((tp = tmp), '\0', NS_IN6ADDRSZ);
> + endp = tp + NS_IN6ADDRSZ;
> + colonp = NULL;
> + /* Leading :: requires some special handling. */
> + if (*src == ':')
> + if (*++src != ':')
> + goto enoent;
> + curtok = src;
> + saw_xdigit = 0;
> + val = 0;
> + digits = 0;
> + bits = -1;
> + while ((ch = *src++) != '\0') {
> + const char *pch;
> +
> + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
> + pch = strchr((xdigits = xdigits_u), ch);
> + if (pch != NULL) {
> + val <<= 4;
> + val |= (pch - xdigits);
> + if (++digits > 4)
> + goto enoent;
> + saw_xdigit = 1;
> + continue;
> + }
> + if (ch == ':') {
> + curtok = src;
> + if (!saw_xdigit) {
> + if (colonp)
> + goto enoent;
> + colonp = tp;
> + continue;
> + } else if (*src == '\0')
> + goto enoent;
> + if (tp + NS_INT16SZ > endp)
> + return (0);
> + *tp++ = (u_char) (val >> 8) & 0xff;
> + *tp++ = (u_char) val & 0xff;
> + saw_xdigit = 0;
> + digits = 0;
> + val = 0;
> + continue;
> + }
> + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
> + getv4(curtok, tp, &bits) > 0) {
> + tp += NS_INADDRSZ;
> + saw_xdigit = 0;
> + break; /* '\0' was seen by inet_pton4(). */
> + }
> + if (ch == '/' && getbits(src, &bits) > 0)
> + break;
> + goto enoent;
> + }
> + if (saw_xdigit) {
> + if (tp + NS_INT16SZ > endp)
> + goto enoent;
> + *tp++ = (u_char) (val >> 8) & 0xff;
> + *tp++ = (u_char) val & 0xff;
> + }
> + if (bits == -1)
> + bits = 128;
> +
> + endp = tmp + 16;
> +
> + if (colonp != NULL) {
> + /*
> + * Since some memmove()'s erroneously fail to handle
> + * overlapping regions, we'll do the shift by hand.
> + */
> + const int n = tp - colonp;
> + int i;
> +
> + if (tp == endp)
> + goto enoent;
> + for (i = 1; i <= n; i++) {
> + endp[- i] = colonp[n - i];
> + colonp[n - i] = 0;
> + }
> + tp = endp;
> + }
> + if (tp != endp)
> + goto enoent;
> +
> + /*
> + * Copy out the result.
> + */
> + memcpy(dst, tmp, NS_IN6ADDRSZ);
> +
> + return (bits);
> +
> + enoent:
> + errno = ENOENT;
> + return (-1);
> +
> + emsgsize:
> + errno = EMSGSIZE;
> + return (-1);
> +}
> diff -ur orig-postgresql-7.3.2/src/backend/utils/adt/network.c postgresql-7.3.2/src/backend/utils/adt/network.c
> --- orig-postgresql-7.3.2/src/backend/utils/adt/network.c 2002-09-01 19:47:04.000000000 -0700
> +++ postgresql-7.3.2/src/backend/utils/adt/network.c 2003-05-20 16:12:33.000000000 -0700
> @@ -1,7 +1,5 @@
> /*
> - * PostgreSQL type definitions for the INET type. This
> - * is for IP V4 CIDR notation, but prepared for V6: just
> - * add the necessary bits where the comments indicate.
> + * PostgreSQL type definitions for the INET and CIDR types.
> *
> * $Header: /cvsroot/pgsql-server/src/backend/utils/adt/network.c,v 1.35 2002/09/02 02:47:04 momjian Exp $
> *
> @@ -15,23 +13,22 @@
> #include <netinet/in.h>
> #include <arpa/inet.h>
>
> +#include <assert.h>
> +
> #include "catalog/pg_type.h"
> #include "utils/builtins.h"
> #include "utils/inet.h"
>
> -
> static Datum text_network(text *src, int type);
> static int32 network_cmp_internal(inet *a1, inet *a2);
> -static int v4bitncmp(unsigned long a1, unsigned long a2, int bits);
> -static bool v4addressOK(unsigned long a1, int bits);
> +static int bitncmp(void *l, void *r, int n);
> +static bool addressOK(unsigned char *a, int bits, int family);
> +static int ip_addrsize(inet *inetptr);
>
> /*
> - * Access macros. Add IPV6 support.
> + * Access macros.
> */
>
> -#define ip_addrsize(inetptr) \
> - (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : -1)
> -
> #define ip_family(inetptr) \
> (((inet_struct *)VARDATA(inetptr))->family)
>
> @@ -41,43 +38,70 @@
> #define ip_type(inetptr) \
> (((inet_struct *)VARDATA(inetptr))->type)
>
> -#define ip_v4addr(inetptr) \
> - (((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr)
> +#define ip_addr(inetptr) \
> + (((inet_struct *)VARDATA(inetptr))->ip_addr)
> +
> +#define ip_maxbits(inetptr) \
> + (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128)
> +
> +/*
> + * Now, as a function!
> + * Return the number of bytes of 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 -1;
> + }
> +}
>
> /* Common input routine */
> static inet *
> network_in(char *src, int type)
> {
> - int bits;
> + int bits;
> inet *dst;
>
> dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct));
> /* make sure any unused bits in a CIDR value are zeroed */
> MemSet(dst, 0, VARHDRSZ + sizeof(inet_struct));
>
> - /* First, try for an IP V4 address: */
> - ip_family(dst) = AF_INET;
> - bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst),
> - type ? ip_addrsize(dst) : -1);
> - if ((bits < 0) || (bits > 32))
> - {
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "invalid %s value '%s'",
> - type ? "CIDR" : "INET", src);
> + /*
> + * First, check to see if this is an IPv6 or IPv4 address. IPv6
> + * addresses will have a : somewhere in them (several, in fact) so
> + * if there is one present, assume it's V6, otherwise assume it's V4.
> + */
> +
> + if (strchr(src, ':') != NULL) {
> + ip_family(dst) = PGSQL_AF_INET6;
> + } else {
> + ip_family(dst) = PGSQL_AF_INET;
> }
>
> + bits = inet_net_pton(ip_family(dst), src, ip_addr(dst),
> + type ? ip_addrsize(dst) : -1);
> + if ((bits < 0) || (bits > ip_maxbits(dst)))
> + elog(ERROR, "invalid %s value '%s'",
> + type ? "CIDR" : "INET", src);
> +
> /*
> - * Error check: CIDR values must not have any bits set beyond the
> - * masklen. XXX this code is not IPV6 ready.
> + * Error check: CIDR values must not have any bits set beyond
> + * the masklen.
> */
> if (type)
> {
> - if (!v4addressOK(ip_v4addr(dst), bits))
> + if (!addressOK(ip_addr(dst), bits, ip_family(dst)))
> elog(ERROR, "invalid CIDR value '%s': has bits set to right of mask", src);
> }
>
> VARATT_SIZEP(dst) = VARHDRSZ
> - + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
> + + ((char *) &ip_addr(dst) - (char *) VARDATA(dst))
> + ip_addrsize(dst);
> ip_bits(dst) = bits;
> ip_type(dst) = type;
> @@ -110,32 +134,20 @@
> inet_out(PG_FUNCTION_ARGS)
> {
> inet *src = PG_GETARG_INET_P(0);
> - char tmp[sizeof("255.255.255.255/32")];
> + char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
> char *dst;
> int len;
>
> - if (ip_family(src) == AF_INET)
> + dst = inet_net_ntop(ip_family(src), ip_addr(src), ip_bits(src),
> + tmp, sizeof(tmp));
> + if (dst == NULL)
> + elog(ERROR, "unable to print address (%s)", strerror(errno));
> + /* For CIDR, add /n if not present */
> + if (ip_type(src) && strchr(tmp, '/') == NULL)
> {
> - /* It's an IP V4 address: */
> -
> - /*
> - * Use inet style for both inet and cidr, since we don't want
> - * abbreviated CIDR style here.
> - */
> - dst = inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
> - tmp, sizeof(tmp));
> - if (dst == NULL)
> - elog(ERROR, "unable to print address (%s)", strerror(errno));
> - /* For CIDR, add /n if not present */
> - if (ip_type(src) && strchr(tmp, '/') == NULL)
> - {
> - len = strlen(tmp);
> - snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src));
> - }
> + len = strlen(tmp);
> + snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src));
> }
> - else
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "unknown address family (%d)", ip_family(src));
>
> PG_RETURN_CSTRING(pstrdup(tmp));
> }
> @@ -162,6 +174,7 @@
> PG_RETURN_INET_P(network_in(str, type));
> }
>
> +
> Datum
> text_cidr(PG_FUNCTION_ARGS)
> {
> @@ -181,8 +194,11 @@
> int bits = PG_GETARG_INT32(1);
> inet *dst;
>
> - if ((bits < 0) || (bits > 32)) /* no support for v6 yet */
> - elog(ERROR, "set_masklen - invalid value '%d'", bits);
> + if ( bits == -1 )
> + bits = ip_maxbits(src);
> +
> + if ((bits < 0) || (bits > ip_maxbits(src)))
> + elog(ERROR, "set_masklen - invalid value '%d'", bits);
>
> /* clone the original data */
> dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct));
> @@ -207,26 +223,21 @@
> static int32
> network_cmp_internal(inet *a1, inet *a2)
> {
> - if (ip_family(a1) == AF_INET && ip_family(a2) == AF_INET)
> + if (ip_family(a1) == ip_family(a2))
> {
> int order;
>
> - order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2),
> - Min(ip_bits(a1), ip_bits(a2)));
> + order = bitncmp(ip_addr(a1), ip_addr(a2),
> + Min(ip_bits(a1), ip_bits(a2)));
> if (order != 0)
> return order;
> order = ((int) ip_bits(a1)) - ((int) ip_bits(a2));
> if (order != 0)
> return order;
> - return v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), 32);
> - }
> - else
> - {
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "cannot compare address families %d and %d",
> - ip_family(a1), ip_family(a2));
> - return 0; /* keep compiler quiet */
> + return bitncmp(ip_addr(a1), ip_addr(a2), ip_maxbits(a1));
> }
> +
> + return ip_family(a1) - ip_family(a2);
> }
>
> Datum
> @@ -304,18 +315,13 @@
> inet *a1 = PG_GETARG_INET_P(0);
> inet *a2 = PG_GETARG_INET_P(1);
>
> - if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
> + if (ip_family(a1) == ip_family(a2))
> {
> PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2)
> - && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0);
> - }
> - else
> - {
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "cannot compare address families %d and %d",
> - ip_family(a1), ip_family(a2));
> - PG_RETURN_BOOL(false);
> + && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0);
> }
> +
> + PG_RETURN_BOOL(false);
> }
>
> Datum
> @@ -324,18 +330,13 @@
> inet *a1 = PG_GETARG_INET_P(0);
> inet *a2 = PG_GETARG_INET_P(1);
>
> - if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
> + if (ip_family(a1) == ip_family(a2))
> {
> PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2)
> - && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0);
> - }
> - else
> - {
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "cannot compare address families %d and %d",
> - ip_family(a1), ip_family(a2));
> - PG_RETURN_BOOL(false);
> + && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0);
> }
> +
> + PG_RETURN_BOOL(false);
> }
>
> Datum
> @@ -344,18 +345,13 @@
> inet *a1 = PG_GETARG_INET_P(0);
> inet *a2 = PG_GETARG_INET_P(1);
>
> - if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
> + if (ip_family(a1) == ip_family(a2))
> {
> PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2)
> - && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0);
> - }
> - else
> - {
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "cannot compare address families %d and %d",
> - ip_family(a1), ip_family(a2));
> - PG_RETURN_BOOL(false);
> + && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0);
> }
> +
> + PG_RETURN_BOOL(false);
> }
>
> Datum
> @@ -364,18 +360,13 @@
> inet *a1 = PG_GETARG_INET_P(0);
> inet *a2 = PG_GETARG_INET_P(1);
>
> - if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
> + if (ip_family(a1) == ip_family(a2))
> {
> PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2)
> - && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0);
> - }
> - else
> - {
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "cannot compare address families %d and %d",
> - ip_family(a1), ip_family(a2));
> - PG_RETURN_BOOL(false);
> + && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0);
> }
> +
> + PG_RETURN_BOOL(false);
> }
>
> /*
> @@ -387,19 +378,13 @@
> inet *ip = PG_GETARG_INET_P(0);
> text *ret;
> int len;
> - char *ptr,
> - tmp[sizeof("255.255.255.255/32")];
> + char *ptr;
> + char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
>
> - 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));
> + /* force display of max bits, regardless of masklen... */
> + if (inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip),
> + tmp, sizeof(tmp)) == NULL)
> + elog(ERROR, "unable to print host (%s)", strerror(errno));
>
> /* Suppress /n if present (shouldn't happen now) */
> if ((ptr = strchr(tmp, '/')) != NULL)
> @@ -419,24 +404,17 @@
> inet *ip = PG_GETARG_INET_P(0);
> text *ret;
> int len;
> - char tmp[sizeof("255.255.255.255/32")];
> + char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
>
> - if (ip_family(ip) == AF_INET)
> + if (inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip),
> + tmp, sizeof(tmp)) == NULL)
> + elog(ERROR, "unable to print host (%s)", strerror(errno));
> + /* Add /n if not present (which it won't be) */
> + if (strchr(tmp, '/') == NULL)
> {
> - /* 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));
> - /* Add /n if not present (which it won't be) */
> - if (strchr(tmp, '/') == NULL)
> - {
> - len = strlen(tmp);
> - snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(ip));
> - }
> + len = strlen(tmp);
> + snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(ip));
> }
> - 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);
> @@ -453,24 +431,18 @@
> text *ret;
> char *dst;
> int len;
> - char tmp[sizeof("255.255.255.255/32")];
> -
> - if (ip_family(ip) == AF_INET)
> - {
> - /* It's an IP V4 address: */
> - if (ip_type(ip))
> - dst = inet_cidr_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip),
> - tmp, sizeof(tmp));
> - else
> - dst = inet_net_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip),
> - tmp, sizeof(tmp));
> + char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
>
> - if (dst == NULL)
> - elog(ERROR, "unable to print address (%s)", strerror(errno));
> - }
> - else
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "unknown address family (%d)", ip_family(ip));
> + if (ip_type(ip))
> + dst = inet_cidr_ntop(ip_family(ip), ip_addr(ip),
> + ip_bits(ip), tmp, sizeof(tmp));
> + else
> + dst = inet_net_ntop(ip_family(ip), ip_addr(ip),
> + ip_bits(ip), tmp, sizeof(tmp));
> +
> + if (dst == NULL)
> + elog(ERROR, "unable to print address (%s)",
> + strerror(errno));
>
> /* Return string as a text datum */
> len = strlen(tmp);
> @@ -489,40 +461,67 @@
> }
>
> Datum
> +network_family(PG_FUNCTION_ARGS)
> +{
> + inet *ip = PG_GETARG_INET_P(0);
> +
> + switch (ip_family(ip)) {
> + case PGSQL_AF_INET:
> + PG_RETURN_INT32(4);
> + break;
> + case PGSQL_AF_INET6:
> + PG_RETURN_INT32(6);
> + break;
> + default:
> + PG_RETURN_INT32(0);
> + break;
> + }
> +}
> +
> +Datum
> network_broadcast(PG_FUNCTION_ARGS)
> {
> inet *ip = PG_GETARG_INET_P(0);
> inet *dst;
> + int byte;
> + int bits;
> + int maxbytes;
> + unsigned char mask;
> + unsigned char *a, *b;
>
> 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: */
> - unsigned long mask = 0xffffffff;
> -
> - /*
> - * Shifting by 32 or more bits does not yield portable results, so
> - * don't try it.
> - */
> - if (ip_bits(ip) < 32)
> - mask >>= ip_bits(ip);
> - else
> - mask = 0;
> -
> - ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) | mask);
> + if (ip_family(ip) == PGSQL_AF_INET) {
> + maxbytes = 4;
> + } else {
> + maxbytes = 16;
> + }
> +
> + bits = ip_bits(ip);
> + a = ip_addr(ip);
> + b = ip_addr(dst);
> +
> + for (byte = 0 ; byte < maxbytes ; byte++) {
> + if (bits >= 8) {
> + mask = 0x00;
> + bits -= 8;
> + } else if (bits == 0) {
> + mask = 0xff;
> + } else {
> + mask = 0xff >> bits;
> + bits = 0;
> + }
> +
> + b[byte] = a[byte] | mask;
> }
> - else
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "unknown address family (%d)", ip_family(ip));
>
> 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))
> + + ((char *)ip_addr(dst) - (char *)VARDATA(dst))
> + ip_addrsize(dst);
>
> PG_RETURN_INET_P(dst);
> @@ -533,36 +532,45 @@
> {
> inet *ip = PG_GETARG_INET_P(0);
> inet *dst;
> + int byte;
> + int bits;
> + int maxbytes;
> + unsigned char mask;
> + unsigned char *a, *b;
>
> 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: */
> - unsigned long mask = 0xffffffff;
> -
> - /*
> - * Shifting by 32 or more bits does not yield portable results, so
> - * don't try it.
> - */
> - if (ip_bits(ip) > 0)
> - mask <<= (32 - ip_bits(ip));
> - else
> - mask = 0;
> -
> - ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) & mask);
> + if (ip_family(ip) == PGSQL_AF_INET) {
> + maxbytes = 4;
> + } else {
> + maxbytes = 16;
> + }
> +
> + bits = ip_bits(ip);
> + a = ip_addr(ip);
> + b = ip_addr(dst);
> +
> + byte = 0;
> + while (bits) {
> + if (bits >= 8) {
> + mask = 0xff;
> + bits -= 8;
> + } else {
> + mask = 0xff << (8 - bits);
> + bits = 0;
> + }
> +
> + b[byte] = a[byte] & mask;
> + byte++;
> }
> - else
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "unknown address family (%d)", ip_family(ip));
>
> 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))
> + + ((char *)ip_addr(dst) - (char *)VARDATA(dst))
> + ip_addrsize(dst);
>
> PG_RETURN_INET_P(dst);
> @@ -573,37 +581,44 @@
> {
> inet *ip = PG_GETARG_INET_P(0);
> inet *dst;
> + int byte;
> + int bits;
> + int maxbytes;
> + unsigned char mask;
> + unsigned char *b;
>
> 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: */
> - unsigned long mask = 0xffffffff;
> -
> - /*
> - * Shifting by 32 or more bits does not yield portable results, so
> - * don't try it.
> - */
> - if (ip_bits(ip) > 0)
> - mask <<= (32 - ip_bits(ip));
> - else
> - mask = 0;
> -
> - ip_v4addr(dst) = htonl(mask);
> -
> - ip_bits(dst) = 32;
> + if (ip_family(ip) == PGSQL_AF_INET) {
> + maxbytes = 4;
> + } else {
> + maxbytes = 16;
> + }
> +
> + bits = ip_bits(ip);
> + b = ip_addr(dst);
> +
> + byte = 0;
> + while (bits) {
> + if (bits >= 8) {
> + mask = 0xff;
> + bits -= 8;
> + } else {
> + mask = 0xff << (8 - bits);
> + bits = 0;
> + }
> +
> + b[byte] = mask;
> + byte++;
> }
> - else
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "unknown address family (%d)", ip_family(ip));
>
> 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))
> + + ((char *)ip_addr(dst) - (char *)VARDATA(dst))
> + ip_addrsize(dst);
>
> PG_RETURN_INET_P(dst);
> @@ -629,12 +644,26 @@
> case CIDROID:
> {
> inet *ip = DatumGetInetP(value);
> -
> - if (ip_family(ip) == AF_INET)
> - return (double) ip_v4addr(ip);
> + int len;
> + double res;
> + int i;
> +
> + /*
> + * Note that we don't use the full address
> + * here.
> + */
> + if (ip_family(ip) == PGSQL_AF_INET)
> + len = 4;
> else
> - /* Go for an IPV6 address here, before faulting out: */
> - elog(ERROR, "unknown address family (%d)", ip_family(ip));
> + len = 5;
> +
> + res = ip_family(ip);
> + for (i = 0 ; i < len ; i++) {
> + res *= 256;
> + res += ip_addr(ip)[i];
> + }
> + return res;
> +
> break;
> }
> case MACADDROID:
> @@ -657,53 +686,78 @@
> return 0;
> }
>
> -
> /*
> - * Bitwise comparison for V4 addresses. Add V6 implementation!
> + * int
> + * bitncmp(l, r, n)
> + * compare bit masks l and r, for n bits.
> + * return:
> + * -1, 1, or 0 in the libc tradition.
> + * note:
> + * network byte order assumed. this means 192.5.5.240/28 has
> + * 0x11110000 in its fourth octet.
> + * author:
> + * Paul Vixie (ISC), June 1996
> */
> -
> static int
> -v4bitncmp(unsigned long a1, unsigned long a2, int bits)
> +bitncmp(void *l, void *r, int n)
> {
> - unsigned long mask;
> + u_int lb, rb;
> + int x, b;
>
> - /*
> - * Shifting by 32 or more bits does not yield portable results, so
> - * don't try it.
> - */
> - if (bits > 0)
> - mask = (0xFFFFFFFFL << (32 - bits)) & 0xFFFFFFFFL;
> - else
> - mask = 0;
> - a1 = ntohl(a1);
> - a2 = ntohl(a2);
> - if ((a1 & mask) < (a2 & mask))
> - return (-1);
> - else if ((a1 & mask) > (a2 & mask))
> - return (1);
> + b = n / 8;
> + x = memcmp(l, r, b);
> + if (x)
> + return (x);
> +
> + lb = ((const u_char *)l)[b];
> + rb = ((const u_char *)r)[b];
> + for (b = n % 8; b > 0; b--) {
> + if ((lb & 0x80) != (rb & 0x80)) {
> + if (lb & 0x80)
> + return (1);
> + return (-1);
> + }
> + lb <<= 1;
> + rb <<= 1;
> + }
> return (0);
> }
>
> -/*
> - * Returns true if given address fits fully within the specified bit width.
> - */
> static bool
> -v4addressOK(unsigned long a1, int bits)
> +addressOK(unsigned char *a, int bits, int family)
> {
> - unsigned long mask;
> + int byte;
> + int nbits;
> + int maxbits;
> + int maxbytes;
> + unsigned char mask;
> +
> + if (family == PGSQL_AF_INET) {
> + maxbits = 32;
> + maxbytes = 4;
> + } else {
> + maxbits = 128;
> + maxbytes = 16;
> + }
> + assert(bits <= maxbits);
> +
> + if (bits == maxbits)
> + return 1;
> +
> + byte = (bits + 7) / 8;
> + nbits = bits % 8;
> + mask = 0xff;
> + if (bits != 0)
> + mask >>= nbits;
> +
> + while (byte < maxbytes) {
> + if ((a[byte] & mask) != 0)
> + return 0;
> + mask = 0xff;
> + byte++;
> + }
>
> - /*
> - * Shifting by 32 or more bits does not yield portable results, so
> - * don't try it.
> - */
> - if (bits > 0)
> - mask = (0xFFFFFFFFL << (32 - bits)) & 0xFFFFFFFFL;
> - else
> - mask = 0;
> - a1 = ntohl(a1);
> - if ((a1 & mask) == a1)
> - return true;
> - return false;
> + return 1;
> }
>
>
> @@ -721,15 +775,16 @@
>
> /*
> * return "last" IP on a given network. It's the broadcast address,
> - * however, masklen has to be set to 32, since
> + * however, masklen has to be set to its max btis, since
> * 192.168.0.255/24 is considered less than 192.168.0.255/32
> *
> - * NB: this is not IPv6 ready ...
> + * inet_set_masklen() hacked to max out the masklength to 128 for IPv6
> + * and 32 for IPv4 when given '-1' as argument.
> */
> Datum
> network_scan_last(Datum in)
> {
> return DirectFunctionCall2(inet_set_masklen,
> DirectFunctionCall1(network_broadcast, in),
> - Int32GetDatum(32));
> + Int32GetDatum(-1));
> }
> diff -ur orig-postgresql-7.3.2/src/include/catalog/pg_proc.h postgresql-7.3.2/src/include/catalog/pg_proc.h
> --- orig-postgresql-7.3.2/src/include/catalog/pg_proc.h 2002-11-02 10:41:22.000000000 -0800
> +++ postgresql-7.3.2/src/include/catalog/pg_proc.h 2003-04-22 13:02:07.000000000 -0700
> @@ -2353,6 +2353,8 @@
> DESCR("show address octets only");
> DATA(insert OID = 730 ( text PGNSP PGUID 12 f f t f i 1 25 "869" network_show - _null_ ));
> DESCR("show all parts of inet/cidr value");
> +DATA(insert OID = 731 ( family PGNSP PGUID 12 f f t f i 1 23 "869" network_family - _null_ ));
> +DESCR("return address family (4 for IPv4, 6 for IPv6)");
> DATA(insert OID = 1713 ( inet PGNSP PGUID 12 f f t f i 1 869 "25" text_inet - _null_ ));
> DESCR("text to inet");
> DATA(insert OID = 1714 ( cidr PGNSP PGUID 12 f f t f i 1 650 "25" text_cidr - _null_ ));
> diff -ur orig-postgresql-7.3.2/src/include/utils/builtins.h postgresql-7.3.2/src/include/utils/builtins.h
> --- orig-postgresql-7.3.2/src/include/utils/builtins.h 2002-11-02 10:41:22.000000000 -0800
> +++ postgresql-7.3.2/src/include/utils/builtins.h 2003-04-22 13:02:07.000000000 -0700
> @@ -566,6 +566,7 @@
> extern Datum network_network(PG_FUNCTION_ARGS);
> extern Datum network_netmask(PG_FUNCTION_ARGS);
> extern Datum network_masklen(PG_FUNCTION_ARGS);
> +extern Datum network_family(PG_FUNCTION_ARGS);
> extern Datum network_broadcast(PG_FUNCTION_ARGS);
> extern Datum network_host(PG_FUNCTION_ARGS);
> extern Datum network_show(PG_FUNCTION_ARGS);
> diff -ur orig-postgresql-7.3.2/src/include/utils/inet.h postgresql-7.3.2/src/include/utils/inet.h
> --- orig-postgresql-7.3.2/src/include/utils/inet.h 2002-06-20 13:29:53.000000000 -0700
> +++ postgresql-7.3.2/src/include/utils/inet.h 2003-04-22 13:02:07.000000000 -0700
> @@ -23,14 +23,20 @@
> unsigned char family;
> unsigned char bits;
> unsigned char type;
> - union
> - {
> - unsigned int ipv4_addr; /* network byte order */
> - /* add IPV6 address type here */
> - } addr;
> + unsigned char ip_addr[16]; /* 128 bits of address */
> } inet_struct;
>
> /*
> + * Referencing all of the non-AF_INET types to AF_INET lets us work on
> + * machines which may not have the appropriate address family (like
> + * inet6 addresses when AF_INET6 isn't present) but doesn't cause a
> + * dump/reload requirement. Existing databases used AF_INET for the family
> + * type on disk.
> + */
> +#define PGSQL_AF_INET (AF_INET + 0)
> +#define PGSQL_AF_INET6 (AF_INET + 1)
> +
> +/*
> * Both INET and CIDR addresses are represented within Postgres as varlena
> * objects, ie, there is a varlena header (basically a length word) in front
> * of the struct type depicted above.
> diff -ur orig-postgresql-7.3.2/src/test/regress/expected/inet.out postgresql-7.3.2/src/test/regress/expected/inet.out
> --- orig-postgresql-7.3.2/src/test/regress/expected/inet.out 2001-06-16 19:05:20.000000000 -0700
> +++ postgresql-7.3.2/src/test/regress/expected/inet.out 2003-04-22 16:48:02.000000000 -0700
> @@ -19,110 +19,132 @@
> INSERT INTO INET_TBL (c, i) VALUES ('10', '10.1.2.3/8');
> 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:23::f1', '10:23::f1/64');
> +INSERT INTO INET_TBL (c, i) VALUES ('10:23::8000/113', '10:23::ffff');
> +INSERT INTO INET_TBL (c, i) VALUES ('::ffff:1.2.3.4', '::4.3.2.1/24');
> -- 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': has bits set to right of mask
> +INSERT INTO INET_TBL (c, i) VALUES ('1234::1234::1234', '::1.2.3.4');
> +ERROR: invalid CIDR value '1234::1234::1234'
> -- check that CIDR rejects invalid input when converting from text:
> INSERT INTO INET_TBL (c, i) VALUES (cidr('192.168.1.2/24'), '192.168.1.226');
> ERROR: invalid CIDR value '192.168.1.2/24': has bits set to right of mask
> +INSERT INTO INET_TBL (c, i) VALUES (cidr('ffff:ffff:ffff:ffff::/24'), '::192.168.1.226');
> +ERROR: invalid CIDR value 'ffff:ffff:ffff:ffff::/24': has bits set to right of mask
> SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL;
> - ten | cidr | inet
> ------+----------------+------------------
> - | 192.168.1.0/24 | 192.168.1.226/24
> - | 192.168.1.0/24 | 192.168.1.226
> - | 192.168.1.0/24 | 192.168.1.0/24
> - | 192.168.1.0/24 | 192.168.1.0/25
> - | 192.168.1.0/24 | 192.168.1.255/24
> - | 192.168.1.0/24 | 192.168.1.255/25
> - | 10.0.0.0/8 | 10.1.2.3/8
> - | 10.0.0.0/32 | 10.1.2.3/8
> - | 10.1.2.3/32 | 10.1.2.3
> - | 10.1.2.0/24 | 10.1.2.3/24
> - | 10.1.0.0/16 | 10.1.2.3/16
> - | 10.0.0.0/8 | 10.1.2.3/8
> - | 10.0.0.0/8 | 11.1.2.3/8
> - | 10.0.0.0/8 | 9.1.2.3/8
> -(14 rows)
> + ten | cidr | inet
> +-----+--------------------+------------------
> + | 192.168.1.0/24 | 192.168.1.226/24
> + | 192.168.1.0/24 | 192.168.1.226
> + | 192.168.1.0/24 | 192.168.1.0/24
> + | 192.168.1.0/24 | 192.168.1.0/25
> + | 192.168.1.0/24 | 192.168.1.255/24
> + | 192.168.1.0/24 | 192.168.1.255/25
> + | 10.0.0.0/8 | 10.1.2.3/8
> + | 10.0.0.0/32 | 10.1.2.3/8
> + | 10.1.2.3/32 | 10.1.2.3
> + | 10.1.2.0/24 | 10.1.2.3/24
> + | 10.1.0.0/16 | 10.1.2.3/16
> + | 10.0.0.0/8 | 10.1.2.3/8
> + | 10.0.0.0/8 | 11.1.2.3/8
> + | 10.0.0.0/8 | 9.1.2.3/8
> + | 10:23::f1/128 | 10:23::f1/64
> + | 10:23::8000/113 | 10:23::ffff
> + | ::ffff:1.2.3.4/128 | ::4.3.2.1/24
> +(17 rows)
>
> -- now test some support functions
> -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
> - | 192.168.1.0/24 | 192.168.1.0 | 192.168.1.0/24
> - | 192.168.1.0/25 | 192.168.1.0 | 192.168.1.0/25
> - | 192.168.1.255/24 | 192.168.1.255 | 192.168.1.255/24
> - | 192.168.1.255/25 | 192.168.1.255 | 192.168.1.255/25
> - | 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
> -(14 rows)
> +SELECT '' AS ten, i AS inet, host(i), text(i), family(i) FROM INET_TBL;
> + ten | inet | host | text | family
> +-----+------------------+---------------+------------------+--------
> + | 192.168.1.226/24 | 192.168.1.226 | 192.168.1.226/24 | 4
> + | 192.168.1.226 | 192.168.1.226 | 192.168.1.226/32 | 4
> + | 192.168.1.0/24 | 192.168.1.0 | 192.168.1.0/24 | 4
> + | 192.168.1.0/25 | 192.168.1.0 | 192.168.1.0/25 | 4
> + | 192.168.1.255/24 | 192.168.1.255 | 192.168.1.255/24 | 4
> + | 192.168.1.255/25 | 192.168.1.255 | 192.168.1.255/25 | 4
> + | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 | 4
> + | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 | 4
> + | 10.1.2.3 | 10.1.2.3 | 10.1.2.3/32 | 4
> + | 10.1.2.3/24 | 10.1.2.3 | 10.1.2.3/24 | 4
> + | 10.1.2.3/16 | 10.1.2.3 | 10.1.2.3/16 | 4
> + | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 | 4
> + | 11.1.2.3/8 | 11.1.2.3 | 11.1.2.3/8 | 4
> + | 9.1.2.3/8 | 9.1.2.3 | 9.1.2.3/8 | 4
> + | 10:23::f1/64 | 10:23::f1 | 10:23::f1/64 | 6
> + | 10:23::ffff | 10:23::ffff | 10:23::ffff/128 | 6
> + | ::4.3.2.1/24 | ::4.3.2.1 | ::4.3.2.1/24 | 6
> +(17 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.0/24 | 192.168.1.255/24 | 192.168.1.226/24 | 192.168.1.255/24
> - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.226 | 192.168.1.226
> - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.255/24
> - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/25 | 192.168.1.127/25
> - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/24 | 192.168.1.255/24
> - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/25 | 192.168.1.255/25
> - | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8
> - | 10.0.0.0/32 | 10.0.0.0 | 10.1.2.3/8 | 10.255.255.255/8
> - | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3 | 10.1.2.3
> - | 10.1.2.0/24 | 10.1.2.255/24 | 10.1.2.3/24 | 10.1.2.255/24
> - | 10.1.0.0/16 | 10.1.255.255/16 | 10.1.2.3/16 | 10.1.255.255/16
> - | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8
> - | 10.0.0.0/8 | 10.255.255.255/8 | 11.1.2.3/8 | 11.255.255.255/8
> - | 10.0.0.0/8 | 10.255.255.255/8 | 9.1.2.3/8 | 9.255.255.255/8
> -(14 rows)
> + ten | cidr | broadcast | inet | broadcast
> +-----+--------------------+------------------+------------------+---------------------------------------
> + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.226/24 | 192.168.1.255/24
> + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.226 | 192.168.1.226
> + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.255/24
> + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/25 | 192.168.1.127/25
> + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/24 | 192.168.1.255/24
> + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/25 | 192.168.1.255/25
> + | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8
> + | 10.0.0.0/32 | 10.0.0.0 | 10.1.2.3/8 | 10.255.255.255/8
> + | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3 | 10.1.2.3
> + | 10.1.2.0/24 | 10.1.2.255/24 | 10.1.2.3/24 | 10.1.2.255/24
> + | 10.1.0.0/16 | 10.1.255.255/16 | 10.1.2.3/16 | 10.1.255.255/16
> + | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8
> + | 10.0.0.0/8 | 10.255.255.255/8 | 11.1.2.3/8 | 11.255.255.255/8
> + | 10.0.0.0/8 | 10.255.255.255/8 | 9.1.2.3/8 | 9.255.255.255/8
> + | 10:23::f1/128 | 10:23::f1 | 10:23::f1/64 | 10:23::ffff:ffff:ffff:ffff/64
> + | 10:23::8000/113 | 10:23::ffff/113 | 10:23::ffff | 10:23::ffff
> + | ::ffff:1.2.3.4/128 | ::ffff:1.2.3.4 | ::4.3.2.1/24 | 0:ff:ffff:ffff:ffff:ffff:ffff:ffff/24
> +(17 rows)
>
> SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)",
> i AS inet, network(i) AS "network(inet)" FROM INET_TBL;
> - ten | cidr | network(cidr) | inet | network(inet)
> ------+----------------+----------------+------------------+------------------
> - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226/24 | 192.168.1.0/24
> - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226 | 192.168.1.226/32
> - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24
> - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/25 | 192.168.1.0/25
> - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24
> - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/25 | 192.168.1.128/25
> - | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8
> - | 10.0.0.0/32 | 10.0.0.0/32 | 10.1.2.3/8 | 10.0.0.0/8
> - | 10.1.2.3/32 | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3/32
> - | 10.1.2.0/24 | 10.1.2.0/24 | 10.1.2.3/24 | 10.1.2.0/24
> - | 10.1.0.0/16 | 10.1.0.0/16 | 10.1.2.3/16 | 10.1.0.0/16
> - | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8
> - | 10.0.0.0/8 | 10.0.0.0/8 | 11.1.2.3/8 | 11.0.0.0/8
> - | 10.0.0.0/8 | 10.0.0.0/8 | 9.1.2.3/8 | 9.0.0.0/8
> -(14 rows)
> + ten | cidr | network(cidr) | inet | network(inet)
> +-----+--------------------+--------------------+------------------+------------------
> + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226/24 | 192.168.1.0/24
> + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226 | 192.168.1.226/32
> + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24
> + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/25 | 192.168.1.0/25
> + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24
> + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/25 | 192.168.1.128/25
> + | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8
> + | 10.0.0.0/32 | 10.0.0.0/32 | 10.1.2.3/8 | 10.0.0.0/8
> + | 10.1.2.3/32 | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3/32
> + | 10.1.2.0/24 | 10.1.2.0/24 | 10.1.2.3/24 | 10.1.2.0/24
> + | 10.1.0.0/16 | 10.1.0.0/16 | 10.1.2.3/16 | 10.1.0.0/16
> + | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8
> + | 10.0.0.0/8 | 10.0.0.0/8 | 11.1.2.3/8 | 11.0.0.0/8
> + | 10.0.0.0/8 | 10.0.0.0/8 | 9.1.2.3/8 | 9.0.0.0/8
> + | 10:23::f1/128 | 10:23::f1/128 | 10:23::f1/64 | 10:23::/64
> + | 10:23::8000/113 | 10:23::8000/113 | 10:23::ffff | 10:23::ffff/128
> + | ::ffff:1.2.3.4/128 | ::ffff:1.2.3.4/128 | ::4.3.2.1/24 | ::/24
> +(17 rows)
>
> SELECT '' AS ten, c AS cidr, masklen(c) AS "masklen(cidr)",
> i AS inet, masklen(i) AS "masklen(inet)" FROM INET_TBL;
> - ten | cidr | masklen(cidr) | inet | masklen(inet)
> ------+----------------+---------------+------------------+---------------
> - | 192.168.1.0/24 | 24 | 192.168.1.226/24 | 24
> - | 192.168.1.0/24 | 24 | 192.168.1.226 | 32
> - | 192.168.1.0/24 | 24 | 192.168.1.0/24 | 24
> - | 192.168.1.0/24 | 24 | 192.168.1.0/25 | 25
> - | 192.168.1.0/24 | 24 | 192.168.1.255/24 | 24
> - | 192.168.1.0/24 | 24 | 192.168.1.255/25 | 25
> - | 10.0.0.0/8 | 8 | 10.1.2.3/8 | 8
> - | 10.0.0.0/32 | 32 | 10.1.2.3/8 | 8
> - | 10.1.2.3/32 | 32 | 10.1.2.3 | 32
> - | 10.1.2.0/24 | 24 | 10.1.2.3/24 | 24
> - | 10.1.0.0/16 | 16 | 10.1.2.3/16 | 16
> - | 10.0.0.0/8 | 8 | 10.1.2.3/8 | 8
> - | 10.0.0.0/8 | 8 | 11.1.2.3/8 | 8
> - | 10.0.0.0/8 | 8 | 9.1.2.3/8 | 8
> -(14 rows)
> + ten | cidr | masklen(cidr) | inet | masklen(inet)
> +-----+--------------------+---------------+------------------+---------------
> + | 192.168.1.0/24 | 24 | 192.168.1.226/24 | 24
> + | 192.168.1.0/24 | 24 | 192.168.1.226 | 32
> + | 192.168.1.0/24 | 24 | 192.168.1.0/24 | 24
> + | 192.168.1.0/24 | 24 | 192.168.1.0/25 | 25
> + | 192.168.1.0/24 | 24 | 192.168.1.255/24 | 24
> + | 192.168.1.0/24 | 24 | 192.168.1.255/25 | 25
> + | 10.0.0.0/8 | 8 | 10.1.2.3/8 | 8
> + | 10.0.0.0/32 | 32 | 10.1.2.3/8 | 8
> + | 10.1.2.3/32 | 32 | 10.1.2.3 | 32
> + | 10.1.2.0/24 | 24 | 10.1.2.3/24 | 24
> + | 10.1.0.0/16 | 16 | 10.1.2.3/16 | 16
> + | 10.0.0.0/8 | 8 | 10.1.2.3/8 | 8
> + | 10.0.0.0/8 | 8 | 11.1.2.3/8 | 8
> + | 10.0.0.0/8 | 8 | 9.1.2.3/8 | 8
> + | 10:23::f1/128 | 128 | 10:23::f1/64 | 64
> + | 10:23::8000/113 | 113 | 10:23::ffff | 128
> + | ::ffff:1.2.3.4/128 | 128 | ::4.3.2.1/24 | 24
> +(17 rows)
>
> SELECT '' AS four, c AS cidr, masklen(c) AS "masklen(cidr)",
> i AS inet, masklen(i) AS "masklen(inet)" FROM INET_TBL
> @@ -149,23 +171,26 @@
> i << c AS sb, i <<= c AS sbe,
> i >> c AS sup, i >>= c AS spe
> FROM INET_TBL;
> - ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe
> ------+------------------+----------------+----+----+----+----+----+----+----+-----+-----+-----
> - | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t
> - | 192.168.1.226 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f
> - | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t
> - | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f
> - | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t
> - | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f
> - | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t
> - | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t
> - | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t
> - | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t
> - | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t
> - | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t
> - | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f
> - | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f
> -(14 rows)
> + ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe
> +-----+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+-----
> + | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t
> + | 192.168.1.226 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f
> + | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t
> + | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f
> + | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t
> + | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f
> + | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t
> + | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t
> + | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t
> + | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t
> + | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t
> + | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t
> + | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f
> + | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f
> + | 10:23::f1/64 | 10:23::f1/128 | t | t | f | f | f | t | f | f | t | t
> + | 10:23::ffff | 10:23::8000/113 | f | f | f | t | t | t | t | t | f | f
> + | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t
> +(17 rows)
>
> -- check the conversion to/from text and set_netmask
> select '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL;
> @@ -185,7 +210,10 @@
> | 10.1.2.3/24
> | 11.1.2.3/24
> | 9.1.2.3/24
> -(14 rows)
> + | 10:23::f1/24
> + | 10:23::ffff/24
> + | ::4.3.2.1/24
> +(17 rows)
>
> -- check that index works correctly
> create index inet_idx1 on inet_tbl(i);
> diff -ur orig-postgresql-7.3.2/src/test/regress/sql/inet.sql postgresql-7.3.2/src/test/regress/sql/inet.sql
> --- orig-postgresql-7.3.2/src/test/regress/sql/inet.sql 2001-06-16 19:05:20.000000000 -0700
> +++ postgresql-7.3.2/src/test/regress/sql/inet.sql 2003-04-22 13:25:24.000000000 -0700
> @@ -20,16 +20,20 @@
> INSERT INTO INET_TBL (c, i) VALUES ('10', '10.1.2.3/8');
> 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:23::f1', '10:23::f1/64');
> +INSERT INTO INET_TBL (c, i) VALUES ('10:23::8000/113', '10:23::ffff');
> +INSERT INTO INET_TBL (c, i) VALUES ('::ffff:1.2.3.4', '::4.3.2.1/24');
> -- 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 ('1234::1234::1234', '::1.2.3.4');
> -- check that CIDR rejects invalid input when converting from text:
> INSERT INTO INET_TBL (c, i) VALUES (cidr('192.168.1.2/24'), '192.168.1.226');
> -
> +INSERT INTO INET_TBL (c, i) VALUES (cidr('ffff:ffff:ffff:ffff::/24'), '::192.168.1.226');
> 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), text(i) FROM INET_TBL;
> +SELECT '' AS ten, i AS inet, host(i), text(i), family(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)",
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
>
> http://archives.postgresql.org
>

--
Bruce Momjian | http://candle.pha.pa.us
pgman(at)candle(dot)pha(dot)pa(dot)us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073

In response to

Browse pgsql-patches by date

  From Date Subject
Next Message Bruce Momjian 2003-05-31 02:20:12 Re: Slightly improved SSL bits...
Previous Message Bruce Momjian 2003-05-31 01:26:33 Re: FK on update no action patch