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: