Re: ipv6 patch #3 - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: ipv6 patch #3
Date
Msg-id 200305310215.h4V2FMx10958@candle.pha.pa.us
Whole thread Raw
In response to ipv6 patch #3  (Michael Graff <explorer@flame.org>)
List 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' < inet '192.168.1.6'</literal></entry>
>         </row>
>         <row>
> +    <entry> < </entry>
> +    <entry>Less than</entry>
> +    <entry><literal>inet '1111::2222' < inet '2222::1111'</literal></entry>
> +       </row>
> +       <row>
>      <entry> <= </entry>
>      <entry>Less than or equal</entry>
>      <entry><literal>inet '192.168.1.5' <= 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@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: FK on update no action patch
Next
From: Bruce Momjian
Date:
Subject: Re: Slightly improved SSL bits...