aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/inet_net_ntop.c288
-rw-r--r--src/backend/utils/adt/inet_net_pton.c214
-rw-r--r--src/backend/utils/adt/network.c608
-rw-r--r--src/include/catalog/pg_proc.h4
-rw-r--r--src/include/utils/builtins.h3
-rw-r--r--src/include/utils/inet.h18
-rw-r--r--src/test/regress/expected/inet.out236
-rw-r--r--src/test/regress/sql/inet.sql8
8 files changed, 979 insertions, 400 deletions
diff --git a/src/backend/utils/adt/inet_net_ntop.c b/src/backend/utils/adt/inet_net_ntop.c
index 1cf0dcec2bd..a355e402cb2 100644
--- a/src/backend/utils/adt/inet_net_ntop.c
+++ b/src/backend/utils/adt/inet_net_ntop.c
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.12 2002/09/02 02:47:04 momjian Exp $";
+static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.13 2003/06/24 22:21:22 momjian Exp $";
#endif
#include "postgres.h"
@@ -27,8 +27,12 @@ static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.12 2002/09/02 02:47:04 mom
#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 @@ static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.12 2002/09/02 02:47:04 mom
#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 @@ inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
{
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 @@ emsgsize:
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 @@ inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
{
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 @@ emsgsize:
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 --git a/src/backend/utils/adt/inet_net_pton.c b/src/backend/utils/adt/inet_net_pton.c
index 2df36de1e9d..4c7ca9d618a 100644
--- a/src/backend/utils/adt/inet_net_pton.c
+++ b/src/backend/utils/adt/inet_net_pton.c
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_net_pton.c,v 1.14 2002/09/02 02:47:04 momjian Exp $";
+static const char rcsid[] = "$Id: inet_net_pton.c,v 1.15 2003/06/24 22:21:22 momjian Exp $";
#endif
#include "postgres.h"
@@ -29,16 +29,14 @@ static const char rcsid[] = "$Id: inet_net_pton.c,v 1.14 2002/09/02 02:47:04 mom
#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 @@ inet_net_pton(int af, const char *src, void *dst, size_t size)
{
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 @@ emsgsize:
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 --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index 3bc645c988b..213bf5d2f66 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -1,9 +1,7 @@
/*
- * 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/src/backend/utils/adt/network.c,v 1.41 2003/05/13 18:03:07 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.42 2003/06/24 22:21:22 momjian Exp $
*
* Jon Postel RIP 16 Oct 1998
*/
@@ -23,16 +21,14 @@
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)
@@ -42,42 +38,68 @@ static bool v4addressOK(unsigned long a1, int bits);
#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;
- /* make sure any unused bits in a CIDR value are zeroed */
dst = (inet *) palloc0(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);
- }
-
/*
- * Error check: CIDR values must not have any bits set beyond the
- * masklen. XXX this code is not IPV6 ready.
+ * 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 (type)
+
+ 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.
+ */
+ 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 +132,20 @@ Datum
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));
}
@@ -172,7 +182,7 @@ inet_recv(PG_FUNCTION_ARGS)
if (ip_family(addr) != AF_INET)
elog(ERROR, "Invalid family in external inet");
bits = pq_getmsgbyte(buf);
- if (bits < 0 || bits > 32)
+ if (bits < 0 || bits > ip_maxbits(addr))
elog(ERROR, "Invalid bits in external inet");
ip_bits(addr) = bits;
ip_type(addr) = pq_getmsgbyte(buf);
@@ -183,10 +193,10 @@ inet_recv(PG_FUNCTION_ARGS)
elog(ERROR, "Invalid length in external inet");
VARATT_SIZEP(addr) = VARHDRSZ
- + ((char *) &ip_v4addr(addr) - (char *) VARDATA(addr))
+ + ((char *)ip_addr(addr) - (char *) VARDATA(addr))
+ ip_addrsize(addr);
- addrptr = (char *) &ip_v4addr(addr);
+ addrptr = (char *)ip_addr(addr);
for (i = 0; i < nb; i++)
addrptr[i] = pq_getmsgbyte(buf);
@@ -196,7 +206,7 @@ inet_recv(PG_FUNCTION_ARGS)
*/
if (ip_type(addr))
{
- if (!v4addressOK(ip_v4addr(addr), bits))
+ if (!addressOK(ip_addr(addr), bits, ip_family(addr)))
elog(ERROR, "invalid external CIDR value: has bits set to right of mask");
}
@@ -230,7 +240,7 @@ inet_send(PG_FUNCTION_ARGS)
if (nb < 0)
nb = 0;
pq_sendbyte(&buf, nb);
- addrptr = (char *) &ip_v4addr(addr);
+ addrptr = (char *)ip_addr(addr);
for (i = 0; i < nb; i++)
pq_sendbyte(&buf, addrptr[i]);
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
@@ -257,6 +267,7 @@ text_network(text *src, int type)
PG_RETURN_INET_P(network_in(str, type));
}
+
Datum
text_cidr(PG_FUNCTION_ARGS)
{
@@ -276,8 +287,11 @@ inet_set_masklen(PG_FUNCTION_ARGS)
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));
@@ -302,26 +316,21 @@ inet_set_masklen(PG_FUNCTION_ARGS)
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
@@ -399,18 +408,13 @@ network_sub(PG_FUNCTION_ARGS)
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
@@ -419,18 +423,13 @@ network_subeq(PG_FUNCTION_ARGS)
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
@@ -439,18 +438,13 @@ network_sup(PG_FUNCTION_ARGS)
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
@@ -459,18 +453,13 @@ network_supeq(PG_FUNCTION_ARGS)
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);
}
/*
@@ -482,19 +471,13 @@ network_host(PG_FUNCTION_ARGS)
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)
@@ -514,24 +497,17 @@ network_show(PG_FUNCTION_ARGS)
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);
@@ -548,24 +524,18 @@ network_abbrev(PG_FUNCTION_ARGS)
text *ret;
char *dst;
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)
- {
- /* 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));
-
- if (dst == NULL)
- elog(ERROR, "unable to print address (%s)", strerror(errno));
- }
+ if (ip_type(ip))
+ dst = inet_cidr_ntop(ip_family(ip), ip_addr(ip),
+ ip_bits(ip), tmp, sizeof(tmp));
else
- /* Go for an IPV6 address here, before faulting out: */
- elog(ERROR, "unknown address family (%d)", ip_family(ip));
+ 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);
@@ -584,39 +554,66 @@ network_masklen(PG_FUNCTION_ARGS)
}
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;
/* make sure any unused bits are zeroed */
dst = (inet *) palloc0(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;
}
- else
- /* Go for an IPV6 address here, before faulting out: */
- elog(ERROR, "unknown address family (%d)", ip_family(ip));
+
+ 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;
+ }
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);
@@ -627,35 +624,44 @@ network_network(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;
/* make sure any unused bits are zeroed */
dst = (inet *) palloc0(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;
}
- else
- /* Go for an IPV6 address here, before faulting out: */
- elog(ERROR, "unknown address family (%d)", ip_family(ip));
+
+ 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++;
+ }
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);
@@ -666,36 +672,43 @@ network_netmask(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
inet *dst;
+ int byte;
+ int bits;
+ int maxbytes;
+ unsigned char mask;
+ unsigned char *b;
/* make sure any unused bits are zeroed */
dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
- if (ip_family(ip) == AF_INET)
- {
- /* It's an IP V4 address: */
- unsigned long mask = 0xffffffff;
+ if (ip_family(ip) == PGSQL_AF_INET) {
+ maxbytes = 4;
+ } else {
+ maxbytes = 16;
+ }
- /*
- * 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;
+ 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;
+ }
- ip_v4addr(dst) = htonl(mask);
-
- ip_bits(dst) = 32;
- }
- else
- /* Go for an IPV6 address here, before faulting out: */
- elog(ERROR, "unknown address family (%d)", ip_family(ip));
+ b[byte] = mask;
+ byte++;
+ }
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);
@@ -706,36 +719,43 @@ network_hostmask(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
inet *dst;
+ int byte;
+ int bits;
+ int maxbytes;
+ unsigned char mask;
+ unsigned char *b;
/* make sure any unused bits are zeroed */
dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
- if (ip_family(ip) == AF_INET)
- {
- /* It's an IP V4 address: */
- unsigned long mask = 0xffffffff;
-
- /*
- * Only shift if the mask len is < 32 bits ..
- */
-
- if (ip_bits(ip) < 32)
- mask >>= ip_bits(ip);
- else
- mask = 0;
+ if (ip_family(ip) == PGSQL_AF_INET) {
+ maxbytes = 4;
+ } else {
+ maxbytes = 16;
+ }
- ip_v4addr(dst) = htonl(mask);
+ bits = ip_maxbits(ip) - ip_bits(ip);
+ b = ip_addr(dst);
+
+ byte = maxbytes - 1;
+ while (bits) {
+ if (bits >= 8) {
+ mask = 0xff;
+ bits -= 8;
+ } else {
+ mask = 0xff >> (8 - bits);
+ bits = 0;
+ }
- ip_bits(dst) = 32;
- }
- else
- /* Go for an IPV6 address here, before faulting out: */
- elog(ERROR, "unknown address family (%d)", ip_family(ip));
+ b[byte] = mask;
+ byte--;
+ }
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);
@@ -760,12 +780,26 @@ convert_network_to_scalar(Datum value, Oid typid)
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:
@@ -788,53 +822,80 @@ convert_network_to_scalar(Datum value, Oid typid)
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)
-{
- unsigned long mask;
-
- /*
- * 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);
+bitncmp(void *l, void *r, int n)
+{
+ u_int lb, rb;
+ int x, b;
+
+ 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)
-{
- unsigned long mask;
+addressOK(unsigned char *a, int bits, int family)
+{
+ 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;
+ }
+#if 0
+ assert(bits <= maxbits);
+#endif
+
+ 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;
}
@@ -852,15 +913,16 @@ network_scan_first(Datum in)
/*
* 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 --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 6cf727cc64b..80d80b59397 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_proc.h,v 1.304 2003/06/22 22:04:55 tgl Exp $
+ * $Id: pg_proc.h,v 1.305 2003/06/24 22:21:23 momjian Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@@ -2369,6 +2369,8 @@ DESCR("is-supernet-or-equal");
/* inet/cidr functions */
DATA(insert OID = 605 ( abbrev PGNSP PGUID 12 f f t f i 1 25 "869" network_abbrev - _null_ ));
DESCR("abbreviated display of inet/cidr value");
+DATA(insert OID = 711 ( 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 = 683 ( network PGNSP PGUID 12 f f t f i 1 650 "869" network_network - _null_ ));
DESCR("network part of address");
DATA(insert OID = 696 ( netmask PGNSP PGUID 12 f f t f i 1 869 "869" network_netmask - _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 42e9a84c77b..099b1ffa378 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: builtins.h,v 1.219 2003/05/26 00:11:28 tgl Exp $
+ * $Id: builtins.h,v 1.220 2003/06/24 22:21:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -644,6 +644,7 @@ extern Datum network_network(PG_FUNCTION_ARGS);
extern Datum network_netmask(PG_FUNCTION_ARGS);
extern Datum network_hostmask(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 --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index c5a100a54d9..dd6df6d56da 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: inet.h,v 1.13 2002/06/20 20:29:53 momjian Exp $
+ * $Id: inet.h,v 1.14 2003/06/24 22:21:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,14 +23,20 @@ typedef struct
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 --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index 59983f5f23c..e4295923281 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -19,110 +19,132 @@ INSERT INTO INET_TBL (c, i) VALUES ('10.1', '10.1.2.3/16');
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 @@ SELECT '' AS ten, i, c,
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 @@ SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL;
| 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 --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index d62337d4d42..ecae68f6e9a 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -20,16 +20,20 @@ INSERT INTO INET_TBL (c, i) VALUES ('10.1', '10.1.2.3/16');
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)",